diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index ab6987f2..719463ae 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -6,11 +6,11 @@ using System.Linq; using System.Net; using System.Net.Http; using System.Reflection; -using System.Reflection.Metadata; using System.Runtime.Loader; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication.OAuth; using Microsoft.AspNetCore.Authentication.OpenIdConnect; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; @@ -47,22 +47,6 @@ namespace Microsoft.Extensions.DependencyInjection return services; } - public static IServiceCollection AddOqtaneAuthorizationPolicies(this IServiceCollection services) - { - services.AddAuthorizationCore(options => - { - options.AddPolicy(PolicyNames.ViewPage, policy => policy.Requirements.Add(new PermissionRequirement(EntityNames.Page, PermissionNames.View))); - options.AddPolicy(PolicyNames.EditPage, policy => policy.Requirements.Add(new PermissionRequirement(EntityNames.Page, PermissionNames.Edit))); - options.AddPolicy(PolicyNames.ViewModule, policy => policy.Requirements.Add(new PermissionRequirement(EntityNames.Module, PermissionNames.View))); - options.AddPolicy(PolicyNames.EditModule, policy => policy.Requirements.Add(new PermissionRequirement(EntityNames.Module, PermissionNames.Edit))); - options.AddPolicy(PolicyNames.ViewFolder, policy => policy.Requirements.Add(new PermissionRequirement(EntityNames.Folder, PermissionNames.View))); - options.AddPolicy(PolicyNames.EditFolder, policy => policy.Requirements.Add(new PermissionRequirement(EntityNames.Folder, PermissionNames.Edit))); - options.AddPolicy(PolicyNames.ListFolder, policy => policy.Requirements.Add(new PermissionRequirement(EntityNames.Folder, PermissionNames.Browse))); - }); - - return services; - } - public static OqtaneSiteOptionsBuilder AddOqtaneSiteOptions(this IServiceCollection services) { return new OqtaneSiteOptionsBuilder(services); @@ -76,6 +60,7 @@ namespace Microsoft.Extensions.DependencyInjection services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); return services; } diff --git a/Oqtane.Server/Security/AuthorizationPolicyProvider.cs b/Oqtane.Server/Security/AuthorizationPolicyProvider.cs new file mode 100644 index 00000000..cdfd48aa --- /dev/null +++ b/Oqtane.Server/Security/AuthorizationPolicyProvider.cs @@ -0,0 +1,54 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Options; +using Oqtane.Shared; +using System.Threading.Tasks; + +namespace Oqtane.Security +{ + public class AuthorizationPolicyProvider : DefaultAuthorizationPolicyProvider + { + private readonly AuthorizationOptions _options; + private readonly IConfiguration _configuration; + + public AuthorizationPolicyProvider(IOptions options, IConfiguration configuration) : base(options) + { + _options = options.Value; + _configuration = configuration; + } + + public override async Task GetPolicyAsync(string policyName) + { + // check static policies first + policyName = GetPolicyName(policyName); + var policy = await base.GetPolicyAsync(policyName); + + if (policy == null) + { + // policy names must be in the form of "Entity:Permission" ie. "User:Read" + if (policyName.Contains(":")) + { + var entityName = policyName.Split(':')[0]; + var permissionName = policyName.Split(':')[1]; + + policy = new AuthorizationPolicyBuilder() + .AddRequirements(new PermissionRequirement(entityName, permissionName)) + .Build(); + + // add policy to the AuthorizationOptions + _options.AddPolicy(policyName, policy); + } + } + + return policy; + } + + private string GetPolicyName(string policyName) + { + // backward compatibility for legacy static policy names + if (policyName == PolicyNames.ViewModule) policyName = "Module:View"; + if (policyName == PolicyNames.EditModule) policyName = "Module:Edit"; + return policyName; + } + } +} diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index dac8d85c..a8eb7e25 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -127,8 +127,6 @@ namespace Oqtane .WithSiteIdentity() .WithSiteAuthentication(); - services.AddOqtaneAuthorizationPolicies(); - services.AddMvc(options => { options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()); diff --git a/Oqtane.Shared/Shared/PolicyNames.cs b/Oqtane.Shared/Shared/PolicyNames.cs index 0e478fe6..1bc7231c 100644 --- a/Oqtane.Shared/Shared/PolicyNames.cs +++ b/Oqtane.Shared/Shared/PolicyNames.cs @@ -1,19 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Text; - namespace Oqtane.Shared { + // static PolicyNames are deprecated and replaced with dynamic policies public class PolicyNames { - public const string ViewPage = "ViewPage"; - public const string EditPage = "EditPage"; - public const string ViewModule = "ViewModule"; public const string EditModule = "EditModule"; - - public const string ViewFolder = "ViewFolder"; - public const string EditFolder = "EditFolder"; - public const string ListFolder = "ListFolder"; } }