mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-08 08:34:07 +00:00
fix(console): auth response interceptor, new assets, async route guard, pipe modules cleanup, disable custom idp editation for orgs, refresh list on idp creation (#793)
* chore(deps-dev): bump @angular/cli from 10.0.8 to 10.1.3 in /console (#785) Bumps [@angular/cli](https://github.com/angular/angular-cli) from 10.0.8 to 10.1.3. - [Release notes](https://github.com/angular/angular-cli/releases) - [Commits](https://github.com/angular/angular-cli/compare/v10.0.8...v10.1.3) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump @angular-devkit/build-angular in /console (#784) Bumps [@angular-devkit/build-angular](https://github.com/angular/angular-cli) from 0.1000.8 to 0.1001.3. - [Release notes](https://github.com/angular/angular-cli/releases) - [Commits](https://github.com/angular/angular-cli/commits) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Max Peintner <max@caos.ch> * chore(deps-dev): bump @angular/language-service in /console (#783) Bumps [@angular/language-service](https://github.com/angular/angular/tree/HEAD/packages/language-service) from 10.1.0 to 10.1.3. - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/master/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/10.1.3/packages/language-service) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump stylelint from 13.7.1 to 13.7.2 in /console (#782) Bumps [stylelint](https://github.com/stylelint/stylelint) from 13.7.1 to 13.7.2. - [Release notes](https://github.com/stylelint/stylelint/releases) - [Changelog](https://github.com/stylelint/stylelint/blob/master/CHANGELOG.md) - [Commits](https://github.com/stylelint/stylelint/compare/13.7.1...13.7.2) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump karma from 5.2.1 to 5.2.3 in /console (#781) Bumps [karma](https://github.com/karma-runner/karma) from 5.2.1 to 5.2.3. - [Release notes](https://github.com/karma-runner/karma/releases) - [Changelog](https://github.com/karma-runner/karma/blob/master/CHANGELOG.md) - [Commits](https://github.com/karma-runner/karma/compare/v5.2.1...v5.2.3) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump moment from 2.27.0 to 2.29.0 in /console (#780) Bumps [moment](https://github.com/moment/moment) from 2.27.0 to 2.29.0. - [Release notes](https://github.com/moment/moment/releases) - [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md) - [Commits](https://github.com/moment/moment/compare/2.27.0...2.29.0) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump @types/node from 14.6.4 to 14.11.2 in /console (#778) Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 14.6.4 to 14.11.2. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump prettier from 2.1.1 to 2.1.2 in /console (#757) Bumps [prettier](https://github.com/prettier/prettier) from 2.1.1 to 2.1.2. - [Release notes](https://github.com/prettier/prettier/releases) - [Changelog](https://github.com/prettier/prettier/blob/master/CHANGELOG.md) - [Commits](https://github.com/prettier/prettier/compare/2.1.1...2.1.2) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump ts-protoc-gen from 0.12.0 to 0.13.0 in /console (#737) Bumps [ts-protoc-gen](https://github.com/improbable-eng/ts-protoc-gen) from 0.12.0 to 0.13.0. - [Release notes](https://github.com/improbable-eng/ts-protoc-gen/releases) - [Changelog](https://github.com/improbable-eng/ts-protoc-gen/blob/master/CHANGELOG.md) - [Commits](https://github.com/improbable-eng/ts-protoc-gen/compare/0.12.0...0.13.0) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump jasmine-spec-reporter in /console (#762) Bumps [jasmine-spec-reporter](https://github.com/bcaudan/jasmine-spec-reporter) from 5.0.2 to 6.0.0. - [Release notes](https://github.com/bcaudan/jasmine-spec-reporter/releases) - [Changelog](https://github.com/bcaudan/jasmine-spec-reporter/blob/master/CHANGELOG.md) - [Commits](https://github.com/bcaudan/jasmine-spec-reporter/compare/v5.0.2...v6.0.0) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Max Peintner <max@caos.ch> * fix: package * change html lang to translation lang * disable detail view org idp * catch errorcode 16 in auth response interceptor * new icons * refactor pipes, idp table config * fix router guard * lint * allowed commonjs deps * Update console/src/assets/i18n/en.json Co-authored-by: Florian Forster <florian@caos.ch> * Update console/src/assets/i18n/de.json Co-authored-by: Florian Forster <florian@caos.ch> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Florian Forster <florian@caos.ch>
This commit is contained in:
@@ -44,6 +44,8 @@ export class GrpcAuthService {
|
||||
private _activeOrgChanged: Subject<Org.AsObject> = new Subject();
|
||||
public user!: Observable<UserProfileView.AsObject>;
|
||||
private zitadelPermissions: BehaviorSubject<string[]> = new BehaviorSubject(['user.resourceowner']);
|
||||
public readonly fetchedZitadelPermissions: BehaviorSubject<boolean> = new BehaviorSubject(false as boolean);
|
||||
|
||||
private cachedOrgs: Org.AsObject[] = [];
|
||||
|
||||
constructor(
|
||||
@@ -125,6 +127,12 @@ export class GrpcAuthService {
|
||||
first(),
|
||||
switchMap(() => from(this.GetMyzitadelPermissions())),
|
||||
map(rolesResp => rolesResp.toObject().permissionsList),
|
||||
catchError(_ => {
|
||||
return of([]);
|
||||
}),
|
||||
finalize(() => {
|
||||
this.fetchedZitadelPermissions.next(true);
|
||||
}),
|
||||
).subscribe(roles => {
|
||||
this.zitadelPermissions.next(roles);
|
||||
});
|
||||
@@ -136,9 +144,7 @@ export class GrpcAuthService {
|
||||
*/
|
||||
public isAllowed(roles: string[] | RegExp[]): Observable<boolean> {
|
||||
if (roles && roles.length > 0) {
|
||||
return this.zitadelPermissions.pipe(switchMap(zroles => {
|
||||
return of(this.hasRoles(zroles, roles));
|
||||
}));
|
||||
return this.zitadelPermissions.pipe(switchMap(zroles => of(this.hasRoles(zroles, roles))));
|
||||
} else {
|
||||
return of(false);
|
||||
}
|
||||
@@ -220,6 +226,10 @@ export class GrpcAuthService {
|
||||
return this.grpcService.auth.updateMyUserProfile(req);
|
||||
}
|
||||
|
||||
public get zitadelPermissionsChanged(): Observable<string[]> {
|
||||
return this.zitadelPermissions;
|
||||
}
|
||||
|
||||
public async getMyUserSessions(): Promise<UserSessionViews> {
|
||||
return this.grpcService.auth.getMyUserSessions(
|
||||
new Empty(),
|
||||
@@ -286,15 +296,15 @@ export class GrpcAuthService {
|
||||
}
|
||||
|
||||
public async SearchExternalIdps(
|
||||
userId: string,
|
||||
limit: number,
|
||||
offset: number,
|
||||
asc?: boolean,
|
||||
userId: string,
|
||||
limit: number,
|
||||
offset: number,
|
||||
asc?: boolean,
|
||||
): Promise<ExternalIDPSearchResponse> {
|
||||
const req = new ExternalIDPSearchRequest();
|
||||
req.setLimit(limit);
|
||||
req.setOffset(offset);
|
||||
return this.grpcService.auth.searchMyExternalIDPs(req);
|
||||
const req = new ExternalIDPSearchRequest();
|
||||
req.setLimit(limit);
|
||||
req.setOffset(offset);
|
||||
return this.grpcService.auth.searchMyExternalIDPs(req);
|
||||
}
|
||||
|
||||
public async AddMfaOTP(): Promise<MfaOtpResponse> {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { PlatformLocation } from '@angular/common';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { AuthConfig } from 'angular-oauth2-oidc';
|
||||
|
||||
import { AdminServicePromiseClient } from '../proto/generated/admin_grpc_web_pb';
|
||||
@@ -24,6 +25,8 @@ export class GrpcService {
|
||||
private platformLocation: PlatformLocation,
|
||||
private authenticationService: AuthenticationService,
|
||||
private storageService: StorageService,
|
||||
private dialog: MatDialog,
|
||||
// private toast: ToastService,
|
||||
) { }
|
||||
|
||||
public async loadAppEnvironment(): Promise<any> {
|
||||
@@ -31,9 +34,9 @@ export class GrpcService {
|
||||
.toPromise().then((data: any) => {
|
||||
if (data && data.authServiceUrl && data.mgmtServiceUrl && data.issuer) {
|
||||
const interceptors = {
|
||||
'unaryInterceptors': [
|
||||
new AuthInterceptor(this.authenticationService, this.storageService),
|
||||
unaryInterceptors: [
|
||||
new OrgInterceptor(this.storageService),
|
||||
new AuthInterceptor(this.authenticationService, this.storageService, this.dialog),
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { Request, UnaryInterceptor, UnaryResponse } from 'grpc-web';
|
||||
import { filter, first } from 'rxjs/operators';
|
||||
import { filter, first, take } from 'rxjs/operators';
|
||||
import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
|
||||
|
||||
import { AuthenticationService } from '../authentication.service';
|
||||
import { StorageService } from '../storage.service';
|
||||
@@ -10,8 +12,15 @@ const authorizationKey = 'Authorization';
|
||||
const bearerPrefix = 'Bearer';
|
||||
const accessTokenStorageKey = 'access_token';
|
||||
@Injectable({ providedIn: 'root' })
|
||||
/**
|
||||
* Set the authentication token
|
||||
*/
|
||||
export class AuthInterceptor<TReq = unknown, TResp = unknown> implements UnaryInterceptor<TReq, TResp> {
|
||||
constructor(private authenticationService: AuthenticationService, private storageService: StorageService) { }
|
||||
constructor(
|
||||
private authenticationService: AuthenticationService,
|
||||
private storageService: StorageService,
|
||||
private dialog: MatDialog,
|
||||
) { }
|
||||
|
||||
public async intercept(request: Request<TReq, TResp>, invoker: any): Promise<UnaryResponse<TReq, TResp>> {
|
||||
await this.authenticationService.authenticationChanged.pipe(
|
||||
@@ -24,17 +33,25 @@ export class AuthInterceptor<TReq = unknown, TResp = unknown> implements UnaryIn
|
||||
metadata[authorizationKey] = `${bearerPrefix} ${accessToken}`;
|
||||
|
||||
return invoker(request).then((response: any) => {
|
||||
// const message = response.getResponseMessage();
|
||||
const respMetadata = response.getMetadata();
|
||||
|
||||
// TODO: intercept unauthenticated an authenticate
|
||||
|
||||
// const status = respMetadata['grpc-status'];
|
||||
// console.log(respMetadata, status);
|
||||
// if (status?.code === 16) {
|
||||
// this.authenticationService.authenticate();
|
||||
// }
|
||||
return response;
|
||||
}).catch((error: any) => {
|
||||
console.error('error: ', error);
|
||||
if (error.code === 16) {
|
||||
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||
data: {
|
||||
confirmKey: 'ACTIONS.LOGIN',
|
||||
titleKey: 'ERRORS.TOKENINVALID.TITLE',
|
||||
descriptionKey: 'ERRORS.TOKENINVALID.DESCRIPTION',
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().pipe(take(1)).subscribe(resp => {
|
||||
if (resp) {
|
||||
this.authenticationService.authenticate(undefined, true, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,7 @@ import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatSnackBar, MatSnackBarConfig } from '@angular/material/snack-bar';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { take } from 'rxjs/operators';
|
||||
|
||||
import { WarnDialogComponent } from '../modules/warn-dialog/warn-dialog.component';
|
||||
import { AuthenticationService } from './authentication.service';
|
||||
|
||||
@Injectable({
|
||||
@@ -32,24 +30,8 @@ export class ToastService {
|
||||
|
||||
public showError(grpcError: any): void {
|
||||
const { message, code, metadata } = grpcError;
|
||||
// TODO: remove check for code === 7
|
||||
if (code === 16 || (code === 7 && message === 'invalid token')) {
|
||||
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||
data: {
|
||||
confirmKey: 'ACTIONS.LOGIN',
|
||||
titleKey: 'ERRORS.TOKENINVALID.TITLE',
|
||||
descriptionKey: 'ERRORS.TOKENINVALID.DESCRIPTION',
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().pipe(take(1)).subscribe(resp => {
|
||||
if (resp) {
|
||||
this.authService.authenticate(undefined, true, true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.showMessage(decodeURI(message), 'close', { duration: 3000 });
|
||||
if (code !== 16) {
|
||||
this.showMessage(decodeURI(message), 'close', { duration: 4000 });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user