From ff8417ed319e7767eb237e5bb5327bf141602c0c Mon Sep 17 00:00:00 2001 From: Leigh Pointer Date: Wed, 31 Dec 2025 11:10:10 +0100 Subject: [PATCH] Refine tab visibility authorization logic Updated the tab visibility logic to clarify and enforce the authorization hierarchy. Host-only tabs now strictly require the Host role, Admins bypass all checks except Host, and null SecurityAccessLevel still enforces RoleName and PermissionName if specified. Improved code comments for clarity and adjusted logic to ensure correct permission checks. --- Oqtane.Client/Modules/Controls/TabStrip.razor | 52 ++++++++++++++----- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/Oqtane.Client/Modules/Controls/TabStrip.razor b/Oqtane.Client/Modules/Controls/TabStrip.razor index a8402d86..53cd6e11 100644 --- a/Oqtane.Client/Modules/Controls/TabStrip.razor +++ b/Oqtane.Client/Modules/Controls/TabStrip.razor @@ -86,11 +86,19 @@ /// /// Determines if a tab should be visible based on user permissions. - /// Authorization hierarchy: - /// 1. Host and Admin roles ALWAYS have access (bypass all checks) - /// 2. Check standard SecurityAccessLevel (View, Edit, etc.) - /// 3. If RoleName specified AND user is not Admin/Host, check RoleName - /// 4. If PermissionName specified AND user is not Admin/Host, check PermissionName + /// Authorization follows this hierarchy: + /// 1. Host tabs (Security == Host): Only users with Host role can access (Admins excluded) + /// 2. Admin users: Bypass all other checks (except Host restrictions) + /// 3. SecurityAccessLevel check (null/Anonymous/View/Edit/Host): + /// - null: No security level restriction (proceeds to step 4) + /// - Anonymous: No authentication required + /// - View/Edit: Requires corresponding module permission + /// - Host: Only Host role can access + /// 4. Additional RoleName requirement (if specified) + /// 5. Additional PermissionName requirement (if specified) + /// + /// Important: When Security is null, RoleName and PermissionName checks STILL apply + /// (Security = null doesn't mean unrestricted, it means "no security level required") /// /// The tab panel to check authorization for /// True if user is authorized to see this tab, false otherwise @@ -99,24 +107,40 @@ // Step 1: Check for Host-only restriction if (tabPanel.Security == SecurityAccessLevel.Host) { - // Only Host users can access Host-level security tabs (Admin users are excluded) return UserSecurity.IsAuthorized(PageState.User, RoleNames.Host); } - // Step 2: Admin bypass all other restrictions + // Step 2: Admin bypass all restrictions except Host if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin)) { return true; } - var authorized = false; + // Step 3: If Security is null, check only RoleName and PermissionName + if (tabPanel.Security == null) + { + // Start with authorized = true for null security + bool isAuthorized = true; - // Step 3: Check standard SecurityAccessLevel + // Only apply RoleName check if provided + if (!string.IsNullOrEmpty(tabPanel.RoleName)) + { + isAuthorized = UserSecurity.IsAuthorized(PageState.User, tabPanel.RoleName); + } + + // Only apply PermissionName check if provided + if (isAuthorized && !string.IsNullOrEmpty(tabPanel.PermissionName)) + { + isAuthorized = UserSecurity.IsAuthorized(PageState.User, tabPanel.PermissionName, ModuleState.PermissionList); + } + + return isAuthorized; + } + + // Handle other SecurityAccessLevel values + bool authorized = false; // Use different variable name or move declaration switch (tabPanel.Security) { - case null: - authorized = true; - break; case SecurityAccessLevel.Anonymous: authorized = true; break; @@ -131,13 +155,13 @@ break; } - // Step 4: Check RoleName if provided (additional requirement) + // Step 4: Additional RoleName requirement if (authorized && !string.IsNullOrEmpty(tabPanel.RoleName)) { authorized = UserSecurity.IsAuthorized(PageState.User, tabPanel.RoleName); } - // Step 5: Check PermissionName if provided (additional requirement) + // Step 5: Additional PermissionName requirement if (authorized && !string.IsNullOrEmpty(tabPanel.PermissionName)) { authorized = UserSecurity.IsAuthorized(PageState.User, tabPanel.PermissionName, ModuleState.PermissionList);