diff --git a/Oqtane.Client/Modules/HtmlText/Services/HtmlTextService.cs b/Oqtane.Client/Modules/HtmlText/Services/HtmlTextService.cs
index 90dfcdde..a90451cd 100644
--- a/Oqtane.Client/Modules/HtmlText/Services/HtmlTextService.cs
+++ b/Oqtane.Client/Modules/HtmlText/Services/HtmlTextService.cs
@@ -2,7 +2,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
-using Oqtane.Modules.HtmlText.Models;
using Oqtane.Services;
using Oqtane.Shared;
@@ -21,23 +20,23 @@ namespace Oqtane.Modules.HtmlText.Services
public async Task GetHtmlTextAsync(int moduleId)
{
- var htmltext = await GetJsonAsync>(CreateAuthorizationPolicyUrl($"{ApiUrl}/{moduleId}", moduleId));
+ var htmltext = await GetJsonAsync>(CreateAuthorizationPolicyUrl($"{ApiUrl}/{moduleId}", new Dictionary() { { EntityNames.Module, moduleId } }));
return htmltext.FirstOrDefault();
}
public async Task AddHtmlTextAsync(Models.HtmlText htmlText)
{
- await PostJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}", htmlText.ModuleId), htmlText);
+ await PostJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}", new Dictionary() { { EntityNames.Module, htmlText.ModuleId } }), htmlText);
}
public async Task UpdateHtmlTextAsync(Models.HtmlText htmlText)
{
- await PutJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{htmlText.HtmlTextId}", htmlText.ModuleId), htmlText);
+ await PutJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{htmlText.HtmlTextId}", new Dictionary() { { EntityNames.Module, htmlText.ModuleId } }), htmlText);
}
public async Task DeleteHtmlTextAsync(int moduleId)
{
- await DeleteAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{moduleId}", moduleId));
+ await DeleteAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{moduleId}", new Dictionary() { { EntityNames.Module, moduleId } }));
}
}
}
diff --git a/Oqtane.Client/Services/ServiceBase.cs b/Oqtane.Client/Services/ServiceBase.cs
index 14a4fea7..5e425bd1 100644
--- a/Oqtane.Client/Services/ServiceBase.cs
+++ b/Oqtane.Client/Services/ServiceBase.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Net.Http.Json;
@@ -54,10 +55,15 @@ namespace Oqtane.Services
return apiurl;
}
- // add entityid parameter to url for custom authorization policy
- public string CreateAuthorizationPolicyUrl(string url, int entityId)
+ // add authentityid parameters to url for custom authorization policy - args in form of entityname = entityid
+ public string CreateAuthorizationPolicyUrl(string url, Dictionary args)
{
- string qs = "entityid=" + entityId.ToString();
+ string qs = "";
+ foreach (KeyValuePair kvp in args)
+ {
+ qs += (qs != "") ? "&" : "";
+ qs += "auth" + kvp.Key.ToLower() + "id=" + kvp.Value.ToString();
+ }
if (url.Contains("?"))
{
@@ -204,5 +210,20 @@ namespace Oqtane.Services
{
return CreateApiUrl(serviceName, alias, ControllerRoutes.Default);
}
+
+ [Obsolete("This method is obsolete. Use CreateAuthorizationPolicyUrl(string url, Dictionary args) instead - in conjunction with _authEntityId in Server Controller.", false)]
+ public string CreateAuthorizationPolicyUrl(string url, int entityId)
+ {
+ string qs = "entityid=" + entityId.ToString();
+
+ if (url.Contains("?"))
+ {
+ return url + "&" + qs;
+ }
+ else
+ {
+ return url + "?" + qs;
+ }
+ }
}
}
diff --git a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor
index a4bf5d16..14e985e1 100644
--- a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor
+++ b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor
@@ -513,28 +513,7 @@
{
List permissions;
- if (action == "publish")
- {
- // publish all modules
- foreach (var module in PageState.Modules.Where(item => item.PageId == PageState.Page.PageId))
- {
- permissions = UserSecurity.GetPermissionStrings(module.Permissions);
- foreach (var permissionstring in permissions)
- {
- 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());
- }
- }
- module.Permissions = UserSecurity.SetPermissionStrings(permissions);
- await ModuleService.UpdateModuleAsync(module);
- }
- }
-
- // publish page
+ // publish/unpublish page
var page = PageState.Page;
permissions = UserSecurity.GetPermissionStrings(page.Permissions);
foreach (var permissionstring in permissions)
diff --git a/Oqtane.Server/Controllers/ModuleControllerBase.cs b/Oqtane.Server/Controllers/ModuleControllerBase.cs
index b934e684..baa9a0a1 100644
--- a/Oqtane.Server/Controllers/ModuleControllerBase.cs
+++ b/Oqtane.Server/Controllers/ModuleControllerBase.cs
@@ -1,21 +1,35 @@
-using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using Oqtane.Infrastructure;
+using System.Collections.Generic;
+using System;
namespace Oqtane.Controllers
{
public class ModuleControllerBase : Controller
{
protected readonly ILogManager _logger;
- protected int _entityId = -1; // passed as a querystring parameter for policy authorization and used for validation
+ // querystring parameters for policy authorization and validation
+ protected Dictionary _authEntityId = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ protected int _entityId = -1; // deprecated
public ModuleControllerBase(ILogManager logger, IHttpContextAccessor accessor)
{
_logger = logger;
+ int value;
+ foreach (var param in accessor.HttpContext.Request.Query)
+ {
+ if (param.Key.StartsWith("auth") && param.Key.EndsWith("id") && int.TryParse(param.Value, out value))
+ {
+ _authEntityId.Add(param.Key.Substring(4, param.Key.Length - 6), int.Parse(param.Value));
+ }
+ }
+ // entityid is deprecated
if (accessor.HttpContext.Request.Query.ContainsKey("entityid"))
{
_entityId = int.Parse(accessor.HttpContext.Request.Query["entityid"]);
}
}
+
}
}
diff --git a/Oqtane.Server/Controllers/PageController.cs b/Oqtane.Server/Controllers/PageController.cs
index 3c9edaef..2ddccb06 100644
--- a/Oqtane.Server/Controllers/PageController.cs
+++ b/Oqtane.Server/Controllers/PageController.cs
@@ -19,17 +19,19 @@ namespace Oqtane.Controllers
private readonly IPageRepository _pages;
private readonly IModuleRepository _modules;
private readonly IPageModuleRepository _pageModules;
+ private readonly IPermissionRepository _permissionRepository;
private readonly ISettingRepository _settings;
private readonly IUserPermissions _userPermissions;
private readonly ISyncManager _syncManager;
private readonly ILogManager _logger;
private readonly Alias _alias;
- public PageController(IPageRepository pages, IModuleRepository modules, IPageModuleRepository pageModules, ISettingRepository settings, IUserPermissions userPermissions, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger)
+ public PageController(IPageRepository pages, IModuleRepository modules, IPageModuleRepository pageModules, IPermissionRepository permissionRepository, ISettingRepository settings, IUserPermissions userPermissions, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger)
{
_pages = pages;
_modules = modules;
_pageModules = pageModules;
+ _permissionRepository = permissionRepository;
_settings = settings;
_userPermissions = userPermissions;
_syncManager = syncManager;
@@ -227,7 +229,54 @@ namespace Oqtane.Controllers
{
if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Page, page.PageId, PermissionNames.Edit))
{
+ // preserve page permissions
+ var oldPermissions = _permissionRepository.GetPermissions(EntityNames.Page, page.PageId).ToList();
+
page = _pages.UpdatePage(page);
+
+ // get differences between old and new page permissions
+ var newPermissions = _permissionRepository.DecodePermissions(page.Permissions, page.SiteId, EntityNames.Page, page.PageId).ToList();
+ var added = GetPermissionsDifferences(newPermissions, oldPermissions);
+ var removed = GetPermissionsDifferences(oldPermissions, newPermissions);
+
+ // synchronize module permissions
+ if (added.Count > 0 || removed.Count > 0)
+ {
+ foreach (PageModule pageModule in _pageModules.GetPageModules(page.PageId, "").ToList())
+ {
+ var modulePermissions = _permissionRepository.GetPermissions(EntityNames.Module, pageModule.Module.ModuleId).ToList();
+ //var modulePermissions = _permissionRepository.DecodePermissions(pageModule.Module.Permissions, page.SiteId, EntityNames.Module, pageModule.ModuleId).ToList();
+ // permissions added
+ foreach(Permission permission in added)
+ {
+ if (!modulePermissions.Any(item => item.PermissionName == permission.PermissionName
+ && item.RoleId == permission.RoleId && item.UserId == permission.UserId && item.IsAuthorized == permission.IsAuthorized))
+ {
+ _permissionRepository.AddPermission(new Permission
+ {
+ SiteId = page.SiteId,
+ EntityName = EntityNames.Module,
+ EntityId = pageModule.ModuleId,
+ PermissionName = permission.PermissionName,
+ RoleId = permission.RoleId,
+ UserId = permission.UserId,
+ IsAuthorized = permission.IsAuthorized
+ });
+ }
+ }
+ // permissions removed
+ foreach (Permission permission in removed)
+ {
+ var modulePermission = modulePermissions.FirstOrDefault(item => item.PermissionName == permission.PermissionName
+ && item.RoleId == permission.RoleId && item.UserId == permission.UserId && item.IsAuthorized == permission.IsAuthorized);
+ if (modulePermission != null)
+ {
+ _permissionRepository.DeletePermission(modulePermission.PermissionId);
+ }
+ }
+ }
+ }
+
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, page.SiteId);
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Page Updated {Page}", page);
}
@@ -240,6 +289,19 @@ namespace Oqtane.Controllers
return page;
}
+ private List GetPermissionsDifferences(List permissions1, List permissions2)
+ {
+ var differences = new List();
+ foreach (Permission p in permissions1)
+ {
+ if (!permissions2.Any(item => item.PermissionName == p.PermissionName && item.RoleId == p.RoleId && item.UserId == p.UserId && item.IsAuthorized == p.IsAuthorized))
+ {
+ differences.Add(p);
+ }
+ }
+ return differences;
+ }
+
// PUT api//?siteid=x&pageid=y&parentid=z
[HttpPut]
[Authorize(Roles = RoleNames.Registered)]
@@ -287,4 +349,5 @@ namespace Oqtane.Controllers
}
}
}
+
}
diff --git a/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs b/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs
index e321b76b..3de69445 100644
--- a/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs
+++ b/Oqtane.Server/Modules/HtmlText/Controllers/HtmlTextController.cs
@@ -30,7 +30,7 @@ namespace Oqtane.Modules.HtmlText.Controllers
try
{
Models.HtmlText htmlText = null;
- if (_entityId == id)
+ if (_authEntityId[EntityNames.Module] == id)
{
htmlText = _htmlText.GetHtmlText(id);
list.Add(htmlText);
@@ -51,7 +51,7 @@ namespace Oqtane.Modules.HtmlText.Controllers
{
try
{
- if (ModelState.IsValid && htmlText.ModuleId == _entityId)
+ if (ModelState.IsValid && htmlText.ModuleId == _authEntityId[EntityNames.Module])
{
htmlText = _htmlText.AddHtmlText(htmlText);
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Html/Text Added {HtmlText}", htmlText);
@@ -72,7 +72,7 @@ namespace Oqtane.Modules.HtmlText.Controllers
{
try
{
- if (ModelState.IsValid && htmlText.ModuleId == _entityId)
+ if (ModelState.IsValid && htmlText.ModuleId == _authEntityId[EntityNames.Module])
{
htmlText = _htmlText.UpdateHtmlText(htmlText);
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Html/Text Updated {HtmlText}", htmlText);
@@ -93,7 +93,7 @@ namespace Oqtane.Modules.HtmlText.Controllers
{
try
{
- if (id == _entityId)
+ if (id == _authEntityId[EntityNames.Module])
{
_htmlText.DeleteHtmlText(id);
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Html/Text Deleted {HtmlTextId}", id);
diff --git a/Oqtane.Server/Security/PermissionHandler.cs b/Oqtane.Server/Security/PermissionHandler.cs
index 8735d0d0..4bd01a3c 100644
--- a/Oqtane.Server/Security/PermissionHandler.cs
+++ b/Oqtane.Server/Security/PermissionHandler.cs
@@ -1,4 +1,4 @@
-using System.Threading.Tasks;
+using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Oqtane.Enums;
@@ -22,11 +22,19 @@ namespace Oqtane.Security
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
{
- // permission is scoped based on EntityId which must be passed as a querystring parameter
+ // permission is scoped based on auth{entityname}id (ie ?authmoduleid ) which must be passed as a querystring parameter
var ctx = _httpContextAccessor.HttpContext;
- if (ctx != null && ctx.Request.Query.ContainsKey("entityid"))
+ if (ctx != null)
{
- int entityId = int.Parse(ctx.Request.Query["entityid"]);
+ int entityId = -1;
+ if (ctx.Request.Query.ContainsKey("auth" + requirement.EntityName.ToLower() + "id"))
+ {
+ entityId = int.Parse(ctx.Request.Query["auth" + requirement.EntityName.ToLower() + "id"]);
+ }
+ if (entityId == -1 && ctx.Request.Query.ContainsKey("entityid"))
+ {
+ entityId = int.Parse(ctx.Request.Query["entityid"]);
+ }
if (_userPermissions.IsAuthorized(context.User, requirement.EntityName, entityId, requirement.PermissionName))
{
context.Succeed(requirement);
@@ -39,4 +47,4 @@ namespace Oqtane.Security
return Task.CompletedTask;
}
}
-}
\ No newline at end of file
+}