From 8605e3ca5ab7a853af5904f8e4cb8b307dd938c4 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Tue, 28 Feb 2023 17:59:21 -0500 Subject: [PATCH] Major refactoring replacing permission strings with permission collections. These changes will require extensive regression testing. These changes may include breaking changes which will need to be identified and resolved to provide backward compatibility. --- Oqtane.Client/Modules/Admin/Files/Edit.razor | 2 +- .../Admin/ModuleDefinitions/Edit.razor | 2 +- .../Modules/Admin/Modules/Settings.razor | 2 +- Oqtane.Client/Modules/Admin/Pages/Add.razor | 3 +- Oqtane.Client/Modules/Admin/Pages/Edit.razor | 2 +- .../Modules/Controls/ActionDialog.razor | 6 +- .../Modules/Controls/ActionLink.razor | 6 +- .../Modules/Controls/PermissionGrid.razor | 238 +++++++++--------- .../Controls/Container/ModuleActionsBase.cs | 36 ++- .../Themes/Controls/Theme/ControlPanel.razor | 48 ++-- Oqtane.Server/Controllers/FolderController.cs | 2 +- Oqtane.Server/Controllers/PageController.cs | 7 +- .../Extensions/PermissionExtension.cs | 56 +---- .../Interfaces/IPermissionRepository.cs | 6 +- .../Repository/PermissionRepository.cs | 142 ++--------- Oqtane.Server/Security/UserPermissions.cs | 11 +- Oqtane.Shared/Models/Folder.cs | 3 +- Oqtane.Shared/Models/Module.cs | 2 +- Oqtane.Shared/Models/ModuleDefinition.cs | 3 +- Oqtane.Shared/Models/Page.cs | 2 +- Oqtane.Shared/Models/Permission.cs | 35 ++- Oqtane.Shared/Models/PermissionString.cs | 23 -- Oqtane.Shared/Models/SiteTemplate.cs | 4 +- Oqtane.Shared/Security/UserSecurity.cs | 110 +++----- 24 files changed, 274 insertions(+), 477 deletions(-) delete mode 100644 Oqtane.Shared/Models/PermissionString.cs diff --git a/Oqtane.Client/Modules/Admin/Files/Edit.razor b/Oqtane.Client/Modules/Admin/Files/Edit.razor index 4f53443f..e474f597 100644 --- a/Oqtane.Client/Modules/Admin/Files/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Files/Edit.razor @@ -99,7 +99,7 @@ private string _imagesizes = string.Empty; private string _capacity = "0"; private bool _isSystem; - private string _permissions = string.Empty; + private List _permissions; private string _createdBy; private DateTime _createdOn; private string _modifiedBy; diff --git a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Edit.razor b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Edit.razor index a8a78168..5da79f52 100644 --- a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Edit.razor +++ b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Edit.razor @@ -206,7 +206,7 @@ private string _contact = ""; private string _license = ""; private string _runtimes = ""; - private string _permissions; + private List _permissions; private string _createdby; private DateTime _createdon; private string _modifiedby; diff --git a/Oqtane.Client/Modules/Admin/Modules/Settings.razor b/Oqtane.Client/Modules/Admin/Modules/Settings.razor index ca84fd46..8195b54a 100644 --- a/Oqtane.Client/Modules/Admin/Modules/Settings.razor +++ b/Oqtane.Client/Modules/Admin/Modules/Settings.razor @@ -101,7 +101,7 @@ private string _containerType; private string _allPages = "false"; private string _permissionNames = ""; - private string _permissions = null; + private List _permissions; private string _pageId; private PermissionGrid _permissionGrid; private Type _moduleSettingsType; diff --git a/Oqtane.Client/Modules/Admin/Pages/Add.razor b/Oqtane.Client/Modules/Admin/Pages/Add.razor index bd0cd704..716677fd 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Add.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Add.razor @@ -183,7 +183,7 @@ private string _themetype = string.Empty; private string _containertype = string.Empty; private string _icon = string.Empty; - private string _permissions = string.Empty; + private List _permissions = null; private PermissionGrid _permissionGrid; private Type _themeSettingsType; private object _themeSettings; @@ -202,7 +202,6 @@ _containers = ThemeService.GetContainerControls(_themeList, _themetype); _containertype = PageState.Site.DefaultContainerType; _children = PageState.Pages.Where(item => item.ParentId == null).ToList(); - _permissions = string.Empty; ThemeSettings(); } catch (Exception ex) diff --git a/Oqtane.Client/Modules/Admin/Pages/Edit.razor b/Oqtane.Client/Modules/Admin/Pages/Edit.razor index 144a4dad..0cfc24b6 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Edit.razor @@ -221,7 +221,7 @@ private string _themetype; private string _containertype = "-"; private string _icon; - private string _permissions = null; + private List _permissions = null; private string _createdby; private DateTime _createdon; private string _modifiedby; diff --git a/Oqtane.Client/Modules/Controls/ActionDialog.razor b/Oqtane.Client/Modules/Controls/ActionDialog.razor index 4e21b91a..13cdf176 100644 --- a/Oqtane.Client/Modules/Controls/ActionDialog.razor +++ b/Oqtane.Client/Modules/Controls/ActionDialog.razor @@ -40,7 +40,7 @@ @code { private bool _visible = false; - private string _permissions = string.Empty; + private List _permissions; private bool _editmode = false; private bool _authorized = false; private string _iconSpan = string.Empty; @@ -61,7 +61,7 @@ public SecurityAccessLevel? Security { get; set; } // optional - can be used to explicitly specify SecurityAccessLevel [Parameter] - public string Permissions { get; set; } // optional - can be used to specify a permission string + public List Permissions { get; set; } // optional - can be used to specify permissions [Parameter] public string Class { get; set; } // optional @@ -109,7 +109,7 @@ Header = Localize(nameof(Header), Header); Message = Localize(nameof(Message), Message); - _permissions = (string.IsNullOrEmpty(Permissions)) ? ModuleState.Permissions : Permissions; + _permissions = (Permissions == null) ? ModuleState.Permissions : Permissions; _authorized = IsAuthorized(); } diff --git a/Oqtane.Client/Modules/Controls/ActionLink.razor b/Oqtane.Client/Modules/Controls/ActionLink.razor index 6f3a29bf..2bc3bc52 100644 --- a/Oqtane.Client/Modules/Controls/ActionLink.razor +++ b/Oqtane.Client/Modules/Controls/ActionLink.razor @@ -26,7 +26,7 @@ private string _text = string.Empty; private string _parameters = string.Empty; private string _url = string.Empty; - private string _permissions = string.Empty; + private List _permissions; private bool _editmode = false; private bool _authorized = false; private string _classname = "btn btn-primary"; @@ -52,7 +52,7 @@ public SecurityAccessLevel? Security { get; set; } // optional - can be used to explicitly specify SecurityAccessLevel [Parameter] - public string Permissions { get; set; } // optional - can be used to specify a permission string + public List Permissions { get; set; } // optional - can be used to specify permissions [Parameter] public bool Disabled { get; set; } // optional @@ -119,7 +119,7 @@ _iconSpan = $"{(IconOnly ? "" : " ")}"; } - _permissions = (string.IsNullOrEmpty(Permissions)) ? ModuleState.Permissions : Permissions; + _permissions = (Permissions == null) ? ModuleState.Permissions : Permissions; _text = Localize(nameof(Text), _text); _url = (ModuleId == -1) ? EditUrl(Action, _parameters) : EditUrl(ModuleId, Action, _parameters); if (!string.IsNullOrEmpty(ReturnUrl)) diff --git a/Oqtane.Client/Modules/Controls/PermissionGrid.razor b/Oqtane.Client/Modules/Controls/PermissionGrid.razor index 4fcdc5ac..b8d5443c 100644 --- a/Oqtane.Client/Modules/Controls/PermissionGrid.razor +++ b/Oqtane.Client/Modules/Controls/PermissionGrid.razor @@ -15,20 +15,19 @@ @Localizer["Role"] - @foreach (PermissionString permission in _permissions) + @foreach (var permissionname in _permissionnames) { - @((MarkupString)GetPermissionName(permission).Replace(" ", "
")) + @((MarkupString)DisplayPermissionName(permissionname).Replace(" ", "
")) } @foreach (Role role in _roles) { @role.Name - @foreach (PermissionString permission in _permissions) + @foreach (var permissionname in _permissionnames) { - var p = permission; - + } @@ -50,23 +49,21 @@ @Localizer["User"] - @foreach (PermissionString permission in _permissions) - { - @Localizer[permission.PermissionName] - } - + @foreach (var permissionname in _permissionnames) + { + @((MarkupString)DisplayPermissionName(permissionname).Replace(" ", "
")) + } + @foreach (User user in _users) { - string userid = "[" + user.UserId.ToString() + "]"; @user.DisplayName - @foreach (PermissionString permission in _permissions) + @foreach (var permissionname in _permissionnames) { - var p = permission; - + } @@ -94,9 +91,9 @@ } @code { - private string _permissionnames = string.Empty; + private List _permissionnames; + private List _permissions; private List _roles; - private List _permissions; private List _users = new List(); private AutoComplete _user; private string _message = string.Empty; @@ -108,28 +105,31 @@ public string PermissionNames { get; set; } [Parameter] - public string Permissions { get; set; } + public List Permissions { get; set; } protected override async Task OnInitializedAsync() { - if (string.IsNullOrEmpty(PermissionNames)) - { - _permissionnames = Shared.PermissionNames.View + "," + Shared.PermissionNames.Edit; - } - else - { - _permissionnames = PermissionNames; - } - _roles = await RoleService.GetRolesAsync(ModuleState.SiteId, true); if (!UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) { _roles.RemoveAll(item => item.Name == RoleNames.Host); } - _permissions = new List(); + // get permission names + if (string.IsNullOrEmpty(PermissionNames)) + { + _permissionnames = new List(); + _permissionnames.Add(Shared.PermissionNames.View); + _permissionnames.Add(Shared.PermissionNames.Edit); + } + else + { + _permissionnames = PermissionNames.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList(); + } - foreach (string permissionname in _permissionnames.Split(',', StringSplitOptions.RemoveEmptyEntries)) + // initialize permissions + _permissions = new List(); + foreach (string permissionname in _permissionnames) { // permission names can be in the form of "EntityName:PermissionName:Roles" if (permissionname.Contains(":")) @@ -137,78 +137,83 @@ var segments = permissionname.Split(':'); if (segments.Length == 3) { - if (!segments[2].Contains(RoleNames.Admin)) + foreach (var role in segments[2].Split(';')) { - segments[2] = RoleNames.Admin + ";" + segments[2]; // ensure admin access + _permissions.Add(new Permission(segments[0], segments[1], role, null, true)); + } + // ensure admin access + if (!_permissions.Any(item => item.EntityName == segments[0] && item.PermissionName == segments[1] && item.Role.Name == RoleNames.Admin)) + { + _permissions.Add(new Permission(segments[0], segments[1], RoleNames.Admin, null, true)); } - _permissions.Add(new PermissionString { EntityName = segments[0], PermissionName = segments[1], Permissions = segments[2] }); } } else { - _permissions.Add(new PermissionString { EntityName = EntityName, PermissionName = permissionname, Permissions = RoleNames.Admin }); + _permissions.Add(new Permission(EntityName, permissionname, RoleNames.Admin, null, true)); } } - if (!string.IsNullOrEmpty(Permissions)) + // populate permissions and users + if (Permissions.Any()) { - // populate permissions - foreach (PermissionString permissionstring in UserSecurity.GetPermissionStrings(Permissions)) + foreach (var permission in Permissions) { - int index = _permissions.FindIndex(item => item.EntityName == permissionstring.EntityName && item.PermissionName == permissionstring.PermissionName); - if (index != -1) + if (!_permissions.Any(item => item.EntityName == permission.EntityName && item.PermissionName == permission.PermissionName && item.Role.Name == permission.Role.Name)) { - _permissions[index].Permissions = permissionstring.Permissions; + _permissions.Add(permission); } - - if (permissionstring.Permissions.Contains("[")) + if (permission.UserId != null) { - foreach (string user in permissionstring.Permissions.Split('[', StringSplitOptions.RemoveEmptyEntries)) + if (!_users.Any(item => item.UserId == permission.UserId.Value)) { - if (user.Contains("]")) - { - var userid = int.Parse(user.Substring(0, user.IndexOf("]"))); - if (_users.Where(item => item.UserId == userid).FirstOrDefault() == null) - { - _users.Add(await UserService.GetUserAsync(userid, ModuleState.SiteId)); - } - } + _users.Add(await UserService.GetUserAsync(permission.UserId.Value, ModuleState.SiteId)); } } } } } - private string GetPermissionName(PermissionString permission) + private string GetPermissionName(string permissionName) { - var permissionname = Localizer[permission.PermissionName].ToString(); - if (!string.IsNullOrEmpty(EntityName)) - { - permissionname += " " + Localizer[permission.EntityName].ToString(); - } - return permissionname; + return (permissionName.Contains(":")) ? permissionName.Split(':')[1] : permissionName; } - private bool? GetPermissionValue(string permissions, string securityKey) + private string GetEntityName(string permissionName) { - if ((";" + permissions + ";").Contains(";" + "!" + securityKey + ";")) + return (permissionName.Contains(":")) ? permissionName.Split(':')[0] : EntityName; + } + + private string DisplayPermissionName(string permissionName) + { + var name = Localizer[GetPermissionName(permissionName)].ToString(); + name += " " + Localizer[GetEntityName(permissionName)].ToString(); + return name; + } + + private bool? GetPermissionValue(string permissionName, string roleName, int userId) + { + bool? isauthorized = null; + if (roleName != "") { - return false; // deny permission + var permission = _permissions.FirstOrDefault(item => item.EntityName == GetEntityName(permissionName) && item.PermissionName == GetPermissionName(permissionName) && item.Role.Name == roleName); + if (permission != null) + { + isauthorized = permission.IsAuthorized; + } } else { - if ((";" + permissions + ";").Contains(";" + securityKey + ";")) + var permission = _permissions.FirstOrDefault(item => item.EntityName == GetEntityName(permissionName) && item.PermissionName == GetPermissionName(permissionName) && item.UserId == userId); + if (permission != null) { - return true; // grant permission - } - else - { - return null; // not specified - } + isauthorized = permission.IsAuthorized; + } } + return isauthorized; } - private bool GetPermissionDisabled(string entityName, string permissionName, string roleName) + private bool GetPermissionDisabled(string permissionName, string roleName) { if (roleName == RoleNames.Admin && !UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) { @@ -216,7 +221,7 @@ } else { - if (entityName != EntityName && !UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin)) + if (GetEntityName(permissionName) != EntityName && !UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin)) { return true; } @@ -227,6 +232,34 @@ } } + private void PermissionChanged(bool? value, string permissionName, string roleName, int userId) + { + if (roleName != "") + { + var permission = _permissions.FirstOrDefault(item => item.EntityName == GetEntityName(permissionName) && item.PermissionName == GetPermissionName(permissionName) && item.Role.Name == roleName); + if (permission == null) + { + _permissions.Remove(permission); + } + if (value != null) + { + _permissions.Add(new Permission(GetEntityName(permissionName), GetPermissionName(permissionName), roleName, null, value.Value)); + } + } + else + { + var permission = _permissions.FirstOrDefault(item => item.EntityName == GetEntityName(permissionName) && item.PermissionName == GetPermissionName(permissionName) && item.UserId == userId); + if (permission == null) + { + _permissions.Remove(permission); + } + if (value != null) + { + _permissions.Add(new Permission(GetEntityName(permissionName), GetPermissionName(permissionName), null, userId, value.Value)); + } + } + } + private async Task> GetUsers(string filter) { var users = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Registered); @@ -251,62 +284,39 @@ _user.Clear(); } - private void PermissionChanged(bool? value, string entityName, string permissionName, string securityId) - { - var selected = value; - int index = _permissions.FindIndex(item => item.EntityName == entityName && item.PermissionName == permissionName); - if (index != -1) - { - var permission = _permissions[index]; - - var ids = permission.Permissions.Split(';').ToList(); - ids.Remove(securityId); // remove grant permission - ids.Remove("!" + securityId); // remove deny permission - - switch (selected) - { - case true: - ids.Add(securityId); // add grant permission - break; - case false: - ids.Add("!" + securityId); // add deny permission - break; - case null: - break; // permission not specified - } - - _permissions[index].Permissions = string.Join(";", ids.ToArray()); - } - } - - public string GetPermissions() + public List GetPermissions() { ValidatePermissions(); - return UserSecurity.SetPermissionStrings(_permissions); + return _permissions; } private void ValidatePermissions() { - PermissionString permission; - for (int index = 0; index < _permissions.Count; index++) + // remove deny all users, unauthenticated, and registered users + var permissions = _permissions.Where(item => !item.IsAuthorized && + (item.Role.Name == RoleNames.Everyone || item.Role.Name == RoleNames.Unauthenticated || item.Role.Name == RoleNames.Registered)); + foreach (var permission in permissions) { - permission = _permissions[index]; - List ids = permission.Permissions.Split(';', StringSplitOptions.RemoveEmptyEntries).ToList(); - ids.Remove("!" + RoleNames.Everyone); // remove deny all users - ids.Remove("!" + RoleNames.Unauthenticated); // remove deny unauthenticated - ids.Remove("!" + RoleNames.Registered); // remove deny registered users - if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) + _permissions.Remove(permission); + } + if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) + { + // remove deny administrators and host users + permissions = _permissions.Where(item => !item.IsAuthorized && + (item.Role.Name == RoleNames.Admin || item.Role.Name == RoleNames.Host)); + foreach (var permission in permissions) { - ids.Remove("!" + RoleNames.Admin); // remove deny administrators - ids.Remove("!" + RoleNames.Host); // remove deny host users - if (!ids.Contains(RoleNames.Host) && !ids.Contains(RoleNames.Admin)) + _permissions.Remove(permission); + } + foreach (var permissionname in _permissionnames) + { + // add administrators role if neither host or administrator is assigned + if (!_permissions.Any(item => item.EntityName == GetEntityName(permissionname) && item.PermissionName == GetPermissionName(permissionname) && + (item.Role.Name == RoleNames.Admin || item.Role.Name == RoleNames.Host))) { - // add administrators role if host user role is not assigned - ids.Add(RoleNames.Admin); + _permissions.Add(new Permission(GetEntityName(permissionname), GetPermissionName(permissionname), RoleNames.Admin, null, true)); } } - permission.Permissions = string.Join(";", ids.ToArray()); - _permissions[index] = permission; - } + } } } diff --git a/Oqtane.Client/Themes/Controls/Container/ModuleActionsBase.cs b/Oqtane.Client/Themes/Controls/Container/ModuleActionsBase.cs index 8714b938..d08d0a44 100644 --- a/Oqtane.Client/Themes/Controls/Container/ModuleActionsBase.cs +++ b/Oqtane.Client/Themes/Controls/Container/ModuleActionsBase.cs @@ -136,36 +136,32 @@ namespace Oqtane.Themes.Controls private async Task Publish(string url, PageModule pagemodule) { - var permissions = UserSecurity.GetPermissionStrings(pagemodule.Module.Permissions); - foreach (var permissionstring in permissions) + var permissions = pagemodule.Module.Permissions; + if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.Role.Name == RoleNames.Everyone)) { - if (permissionstring.PermissionName == PermissionNames.View) - { - List ids = permissionstring.Permissions.Split(';').ToList(); - if (!ids.Contains(RoleNames.Everyone)) ids.Add(RoleNames.Everyone); - if (!ids.Contains(RoleNames.Registered)) ids.Add(RoleNames.Registered); - permissionstring.Permissions = string.Join(";", ids.ToArray()); - } + permissions.Add(new Permission(EntityNames.Page, pagemodule.PageId, PermissionNames.View, RoleNames.Everyone, null, true)); } - pagemodule.Module.Permissions = UserSecurity.SetPermissionStrings(permissions); + if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.Role.Name == RoleNames.Registered)) + { + permissions.Add(new Permission(EntityNames.Page, pagemodule.PageId, PermissionNames.View, RoleNames.Registered, null, true)); + } + pagemodule.Module.Permissions = permissions; await ModuleService.UpdateModuleAsync(pagemodule.Module); return url; } private async Task Unpublish(string url, PageModule pagemodule) { - var permissions = UserSecurity.GetPermissionStrings(pagemodule.Module.Permissions); - foreach (var permissionstring in permissions) + var permissions = pagemodule.Module.Permissions; + if (permissions.Any(item => item.PermissionName == PermissionNames.View && item.Role.Name == RoleNames.Everyone)) { - if (permissionstring.PermissionName == PermissionNames.View) - { - List ids = permissionstring.Permissions.Split(';').ToList(); - ids.Remove(RoleNames.Everyone); - ids.Remove(RoleNames.Registered); - permissionstring.Permissions = string.Join(";", ids.ToArray()); - } + permissions.Remove(permissions.First(item => item.PermissionName == PermissionNames.View && item.Role.Name == RoleNames.Everyone)); } - pagemodule.Module.Permissions = UserSecurity.SetPermissionStrings(permissions); + if (permissions.Any(item => item.PermissionName == PermissionNames.View && item.Role.Name == RoleNames.Registered)) + { + permissions.Remove(permissions.First(item => item.PermissionName == PermissionNames.View && item.Role.Name == RoleNames.Registered)); + } + pagemodule.Module.Permissions = permissions; await ModuleService.UpdateModuleAsync(pagemodule.Module); return url; } diff --git a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor index e72a20d4..a49527c6 100644 --- a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor +++ b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor @@ -392,20 +392,21 @@ module.ModuleDefinitionName = ModuleDefinitionName; module.AllPages = false; - List permissions = UserSecurity.GetPermissionStrings(PageState.Page.Permissions); + var permissions = new List(); if (Visibility == "view") { // set module view permissions to page view permissions - permissions.Find(p => p.PermissionName == PermissionNames.View).Permissions = permissions.Find(p => p.PermissionName == PermissionNames.View).Permissions; + permissions = PageState.Page.Permissions.Where(item => item.PermissionName == PermissionNames.View).ToList(); } else { // set module view permissions to page edit permissions - permissions.Find(p => p.PermissionName == PermissionNames.View).Permissions = permissions.Find(p => p.PermissionName == PermissionNames.Edit).Permissions; + permissions = PageState.Page.Permissions.Where(item => item.PermissionName == PermissionNames.Edit).ToList(); } - // set entityname + // set entity name and permission name permissions.ForEach(item => item.EntityName = EntityNames.Module); - module.Permissions = UserSecurity.SetPermissionStrings(permissions); + permissions.ForEach(item => item.PermissionName = PermissionNames.View); + module.Permissions = permissions; module = await ModuleService.AddModuleAsync(module); ModuleId = module.ModuleId.ToString(); @@ -527,32 +528,17 @@ { if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions)) { - List permissions; - - // publish/unpublish page - var page = PageState.Page; - permissions = UserSecurity.GetPermissionStrings(page.Permissions); - foreach (var permissionstring in permissions) - { - if (permissionstring.PermissionName == PermissionNames.View) - { - List ids = permissionstring.Permissions.Split(';').ToList(); - switch (action) - { - case "publish": - if (!ids.Contains(RoleNames.Everyone)) ids.Add(RoleNames.Everyone); - if (!ids.Contains(RoleNames.Registered)) ids.Add(RoleNames.Registered); - break; - case "unpublish": - ids.Remove(RoleNames.Everyone); - ids.Remove(RoleNames.Registered); - break; - } - permissionstring.Permissions = string.Join(";", ids.ToArray()); - } - } - page.Permissions = UserSecurity.SetPermissionStrings(permissions); - await PageService.UpdatePageAsync(page); + var permissions = PageState.Page.Permissions; + if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.Role.Name == RoleNames.Everyone)) + { + permissions.Add(new Permission(EntityNames.Page, PageState.Page.PageId, PermissionNames.View, RoleNames.Everyone, null, true)); + } + if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.Role.Name == RoleNames.Registered)) + { + permissions.Add(new Permission(EntityNames.Page, PageState.Page.PageId, PermissionNames.View, RoleNames.Registered, null, true)); + } + PageState.Page.Permissions = permissions; + await PageService.UpdatePageAsync(PageState.Page); NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, true)); } } diff --git a/Oqtane.Server/Controllers/FolderController.cs b/Oqtane.Server/Controllers/FolderController.cs index 839c8e1f..445d41c5 100644 --- a/Oqtane.Server/Controllers/FolderController.cs +++ b/Oqtane.Server/Controllers/FolderController.cs @@ -104,7 +104,7 @@ namespace Oqtane.Controllers { if (ModelState.IsValid && folder.SiteId == _alias.SiteId) { - string permissions; + List permissions; if (folder.ParentId != null) { permissions = _folders.GetFolder(folder.ParentId.Value).Permissions; diff --git a/Oqtane.Server/Controllers/PageController.cs b/Oqtane.Server/Controllers/PageController.cs index 80d56d78..fd12234e 100644 --- a/Oqtane.Server/Controllers/PageController.cs +++ b/Oqtane.Server/Controllers/PageController.cs @@ -128,7 +128,7 @@ namespace Oqtane.Controllers { if (ModelState.IsValid && page.SiteId == _alias.SiteId) { - string permissions; + List permissions; if (page.ParentId != null) { permissions = _pages.GetPage(page.ParentId.Value).Permissions; @@ -274,9 +274,8 @@ namespace Oqtane.Controllers } // get differences between current and new page permissions - var newPermissions = _permissionRepository.DecodePermissions(page.Permissions, page.SiteId, EntityNames.Page, page.PageId).ToList(); - var added = GetPermissionsDifferences(newPermissions, currentPermissions); - var removed = GetPermissionsDifferences(currentPermissions, newPermissions); + var added = GetPermissionsDifferences(page.Permissions, currentPermissions); + var removed = GetPermissionsDifferences(currentPermissions, page.Permissions); // synchronize module permissions if (added.Count > 0 || removed.Count > 0) diff --git a/Oqtane.Server/Extensions/PermissionExtension.cs b/Oqtane.Server/Extensions/PermissionExtension.cs index ba02e294..bc2c4705 100644 --- a/Oqtane.Server/Extensions/PermissionExtension.cs +++ b/Oqtane.Server/Extensions/PermissionExtension.cs @@ -1,66 +1,14 @@ using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Text.Json; using Oqtane.Models; namespace Oqtane.Extensions { public static class PermissionExtension { - public static string EncodePermissions(this IEnumerable permissionList) + public static List EncodePermissions(this IEnumerable permissionList) { - List permissionstrings = new List(); - string entityname = ""; - string permissionname = ""; - string permissions = ""; - StringBuilder permissionsbuilder = new StringBuilder(); - string securityid = ""; - foreach (Permission permission in permissionList.OrderBy(item => item.EntityName).ThenBy(item => item.PermissionName)) - { - // permission collections are grouped by entityname and permissionname - if (entityname != permission.EntityName || permissionname != permission.PermissionName) - { - permissions = permissionsbuilder.ToString(); - if (permissions != "") - { - permissionstrings.Add(new PermissionString { EntityName = entityname, PermissionName = permissionname, Permissions = permissions.Substring(0, permissions.Length - 1) }); - } - entityname = permission.EntityName; - permissionname = permission.PermissionName; - permissionsbuilder = new StringBuilder(); - } - - // deny permissions are prefixed with a "!" - string prefix = !permission.IsAuthorized ? "!" : ""; - - // encode permission - if (permission.UserId == null) - { - securityid = prefix + permission.Role.Name + ";"; - } - else - { - securityid = prefix + "[" + permission.UserId + "];"; - } - - // insert deny permissions at the beginning and append grant permissions at the end - if (prefix == "!") - { - permissionsbuilder.Insert(0, securityid); - } - else - { - permissionsbuilder.Append(securityid); - } - } - - permissions = permissionsbuilder.ToString(); - if (permissions != "") - { - permissionstrings.Add(new PermissionString { EntityName = entityname, PermissionName = permissionname, Permissions = permissions.Substring(0, permissions.Length - 1) }); - } - return JsonSerializer.Serialize(permissionstrings); + return permissionList.ToList(); } } } diff --git a/Oqtane.Server/Repository/Interfaces/IPermissionRepository.cs b/Oqtane.Server/Repository/Interfaces/IPermissionRepository.cs index 8ba2c9b0..a3dc7358 100644 --- a/Oqtane.Server/Repository/Interfaces/IPermissionRepository.cs +++ b/Oqtane.Server/Repository/Interfaces/IPermissionRepository.cs @@ -10,14 +10,12 @@ namespace Oqtane.Repository IEnumerable GetPermissions(int siteId, string entityName); IEnumerable GetPermissions(int siteId, string entityName, string permissionName); IEnumerable GetPermissions(int siteId, string entityName, int entityId); - IEnumerable GetPermissions(int siteId, string entityName, int entityId, string permissionName); - + IEnumerable GetPermissions(int siteId, string entityName, int entityId, string permissionName); Permission AddPermission(Permission permission); Permission UpdatePermission(Permission permission); - void UpdatePermissions(int siteId, string entityName, int entityId, string permissionStrings); + void UpdatePermissions(int siteId, string entityName, int entityId, List permissions); Permission GetPermission(int permissionId); void DeletePermission(int permissionId); void DeletePermissions(int siteId, string entityName, int entityId); - IEnumerable DecodePermissions(string permissions, int siteId, string entityName, int entityId); } } diff --git a/Oqtane.Server/Repository/PermissionRepository.cs b/Oqtane.Server/Repository/PermissionRepository.cs index d6e3d75f..c3f4acc6 100644 --- a/Oqtane.Server/Repository/PermissionRepository.cs +++ b/Oqtane.Server/Repository/PermissionRepository.cs @@ -7,6 +7,7 @@ using Microsoft.EntityFrameworkCore; using Oqtane.Models; using Microsoft.Extensions.Caching.Memory; using Oqtane.Infrastructure; +using Oqtane.Modules.Admin.Users; namespace Oqtane.Repository { @@ -77,11 +78,28 @@ namespace Oqtane.Repository return permission; } - public void UpdatePermissions(int siteId, string entityName, int entityId, string permissionStrings) + public void UpdatePermissions(int siteId, string entityName, int entityId, List permissions) { + // ensure permissions are fully populated + List roles = _roles.GetRoles(siteId, true).ToList(); + foreach (var permission in permissions) + { + permission.SiteId = siteId; + permission.EntityName = (string.IsNullOrEmpty(permission.EntityName)) ? entityName : permission.EntityName; + permission.EntityId = (permission.EntityName == entityName) ? entityId : -1; + if (permission.RoleId == null && permission.Role != null && !string.IsNullOrEmpty(permission.Role.Name)) + { + var role = roles.FirstOrDefault(item => item.Name == permission.Role.Name); + if (role != null) + { + permission.RoleId = role.RoleId; + } + } + permission.Role = null; + } + // add or update permissions bool modified = false; var existing = new List(); - var permissions = DecodePermissions(permissionStrings, siteId, entityName, entityId); foreach (var permission in permissions) { if (!existing.Any(item => item.EntityName == permission.EntityName && item.PermissionName == permission.PermissionName)) @@ -108,6 +126,7 @@ namespace Oqtane.Repository modified = true; } } + // delete permissions foreach (var permission in existing) { if (!permissions.Any(item => item.EntityName == permission.EntityName && item.PermissionName == permission.PermissionName @@ -163,122 +182,5 @@ namespace Oqtane.Repository _cache.Remove($"permissions:{alias.TenantId}:{siteId}:{entityName}"); } } - - // permissions are stored in the format "{permissionname:!rolename1;![userid1];rolename2;rolename3;[userid2];[userid3]}" where "!" designates Deny permissions - public string EncodePermissions(IEnumerable permissionList) - { - List permissionstrings = new List(); - string permissionname = ""; - string permissions = ""; - StringBuilder permissionsbuilder = new StringBuilder(); - string securityid = ""; - foreach (Permission permission in permissionList.OrderBy(item => item.PermissionName)) - { - // permission collections are grouped by permissionname - if (permissionname != permission.PermissionName) - { - permissions = permissionsbuilder.ToString(); - if (permissions != "") - { - permissionstrings.Add(new PermissionString { PermissionName = permissionname, Permissions = permissions.Substring(0, permissions.Length - 1) }); - } - permissionname = permission.PermissionName; - permissionsbuilder = new StringBuilder(); - } - - // deny permissions are prefixed with a "!" - string prefix = !permission.IsAuthorized ? "!" : ""; - - // encode permission - if (permission.UserId == null) - { - securityid = prefix + permission.Role.Name + ";"; - } - else - { - securityid = prefix + "[" + permission.UserId + "];"; - } - - // insert deny permissions at the beginning and append grant permissions at the end - if (prefix == "!") - { - permissionsbuilder.Insert(0, securityid); - } - else - { - permissionsbuilder.Append(securityid); - } - } - - permissions = permissionsbuilder.ToString(); - if (permissions != "") - { - permissionstrings.Add(new PermissionString { PermissionName = permissionname, Permissions = permissions.Substring(0, permissions.Length - 1) }); - } - return JsonSerializer.Serialize(permissionstrings); - } - - public IEnumerable DecodePermissions(string permissionStrings, int siteId, string entityName, int entityId) - { - List permissions = new List(); - List roles = _roles.GetRoles(siteId, true).ToList(); - string securityid = ""; - foreach (PermissionString permissionstring in JsonSerializer.Deserialize>(permissionStrings)) - { - foreach (string id in permissionstring.Permissions.Split(';', StringSplitOptions.RemoveEmptyEntries)) - { - securityid = id; - Permission permission = new Permission(); - permission.SiteId = siteId; - if (!string.IsNullOrEmpty(permissionstring.EntityName)) - { - permission.EntityName = permissionstring.EntityName; - } - else - { - permission.EntityName = entityName; - } - if (permission.EntityName == entityName) - { - permission.EntityId = entityId; - } - else - { - permission.EntityId = -1; - } - permission.PermissionName = permissionstring.PermissionName; - permission.RoleId = null; - permission.UserId = null; - permission.IsAuthorized = true; - - if (securityid.StartsWith("!")) - { - // deny permission - securityid = securityid.Replace("!", ""); - permission.IsAuthorized = false; - } - if (securityid.StartsWith("[") && securityid.EndsWith("]")) - { - // user id - securityid = securityid.Replace("[", "").Replace("]", ""); - permission.UserId = int.Parse(securityid); - } - else - { - // role name - Role role = roles.SingleOrDefault(item => item.Name == securityid); - if (role != null) - { - permission.RoleId = role.RoleId; - } - } - if (permission.UserId != null || permission.RoleId != null) - { - permissions.Add(permission); - } - } - } - return permissions; - } - } + } } diff --git a/Oqtane.Server/Security/UserPermissions.cs b/Oqtane.Server/Security/UserPermissions.cs index cf0217c4..91d2cc90 100644 --- a/Oqtane.Server/Security/UserPermissions.cs +++ b/Oqtane.Server/Security/UserPermissions.cs @@ -5,6 +5,7 @@ using System.Security.Claims; using Oqtane.Repository; using Oqtane.Extensions; using System; +using System.Collections.Generic; namespace Oqtane.Security { @@ -12,7 +13,7 @@ namespace Oqtane.Security { bool IsAuthorized(ClaimsPrincipal user, int siteId, string entityName, int entityId, string permissionName, string roles); bool IsAuthorized(ClaimsPrincipal user, int siteId, string entityName, int entityId, string permissionName); - bool IsAuthorized(ClaimsPrincipal user, string permissionName, string permissions); + bool IsAuthorized(ClaimsPrincipal user, string permissionName, List permissions); User GetUser(ClaimsPrincipal user); User GetUser(); @@ -36,7 +37,7 @@ namespace Oqtane.Security var permissions = _permissions.GetPermissions(siteId, entityName, entityId, permissionName).ToList(); if (permissions != null && permissions.Count != 0) { - return IsAuthorized(principal, permissionName, permissions.EncodePermissions()); + return IsAuthorized(principal, permissionName, permissions.ToList()); } else { @@ -46,10 +47,10 @@ namespace Oqtane.Security public bool IsAuthorized(ClaimsPrincipal principal, int siteId, string entityName, int entityId, string permissionName) { - return IsAuthorized(principal, permissionName, _permissions.GetPermissions(siteId, entityName, entityId, permissionName)?.EncodePermissions()); + return IsAuthorized(principal, permissionName, _permissions.GetPermissions(siteId, entityName, entityId, permissionName).ToList()); } - public bool IsAuthorized(ClaimsPrincipal principal, string permissionName, string permissions) + public bool IsAuthorized(ClaimsPrincipal principal, string permissionName, List permissions) { return UserSecurity.IsAuthorized(GetUser(principal), permissionName, permissions); } @@ -96,7 +97,7 @@ namespace Oqtane.Security // deprecated public bool IsAuthorized(ClaimsPrincipal principal, string entityName, int entityId, string permissionName) { - return IsAuthorized(principal, permissionName, _permissions.GetPermissions(_accessor.HttpContext.GetAlias().SiteId, entityName, entityId, permissionName)?.EncodePermissions()); + return IsAuthorized(principal, permissionName, _permissions.GetPermissions(_accessor.HttpContext.GetAlias().SiteId, entityName, entityId, permissionName).ToList()); } } } diff --git a/Oqtane.Shared/Models/Folder.cs b/Oqtane.Shared/Models/Folder.cs index 90bf87bd..46e5fa90 100644 --- a/Oqtane.Shared/Models/Folder.cs +++ b/Oqtane.Shared/Models/Folder.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; namespace Oqtane.Models @@ -68,7 +69,7 @@ namespace Oqtane.Models /// TODO: todoc what would this contain? /// [NotMapped] - public string Permissions { get; set; } + public List Permissions { get; set; } /// /// Folder Depth diff --git a/Oqtane.Shared/Models/Module.cs b/Oqtane.Shared/Models/Module.cs index d6f219fd..0c8b5f97 100644 --- a/Oqtane.Shared/Models/Module.cs +++ b/Oqtane.Shared/Models/Module.cs @@ -42,7 +42,7 @@ namespace Oqtane.Models #endregion [NotMapped] - public string Permissions { get; set; } + public List Permissions { get; set; } [NotMapped] public Dictionary Settings { get; set; } diff --git a/Oqtane.Shared/Models/ModuleDefinition.cs b/Oqtane.Shared/Models/ModuleDefinition.cs index aec53d88..796611b1 100644 --- a/Oqtane.Shared/Models/ModuleDefinition.cs +++ b/Oqtane.Shared/Models/ModuleDefinition.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using Oqtane.Documentation; @@ -99,7 +100,7 @@ namespace Oqtane.Models [NotMapped] public string AssemblyName { get; set; } [NotMapped] - public string Permissions { get; set; } + public List Permissions { get; set; } [NotMapped] public string Template { get; set; } } diff --git a/Oqtane.Shared/Models/Page.cs b/Oqtane.Shared/Models/Page.cs index 94c1d8f0..e24a3268 100644 --- a/Oqtane.Shared/Models/Page.cs +++ b/Oqtane.Shared/Models/Page.cs @@ -98,7 +98,7 @@ namespace Oqtane.Models public List Resources { get; set; } [NotMapped] - public string Permissions { get; set; } + public List Permissions { get; set; } [NotMapped] public Dictionary Settings { get; set; } diff --git a/Oqtane.Shared/Models/Permission.cs b/Oqtane.Shared/Models/Permission.cs index 4c93d8c0..f53e699c 100644 --- a/Oqtane.Shared/Models/Permission.cs +++ b/Oqtane.Shared/Models/Permission.cs @@ -1,4 +1,5 @@ using System; +using Oqtane.Shared; namespace Oqtane.Models { @@ -66,15 +67,41 @@ namespace Oqtane.Models public Permission(string permissionName, string roleName, bool isAuthorized) { - PermissionName = permissionName; - Role = new Role { Name = roleName }; - IsAuthorized = isAuthorized; + Initialize("", -1, permissionName, roleName, null, isAuthorized); } public Permission(string permissionName, int userId, bool isAuthorized) { + Initialize("", -1, permissionName, "", userId, isAuthorized); + } + + public Permission(string entityName, string permissionName, string roleName, int? userId, bool isAuthorized) + { + Initialize(entityName, -1, permissionName, roleName, userId, isAuthorized); + } + + public Permission(string entityName, int entityId, string permissionName, string roleName, int? userId, bool isAuthorized) + { + Initialize(entityName, entityId, permissionName, roleName, userId, isAuthorized); + } + + private void Initialize(string entityName, int entityId, string permissionName, string roleName, int? userId, bool isAuthorized) + { + EntityName = entityName; + EntityId = entityId; PermissionName = permissionName; - UserId = userId; + if (!string.IsNullOrEmpty(roleName)) + { + Role = new Role { Name = roleName }; + RoleId = null; + UserId = null; + } + else + { + Role = null; + RoleId = null; + UserId = userId; + } IsAuthorized = isAuthorized; } } diff --git a/Oqtane.Shared/Models/PermissionString.cs b/Oqtane.Shared/Models/PermissionString.cs deleted file mode 100644 index 44bcfc36..00000000 --- a/Oqtane.Shared/Models/PermissionString.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Oqtane.Models -{ - /// - /// Use this to define a which addresses a set of multiple permissions. - /// - public class PermissionString - { - /// - /// A term describing the entity - /// - public string EntityName { get; set; } - - /// - /// A term describing a set of permissions - /// - public string PermissionName { get; set; } - - /// - /// The permissions - /// - public string Permissions { get; set; } - } -} diff --git a/Oqtane.Shared/Models/SiteTemplate.cs b/Oqtane.Shared/Models/SiteTemplate.cs index 7ef52696..dba0302f 100644 --- a/Oqtane.Shared/Models/SiteTemplate.cs +++ b/Oqtane.Shared/Models/SiteTemplate.cs @@ -18,7 +18,7 @@ namespace Oqtane.Models public string Icon { get; set; } public bool IsNavigation { get; set; } public bool IsPersonalizable { get; set; } - public string PagePermissions { get; set; } + public List PagePermissions { get; set; } public List PageTemplateModules { get; set; } [Obsolete("This property is obsolete", false)] @@ -30,7 +30,7 @@ namespace Oqtane.Models public string ModuleDefinitionName { get; set; } public string Title { get; set; } public string Pane { get; set; } - public string ModulePermissions { get; set; } + public List ModulePermissions { get; set; } public string Content { get; set; } } } diff --git a/Oqtane.Shared/Security/UserSecurity.cs b/Oqtane.Shared/Security/UserSecurity.cs index 36cb21c9..9c550f4a 100644 --- a/Oqtane.Shared/Security/UserSecurity.cs +++ b/Oqtane.Shared/Security/UserSecurity.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Linq; using System.Security.Claims; -using System.Text.Json; using Oqtane.Models; using Oqtane.Shared; @@ -10,38 +9,25 @@ namespace Oqtane.Security { public class UserSecurity { - public static List GetPermissionStrings(string permissionStrings) + public static bool IsAuthorized(User user, string roles) { - return JsonSerializer.Deserialize>(permissionStrings); - } - - public static string SetPermissionStrings(List permissionStrings) - { - return JsonSerializer.Serialize(permissionStrings); - } - - public static string GetPermissions(string permissionName, string permissionStrings) - { - string permissions = ""; - List permissionstrings = JsonSerializer.Deserialize>(permissionStrings); - PermissionString permissionstring = permissionstrings.FirstOrDefault(item => item.PermissionName == permissionName); - if (permissionstring != null) + var permissions = new List(); + foreach (var role in roles.Split(';', StringSplitOptions.RemoveEmptyEntries)) { - permissions = permissionstring.Permissions; + permissions.Add(new Permission("", role, true)); } - return permissions; + return IsAuthorized(user, permissions); } - public static bool IsAuthorized(User user, string permissionName, string permissionStrings) + public static bool IsAuthorized(User user, string permissionName, List permissions) { - return IsAuthorized(user, GetPermissions(permissionName, permissionStrings)); + return IsAuthorized(user, permissions.Where(item => item.PermissionName == permissionName).ToList()); } - // permissions are stored in the format "!rolename1;![userid1];rolename2;rolename3;[userid2];[userid3]" where "!" designates Deny permissions - public static bool IsAuthorized(User user, string permissions) + public static bool IsAuthorized(User user, List permissions) { bool authorized = false; - if (permissions != "") + if (permissions != null && permissions.Any()) { if (user == null) { @@ -56,77 +42,43 @@ namespace Oqtane.Security return authorized; } - private static bool IsAuthorized(int userId, string roles, string permissions) + private static bool IsAuthorized(int userId, string roles, List permissions) { bool isAuthorized = false; - if (permissions != null) + if (permissions != null && permissions.Any()) { - foreach (string permission in permissions.Split(';', StringSplitOptions.RemoveEmptyEntries)) + // check if denied first + isAuthorized = !permissions.Where(item => !item.IsAuthorized && ( + (item.Role != null && ( + (item.Role.Name == RoleNames.Everyone) || + (item.Role.Name == RoleNames.Unauthenticated && userId == -1) || + roles.Split(';', StringSplitOptions.RemoveEmptyEntries).Contains(item.Role.Name))) || + (item.UserId != null && item.UserId.Value == userId))).Any(); + + if (isAuthorized) { - bool? allowed = VerifyPermission(userId, roles, permission); - if (allowed.HasValue) - { - isAuthorized = allowed.Value; - break; - } + // then check if authorized + isAuthorized = permissions.Where(item => item.IsAuthorized && ( + (item.Role != null && ( + (item.Role.Name == RoleNames.Everyone) || + (item.Role.Name == RoleNames.Unauthenticated && userId == -1) || + roles.Split(';', StringSplitOptions.RemoveEmptyEntries).Contains(item.Role.Name))) || + (item.UserId != null && item.UserId.Value == userId))).Any(); } } return isAuthorized; } - private static bool? VerifyPermission(int userId, string roles, string permission) + public static bool ContainsRole(List permissions, string permissionName, string roleName) { - bool? allowed = null; - //permissions strings are encoded with deny permissions at the beginning and grant permissions at the end for optimal performance - if (!String.IsNullOrEmpty(permission)) - { - // deny permission - if (permission.StartsWith("!")) - { - string denyRole = permission.Replace("!", ""); - if (denyRole == RoleNames.Everyone || IsAllowed(userId, roles, denyRole)) - { - allowed = false; - } - } - else // grant permission - { - if (permission == RoleNames.Everyone || IsAllowed(userId, roles, permission)) - { - allowed = true; - } - } - } - return allowed; + return permissions.Any(item => item.PermissionName == permissionName && item.Role.Name == roleName); } - private static bool IsAllowed(int userId, string roles, string permission) + public static bool ContainsUser(List permissions, string permissionName, int userId) { - if (permission == RoleNames.Unauthenticated) - { - return userId == -1; - } - if ("[" + userId + "]" == permission) - { - return true; - } - if (roles != null) - { - return roles.IndexOf(";" + permission + ";") != -1; - } - return false; - } - - public static bool ContainsRole(string permissionStrings, string permissionName, string roleName) - { - return GetPermissionStrings(permissionStrings).FirstOrDefault(item => item.PermissionName == permissionName).Permissions.Split(';').Contains(roleName); - } - - public static bool ContainsUser(string permissionStrings, string permissionName, int userId) - { - return GetPermissionStrings(permissionStrings).FirstOrDefault(item => item.PermissionName == permissionName).Permissions.Split(';').Contains($"[{userId}]"); + return permissions.Any(item => item.PermissionName == permissionName && item.UserId == userId); } public static ClaimsIdentity CreateClaimsIdentity(Alias alias, User user, List userroles)