From 42424dff8b2aaea861ad3372adda92496cec3c21 Mon Sep 17 00:00:00 2001 From: Nitesh Yadav Date: Fri, 11 Sep 2026 15:13:29 +0530 Subject: [PATCH] feat(security): tenant-level nav menu access control panel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the frontend half of the per-tenant menu-access ceiling (TenantMenuAccessApiResource on the backend): a bank cannot show a top-nav section the platform operator has capped, no matter what any role inside that tenant grants itself — closing the gap where a role carrying ALL_FUNCTIONS (as "Clerk" was found to, in two tenants this session) bypassed every ordinary MENU_.../SIDEBAR_... permission check. - tenant-menu-access.service.ts: loads the current tenant's list once, into a plain Set (not an Observable the directive would have to subscribe to, since mifosxHasPermission's setter runs synchronously). A failed load is treated as "nothing disabled" so a network hiccup on login never hides the whole nav. - has-permission.directive.ts: checks the tenant's ceiling first, ahead of the ALL_FUNCTIONS bypass — that ordering is the actual fix. - shell.component.ts/html: the nav now waits on the list being loaded before rendering at all, so a disabled menu is never shown and then hidden a moment later. - New standalone platform-admin/menu-access screen (#/platform-admin/ menu-access), reachable without logging in — its own X-Api-Key is the real boundary, checked on the backend, not this route. Lets the operator pick any tenant and toggle its menu list. Redesigned per request: full-width layout, icon-matched toggle tiles (same icon per item as the real nav), live enabled-count, connection status. - Loan Origination and Investment now use their own MENU_LOAN_ORIGINATION / MENU_INVESTMENT codes (see backend 0542) instead of sharing MENU_ADVANCES / MENU_RBI, so all 27 nav items are independently controllable from this screen. Also: src/assets/env.js — restored 'socity_bank' to fineractPlatformTenantIds. The tenant now exists in the tenant-store database; the comment explaining its earlier removal was stale. --- src/app/app-routing.module.ts | 7 + src/app/core/shell/shell.component.html | 11 +- src/app/core/shell/shell.component.ts | 11 + .../has-permission.directive.ts | 9 + .../tenant-menu-access.service.ts | 61 +++ .../menu-access/menu-access.component.html | 135 ++++++ .../menu-access/menu-access.component.scss | 431 ++++++++++++++++++ .../menu-access/menu-access.component.ts | 217 +++++++++ src/assets/env.js | 4 +- src/environments/.env.ts | 2 +- 10 files changed, 882 insertions(+), 6 deletions(-) create mode 100644 src/app/directives/has-permission/tenant-menu-access.service.ts create mode 100644 src/app/platform-admin/menu-access/menu-access.component.html create mode 100644 src/app/platform-admin/menu-access/menu-access.component.scss create mode 100644 src/app/platform-admin/menu-access/menu-access.component.ts diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index c2317b327..4cfde7def 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -13,6 +13,7 @@ import { Routes, RouterModule } from '@angular/router'; // Not Found Component import { NotFoundComponent } from './not-found/not-found.component'; import { CallbackComponent } from './zitadel/callback/callback.component'; +import { PlatformMenuAccessComponent } from './platform-admin/menu-access/menu-access.component'; /** * Fallback to this route when no prior route is matched. @@ -22,6 +23,12 @@ const routes: Routes = [ path: 'callback', component: CallbackComponent }, + { + // Platform-operator only — outside the normal login/tenant flow on purpose, see + // PlatformMenuAccessComponent's own doc comment for why that is safe. + path: 'platform-admin/menu-access', + component: PlatformMenuAccessComponent + }, { path: '**', component: NotFoundComponent diff --git a/src/app/core/shell/shell.component.html b/src/app/core/shell/shell.component.html index a2390e459..cf61082bd 100644 --- a/src/app/core/shell/shell.component.html +++ b/src/app/core/shell/shell.component.html @@ -473,7 +473,7 @@ ════════ END OLD ORDER ════════ --> - @if (!hideShellLayout) { + @if (!hideShellLayout && menuAccessReady) {