mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 14:37:34 +00:00
fix(console): allow management of metadata of users of other organizations again (#9490)
# Which Problems Are Solved With the recent change in Console to use the User V2 API (https://github.com/zitadel/zitadel/pull/9312), some functionality still needs to call the management API, which requires the organization context. The context was not passed anymore, leading to error in cases where the calling user (e.g. an IAM_OWNER) was not part of the same organization. # How the Problems Are Solved Added an interceptor to provide the `x-zitadel-orgid` header for the new management client. # Additional Changes None # Additional Context - closes #9488
This commit is contained in:
@@ -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<any> {
|
||||
@@ -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 = {
|
||||
|
@@ -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<TReq = unknown, TResp = unknown> implements UnaryInterceptor<TReq, TResp> {
|
||||
constructor(private readonly storageService: StorageService) {}
|
||||
constructor(private readonly orgInterceptorProvider: OrgInterceptorProvider) {}
|
||||
|
||||
public async intercept(request: Request<TReq, TResp>, invoker: any): Promise<UnaryResponse<TReq, TResp>> {
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
Reference in New Issue
Block a user