diff --git a/console/src/app/services/grpc.service.ts b/console/src/app/services/grpc.service.ts index e554e2b647..52332eae15 100644 --- a/console/src/app/services/grpc.service.ts +++ b/console/src/app/services/grpc.service.ts @@ -14,7 +14,7 @@ import { ExhaustedService } from './exhausted.service'; import { AuthInterceptor, AuthInterceptorProvider, NewConnectWebAuthInterceptor } from './interceptors/auth.interceptor'; import { ExhaustedGrpcInterceptor } from './interceptors/exhausted.grpc.interceptor'; import { I18nInterceptor } from './interceptors/i18n.interceptor'; -import { OrgInterceptor } from './interceptors/org.interceptor'; +import { NewConnectWebOrgInterceptor, OrgInterceptor, OrgInterceptorProvider } from './interceptors/org.interceptor'; import { StorageService } from './storage.service'; import { UserServiceClient } from '../proto/generated/zitadel/user/v2/User_serviceServiceClientPb'; //@ts-ignore @@ -46,6 +46,7 @@ export class GrpcService { private readonly exhaustedService: ExhaustedService, private readonly authInterceptor: AuthInterceptor, private readonly authInterceptorProvider: AuthInterceptorProvider, + private readonly orgInterceptorProvider: OrgInterceptorProvider, ) {} public loadAppEnvironment(): Promise { @@ -62,7 +63,7 @@ export class GrpcService { const interceptors = { unaryInterceptors: [ new ExhaustedGrpcInterceptor(this.exhaustedService, this.envService), - new OrgInterceptor(this.storageService), + new OrgInterceptor(this.orgInterceptorProvider), this.authInterceptor, new I18nInterceptor(this.translate), ], @@ -103,8 +104,15 @@ export class GrpcService { baseUrl: env.api, interceptors: [NewConnectWebAuthInterceptor(this.authInterceptorProvider)], }); + const transportOldAPIs = createGrpcWebTransport({ + baseUrl: env.api, + interceptors: [ + NewConnectWebAuthInterceptor(this.authInterceptorProvider), + NewConnectWebOrgInterceptor(this.orgInterceptorProvider), + ], + }); this.userNew = createUserServiceClient(transport); - this.mgmtNew = createManagementServiceClient(transport); + this.mgmtNew = createManagementServiceClient(transportOldAPIs); this.authNew = createAuthServiceClient(transport); const authConfig: AuthConfig = { diff --git a/console/src/app/services/interceptors/org.interceptor.ts b/console/src/app/services/interceptors/org.interceptor.ts index 2e85b8f4b9..e9e9745b12 100644 --- a/console/src/app/services/interceptors/org.interceptor.ts +++ b/console/src/app/services/interceptors/org.interceptor.ts @@ -3,32 +3,63 @@ import { Request, RpcError, StatusCode, UnaryInterceptor, UnaryResponse } from ' import { Org } from 'src/app/proto/generated/zitadel/org_pb'; import { StorageKey, StorageLocation, StorageService } from '../storage.service'; +import { ConnectError, Interceptor } from '@connectrpc/connect'; +import { firstValueFrom, identity, Observable, Subject } from 'rxjs'; +import { debounceTime, filter, map } from 'rxjs/operators'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; const ORG_HEADER_KEY = 'x-zitadel-orgid'; @Injectable({ providedIn: 'root' }) export class OrgInterceptor implements UnaryInterceptor { - constructor(private readonly storageService: StorageService) {} + constructor(private readonly orgInterceptorProvider: OrgInterceptorProvider) {} public async intercept(request: Request, invoker: any): Promise> { const metadata = request.getMetadata(); - const org: Org.AsObject | null = this.storageService.getItem(StorageKey.organization, StorageLocation.session); - - if (org) { - metadata[ORG_HEADER_KEY] = `${org.id}`; + const orgId = this.orgInterceptorProvider.getOrgId(); + if (orgId) { + metadata[ORG_HEADER_KEY] = orgId; } - try { - return await invoker(request); - } catch (error: any) { - if ( - error instanceof RpcError && - error.code === StatusCode.PERMISSION_DENIED && - error.message.startsWith("Organisation doesn't exist") - ) { - this.storageService.removeItem(StorageKey.organization, StorageLocation.session); - } - throw error; - } + return invoker(request).catch(this.orgInterceptorProvider.handleError); } } + +export function NewConnectWebOrgInterceptor(orgInterceptorProvider: OrgInterceptorProvider): Interceptor { + return (next) => async (req) => { + if (!req.header.get(ORG_HEADER_KEY)) { + const orgId = orgInterceptorProvider.getOrgId(); + if (orgId) { + req.header.set(ORG_HEADER_KEY, orgId); + } + } + + return next(req).catch(orgInterceptorProvider.handleError); + }; +} + +@Injectable({ providedIn: 'root' }) +export class OrgInterceptorProvider { + constructor(private storageService: StorageService) {} + + getOrgId() { + const org: Org.AsObject | null = this.storageService.getItem(StorageKey.organization, StorageLocation.session); + return org?.id; + } + + handleError = (error: any): never => { + if (!(error instanceof RpcError) && !(error instanceof ConnectError)) { + throw error; + } + + if ( + error instanceof RpcError && + error.code === StatusCode.PERMISSION_DENIED && + error.message.startsWith("Organisation doesn't exist") + ) { + this.storageService.removeItem(StorageKey.organization, StorageLocation.session); + } + + throw error; + }; +}