fix(console): initialize org owner with or without password (#471)

* set password validators only if needed

* create org initialize without pwd

* no caps

* self xss message
This commit is contained in:
Max Peintner
2020-07-15 09:04:45 +02:00
committed by GitHub
parent c051fa8ae1
commit 30282acb42
11 changed files with 148 additions and 113 deletions

View File

@@ -155,7 +155,7 @@ export class AppComponent implements OnDestroy {
update: UpdateService, update: UpdateService,
) { ) {
console.log('%cWait!', 'text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; color: #5282c1; font-size: 50px'); console.log('%cWait!', 'text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; color: #5282c1; font-size: 50px');
console.log('%cInserting something here could give attackers access to your caos account.', 'color: red; font-size: 18px'); console.log('%cInserting something here could give attackers access to your zitadel account.', 'color: red; font-size: 18px');
console.log('%cIf you don\'t know exactly what you\'re doing, close the window and stay on the safe side', 'font-size: 16px'); console.log('%cIf you don\'t know exactly what you\'re doing, close the window and stay on the safe side', 'font-size: 16px');
console.log('%cIf you know exactly what you are doing, you should work for us', 'font-size: 16px'); console.log('%cIf you know exactly what you are doing, you should work for us', 'font-size: 16px');
this.setLanguage(); this.setLanguage();

View File

@@ -10,7 +10,7 @@
<ng-container *ngIf="currentCreateStep == 1"> <ng-container *ngIf="currentCreateStep == 1">
<h1>{{'ORG.PAGES.ORGDETAIL_TITLE' | translate}}</h1> <h1>{{'ORG.PAGES.ORGDETAIL_TITLE' | translate}}</h1>
<form [formGroup]="orgForm"> <form [formGroup]="orgForm" (ngSubmit)="next()">
<div class="content"> <div class="content">
<mat-form-field class="formfield"> <mat-form-field class="formfield">
<mat-label>{{ 'ORG_DETAIL.DETAIL.NAME' | translate }}</mat-label> <mat-label>{{ 'ORG_DETAIL.DETAIL.NAME' | translate }}</mat-label>
@@ -21,6 +21,11 @@
<input matInput formControlName="domain" /> <input matInput formControlName="domain" />
</mat-form-field> </mat-form-field>
</div> </div>
<button [disabled]="orgForm.invalid" color="primary" mat-raised-button class="continue-button"
cdkFocusInitial type="submit">
{{'CONTINUE' | translate}}
</button>
</form> </form>
<!-- <div *ngIf="name?.touched" @openClose> <!-- <div *ngIf="name?.touched" @openClose>
@@ -107,61 +112,66 @@
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<p class="section">{{ 'USER.CREATE.PASSWORDSECTION' | translate }}</p> <mat-checkbox [(ngModel)]="usePassword" [ngModelOptions]="{standalone: true}"
(change)="initPwdValidators()">
{{'ORG.PAGES.USEPASSWORD' | translate}}</mat-checkbox>
<mat-form-field class="formfield"> <ng-container *ngIf="usePassword">
<mat-label>{{ 'USER.PASSWORD.NEW' | translate }}</mat-label> <p class="section">{{ 'USER.CREATE.PASSWORDSECTION' | translate }}</p>
<input autocomplete="off" name="firstpassword" matInput formControlName="password"
type="password" />
<mat-error *ngIf="password?.errors?.required"> <mat-form-field class="formfield" *ngIf="password">
{{ 'USER.VALIDATION.REQUIRED' | translate }} <mat-label>{{ 'USER.PASSWORD.NEW' | translate }}</mat-label>
</mat-error> <input autocomplete="off" name="firstpassword" matInput formControlName="password"
<mat-error *ngIf="password?.errors?.symbolValidator"> type="password" />
{{ 'USER.VALIDATION.SYMBOLERROR' | translate }}
</mat-error> <mat-error *ngIf="password?.errors?.required">
<mat-error *ngIf="password?.errors?.numberValidator"> {{ 'USER.VALIDATION.REQUIRED' | translate }}
{{ 'USER.VALIDATION.NUMBERERROR' | translate }} </mat-error>
</mat-error> <mat-error *ngIf="password?.errors?.symbolValidator">
<mat-error *ngIf="password?.errors?.upperCaseValidator"> {{ 'USER.VALIDATION.SYMBOLERROR' | translate }}
{{ 'USER.VALIDATION.UPPERCASEMISSING' | translate }} </mat-error>
</mat-error> <mat-error *ngIf="password?.errors?.numberValidator">
<mat-error *ngIf="password?.errors?.lowerCaseValidator"> {{ 'USER.VALIDATION.NUMBERERROR' | translate }}
{{ 'USER.VALIDATION.LOWERCASEMISSING' | translate }} </mat-error>
</mat-error> <mat-error *ngIf="password?.errors?.upperCaseValidator">
<mat-error *ngIf="password?.errors?.minlength"> {{ 'USER.VALIDATION.UPPERCASEMISSING' | translate }}
{{ 'USER.VALIDATION.MINLENGTH' | translate:password?.errors?.minlength }} </mat-error>
</mat-error> <mat-error *ngIf="password?.errors?.lowerCaseValidator">
</mat-form-field> {{ 'USER.VALIDATION.LOWERCASEMISSING' | translate }}
<mat-form-field class="formfield"> </mat-error>
<mat-label>{{ 'USER.PASSWORD.CONFIRM' | translate }}</mat-label> <mat-error *ngIf="password?.errors?.minlength">
<input autocomplete="off" name="confirmPassword" matInput formControlName="confirmPassword" {{ 'USER.VALIDATION.MINLENGTH' | translate:password?.errors?.minlength }}
type="password" /> </mat-error>
</mat-form-field>
<mat-form-field class="formfield" *ngIf="confirmPassword">
<mat-label>{{ 'USER.PASSWORD.CONFIRM' | translate }}</mat-label>
<input autocomplete="off" name="confirmPassword" matInput formControlName="confirmPassword"
type="password" />
<mat-error *ngIf="confirmPassword?.errors?.required"> <mat-error *ngIf="confirmPassword?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }} {{ 'USER.VALIDATION.REQUIRED' | translate }}
</mat-error> </mat-error>
<mat-error *ngIf="confirmPassword?.errors?.symbolValidator"> <mat-error *ngIf="confirmPassword?.errors?.symbolValidator">
{{ 'USER.VALIDATION.SYMBOLERROR' | translate }} {{ 'USER.VALIDATION.SYMBOLERROR' | translate }}
</mat-error> </mat-error>
<mat-error *ngIf="confirmPassword?.errors?.numberValidator"> <mat-error *ngIf="confirmPassword?.errors?.numberValidator">
{{ 'USER.VALIDATION.NUMBERERROR' | translate }} {{ 'USER.VALIDATION.NUMBERERROR' | translate }}
</mat-error> </mat-error>
<mat-error *ngIf="confirmPassword?.errors?.notequal"> <mat-error *ngIf="confirmPassword?.errors?.notequal">
{{ 'USER.PASSWORD.NOTEQUAL' | translate }} {{ 'USER.PASSWORD.NOTEQUAL' | translate }}
</mat-error> </mat-error>
<mat-error *ngIf="confirmPassword?.errors?.upperCaseValidator"> <mat-error *ngIf="confirmPassword?.errors?.upperCaseValidator">
{{ 'USER.VALIDATION.UPPERCASEMISSING' | translate }} {{ 'USER.VALIDATION.UPPERCASEMISSING' | translate }}
</mat-error> </mat-error>
<mat-error *ngIf="confirmPassword?.errors?.lowerCaseValidator"> <mat-error *ngIf="confirmPassword?.errors?.lowerCaseValidator">
{{ 'USER.VALIDATION.LOWERCASEMISSING' | translate }} {{ 'USER.VALIDATION.LOWERCASEMISSING' | translate }}
</mat-error> </mat-error>
<mat-error *ngIf="confirmPassword?.errors?.minlength"> <mat-error *ngIf="confirmPassword?.errors?.minlength">
{{ 'USER.VALIDATION.MINLENGTH' | translate:confirmPassword?.errors?.minlength }} {{ 'USER.VALIDATION.MINLENGTH' | translate:confirmPassword?.errors?.minlength }}
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
</ng-container>
</div> </div>
<div class="btn-container"> <div class="btn-container">
<button color="primary" class="continue-button" [disabled]="orgForm.invalid || userForm.invalid" <button color="primary" class="continue-button" [disabled]="orgForm.invalid || userForm.invalid"
@@ -170,11 +180,4 @@
</form> </form>
</div> </div>
</ng-container> </ng-container>
<ng-container *ngIf="currentCreateStep == 1">
<button (click)="next()" color="primary" mat-raised-button class="continue-button" cdkFocusInitial
type="submit">
{{'CONTINUE' | translate}}
</button>
</ng-container>
</div> </div>

View File

@@ -140,3 +140,7 @@ h1 {
border-radius: 0.5rem; border-radius: 0.5rem;
} }
mat-checkbox {
flex-basis: 100%;
margin: .5rem;
}

View File

@@ -7,7 +7,7 @@ import { lowerCaseValidator, numberValidator, symbolValidator, upperCaseValidato
import { CreateOrgRequest, CreateUserRequest, Gender, OrgSetUpResponse } from 'src/app/proto/generated/admin_pb'; import { CreateOrgRequest, CreateUserRequest, Gender, OrgSetUpResponse } from 'src/app/proto/generated/admin_pb';
import { PasswordComplexityPolicy } from 'src/app/proto/generated/auth_pb'; import { PasswordComplexityPolicy } from 'src/app/proto/generated/auth_pb';
import { AdminService } from 'src/app/services/admin.service'; import { AdminService } from 'src/app/services/admin.service';
import { AuthUserService } from 'src/app/services/auth-user.service'; import { OrgService } from 'src/app/services/org.service';
import { ToastService } from 'src/app/services/toast.service'; import { ToastService } from 'src/app/services/toast.service';
function passwordConfirmValidator(c: AbstractControl): any { function passwordConfirmValidator(c: AbstractControl): any {
@@ -54,14 +54,14 @@ export class OrgCreateComponent {
public languages: string[] = ['de', 'en']; public languages: string[] = ['de', 'en'];
public policy!: PasswordComplexityPolicy.AsObject; public policy!: PasswordComplexityPolicy.AsObject;
public usePassword: boolean = false;
constructor( constructor(
private router: Router, private router: Router,
private toast: ToastService, private toast: ToastService,
private adminService: AdminService, private adminService: AdminService,
private _location: Location, private _location: Location,
private fb: FormBuilder, private fb: FormBuilder,
private authUserService: AuthUserService, private orgService: OrgService,
) { ) {
const validators: Validators[] = []; const validators: Validators[] = [];
@@ -69,49 +69,8 @@ export class OrgCreateComponent {
name: ['', [Validators.required]], name: ['', [Validators.required]],
domain: [''], domain: [''],
}); });
this.authUserService.GetMyPasswordComplexityPolicy().then(data => {
this.policy = data.toObject();
if (this.policy.minLength) {
validators.push(Validators.minLength(this.policy.minLength));
}
if (this.policy.hasLowercase) {
validators.push(lowerCaseValidator);
}
if (this.policy.hasUppercase) {
validators.push(upperCaseValidator);
}
if (this.policy.hasNumber) {
validators.push(numberValidator);
}
if (this.policy.hasSymbol) {
validators.push(symbolValidator);
}
this.userForm = this.fb.group({ this.initForm();
userName: ['', [Validators.required]],
firstName: ['', [Validators.required]],
lastName: ['', [Validators.required]],
email: ['', [Validators.required]],
gender: [''],
nickName: [''],
preferredLanguage: [''],
password: ['', validators],
confirmPassword: ['', [...validators, passwordConfirmValidator]],
});
}).catch(error => {
console.error(error);
this.userForm = this.fb.group({
userName: ['', [Validators.required]],
firstName: ['', [Validators.required]],
lastName: ['', [Validators.required]],
email: ['', [Validators.required]],
gender: [''],
nickName: [''],
preferredLanguage: [''],
password: ['', validators],
confirmPassword: ['', [...validators, passwordConfirmValidator]],
});
});
} }
public createSteps: number = 2; public createSteps: number = 2;
@@ -150,6 +109,66 @@ export class OrgCreateComponent {
this.currentCreateStep--; this.currentCreateStep--;
} }
private initForm(pwdValidators?: Validators[]): void {
if (pwdValidators) {
console.log('init with pwd');
this.userForm = this.fb.group({
userName: ['', [Validators.required]],
firstName: ['', [Validators.required]],
lastName: ['', [Validators.required]],
email: ['', [Validators.required]],
gender: [''],
nickName: [''],
preferredLanguage: [''],
password: ['', [...pwdValidators]],
confirmPassword: ['', [...pwdValidators, passwordConfirmValidator]],
});
} else {
console.log('init without pwd');
this.userForm = this.fb.group({
userName: ['', [Validators.required]],
firstName: ['', [Validators.required]],
lastName: ['', [Validators.required]],
email: ['', [Validators.required]],
gender: [''],
nickName: [''],
preferredLanguage: [''],
});
}
}
public initPwdValidators(): void {
const validators: Validators[] = [Validators.required];
console.log(this.usePassword);
if (this.usePassword) {
this.orgService.GetDefaultPasswordComplexityPolicy().then(data => {
this.policy = data.toObject();
console.log(this.policy);
if (this.policy.minLength) {
validators.push(Validators.minLength(this.policy.minLength));
}
if (this.policy.hasLowercase) {
validators.push(lowerCaseValidator);
}
if (this.policy.hasUppercase) {
validators.push(upperCaseValidator);
}
if (this.policy.hasNumber) {
validators.push(numberValidator);
}
if (this.policy.hasSymbol) {
validators.push(symbolValidator);
}
this.initForm(validators);
});
} else {
this.initForm();
}
}
public get name(): AbstractControl | null { public get name(): AbstractControl | null {
return this.orgForm.get('name'); return this.orgForm.get('name');
} }

View File

@@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
@@ -26,6 +27,7 @@ import { OrgCreateComponent } from './org-create.component';
MatSelectModule, MatSelectModule,
PipesModule, PipesModule,
TranslateModule, TranslateModule,
MatCheckboxModule,
], ],
}) })
export class OrgCreateModule { } export class OrgCreateModule { }

View File

@@ -58,7 +58,6 @@
padding: .5rem 0; padding: .5rem 0;
.left-desc { .left-desc {
text-transform: uppercase;
color: #8795a1; color: #8795a1;
font-size: .9rem; font-size: .9rem;
} }

View File

@@ -36,8 +36,7 @@
</app-card> </app-card>
<ng-template appHasRole [appHasRole]="['user.read', 'user.read:'+user?.id]"> <ng-template appHasRole [appHasRole]="['user.read', 'user.read:'+user?.id]">
<app-card title="{{ 'USER.PROFILE.TITLE' | translate }}" <app-card title="{{ 'USER.PROFILE.TITLE' | translate }}">
description="{{'USER.PROFILE.DESCRIPTION' | translate}}">
<app-detail-form <app-detail-form
*ngIf="((authUserService.isAllowed(['user.write:' + user?.id, 'user.write']) | async) || false) as canwrite" *ngIf="((authUserService.isAllowed(['user.write:' + user?.id, 'user.write']) | async) || false) as canwrite"
[disabled]="canwrite" [genders]="genders" [languages]="languages" [profile]="user" [disabled]="canwrite" [genders]="genders" [languages]="languages" [profile]="user"

View File

@@ -43,9 +43,7 @@
<td mat-cell *matCellDef="let user"> <td mat-cell *matCellDef="let user">
<mat-checkbox color="primary" (click)="$event.stopPropagation()" <mat-checkbox color="primary" (click)="$event.stopPropagation()"
(change)="$event ? selection.toggle(user) : null" [checked]="selection.isSelected(user)"> (change)="$event ? selection.toggle(user) : null" [checked]="selection.isSelected(user)">
<app-avatar *ngIf="user && (user.displayName || (user.firstName && user.lastName))" <app-avatar *ngIf="user && user.displayName" class="avatar" [name]="user.displayName"
class="avatar"
[name]="user.displayName ? user.displayName : (user.firstName + ' '+ user.lastName)"
[size]="32"> [size]="32">
</app-avatar> </app-avatar>
</mat-checkbox> </mat-checkbox>

View File

@@ -68,6 +68,15 @@ export class OrgService {
); );
} }
public async GetDefaultPasswordComplexityPolicy(): Promise<PasswordComplexityPolicy> {
const req: Empty = new Empty();
return await this.request(
c => c.getDefaultPasswordComplexityPolicy,
req,
f => f,
);
}
public async GetMyOrg(): Promise<Org> { public async GetMyOrg(): Promise<Org> {
return await this.request( return await this.request(
c => c.getMyOrg, c => c.getMyOrg,

View File

@@ -245,7 +245,8 @@
"DOWNLOAD_FILE":"Datei download", "DOWNLOAD_FILE":"Datei download",
"SELECTORGTOOLTIP":"Wähle diese Organisation", "SELECTORGTOOLTIP":"Wähle diese Organisation",
"PRIMARYDOMAIN":"Primäre Domain", "PRIMARYDOMAIN":"Primäre Domain",
"STATE":"Status" "STATE":"Status",
"USEPASSWORD":"Initiales Password setzen"
}, },
"DOMAINS": { "DOMAINS": {
"NEW":"Domain hinzufügen", "NEW":"Domain hinzufügen",

View File

@@ -245,7 +245,8 @@
"DOWNLOAD_FILE":"Download file", "DOWNLOAD_FILE":"Download file",
"SELECTORGTOOLTIP":"Select this organisation", "SELECTORGTOOLTIP":"Select this organisation",
"PRIMARYDOMAIN":"Primary Domain", "PRIMARYDOMAIN":"Primary Domain",
"STATE":"State" "STATE":"State",
"USEPASSWORD":"Set initial password"
}, },
"DOMAINS": { "DOMAINS": {
"NEW":"Add Domain", "NEW":"Add Domain",