feat(console): seo metatags, fix policy bugs, project options (#844)

* add seo service, index meta info

* fix policy buttons, refresh

* refresh after timeout

* loading spinner for login policy, complexity

* fix user form, add project role options

* authtoken options

* seo service lint

* style lint

* remove duplicate authmethod

* en i18n

* Update console/src/assets/i18n/en.json

Co-authored-by: Fabi <[email protected]>

Co-authored-by: Fabi <[email protected]>
This commit is contained in:
Max Peintner
2020-10-16 13:51:52 +02:00
committed by GitHub
co-authored by Fabi
parent c3b4c3f264
commit b1d61afc8f
30 changed files with 310 additions and 80 deletions
@@ -3,6 +3,7 @@ import { PolicyComponentType } from 'src/app/modules/policies/policy-component-t
import { DefaultLoginPolicy, DefaultPasswordComplexityPolicyView, OrgIamPolicyView } from 'src/app/proto/generated/admin_pb';
import { PolicyState } from 'src/app/proto/generated/management_pb';
import { AdminService } from 'src/app/services/admin.service';
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
@Component({
selector: 'app-iam-policy-grid',
@@ -18,14 +19,25 @@ export class IamPolicyGridComponent {
public PolicyComponentType: any = PolicyComponentType;
constructor(
private authService: GrpcAuthService,
private adminService: AdminService,
) {
this.getData();
}
private getData(): void {
this.adminService.GetDefaultLoginPolicy().then(data => this.loginPolicy = data.toObject());
this.adminService.GetDefaultOrgIamPolicy().then(data => this.iamPolicy = data.toObject());
this.adminService.GetDefaultPasswordComplexityPolicy().then(data => this.complexityPolicy = data.toObject());
this.authService.isAllowed(['policy.read']).subscribe(allowed => {
if (allowed) {
this.adminService.GetDefaultLoginPolicy().then(data => this.loginPolicy = data.toObject());
this.adminService.GetDefaultPasswordComplexityPolicy().then(data => this.complexityPolicy = data.toObject());
}
});
this.authService.isAllowed(['iam.policy.read']).subscribe(allowed => {
if (allowed) {
this.adminService.GetDefaultOrgIamPolicy().then(data => this.iamPolicy = data.toObject());
}
});
}
}
+1 -1
View File
@@ -22,4 +22,4 @@
(showDetailClicked)="showDetail()" (refreshClicked)="loadMembers()" [disabled]="false">
</app-contributors>
</div>
</app-meta-layout>
</app-meta-layout>
@@ -95,11 +95,36 @@
</mat-select>
</mat-form-field>
<div class="divider"></div>
<p class="full-width section-title">{{'APP.OIDC.TOKENSECTIONTITLE' | translate}}</p>
<mat-form-field appearance="outline" class="formfield">
<mat-label>{{ 'APP.OIDC.TOKENTYPE' | translate }}</mat-label>
<mat-select formControlName="accessTokenType">
<mat-option *ngFor="let type of oidcTokenTypes" [value]="type">
{{ 'APP.OIDC.TOKENTYPE'+type | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-checkbox *ngIf="accessTokenType?.value === OIDCTokenType.OIDCTOKENTYPE_JWT" class="full-width"
formControlName="accessTokenRoleAssertion">
{{'APP.OIDC.ACCESSTOKENROLEASSERTION' | translate}}</mat-checkbox>
<p class="full-width desc">{{'APP.OIDC.ACCESSTOKENROLEASSERTION_DESCRIPTION' | translate}}</p>
<mat-checkbox class="full-width" formControlName="idTokenRoleAssertion">
{{'APP.OIDC.IDTOKENROLEASSERTION' | translate}}</mat-checkbox>
<p class="full-width desc">{{'APP.OIDC.IDTOKENROLEASSERTION_DESCRIPTION' | translate}}</p>
<div class="divider"></div>
<p class="full-width section-title">{{'APP.OIDC.REDIRECTSECTIONTITLE' | translate}}</p>
<mat-slide-toggle color="primary" class="devmode" formControlName="devMode" name="devMode">
{{ 'APP.OIDC.DEVMODE' | translate }}
</mat-slide-toggle>
<p class="step-description">{{'APP.OIDC.DEVMODEDESC' | translate}}</p>
<p class="step-description" style="margin-bottom: 2rem;">{{'APP.OIDC.DEVMODEDESC' | translate}}</p>
<p class="step-description"
*ngIf="applicationType?.value == OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE">
{{'APP.OIDC.REDIRECTDESCRIPTIONNATIVE' | translate}}</p>
@@ -60,6 +60,21 @@
}
}
.section-title {
margin-bottom: 1.5rem;
}
.full-width {
flex-basis: 100%;
margin-left: .5rem;
margin-right: .5rem;
}
.desc {
color: var(--grey);
font-size: 14px;
}
.devmode {
flex: 1 1 100%;
margin: 1rem .5rem;
@@ -115,3 +130,10 @@
.chip[color='green'] {
background-color: #56a392 !important;
}
.divider {
flex-basis: 100%;
margin: 1.5rem .5rem;
height: 1px;
background-color: var(--grey);
}
@@ -17,6 +17,7 @@ import {
OIDCConfig,
OIDCGrantType,
OIDCResponseType,
OIDCTokenType,
ZitadelDocs,
} from 'src/app/proto/generated/management_pb';
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
@@ -67,6 +68,11 @@ export class AppDetailComponent implements OnInit, OnDestroy {
OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE,
];
public oidcTokenTypes: OIDCTokenType[] = [
OIDCTokenType.OIDCTOKENTYPE_BEARER,
OIDCTokenType.OIDCTOKENTYPE_JWT,
];
public AppState: any = AppState;
public appNameForm!: FormGroup;
public appForm!: FormGroup;
@@ -80,6 +86,7 @@ export class AppDetailComponent implements OnInit, OnDestroy {
public OIDCApplicationType: any = OIDCApplicationType;
public OIDCAuthMethodType: any = OIDCAuthMethodType;
public OIDCTokenType: any = OIDCTokenType;
public redirectControl: FormControl = new FormControl({ value: '', disabled: true });
public postRedirectControl: FormControl = new FormControl({ value: '', disabled: true });
@@ -106,6 +113,9 @@ export class AppDetailComponent implements OnInit, OnDestroy {
grantTypesList: [{ value: [], disabled: true }],
applicationType: [{ value: '', disabled: true }],
authMethodType: [{ value: '', disabled: true }],
accessTokenType: [{ value: '', disabled: true }],
accessTokenRoleAssertion: [{ value: false, disabled: true }],
idTokenRoleAssertion: [{ value: false, disabled: true }],
});
}
@@ -220,6 +230,9 @@ export class AppDetailComponent implements OnInit, OnDestroy {
this.app.oidcConfig.redirectUrisList = this.redirectUrisList;
this.app.oidcConfig.postLogoutRedirectUrisList = this.postLogoutRedirectUrisList;
this.app.oidcConfig.devMode = this.devMode?.value;
this.app.oidcConfig.accessTokenType = this.accessTokenType?.value;
this.app.oidcConfig.accessTokenRoleAssertion = this.accessTokenRoleAssertion?.value;
this.app.oidcConfig.idTokenRoleAssertion = this.idTokenRoleAssertion?.value;
this.mgmtService
.UpdateOIDCAppConfig(this.projectId, this.app.id, this.app.oidcConfig)
@@ -280,4 +293,16 @@ export class AppDetailComponent implements OnInit, OnDestroy {
public get devMode(): AbstractControl | null {
return this.appForm.get('devMode');
}
public get accessTokenType(): AbstractControl | null {
return this.appForm.get('accessTokenType');
}
public get idTokenRoleAssertion(): AbstractControl | null {
return this.appForm.get('idTokenRoleAssertion');
}
public get accessTokenRoleAssertion(): AbstractControl | null {
return this.appForm.get('accessTokenRoleAssertion');
}
}
@@ -78,6 +78,14 @@
<ng-template appHasRole [appHasRole]="['project.role.read:' + project.projectId, 'project.role.read']">
<app-card title="{{ 'PROJECT.ROLE.TITLE' | translate }}"
description="{{ 'PROJECT.ROLE.DESCRIPTION' | translate }}">
<p>{{'PROJECT.ROLE.OPTIONS' | translate}}</p>
<mat-checkbox [(ngModel)]="project.projectRoleAssertion" (change)="saveProject()">
{{'PROJECT.ROLE.ASSERTION' | translate}}</mat-checkbox>
<p class="desc">{{'PROJECT.ROLE.ASSERTION_DESCRIPTION' | translate}}</p>
<mat-checkbox [(ngModel)]="project.projectRoleCheck" (change)="saveProject()">
{{'PROJECT.ROLE.CHECK' | translate}}</mat-checkbox>
<p class="desc">{{'PROJECT.ROLE.CHECK_DESCRIPTION' | translate}}</p>
<div class="divider"></div>
<app-project-roles
[disabled]="(['project.role.write$', 'project.role.write:'+ project.projectId]| hasRole | async) == false"
[actionsVisible]="true" [projectId]="projectId">
@@ -76,3 +76,15 @@
flex-direction: column;
}
}
.desc {
color: var(--grey);
font-size: 14px;
margin-bottom: 1.5rem;
}
.divider {
height: 1px;
background-color: var(--grey);
margin-bottom: 1.5rem;
}
@@ -191,7 +191,8 @@ export class OwnedProjectDetailComponent implements OnInit, OnDestroy {
}
public saveProject(): void {
this.mgmtService.UpdateProject(this.project.projectId, this.project.name).then(() => {
console.log(this.project);
this.mgmtService.UpdateProject(this.project.projectId, this.project).then(() => {
this.toast.showInfo('PROJECT.TOAST.UPDATED', true);
}).catch(error => {
this.toast.showError(error);
@@ -105,7 +105,9 @@ export class ExternalIdpsComponent implements OnInit {
if (promise) {
promise.then(_ => {
this.refreshPage();
setTimeout(() => {
this.refreshPage();
}, 1000);
}).catch((error: any) => {
this.toast.showError(error);
});
@@ -41,7 +41,7 @@
</div>
</app-card>
<ng-template appHasRole [appHasRole]="['user.read', 'user.read:'+user?.id]">
<ng-template appHasRole [appHasRole]="['user.read$', 'user.read:'+user?.id]">
<app-card *ngIf="user.human" title="{{ 'USER.PROFILE.TITLE' | translate }}">
<app-detail-form [disabled]="(canWrite$ | async) == false" [genders]="genders" [languages]="languages"
[username]="user.userName" [user]="user.human" (submitData)="saveProfile($event)">
@@ -54,9 +54,8 @@
</app-card>
<app-card *ngIf="user.machine" title="{{ 'USER.MACHINE.TITLE' | translate }}">
<app-detail-form-machine
[disabled]="(['user.write:' + user?.id, 'user.write$'] | hasRole | async) == false"
[username]="user.userName" [user]="user.machine" (submitData)="saveMachine($event)">
<app-detail-form-machine [disabled]="(canWrite$ | async) == false" [username]="user.userName"
[user]="user.machine" (submitData)="saveMachine($event)">
</app-detail-form-machine>
</app-card>