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.
This commit is contained in:
@ -104,7 +104,7 @@ namespace Oqtane.Controllers
|
||||
{
|
||||
if (ModelState.IsValid && folder.SiteId == _alias.SiteId)
|
||||
{
|
||||
string permissions;
|
||||
List<Permission> permissions;
|
||||
if (folder.ParentId != null)
|
||||
{
|
||||
permissions = _folders.GetFolder(folder.ParentId.Value).Permissions;
|
||||
|
@ -128,7 +128,7 @@ namespace Oqtane.Controllers
|
||||
{
|
||||
if (ModelState.IsValid && page.SiteId == _alias.SiteId)
|
||||
{
|
||||
string permissions;
|
||||
List<Permission> 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)
|
||||
|
@ -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<Permission> permissionList)
|
||||
public static List<Permission> EncodePermissions(this IEnumerable<Permission> permissionList)
|
||||
{
|
||||
List<PermissionString> permissionstrings = new List<PermissionString>();
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,14 +10,12 @@ namespace Oqtane.Repository
|
||||
IEnumerable<Permission> GetPermissions(int siteId, string entityName);
|
||||
IEnumerable<Permission> GetPermissions(int siteId, string entityName, string permissionName);
|
||||
IEnumerable<Permission> GetPermissions(int siteId, string entityName, int entityId);
|
||||
IEnumerable<Permission> GetPermissions(int siteId, string entityName, int entityId, string permissionName);
|
||||
|
||||
IEnumerable<Permission> 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<Permission> permissions);
|
||||
Permission GetPermission(int permissionId);
|
||||
void DeletePermission(int permissionId);
|
||||
void DeletePermissions(int siteId, string entityName, int entityId);
|
||||
IEnumerable<Permission> DecodePermissions(string permissions, int siteId, string entityName, int entityId);
|
||||
}
|
||||
}
|
||||
|
@ -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<Permission> permissions)
|
||||
{
|
||||
// ensure permissions are fully populated
|
||||
List<Role> 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<Permission>();
|
||||
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<Permission> permissionList)
|
||||
{
|
||||
List<PermissionString> permissionstrings = new List<PermissionString>();
|
||||
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<Permission> DecodePermissions(string permissionStrings, int siteId, string entityName, int entityId)
|
||||
{
|
||||
List<Permission> permissions = new List<Permission>();
|
||||
List<Role> roles = _roles.GetRoles(siteId, true).ToList();
|
||||
string securityid = "";
|
||||
foreach (PermissionString permissionstring in JsonSerializer.Deserialize<List<PermissionString>>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<Permission> 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<Permission> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user