add support for API permissions at the UI layer - including ability to delegate user, role, profile management
This commit is contained in:
@ -1,172 +0,0 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using System.Collections.Generic;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Enums;
|
||||
using System.Net;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Extensions;
|
||||
using System.Reflection;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class ApiController : Controller
|
||||
{
|
||||
private readonly IPermissionRepository _permissions;
|
||||
private readonly IRoleRepository _roles;
|
||||
private readonly ILogManager _logger;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public ApiController(IPermissionRepository permissions, IRoleRepository roles, ILogManager logger, ITenantManager tenantManager)
|
||||
{
|
||||
_permissions = permissions;
|
||||
_roles = roles;
|
||||
_logger = logger;
|
||||
_alias = tenantManager.GetAlias();
|
||||
}
|
||||
|
||||
// GET: api/<controller>?siteid=x
|
||||
[HttpGet]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public List<Api> Get(string siteid)
|
||||
{
|
||||
int SiteId;
|
||||
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
|
||||
{
|
||||
var apis = new List<Api>();
|
||||
|
||||
var assemblies = AppDomain.CurrentDomain.GetOqtaneAssemblies();
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
// iterate controllers
|
||||
foreach (var type in assembly.GetTypes().Where(type => typeof(Controller).IsAssignableFrom(type)))
|
||||
{
|
||||
// iterate controller methods with authorize attribute
|
||||
var actions = type.GetMethods(BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(m => m.GetCustomAttributes<AuthorizeAttribute>().Any());
|
||||
foreach(var action in actions)
|
||||
{
|
||||
// get policy
|
||||
var policy = action.GetCustomAttribute<AuthorizeAttribute>().Policy;
|
||||
if (!string.IsNullOrEmpty(policy) && policy.Contains(":") && !policy.Contains(Constants.RequireEntityId))
|
||||
{
|
||||
// parse policy
|
||||
var segments = policy.Split(':');
|
||||
if (!apis.Any(item => item.EntityName == segments[0]))
|
||||
{
|
||||
apis.Add(new Api { SiteId = SiteId, EntityName = segments[0], Permissions = segments[1] });
|
||||
}
|
||||
else
|
||||
{
|
||||
// concatenate permissions
|
||||
var permissions = apis.SingleOrDefault(item => item.EntityName == segments[0]).Permissions;
|
||||
if (!permissions.Split(',').Contains(segments[1]))
|
||||
{
|
||||
apis.SingleOrDefault(item => item.EntityName == segments[0]).Permissions += "," + segments[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return apis;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Api Get Attempt {SiteId}", siteid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// GET: api/<controller>/1/user
|
||||
[HttpGet("{siteid}/{entityname}")]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public Api Get(int siteid, string entityname)
|
||||
{
|
||||
if (siteid == _alias.SiteId)
|
||||
{
|
||||
var permissions = _permissions.GetPermissions(siteid, entityname);
|
||||
if (permissions == null || permissions.ToList().Count == 0)
|
||||
{
|
||||
permissions = GetPermissions(siteid, entityname);
|
||||
}
|
||||
return new Api { SiteId = siteid, EntityName = entityname, Permissions = permissions.EncodePermissions() };
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Api Get Attempt {SiteId} {EntityName}", siteid, entityname);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// POST: api/<controller>
|
||||
[HttpPost]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public void Post([FromBody] Api api)
|
||||
{
|
||||
if (ModelState.IsValid && api.SiteId == _alias.SiteId)
|
||||
{
|
||||
_permissions.UpdatePermissions(api.SiteId, api.EntityName, -1, api.Permissions);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Api Updated {Api}", api);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Api Post Attempt {Api}", api);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
|
||||
private List<Permission> GetPermissions(int siteid, string entityname)
|
||||
{
|
||||
var permissions = new List<Permission>();
|
||||
|
||||
var assemblies = AppDomain.CurrentDomain.GetOqtaneAssemblies();
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
// iterate controllers
|
||||
foreach (var type in assembly.GetTypes().Where(type => typeof(Controller).IsAssignableFrom(type)))
|
||||
{
|
||||
// iterate controller methods with authorize attribute
|
||||
var actions = type.GetMethods(BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(m => m.GetCustomAttributes<AuthorizeAttribute>().Any());
|
||||
foreach (var action in actions)
|
||||
{
|
||||
// get policy
|
||||
var policy = action.GetCustomAttribute<AuthorizeAttribute>().Policy;
|
||||
if (!string.IsNullOrEmpty(policy) && policy.Contains(":") && !policy.Contains(Constants.RequireEntityId))
|
||||
{
|
||||
// parse policy
|
||||
var segments = policy.Split(':');
|
||||
// entity match
|
||||
if (segments[0] == entityname && segments.Length > 2)
|
||||
{
|
||||
var roles = _roles.GetRoles(siteid);
|
||||
foreach (var rolename in (segments[2]).Split(','))
|
||||
{
|
||||
var role = roles.FirstOrDefault(item => item.Name == rolename);
|
||||
if (role != null)
|
||||
{
|
||||
if (!permissions.Any(item => item.EntityName == entityname && item.PermissionName == segments[1] && item.RoleId == role.RoleId))
|
||||
{
|
||||
permissions.Add(new Permission { SiteId = siteid, EntityName = entityname, EntityId = -1, PermissionName = segments[1], RoleId = role.RoleId, Role = role, UserId = null, IsAuthorized = true });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
}
|
||||
}
|
@ -47,7 +47,6 @@ namespace Oqtane.Controllers
|
||||
int SiteId;
|
||||
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
|
||||
{
|
||||
List<ModuleDefinition> moduledefinitions = _moduleDefinitions.GetModuleDefinitions(SiteId).ToList();
|
||||
List<Setting> settings = _settings.GetSettings(EntityNames.Module).ToList();
|
||||
|
||||
foreach (PageModule pagemodule in _pageModules.GetPageModules(SiteId))
|
||||
@ -75,7 +74,6 @@ namespace Oqtane.Controllers
|
||||
module.Order = pagemodule.Order;
|
||||
module.ContainerType = pagemodule.ContainerType;
|
||||
|
||||
module.ModuleDefinition = moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName);
|
||||
module.Settings = settings.Where(item => item.EntityId == pagemodule.ModuleId)
|
||||
.Where(item => !item.IsPrivate || _userPermissions.IsAuthorized(User, PermissionNames.Edit, pagemodule.Module.Permissions))
|
||||
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
|
||||
|
@ -281,7 +281,7 @@ namespace Oqtane.Controllers
|
||||
// synchronize module permissions
|
||||
if (added.Count > 0 || removed.Count > 0)
|
||||
{
|
||||
foreach (PageModule pageModule in _pageModules.GetPageModules(page.PageId, "").ToList())
|
||||
foreach (PageModule pageModule in _pageModules.GetPageModules(page.SiteId).Where(item => item.PageId == page.PageId).ToList())
|
||||
{
|
||||
var modulePermissions = _permissionRepository.GetPermissions(pageModule.Module.SiteId, EntityNames.Module, pageModule.Module.ModuleId).ToList();
|
||||
// permissions added
|
||||
|
@ -120,7 +120,8 @@ namespace Oqtane.Controllers
|
||||
if (page != null && page.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, page.SiteId, EntityNames.Page, pageid, PermissionNames.Edit))
|
||||
{
|
||||
int order = 1;
|
||||
List<PageModule> pagemodules = _pageModules.GetPageModules(pageid, pane).OrderBy(item => item.Order).ToList();
|
||||
List<PageModule> pagemodules = _pageModules.GetPageModules(page.SiteId)
|
||||
.Where(item => item.PageId == pageid && item.Pane == pane).OrderBy(item => item.Order).ToList();
|
||||
foreach (PageModule pagemodule in pagemodules)
|
||||
{
|
||||
if (pagemodule.Order != order)
|
||||
|
@ -28,7 +28,7 @@ namespace Oqtane.Controllers
|
||||
|
||||
// GET: api/<controller>?siteid=x
|
||||
[HttpGet]
|
||||
[Authorize(Policy = $"{EntityNames.Profile}:{PermissionNames.Read}:{RoleNames.Registered}")]
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public IEnumerable<Profile> Get(string siteid)
|
||||
{
|
||||
int SiteId;
|
||||
@ -46,7 +46,7 @@ namespace Oqtane.Controllers
|
||||
|
||||
// GET api/<controller>/5
|
||||
[HttpGet("{id}")]
|
||||
[Authorize(Policy = $"{EntityNames.Profile}:{PermissionNames.Read}:{RoleNames.Registered}")]
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public Profile Get(int id)
|
||||
{
|
||||
var profile = _profiles.GetProfile(id);
|
||||
|
@ -28,7 +28,7 @@ namespace Oqtane.Controllers
|
||||
|
||||
// GET: api/<controller>?siteid=x&global=true/false
|
||||
[HttpGet]
|
||||
[Authorize(Policy = $"{EntityNames.Role}:{PermissionNames.Read}:{RoleNames.Registered}")]
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public IEnumerable<Role> Get(string siteid, string global)
|
||||
{
|
||||
int SiteId;
|
||||
@ -50,7 +50,7 @@ namespace Oqtane.Controllers
|
||||
|
||||
// GET api/<controller>/5
|
||||
[HttpGet("{id}")]
|
||||
[Authorize(Policy = $"{EntityNames.Role}:{PermissionNames.Read}:{RoleNames.Registered}")]
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public Role Get(int id)
|
||||
{
|
||||
var role = _roles.GetRole(id);
|
||||
|
@ -212,7 +212,7 @@ namespace Oqtane.Controllers
|
||||
authorized = true;
|
||||
if (permissionName == PermissionNames.Edit)
|
||||
{
|
||||
authorized = User.IsInRole(RoleNames.Admin) || (_userPermissions.GetUser(User).UserId == entityId);
|
||||
authorized = _userPermissions.IsAuthorized(User, _alias.SiteId, entityName, -1, PermissionNames.Write, RoleNames.Admin) || (_userPermissions.GetUser(User).UserId == entityId);
|
||||
}
|
||||
break;
|
||||
case EntityNames.Visitor:
|
||||
@ -226,14 +226,11 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
break;
|
||||
default: // custom entity
|
||||
authorized = true;
|
||||
if (permissionName == PermissionNames.Edit)
|
||||
{
|
||||
authorized = User.IsInRole(RoleNames.Admin) || _userPermissions.IsAuthorized(User, _alias.SiteId, entityName, entityId, permissionName);
|
||||
}
|
||||
else
|
||||
{
|
||||
authorized = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return authorized;
|
||||
|
@ -29,23 +29,25 @@ namespace Oqtane.Controllers
|
||||
private readonly ITenantManager _tenantManager;
|
||||
private readonly INotificationRepository _notifications;
|
||||
private readonly IFolderRepository _folders;
|
||||
private readonly ISyncManager _syncManager;
|
||||
private readonly ISiteRepository _sites;
|
||||
private readonly IUserPermissions _userPermissions;
|
||||
private readonly IJwtManager _jwtManager;
|
||||
private readonly ISyncManager _syncManager;
|
||||
private readonly ILogManager _logger;
|
||||
|
||||
public UserController(IUserRepository users, IUserRoleRepository userRoles, UserManager<IdentityUser> identityUserManager, SignInManager<IdentityUser> identitySignInManager, ITenantManager tenantManager, INotificationRepository notifications, IFolderRepository folders, ISyncManager syncManager, ISiteRepository sites, IJwtManager jwtManager, ILogManager logger)
|
||||
public UserController(IUserRepository users, IUserRoleRepository userRoles, UserManager<IdentityUser> identityUserManager, SignInManager<IdentityUser> identitySignInManager, ITenantManager tenantManager, INotificationRepository notifications, IFolderRepository folders, ISiteRepository sites, IUserPermissions userPermissions, IJwtManager jwtManager, ISyncManager syncManager, ILogManager logger)
|
||||
{
|
||||
_users = users;
|
||||
_userRoles = userRoles;
|
||||
_identityUserManager = identityUserManager;
|
||||
_identitySignInManager = identitySignInManager;
|
||||
_tenantManager = tenantManager;
|
||||
_folders = folders;
|
||||
_notifications = notifications;
|
||||
_syncManager = syncManager;
|
||||
_folders = folders;
|
||||
_sites = sites;
|
||||
_userPermissions = userPermissions;
|
||||
_jwtManager = jwtManager;
|
||||
_syncManager = syncManager;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@ -105,7 +107,7 @@ namespace Oqtane.Controllers
|
||||
user.TwoFactorCode = "";
|
||||
user.TwoFactorExpiry = null;
|
||||
|
||||
if (!User.IsInRole(RoleNames.Admin) && User.Identity.Name?.ToLower() != user.Username.ToLower())
|
||||
if (!_userPermissions.IsAuthorized(User, user.SiteId, EntityNames.User, -1, PermissionNames.Write, RoleNames.Admin) && User.Identity.Name?.ToLower() != user.Username.ToLower())
|
||||
{
|
||||
user.Email = "";
|
||||
user.PhotoFileId = null;
|
||||
@ -148,8 +150,8 @@ namespace Oqtane.Controllers
|
||||
User newUser = null;
|
||||
|
||||
bool verified;
|
||||
bool allowregistration;
|
||||
if (User.IsInRole(RoleNames.Admin))
|
||||
bool allowregistration;
|
||||
if (_userPermissions.IsAuthorized(User, user.SiteId, EntityNames.User, -1, PermissionNames.Write, RoleNames.Admin))
|
||||
{
|
||||
verified = true;
|
||||
allowregistration = true;
|
||||
@ -241,7 +243,8 @@ namespace Oqtane.Controllers
|
||||
[Authorize]
|
||||
public async Task<User> Put(int id, [FromBody] User user)
|
||||
{
|
||||
if (ModelState.IsValid && user.SiteId == _tenantManager.GetAlias().SiteId && _users.GetUser(user.UserId, false) != null && (User.IsInRole(RoleNames.Admin) || User.Identity.Name == user.Username))
|
||||
if (ModelState.IsValid && user.SiteId == _tenantManager.GetAlias().SiteId && _users.GetUser(user.UserId, false) != null
|
||||
&& (_userPermissions.IsAuthorized(User, user.SiteId, EntityNames.User, -1, PermissionNames.Write, RoleNames.Admin) || User.Identity.Name == user.Username))
|
||||
{
|
||||
IdentityUser identityuser = await _identityUserManager.FindByNameAsync(user.Username);
|
||||
if (identityuser != null)
|
||||
@ -287,7 +290,7 @@ namespace Oqtane.Controllers
|
||||
|
||||
// DELETE api/<controller>/5?siteid=x
|
||||
[HttpDelete("{id}")]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
[Authorize(Policy = $"{EntityNames.User}:{PermissionNames.Write}:{RoleNames.Admin}")]
|
||||
public async Task Delete(int id, string siteid)
|
||||
{
|
||||
int SiteId;
|
||||
|
@ -10,6 +10,7 @@ using System.Linq;
|
||||
using System.Net;
|
||||
using Oqtane.Security;
|
||||
using System;
|
||||
using Oqtane.Modules.Admin.Roles;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
@ -93,7 +94,7 @@ namespace Oqtane.Controllers
|
||||
userrole.User.TwoFactorCode = "";
|
||||
userrole.User.TwoFactorExpiry = null;
|
||||
|
||||
if (!User.IsInRole(RoleNames.Admin) && userid != userrole.User.UserId)
|
||||
if (!_userPermissions.IsAuthorized(User, userrole.User.SiteId, EntityNames.User, -1, PermissionNames.Write, RoleNames.Admin) && userid != userrole.User.UserId)
|
||||
{
|
||||
userrole.User.Email = "";
|
||||
userrole.User.PhotoFileId = null;
|
||||
@ -115,7 +116,7 @@ namespace Oqtane.Controllers
|
||||
|
||||
// POST api/<controller>
|
||||
[HttpPost]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
[Authorize(Policy = $"{EntityNames.UserRole}:{PermissionNames.Write}:{RoleNames.Admin}")]
|
||||
public UserRole Post([FromBody] UserRole userRole)
|
||||
{
|
||||
var role = _roles.GetRole(userRole.RoleId);
|
||||
@ -138,7 +139,7 @@ namespace Oqtane.Controllers
|
||||
|
||||
// PUT api/<controller>/5
|
||||
[HttpPut("{id}")]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
[Authorize(Policy = $"{EntityNames.UserRole}:{PermissionNames.Write}:{RoleNames.Admin}")]
|
||||
public UserRole Put(int id, [FromBody] UserRole userRole)
|
||||
{
|
||||
var role = _roles.GetRole(userRole.RoleId);
|
||||
@ -160,7 +161,7 @@ namespace Oqtane.Controllers
|
||||
|
||||
// DELETE api/<controller>/5
|
||||
[HttpDelete("{id}")]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
[Authorize(Policy = $"{EntityNames.UserRole}:{PermissionNames.Write}:{RoleNames.Admin}")]
|
||||
public void Delete(int id)
|
||||
{
|
||||
UserRole userrole = _userRoles.GetUserRole(id);
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
@ -11,20 +11,22 @@ namespace Oqtane.Extensions
|
||||
public static string 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.PermissionName))
|
||||
foreach (Permission permission in permissionList.OrderBy(item => item.EntityName).ThenBy(item => item.PermissionName))
|
||||
{
|
||||
// permission collections are grouped by permissionname
|
||||
if (permissionname != permission.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 { PermissionName = permissionname, Permissions = permissions.Substring(0, permissions.Length - 1) });
|
||||
permissionstrings.Add(new PermissionString { EntityName = entityname, PermissionName = permissionname, Permissions = permissions.Substring(0, permissions.Length - 1) });
|
||||
}
|
||||
entityname = permission.EntityName;
|
||||
permissionname = permission.PermissionName;
|
||||
permissionsbuilder = new StringBuilder();
|
||||
}
|
||||
@ -56,7 +58,7 @@ namespace Oqtane.Extensions
|
||||
permissions = permissionsbuilder.ToString();
|
||||
if (permissions != "")
|
||||
{
|
||||
permissionstrings.Add(new PermissionString { PermissionName = permissionname, Permissions = permissions.Substring(0, permissions.Length - 1) });
|
||||
permissionstrings.Add(new PermissionString { EntityName = entityname, PermissionName = permissionname, Permissions = permissions.Substring(0, permissions.Length - 1) });
|
||||
}
|
||||
return JsonSerializer.Serialize(permissionstrings);
|
||||
}
|
||||
|
@ -308,43 +308,45 @@ namespace Oqtane.Infrastructure
|
||||
|
||||
private void Upgrade_3_3_0(Tenant tenant, IServiceScope scope)
|
||||
{
|
||||
var pageTemplates = new List<PageTemplate>();
|
||||
|
||||
pageTemplates.Add(new PageTemplate
|
||||
try
|
||||
{
|
||||
Name = "API Management",
|
||||
Parent = "Admin",
|
||||
Order = 35,
|
||||
Path = "admin/apis",
|
||||
Icon = Icons.CloudDownload,
|
||||
IsNavigation = true,
|
||||
IsPersonalizable = false,
|
||||
PagePermissions = new List<Permission>
|
||||
var roles = scope.ServiceProvider.GetRequiredService<IRoleRepository>();
|
||||
var pages = scope.ServiceProvider.GetRequiredService<IPageRepository>();
|
||||
var modules = scope.ServiceProvider.GetRequiredService<IModuleRepository>();
|
||||
var permissions = scope.ServiceProvider.GetRequiredService<IPermissionRepository>();
|
||||
var siteRepository = scope.ServiceProvider.GetRequiredService<ISiteRepository>();
|
||||
foreach (Site site in siteRepository.GetSites().ToList())
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
}.EncodePermissions(),
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
int roleid = roles.GetRoles(site.SiteId).FirstOrDefault(item => item.Name == RoleNames.Registered).RoleId;
|
||||
|
||||
int pageid = pages.GetPages(site.SiteId).FirstOrDefault(item => item.Path == "admin").PageId;
|
||||
var permission = new Permission
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Visitors.Index).ToModuleDefinitionName(), Title = "Visitor Management", Pane = PaneNames.Default,
|
||||
ModulePermissions = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
}.EncodePermissions(),
|
||||
Content = ""
|
||||
}
|
||||
SiteId = site.SiteId,
|
||||
EntityName = EntityNames.Page,
|
||||
EntityId = pageid,
|
||||
PermissionName = PermissionNames.View,
|
||||
RoleId = roleid,
|
||||
IsAuthorized = true
|
||||
};
|
||||
permissions.AddPermission(permission);
|
||||
|
||||
int moduleid = modules.GetModules(site.SiteId).FirstOrDefault(item => item.ModuleDefinitionName == "Oqtane.Modules.Admin.Dashboard, Oqtane.Client").ModuleId;
|
||||
permission = new Permission
|
||||
{
|
||||
SiteId = site.SiteId,
|
||||
EntityName = EntityNames.Module,
|
||||
EntityId = moduleid,
|
||||
PermissionName = PermissionNames.View,
|
||||
RoleId = roleid,
|
||||
IsAuthorized = true
|
||||
};
|
||||
permissions.AddPermission(permission);
|
||||
}
|
||||
});
|
||||
|
||||
var pages = scope.ServiceProvider.GetRequiredService<IPageRepository>();
|
||||
|
||||
var sites = scope.ServiceProvider.GetRequiredService<ISiteRepository>();
|
||||
foreach (Site site in sites.GetSites().ToList())
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
sites.CreatePages(site, pageTemplates);
|
||||
Debug.WriteLine($"Oqtane Error: Error In 3.3.0 Upgrade Logic - {ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ namespace Oqtane.Repository
|
||||
public interface IPageModuleRepository
|
||||
{
|
||||
IEnumerable<PageModule> GetPageModules(int siteId);
|
||||
IEnumerable<PageModule> GetPageModules(int pageId, string pane);
|
||||
PageModule AddPageModule(PageModule pageModule);
|
||||
PageModule UpdatePageModule(PageModule pageModule);
|
||||
PageModule GetPageModule(int pageModuleId);
|
||||
|
@ -10,46 +10,28 @@ namespace Oqtane.Repository
|
||||
public class PageModuleRepository : IPageModuleRepository
|
||||
{
|
||||
private TenantDBContext _db;
|
||||
private readonly IModuleDefinitionRepository _moduleDefinitions;
|
||||
private readonly IPermissionRepository _permissions;
|
||||
|
||||
public PageModuleRepository(TenantDBContext context, IPermissionRepository permissions)
|
||||
public PageModuleRepository(TenantDBContext context, IModuleDefinitionRepository moduleDefinitions, IPermissionRepository permissions)
|
||||
{
|
||||
_db = context;
|
||||
_moduleDefinitions = moduleDefinitions;
|
||||
_permissions = permissions;
|
||||
}
|
||||
|
||||
public IEnumerable<PageModule> GetPageModules(int siteId)
|
||||
{
|
||||
IEnumerable<PageModule> pagemodules = _db.PageModule
|
||||
var pagemodules = _db.PageModule
|
||||
.Include(item => item.Module) // eager load modules
|
||||
.Where(item => item.Module.SiteId == siteId);
|
||||
.Where(item => item.Module.SiteId == siteId).ToList();
|
||||
if (pagemodules.Any())
|
||||
{
|
||||
IEnumerable<Permission> permissions = _permissions.GetPermissions(siteId, EntityNames.Module).ToList();
|
||||
foreach (PageModule pagemodule in pagemodules)
|
||||
var moduledefinitions = _moduleDefinitions.GetModuleDefinitions(siteId).ToList();
|
||||
var permissions = _permissions.GetPermissions(siteId, EntityNames.Module).ToList();
|
||||
for (int index = 0; index < pagemodules.Count; index++)
|
||||
{
|
||||
pagemodule.Module.Permissions = permissions.Where(item => item.EntityId == pagemodule.ModuleId).EncodePermissions();
|
||||
}
|
||||
}
|
||||
return pagemodules;
|
||||
}
|
||||
|
||||
public IEnumerable<PageModule> GetPageModules(int pageId, string pane)
|
||||
{
|
||||
IEnumerable<PageModule> pagemodules = _db.PageModule
|
||||
.Include(item => item.Module) // eager load modules
|
||||
.Where(item => item.PageId == pageId);
|
||||
if (pane != "" && pagemodules.Any())
|
||||
{
|
||||
pagemodules = pagemodules.Where(item => item.Pane == pane);
|
||||
}
|
||||
if (pagemodules.Any())
|
||||
{
|
||||
var siteId = pagemodules.FirstOrDefault().Module.SiteId;
|
||||
IEnumerable<Permission> permissions = _permissions.GetPermissions(siteId, EntityNames.Module).ToList();
|
||||
foreach (PageModule pagemodule in pagemodules)
|
||||
{
|
||||
pagemodule.Module.Permissions = permissions.Where(item => item.EntityId == pagemodule.ModuleId).EncodePermissions();
|
||||
pagemodules[index] = GetPageModule(pagemodules[index], moduledefinitions, permissions);
|
||||
}
|
||||
}
|
||||
return pagemodules;
|
||||
@ -89,7 +71,9 @@ namespace Oqtane.Repository
|
||||
}
|
||||
if (pagemodule != null)
|
||||
{
|
||||
pagemodule.Module.Permissions = _permissions.GetPermissions(pagemodule.Module.SiteId, EntityNames.Module, pagemodule.ModuleId)?.EncodePermissions();
|
||||
var moduledefinitions = _moduleDefinitions.GetModuleDefinitions(pagemodule.Module.SiteId).ToList();
|
||||
var permissions = _permissions.GetPermissions(pagemodule.Module.SiteId, EntityNames.Module).ToList();
|
||||
pagemodule = GetPageModule(pagemodule, moduledefinitions, permissions);
|
||||
}
|
||||
return pagemodule;
|
||||
}
|
||||
@ -100,7 +84,9 @@ namespace Oqtane.Repository
|
||||
.SingleOrDefault(item => item.PageId == pageId && item.ModuleId == moduleId);
|
||||
if (pagemodule != null)
|
||||
{
|
||||
pagemodule.Module.Permissions = _permissions.GetPermissions(pagemodule.Module.SiteId, EntityNames.Module, pagemodule.ModuleId)?.EncodePermissions();
|
||||
var moduledefinitions = _moduleDefinitions.GetModuleDefinitions(pagemodule.Module.SiteId).ToList();
|
||||
var permissions = _permissions.GetPermissions(pagemodule.Module.SiteId, EntityNames.Module).ToList();
|
||||
pagemodule = GetPageModule(pagemodule, moduledefinitions, permissions);
|
||||
}
|
||||
return pagemodule;
|
||||
}
|
||||
@ -111,5 +97,30 @@ namespace Oqtane.Repository
|
||||
_db.PageModule.Remove(pageModule);
|
||||
_db.SaveChanges();
|
||||
}
|
||||
|
||||
private PageModule GetPageModule(PageModule pageModule, List<ModuleDefinition> moduleDefinitions, List<Permission> modulePermissions)
|
||||
{
|
||||
var permissions = modulePermissions.Where(item => item.EntityId == pageModule.ModuleId).ToList();
|
||||
|
||||
// moduledefinition permissionnames can specify permissions for other entities (ie. API permissions)
|
||||
pageModule.Module.ModuleDefinition = moduleDefinitions.Find(item => item.ModuleDefinitionName == pageModule.Module.ModuleDefinitionName);
|
||||
if (!string.IsNullOrEmpty(pageModule.Module.ModuleDefinition.PermissionNames) && pageModule.Module.ModuleDefinition.PermissionNames.Contains(":"))
|
||||
{
|
||||
foreach (var permissionname in pageModule.Module.ModuleDefinition.PermissionNames.Split(",", System.StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
if (permissionname.Contains(":"))
|
||||
{
|
||||
// moduledefinition permissionnames can be in the form of "EntityName:PermissionName:Roles"
|
||||
var segments = permissionname.Split(':');
|
||||
if (segments.Length == 3 && segments[0] != EntityNames.Module)
|
||||
{
|
||||
permissions.AddRange(_permissions.GetPermissions(pageModule.Module.SiteId, segments[0], segments[1]).Where(item => item.EntityId == -1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pageModule.Module.Permissions = permissions?.EncodePermissions();
|
||||
return pageModule;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -79,23 +79,52 @@ namespace Oqtane.Repository
|
||||
|
||||
public void UpdatePermissions(int siteId, string entityName, int entityId, string permissionStrings)
|
||||
{
|
||||
// get current permissions and delete
|
||||
IEnumerable<Permission> permissions = _db.Permission
|
||||
.Where(item => item.EntityName == entityName)
|
||||
.Where(item => item.EntityId == entityId)
|
||||
.Where(item => item.SiteId == siteId);
|
||||
foreach (Permission permission in permissions)
|
||||
bool modified = false;
|
||||
var existing = new List<Permission>();
|
||||
var permissions = DecodePermissions(permissionStrings, siteId, entityName, entityId);
|
||||
foreach (var permission in permissions)
|
||||
{
|
||||
_db.Permission.Remove(permission);
|
||||
if (!existing.Any(item => item.EntityName == permission.EntityName && item.PermissionName == permission.PermissionName))
|
||||
{
|
||||
existing.AddRange(GetPermissions(siteId, permission.EntityName, permission.PermissionName)
|
||||
.Where(item => item.EntityId == entityId || item.EntityId == -1));
|
||||
}
|
||||
|
||||
var current = existing.FirstOrDefault(item => item.EntityName == permission.EntityName && item.EntityId == permission.EntityId
|
||||
&& item.PermissionName == permission.PermissionName && item.RoleId == permission.RoleId && item.UserId == permission.UserId);
|
||||
if (current != null)
|
||||
{
|
||||
if (current.IsAuthorized != permission.IsAuthorized)
|
||||
{
|
||||
current.IsAuthorized = permission.IsAuthorized;
|
||||
_db.Entry(current).State = EntityState.Modified;
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_db.Permission.Add(permission);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
// add permissions
|
||||
permissions = DecodePermissions(permissionStrings, siteId, entityName, entityId);
|
||||
foreach (Permission permission in permissions)
|
||||
foreach (var permission in existing)
|
||||
{
|
||||
_db.Permission.Add(permission);
|
||||
if (!permissions.Any(item => item.EntityName == permission.EntityName && item.PermissionName == permission.PermissionName
|
||||
&& item.EntityId == permission.EntityId && item.RoleId == permission.RoleId && item.UserId == permission.UserId))
|
||||
{
|
||||
permission.Role = null; // remove linked reference to Role which can cause errors in EF Core change tracking
|
||||
_db.Permission.Remove(permission);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
if (modified)
|
||||
{
|
||||
_db.SaveChanges();
|
||||
foreach (var entityname in permissions.Select(item => item.EntityName).Distinct())
|
||||
{
|
||||
ClearCache(siteId, entityname);
|
||||
}
|
||||
}
|
||||
_db.SaveChanges();
|
||||
ClearCache(siteId, entityName);
|
||||
}
|
||||
|
||||
public Permission GetPermission(int permissionId)
|
||||
@ -200,8 +229,22 @@ namespace Oqtane.Repository
|
||||
securityid = id;
|
||||
Permission permission = new Permission();
|
||||
permission.SiteId = siteId;
|
||||
permission.EntityName = entityName;
|
||||
permission.EntityId = entityId;
|
||||
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;
|
||||
|
@ -431,6 +431,7 @@ namespace Oqtane.Repository
|
||||
PagePermissions = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Registered, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
}.EncodePermissions(),
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
@ -441,6 +442,7 @@ namespace Oqtane.Repository
|
||||
ModulePermissions = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Registered, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
}.EncodePermissions(),
|
||||
Content = ""
|
||||
|
@ -22,22 +22,15 @@ namespace Oqtane.Security
|
||||
|
||||
if (policy == null)
|
||||
{
|
||||
// policy names must be in the form of "EntityName:PermissionName:Roles" ie. "Module:Edit:Administrators" (roles are comma delimited)
|
||||
// policy names must be in the form of "EntityName:PermissionName:Roles"
|
||||
if (policyName.Contains(':'))
|
||||
{
|
||||
var policySegments = policyName.Split(':');
|
||||
if (policySegments.Length >= 3)
|
||||
var segments = policyName.Split(':');
|
||||
if (segments.Length == 3)
|
||||
{
|
||||
// check for optional RequireEntityId segment
|
||||
var requireEntityId = false;
|
||||
if (policySegments.Length == 4 && policySegments[3] == Constants.RequireEntityId)
|
||||
{
|
||||
requireEntityId = true;
|
||||
}
|
||||
|
||||
// create policy
|
||||
var builder = new AuthorizationPolicyBuilder();
|
||||
builder.AddRequirements(new PermissionRequirement(policySegments[0], policySegments[1], policySegments[2], requireEntityId));
|
||||
builder.AddRequirements(new PermissionRequirement(segments[0], segments[1], segments[2]));
|
||||
policy = builder.Build();
|
||||
|
||||
// add policy to the AuthorizationOptions
|
||||
@ -59,8 +52,8 @@ namespace Oqtane.Security
|
||||
private string GetPolicyName(string policyName)
|
||||
{
|
||||
// backward compatibility for legacy static policy names
|
||||
if (policyName == PolicyNames.ViewModule) policyName = $"{EntityNames.Module}:{PermissionNames.View}:{RoleNames.Admin}:{Constants.RequireEntityId}";
|
||||
if (policyName == PolicyNames.EditModule) policyName = $"{EntityNames.Module}:{PermissionNames.Edit}:{RoleNames.Admin}:{Constants.RequireEntityId}";
|
||||
if (policyName == PolicyNames.ViewModule) policyName = $"{EntityNames.Module}:{PermissionNames.View}:{RoleNames.Admin}";
|
||||
if (policyName == PolicyNames.EditModule) policyName = $"{EntityNames.Module}:{PermissionNames.Edit}:{RoleNames.Admin}";
|
||||
return policyName;
|
||||
}
|
||||
}
|
||||
|
@ -34,28 +34,26 @@ namespace Oqtane.Security
|
||||
}
|
||||
|
||||
int entityId = -1;
|
||||
if (requirement.RequireEntityId)
|
||||
|
||||
// get entityid from querystring based on a parameter format of auth{entityname}id (ie. authmoduleid )
|
||||
if (ctx.Request.Query.ContainsKey("auth" + requirement.EntityName.ToLower() + "id"))
|
||||
{
|
||||
// get entityid from querystring based on a parameter format of auth{entityname}id (ie. authmoduleid )
|
||||
if (ctx.Request.Query.ContainsKey("auth" + requirement.EntityName.ToLower() + "id"))
|
||||
if (!int.TryParse(ctx.Request.Query["auth" + requirement.EntityName.ToLower() + "id"], out entityId))
|
||||
{
|
||||
if (!int.TryParse(ctx.Request.Query["auth" + requirement.EntityName.ToLower() + "id"], out entityId))
|
||||
entityId = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// legacy support for deprecated CreateAuthorizationPolicyUrl(string url, int entityId)
|
||||
if (entityId == -1)
|
||||
{
|
||||
if (ctx.Request.Query.ContainsKey("entityid"))
|
||||
{
|
||||
if (!int.TryParse(ctx.Request.Query["entityid"], out entityId))
|
||||
{
|
||||
entityId = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// legacy support for deprecated CreateAuthorizationPolicyUrl(string url, int entityId)
|
||||
if (entityId == -1)
|
||||
{
|
||||
if (ctx.Request.Query.ContainsKey("entityid"))
|
||||
{
|
||||
if (!int.TryParse(ctx.Request.Query["entityid"], out entityId))
|
||||
{
|
||||
entityId = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// validate permissions
|
||||
|
@ -8,16 +8,13 @@ namespace Oqtane.Security
|
||||
|
||||
public string PermissionName { get; }
|
||||
|
||||
public string Roles { get; }
|
||||
public string Roles { get; } // semi-colon delimited
|
||||
|
||||
public bool RequireEntityId { get; }
|
||||
|
||||
public PermissionRequirement(string entityName, string permissionName, string roles, bool requireEntityId)
|
||||
public PermissionRequirement(string entityName, string permissionName, string roles)
|
||||
{
|
||||
EntityName = entityName;
|
||||
PermissionName = permissionName;
|
||||
Roles = roles;
|
||||
RequireEntityId = requireEntityId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ namespace Oqtane.Security
|
||||
}
|
||||
else
|
||||
{
|
||||
return UserSecurity.IsAuthorized(GetUser(principal), roles.Replace(",",";"));
|
||||
return UserSecurity.IsAuthorized(GetUser(principal), roles);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user