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);