fix(console, e2e): optimize console and activate tests (#4207)

* activate some tests

* unskip remove project tests

* focus input elements before typing

* fix: prune permissions observable

* cleanup

* remove timeout

* remove ngIf

* test with chrome

* with ngIf

* single observable

* juhu

* maybe better

* fix isAllowed response

* cleanup

Co-authored-by: Max Peintner <max@caos.ch>
This commit is contained in:
Elio Bischof
2022-09-02 15:43:44 +02:00
committed by GitHub
parent adb5394ae3
commit f0250a3fdb
10 changed files with 178 additions and 151 deletions

View File

@@ -265,7 +265,7 @@ export class AppComponent implements OnDestroy {
public changedOrg(org: Org.AsObject): void {
this.themeService.loadPrivateLabelling();
this.authService.zitadelPermissionsChanged.pipe(take(1)).subscribe(() => {
this.authService.zitadelPermissions$.pipe(take(1)).subscribe(() => {
this.router.navigate(['/org'], { fragment: org.id });
});
}

View File

@@ -12,8 +12,6 @@ export class RoleGuard implements CanActivate {
constructor(private authService: GrpcAuthService) {}
public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
return this.authService.fetchedZitadelPermissions
.pipe(filter((permissionsFetched) => !!permissionsFetched))
.pipe(switchMap((_) => this.authService.isAllowed(route.data['roles'], route.data['requiresAll'])));
return this.authService.isAllowed(route.data['roles'], route.data['requiresAll']);
}
}

View File

@@ -97,7 +97,7 @@ export class OrgTableComponent {
public selectOrg(item: Org.AsObject, event?: any): void {
this.authService.setActiveOrg(item);
this.themeService.loadPrivateLabelling();
this.authService.zitadelPermissionsChanged.pipe(take(1)).subscribe(() => {
this.authService.zitadelPermissions$.pipe(take(1)).subscribe(() => {
this.router.navigate(['/org'], { fragment: item.id });
});
}
@@ -146,7 +146,7 @@ export class OrgTableComponent {
public setAndNavigateToOrg(org: Org.AsObject): void {
this.authService.setActiveOrg(org);
this.themeService.loadPrivateLabelling();
this.authService.zitadelPermissionsChanged.pipe(take(1)).subscribe(() => {
this.authService.zitadelPermissions$.pipe(take(1)).subscribe(() => {
this.router.navigate(['/org'], { fragment: org.id });
});
}

View File

@@ -52,12 +52,12 @@
(filterOpen)="filterOpen = $event"
></cnsl-filter-user>
<a
*ngIf="!selection.hasValue()"
[routerLink]="['/users', type === Type.TYPE_HUMAN ? 'create' : 'create-machine']"
color="primary"
mat-raised-button
[disabled]="!canWrite"
class="cnsl-action-button"
*ngIf="!selection.hasValue()"
data-e2e="create-user-button"
>
<mat-icon class="icon">add</mat-icon>

View File

@@ -2,91 +2,102 @@ import { Injectable } from '@angular/core';
import { SortDirection } from '@angular/material/sort';
import { OAuthService } from 'angular-oauth2-oidc';
import { BehaviorSubject, from, merge, Observable, of, Subject } from 'rxjs';
import { catchError, filter, finalize, map, mergeMap, switchMap, take, timeout } from 'rxjs/operators';
import {
catchError,
distinctUntilChanged,
filter,
finalize,
map,
mergeMap,
switchMap,
take,
timeout,
withLatestFrom,
} from 'rxjs/operators';
import {
AddMyAuthFactorOTPRequest,
AddMyAuthFactorOTPResponse,
AddMyAuthFactorU2FRequest,
AddMyAuthFactorU2FResponse,
AddMyPasswordlessLinkRequest,
AddMyPasswordlessLinkResponse,
AddMyPasswordlessRequest,
AddMyPasswordlessResponse,
GetMyEmailRequest,
GetMyEmailResponse,
GetMyLabelPolicyRequest,
GetMyLabelPolicyResponse,
GetMyPasswordComplexityPolicyRequest,
GetMyPasswordComplexityPolicyResponse,
GetMyPhoneRequest,
GetMyPhoneResponse,
GetMyPrivacyPolicyRequest,
GetMyPrivacyPolicyResponse,
GetMyProfileRequest,
GetMyProfileResponse,
GetMyUserRequest,
GetMyUserResponse,
GetSupportedLanguagesRequest,
GetSupportedLanguagesResponse,
ListMyAuthFactorsRequest,
ListMyAuthFactorsResponse,
ListMyLinkedIDPsRequest,
ListMyLinkedIDPsResponse,
ListMyMembershipsRequest,
ListMyMembershipsResponse,
ListMyMetadataRequest,
ListMyMetadataResponse,
ListMyPasswordlessRequest,
ListMyPasswordlessResponse,
ListMyProjectOrgsRequest,
ListMyProjectOrgsResponse,
ListMyUserChangesRequest,
ListMyUserChangesResponse,
ListMyUserGrantsRequest,
ListMyUserGrantsResponse,
ListMyUserSessionsRequest,
ListMyUserSessionsResponse,
ListMyZitadelPermissionsRequest,
ListMyZitadelPermissionsResponse,
RemoveMyAuthFactorOTPRequest,
RemoveMyAuthFactorOTPResponse,
RemoveMyAuthFactorU2FRequest,
RemoveMyAuthFactorU2FResponse,
RemoveMyAvatarRequest,
RemoveMyAvatarResponse,
RemoveMyLinkedIDPRequest,
RemoveMyLinkedIDPResponse,
RemoveMyPasswordlessRequest,
RemoveMyPasswordlessResponse,
RemoveMyPhoneRequest,
RemoveMyPhoneResponse,
RemoveMyUserRequest,
RemoveMyUserResponse,
ResendMyEmailVerificationRequest,
ResendMyEmailVerificationResponse,
ResendMyPhoneVerificationRequest,
ResendMyPhoneVerificationResponse,
SendMyPasswordlessLinkRequest,
SendMyPasswordlessLinkResponse,
SetMyEmailRequest,
SetMyEmailResponse,
SetMyPhoneRequest,
SetMyPhoneResponse,
UpdateMyPasswordRequest,
UpdateMyPasswordResponse,
UpdateMyProfileRequest,
UpdateMyProfileResponse,
UpdateMyUserNameRequest,
UpdateMyUserNameResponse,
VerifyMyAuthFactorOTPRequest,
VerifyMyAuthFactorOTPResponse,
VerifyMyAuthFactorU2FRequest,
VerifyMyAuthFactorU2FResponse,
VerifyMyPasswordlessRequest,
VerifyMyPasswordlessResponse,
VerifyMyPhoneRequest,
VerifyMyPhoneResponse,
AddMyAuthFactorOTPRequest,
AddMyAuthFactorOTPResponse,
AddMyAuthFactorU2FRequest,
AddMyAuthFactorU2FResponse,
AddMyPasswordlessLinkRequest,
AddMyPasswordlessLinkResponse,
AddMyPasswordlessRequest,
AddMyPasswordlessResponse,
GetMyEmailRequest,
GetMyEmailResponse,
GetMyLabelPolicyRequest,
GetMyLabelPolicyResponse,
GetMyPasswordComplexityPolicyRequest,
GetMyPasswordComplexityPolicyResponse,
GetMyPhoneRequest,
GetMyPhoneResponse,
GetMyPrivacyPolicyRequest,
GetMyPrivacyPolicyResponse,
GetMyProfileRequest,
GetMyProfileResponse,
GetMyUserRequest,
GetMyUserResponse,
GetSupportedLanguagesRequest,
GetSupportedLanguagesResponse,
ListMyAuthFactorsRequest,
ListMyAuthFactorsResponse,
ListMyLinkedIDPsRequest,
ListMyLinkedIDPsResponse,
ListMyMembershipsRequest,
ListMyMembershipsResponse,
ListMyMetadataRequest,
ListMyMetadataResponse,
ListMyPasswordlessRequest,
ListMyPasswordlessResponse,
ListMyProjectOrgsRequest,
ListMyProjectOrgsResponse,
ListMyUserChangesRequest,
ListMyUserChangesResponse,
ListMyUserGrantsRequest,
ListMyUserGrantsResponse,
ListMyUserSessionsRequest,
ListMyUserSessionsResponse,
ListMyZitadelPermissionsRequest,
ListMyZitadelPermissionsResponse,
RemoveMyAuthFactorOTPRequest,
RemoveMyAuthFactorOTPResponse,
RemoveMyAuthFactorU2FRequest,
RemoveMyAuthFactorU2FResponse,
RemoveMyAvatarRequest,
RemoveMyAvatarResponse,
RemoveMyLinkedIDPRequest,
RemoveMyLinkedIDPResponse,
RemoveMyPasswordlessRequest,
RemoveMyPasswordlessResponse,
RemoveMyPhoneRequest,
RemoveMyPhoneResponse,
RemoveMyUserRequest,
RemoveMyUserResponse,
ResendMyEmailVerificationRequest,
ResendMyEmailVerificationResponse,
ResendMyPhoneVerificationRequest,
ResendMyPhoneVerificationResponse,
SendMyPasswordlessLinkRequest,
SendMyPasswordlessLinkResponse,
SetMyEmailRequest,
SetMyEmailResponse,
SetMyPhoneRequest,
SetMyPhoneResponse,
UpdateMyPasswordRequest,
UpdateMyPasswordResponse,
UpdateMyProfileRequest,
UpdateMyProfileResponse,
UpdateMyUserNameRequest,
UpdateMyUserNameResponse,
VerifyMyAuthFactorOTPRequest,
VerifyMyAuthFactorOTPResponse,
VerifyMyAuthFactorU2FRequest,
VerifyMyAuthFactorU2FResponse,
VerifyMyPasswordlessRequest,
VerifyMyPasswordlessResponse,
VerifyMyPhoneRequest,
VerifyMyPhoneResponse,
} from '../proto/generated/zitadel/auth_pb';
import { ChangeQuery } from '../proto/generated/zitadel/change_pb';
import { MetadataQuery } from '../proto/generated/zitadel/metadata_pb';
@@ -103,9 +114,26 @@ export class GrpcAuthService {
private _activeOrgChanged: Subject<Org.AsObject> = new Subject();
public user!: Observable<User.AsObject | undefined>;
public userSubject: BehaviorSubject<User.AsObject | undefined> = new BehaviorSubject<User.AsObject | undefined>(undefined);
private zitadelPermissions: BehaviorSubject<string[]> = new BehaviorSubject(['user.resourceowner']);
public readonly fetchedZitadelPermissions: BehaviorSubject<boolean> = new BehaviorSubject(false as boolean);
private triggerPermissionsRefresh: Subject<void> = new Subject();
public zitadelPermissions$: Observable<string[]> = this.triggerPermissionsRefresh.pipe(
switchMap(() =>
from(this.listMyZitadelPermissions()).pipe(
map((rolesResp) => rolesResp.resultList),
filter((roles) => !!roles.length),
catchError((_) => {
return of([]);
}),
distinctUntilChanged((a, b) => {
return JSON.stringify(a.sort()) === JSON.stringify(b.sort());
}),
finalize(() => {
this.fetchedZitadelPermissions.next(true);
}),
),
),
);
private zitadelPermissions: BehaviorSubject<string[]> = new BehaviorSubject<string[]>([]);
public readonly fetchedZitadelPermissions: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
private cachedOrgs: Org.AsObject[] = [];
@@ -114,6 +142,8 @@ export class GrpcAuthService {
private oauthService: OAuthService,
private storage: StorageService,
) {
this.zitadelPermissions$.subscribe(this.zitadelPermissions);
this.user = merge(
of(this.oauthService.getAccessToken()).pipe(filter((token) => (token ? true : false))),
this.oauthService.events.pipe(
@@ -223,19 +253,7 @@ export class GrpcAuthService {
}
private loadPermissions(): void {
from(this.listMyZitadelPermissions())
.pipe(
map((rolesResp) => rolesResp.resultList),
catchError((_) => {
return of([]);
}),
finalize(() => {
this.fetchedZitadelPermissions.next(true);
}),
)
.subscribe((roles) => {
this.zitadelPermissions.next(roles);
});
this.triggerPermissionsRefresh.next();
}
/**
@@ -244,7 +262,17 @@ export class GrpcAuthService {
*/
public isAllowed(roles: string[] | RegExp[], requiresAll: boolean = false): Observable<boolean> {
if (roles && roles.length > 0) {
return this.zitadelPermissions.pipe(switchMap((zroles) => of(this.hasRoles(zroles, roles, requiresAll))));
return this.fetchedZitadelPermissions.pipe(
withLatestFrom(this.zitadelPermissions),
filter(([hL, p]) => {
return hL === true && !!p.length;
}),
map(([_, zroles]) => {
const what = this.hasRoles(zroles, roles, requiresAll);
return what;
}),
distinctUntilChanged(),
);
} else {
return of(false);
}
@@ -356,10 +384,6 @@ export class GrpcAuthService {
return this.grpcService.auth.updateMyProfile(req, null).then((resp) => resp.toObject());
}
public get zitadelPermissionsChanged(): Observable<string[]> {
return this.zitadelPermissions;
}
public listMyUserSessions(): Promise<ListMyUserSessionsResponse.AsObject> {
const req = new ListMyUserSessionsRequest();
return this.grpcService.auth.listMyUserSessions(req, null).then((resp) => resp.toObject());