fix(console): fix self-management without explicit roles (#11583)

# Which Problems Are Solved

The self-management of user without any permissions in Console was no
longer possible and the UI was completely stuck.
This was due to the method `getActiveOrg`, which returned an error in
case no organization could be retrieved.

# How the Problems Are Solved

- Return `undefined` in case no organization is found and handle cases
where an organization is required.
- Redirect the user to `/users/me` if no organization is retrieved on
the start
- Prevent users without roles to access the home page

# Additional Changes

None

# Additional Context

closes #11567
This commit is contained in:
Livio Spring
2026-02-13 10:11:23 +01:00
committed by GitHub
parent 9b064d8b74
commit 5b8ba90295
6 changed files with 53 additions and 33 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ const routes: Routes = [
{
path: '',
loadChildren: () => import('./pages/home/home.module'),
canActivate: [authGuard],
canActivate: [authGuard, roleGuard],
data: {
roles: ['.'],
},
+6
View File
@@ -223,6 +223,12 @@ export class AppComponent {
takeUntilDestroyed(),
)
.subscribe({
next: async (org) => {
if (!org) {
return this.router.navigate(['/users/me']);
}
return true;
},
error: async (err) => {
console.error(err);
return this.router.navigate(['/users/me']);
@@ -117,40 +117,42 @@ export class MembershipsTableComponent implements OnInit, OnDestroy {
public async goto(membership: Membership.AsObject) {
const org = await this.authService.getActiveOrg();
if (membership.orgId && !membership.projectId && !membership.projectGrantId) {
// only shown on auth user, or if currentOrg === resourceOwner
try {
const membershipOrg = await this.authService.getActiveOrg(membership.orgId);
await this.router.navigate(['/org/members']);
this.startOrgContextWorkflow(membershipOrg.id, org.id);
} catch (error) {
this.toast.showInfo('USER.MEMBERSHIPS.NOPERMISSIONTOEDIT', true);
if (org) {
if (membership.orgId && !membership.projectId && !membership.projectGrantId) {
// only shown on auth user, or if currentOrg === resourceOwner
try {
const membershipOrg = await this.authService.getActiveOrg(membership.orgId);
await this.router.navigate(['/org/members']);
this.startOrgContextWorkflow(membershipOrg?.id, org.id);
} catch (error) {
this.toast.showInfo('USER.MEMBERSHIPS.NOPERMISSIONTOEDIT', true);
}
} else if (membership.projectGrantId && membership.details?.resourceOwner) {
// only shown on auth user
try {
const membershipOrg = await this.authService.getActiveOrg(membership.details?.resourceOwner);
await this.router.navigate(['/granted-projects', membership.projectId, 'grants', membership.projectGrantId]);
this.startOrgContextWorkflow(membershipOrg?.id, org.id);
} catch (error) {
this.toast.showInfo('USER.MEMBERSHIPS.NOPERMISSIONTOEDIT', true);
}
} else if (membership.projectId && membership.details?.resourceOwner) {
// only shown on auth user, or if currentOrg === resourceOwner
try {
const membershipOrg = await this.authService.getActiveOrg(membership.details?.resourceOwner);
await this.router.navigate(['/projects', membership.projectId, 'members']);
this.startOrgContextWorkflow(membershipOrg?.id, org.id);
} catch (error) {
this.toast.showInfo('USER.MEMBERSHIPS.NOPERMISSIONTOEDIT', true);
}
} else if (membership.iam) {
// only shown on auth user
await this.router.navigate(['/instance/members']);
}
} else if (membership.projectGrantId && membership.details?.resourceOwner) {
// only shown on auth user
try {
const membershipOrg = await this.authService.getActiveOrg(membership.details?.resourceOwner);
await this.router.navigate(['/granted-projects', membership.projectId, 'grants', membership.projectGrantId]);
this.startOrgContextWorkflow(membershipOrg.id, org.id);
} catch (error) {
this.toast.showInfo('USER.MEMBERSHIPS.NOPERMISSIONTOEDIT', true);
}
} else if (membership.projectId && membership.details?.resourceOwner) {
// only shown on auth user, or if currentOrg === resourceOwner
try {
const membershipOrg = await this.authService.getActiveOrg(membership.details?.resourceOwner);
await this.router.navigate(['/projects', membership.projectId, 'members']);
this.startOrgContextWorkflow(membershipOrg.id, org.id);
} catch (error) {
this.toast.showInfo('USER.MEMBERSHIPS.NOPERMISSIONTOEDIT', true);
}
} else if (membership.iam) {
// only shown on auth user
await this.router.navigate(['/instance/members']);
}
}
private startOrgContextWorkflow(membershipOrgId: string, currentOrgId?: string | null): void {
private startOrgContextWorkflow(membershipOrgId?: string, currentOrgId?: string | null): void {
if (!currentOrgId || (membershipOrgId && currentOrgId && currentOrgId !== membershipOrgId)) {
setTimeout(() => {
this.workflowService.startWorkflow(OrgContextChangedWorkflowOverlays, null);
@@ -75,6 +75,10 @@ export class DomainPolicyComponent implements OnInit {
public async savePolicy(): Promise<void> {
const org = await this.authService.getActiveOrg();
if (!org) {
console.log('No active organization found. Cannot save domain policy.');
return;
}
switch (this.serviceType) {
case PolicyComponentServiceType.MGMT:
if ((this.domainData as OrgIAMPolicy.AsObject).isDefault) {
@@ -150,6 +154,10 @@ export class DomainPolicyComponent implements OnInit {
try {
const org = await this.authService.getActiveOrg();
if (!org) {
console.log('No active organization found. Cannot reset domain policy.');
return;
}
await this.adminService.resetCustomDomainPolicyToDefault(org.id);
this.toast.showInfo('POLICY.TOAST.RESETSUCCESS', true);
await new Promise((res) => setTimeout(res, 1000));
@@ -184,6 +184,10 @@ export class UserCreateV2Component implements OnInit {
this.loading.set(true);
const activeOrg = await this.authService.getActiveOrg();
if (!activeOrg) {
console.log('No active organization found. Cannot create user.');
return;
}
const userValues = this.userForm.getRawValue();
const humanReq: MessageInitShape<typeof AddHumanUserRequestSchema> = {
@@ -197,7 +197,7 @@ export class GrpcAuthService {
return this.grpcService.auth.listMyMetadata(req, null).then((resp) => resp.toObject());
}
public async getActiveOrg(id?: string): Promise<Org.AsObject> {
public async getActiveOrg(id?: string): Promise<Org.AsObject | undefined> {
if (id) {
const find = this.cachedOrgs.getValue().find((tmp) => tmp.id === id);
if (find) {
@@ -249,7 +249,7 @@ export class GrpcAuthService {
if (orgs.length === 0) {
this._activeOrgChanged.next(undefined);
return Promise.reject(new Error('No organizations found!'));
return undefined;
}
const orgToSet = orgs.find((element) => element.id !== '0' && element.name !== '');