Added initial permission management infrastructure.

pull/206/head
Halil İbrahim Kalkan 7 years ago
parent d03f32ec15
commit b17a190264

@ -0,0 +1,9 @@
namespace Volo.Abp.Authorization.Permissions
{
public interface IPermissionDefinitionContext
{
PermissionDefinition GetOrNull(string name);
void Add(params PermissionDefinition[] definitions);
}
}

@ -0,0 +1,13 @@
using System.Collections.Generic;
using JetBrains.Annotations;
namespace Volo.Abp.Authorization.Permissions
{
public interface IPermissionDefinitionManager
{
[NotNull]
PermissionDefinition Get([NotNull] string name);
IReadOnlyList<PermissionDefinition> GetAll();
}
}

@ -0,0 +1,7 @@
namespace Volo.Abp.Authorization.Permissions
{
public interface IPermissionDefinitionProvider
{
void Define(IPermissionDefinitionContext context);
}
}

@ -0,0 +1,21 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using JetBrains.Annotations;
namespace Volo.Abp.Authorization.Permissions
{
//TODO: Change fallback to inherit?
public interface IPermissionManager
{
Task<bool> IsGrantedAsync([NotNull]string name);
Task<bool> IsGrantedAsync([NotNull]string name, [NotNull] string providerName, [CanBeNull] string providerKey, bool fallback = true);
Task<List<PermissionGrantInfo>> GetAllAsync();
Task<List<PermissionGrantInfo>> GetAllAsync([NotNull] string providerName, [CanBeNull] string providerKey, bool fallback = true);
Task SetAsync([NotNull] string name, bool? isGranted, [NotNull] string providerName, [CanBeNull] string providerKey, bool forceToSet = false);
}
}

@ -0,0 +1,17 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using JetBrains.Annotations;
namespace Volo.Abp.Authorization.Permissions
{
public interface IPermissionStore
{
Task<bool?> GetOrNullAsync([NotNull] string name, [CanBeNull] string providerName, [CanBeNull] string providerKey);
Task SetAsync([NotNull] string name, bool isGranted, [CanBeNull] string providerName, [CanBeNull] string providerKey);
Task<List<PermissionGrantInfo>> GetListAsync([CanBeNull] string providerName, [CanBeNull] string providerKey);
Task DeleteAsync([NotNull] string name, [CanBeNull]string providerName, [CanBeNull]string providerKey);
}
}

@ -0,0 +1,16 @@
using System.Threading.Tasks;
using JetBrains.Annotations;
namespace Volo.Abp.Authorization.Permissions
{
public interface IPermissionValueProvider
{
string Name { get; }
Task<bool?> IsGrantedAsync([NotNull] PermissionDefinition permission, [CanBeNull] string providerKey);
Task SetAsync([NotNull] PermissionDefinition permission, bool isGranted, [CanBeNull] string providerKey);
Task ClearAsync([NotNull] PermissionDefinition permission, [CanBeNull] string providerKey);
}
}

@ -0,0 +1,39 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Authorization.Permissions
{
public class NullPermissionStore : IPermissionStore, ISingletonDependency
{
public ILogger<NullPermissionStore> Logger { get; set; }
public NullPermissionStore()
{
Logger = NullLogger<NullPermissionStore>.Instance;
}
public Task<bool?> GetOrNullAsync(string name, string providerName, string providerKey)
{
return Task.FromResult((bool?)null);
}
public Task SetAsync(string name, bool isGranted, string providerName, string providerKey)
{
Logger.LogWarning($"Setting the grant value for {name} is not possible because current permission store is {nameof(NullPermissionStore)}");
return Task.CompletedTask;
}
public Task<List<PermissionGrantInfo>> GetListAsync(string providerName, string providerKey)
{
return Task.FromResult(new List<PermissionGrantInfo>());
}
public Task DeleteAsync(string name, string providerName, string providerKey)
{
return Task.CompletedTask;
}
}
}

@ -0,0 +1,28 @@
namespace Volo.Abp.Authorization.Permissions
{
public class PermissionDefinition
{
/// <summary>
/// Unique name of the permission.
/// </summary>
public string Name { get; }
/// <summary>
/// Parent of this permission if one exists.
/// If set, this permission can be granted only if parent is granted.
/// </summary>
public PermissionDefinition Parent { get; private set; }
//TODO: Add Properties dictionary for custom stuff
public PermissionDefinition(string name)
{
Name = name;
}
public PermissionDefinition CreateChild(string name)
{
return new PermissionDefinition(name) {Parent = this};
}
}
}

@ -0,0 +1,38 @@
using System.Collections.Generic;
using System.Collections.Immutable;
namespace Volo.Abp.Authorization.Permissions
{
public class PermissionDefinitionContext : IPermissionDefinitionContext
{
protected Dictionary<string, PermissionDefinition> Permissions { get; }
public PermissionDefinitionContext(Dictionary<string, PermissionDefinition> permissions)
{
Permissions = permissions;
}
public virtual PermissionDefinition GetOrNull(string name)
{
return Permissions.GetOrDefault(name);
}
public virtual IReadOnlyList<PermissionDefinition> GetAll()
{
return Permissions.Values.ToImmutableList();
}
public virtual void Add(params PermissionDefinition[] definitions)
{
if (definitions.IsNullOrEmpty())
{
return;
}
foreach (var definition in definitions)
{
Permissions[definition.Name] = definition;
}
}
}
}

@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Authorization.Permissions
{
public class PermissionDefinitionManager : IPermissionDefinitionManager, ISingletonDependency
{
protected Lazy<List<IPermissionDefinitionProvider>> Providers { get; }
protected Lazy<IDictionary<string, PermissionDefinition>> PermissionDefinitions { get; }
protected PermissionOptions Options { get; }
private readonly IServiceProvider _serviceProvider;
public PermissionDefinitionManager(
IOptions<PermissionOptions> options,
IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
Options = options.Value;
Providers = new Lazy<List<IPermissionDefinitionProvider>>(CreatePermissionProviders, true);
PermissionDefinitions = new Lazy<IDictionary<string, PermissionDefinition>>(CreatePermissionDefinitions, true);
}
public virtual PermissionDefinition Get(string name)
{
Check.NotNull(name, nameof(name));
var permission = GetOrNull(name);
if (permission == null)
{
throw new AbpException("Undefined permission: " + name);
}
return permission;
}
public virtual IReadOnlyList<PermissionDefinition> GetAll()
{
return PermissionDefinitions.Value.Values.ToImmutableList();
}
public virtual PermissionDefinition GetOrNull(string name)
{
return PermissionDefinitions.Value.GetOrDefault(name);
}
protected virtual List<IPermissionDefinitionProvider> CreatePermissionProviders()
{
return Options
.DefinitionProviders
.Select(p => _serviceProvider.GetRequiredService(p) as IPermissionDefinitionProvider)
.ToList();
}
protected virtual IDictionary<string, PermissionDefinition> CreatePermissionDefinitions()
{
var permissions = new Dictionary<string, PermissionDefinition>();
foreach (var provider in Providers.Value)
{
provider.Define(new PermissionDefinitionContext(permissions));
}
return permissions;
}
}
}

@ -0,0 +1,9 @@
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Authorization.Permissions
{
public abstract class PermissionDefinitionProvider : IPermissionDefinitionProvider, ISingletonDependency
{
public abstract void Define(IPermissionDefinitionContext context);
}
}

@ -0,0 +1,19 @@
using JetBrains.Annotations;
namespace Volo.Abp.Authorization.Permissions
{
public class PermissionGrantInfo
{
public string Name { get; }
public bool IsGranted { get; }
public PermissionGrantInfo([NotNull] string name, bool isGranted)
{
Check.NotNull(name, nameof(name));
Name = name;
IsGranted = isGranted;
}
}
}

@ -0,0 +1,184 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Authorization.Permissions
{
public class PermissionManager : IPermissionManager, ISingletonDependency
{
protected IPermissionDefinitionManager PermissionDefinitionManager { get; }
protected Lazy<List<IPermissionValueProvider>> Providers { get; }
protected PermissionOptions Options { get; }
protected IPermissionStore PermissionStore { get; }
public PermissionManager(
IOptions<PermissionOptions> options,
IServiceProvider serviceProvider,
IPermissionDefinitionManager permissionDefinitionManager,
IPermissionStore permissionStore)
{
PermissionStore = permissionStore;
PermissionDefinitionManager = permissionDefinitionManager;
Options = options.Value;
Providers = new Lazy<List<IPermissionValueProvider>>(
() => Options
.ValueProviders
.Select(c => serviceProvider.GetRequiredService(c) as IPermissionValueProvider)
.ToList(),
true
);
}
public virtual Task<bool> IsGrantedAsync(string name)
{
Check.NotNull(name, nameof(name));
return IsGrantedInternalAsync(name, null, null);
}
public virtual Task<bool> IsGrantedAsync(string name, string providerName, string providerKey, bool fallback = true)
{
Check.NotNull(name, nameof(name));
Check.NotNull(providerName, nameof(providerName));
return IsGrantedInternalAsync(name, providerName, providerKey, fallback);
}
public virtual async Task<bool> IsGrantedInternalAsync(string name, string providerName, string providerKey, bool fallback = true)
{
var permission = PermissionDefinitionManager.Get(name);
var providers = Enumerable
.Reverse(Providers.Value);
if (providerName != null)
{
providers = providers.SkipWhile(c => c.Name != providerName);
}
if (!fallback)
{
providers = providers.TakeWhile(c => c.Name == providerName);
}
foreach (var provider in providers)
{
var value = await provider.IsGrantedAsync(permission, providerKey);
if (value != null)
{
return value.Value;
}
}
return false;
}
public virtual async Task<List<PermissionGrantInfo>> GetAllAsync()
{
var permissionGrantInfos = new Dictionary<string, PermissionGrantInfo>();
var permissionDefinitions = PermissionDefinitionManager.GetAll();
foreach (var provider in Providers.Value)
{
foreach (var permission in permissionDefinitions)
{
var value = await provider.IsGrantedAsync(permission, null);
if (value != null)
{
permissionGrantInfos[permission.Name] = new PermissionGrantInfo(permission.Name, value.Value);
}
}
}
return permissionGrantInfos.Values.ToList();
}
public virtual async Task<List<PermissionGrantInfo>> GetAllAsync(string providerName, string providerKey, bool fallback = true)
{
Check.NotNull(providerName, nameof(providerName));
var permissionGrantInfos = new Dictionary<string, PermissionGrantInfo>();
var permissionDefinitions = PermissionDefinitionManager.GetAll();
var providers = Enumerable.Reverse(Providers.Value)
.SkipWhile(c => c.Name != providerName);
if (!fallback)
{
providers = providers.TakeWhile(c => c.Name == providerName);
}
var providerList = providers.Reverse().ToList();
if (providerList.Any())
{
foreach (var permission in permissionDefinitions)
{
foreach (var provider in providerList)
{
var value = await provider.IsGrantedAsync(permission, providerKey);
if (value != null)
{
permissionGrantInfos[permission.Name] = new PermissionGrantInfo(permission.Name, value.Value);
}
}
}
}
return permissionGrantInfos.Values.ToList();
}
public virtual async Task SetAsync(string name, bool? isGranted, string providerName, string providerKey, bool forceToSet = false)
{
Check.NotNull(name, nameof(name));
Check.NotNull(providerName, nameof(providerName));
var permission = PermissionDefinitionManager.Get(name);
var providers = Enumerable
.Reverse(Providers.Value)
.SkipWhile(p => p.Name != providerName)
.ToList();
if (!providers.Any())
{
return;
}
if (providers.Count > 1 && !forceToSet)
{
//Clear the value if it's same as it's fallback value
var fallbackValue = await IsGrantedInternalAsync(name, providers[1].Name, providerKey);
if (fallbackValue == isGranted)
{
isGranted = null;
}
}
providers = providers
.TakeWhile(p => p.Name == providerName)
.ToList(); //Getting list for case of there are more than one provider with same EntityType
if (isGranted == null)
{
foreach (var provider in providers)
{
await provider.ClearAsync(permission, providerKey);
}
}
else
{
foreach (var provider in providers)
{
await provider.SetAsync(permission, isGranted.Value, providerKey);
}
}
}
}
}

@ -0,0 +1,8 @@
namespace Volo.Abp.Authorization.Permissions
{
public static class PermissionManagerSyncExtensions
{
//TODO: Add sync extension methods for all permission manager methods.
//TODO: Also add sync extension methods for all value provider extensions.
}
}

@ -0,0 +1,17 @@
using Volo.Abp.Collections;
namespace Volo.Abp.Authorization.Permissions
{
public class PermissionOptions
{
public ITypeList<IPermissionDefinitionProvider> DefinitionProviders { get; }
public ITypeList<IPermissionValueProvider> ValueProviders { get; }
public PermissionOptions()
{
DefinitionProviders = new TypeList<IPermissionDefinitionProvider>();
ValueProviders = new TypeList<IPermissionValueProvider>();
}
}
}

@ -0,0 +1,23 @@
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Authorization.Permissions
{
public abstract class PermissionValueProvider : IPermissionValueProvider, ISingletonDependency
{
public abstract string Name { get; }
protected IPermissionStore PermissionStore { get; }
protected PermissionValueProvider(IPermissionStore permissionStore)
{
PermissionStore = permissionStore;
}
public abstract Task<bool?> IsGrantedAsync(PermissionDefinition permission, string providerKey);
public abstract Task SetAsync(PermissionDefinition permission, bool isGranted, string providerKey);
public abstract Task ClearAsync(PermissionDefinition permission, string providerKey);
}
}

@ -1,11 +1,20 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Settings
{
public class NullSettingStore : ISettingStore, ISingletonDependency
{
public ILogger<NullSettingStore> Logger { get; set; }
public NullSettingStore()
{
Logger = NullLogger<NullSettingStore>.Instance;
}
public Task<string> GetOrNullAsync(string name, string providerName, string providerKey)
{
return Task.FromResult((string) null);
@ -13,6 +22,7 @@ namespace Volo.Abp.Settings
public Task SetAsync(string name, string value, string providerName, string providerKey)
{
Logger.LogWarning($"Setting the value for {name} is not possible because current setting store is {nameof(NullSettingStore)}");
return Task.CompletedTask;
}

@ -30,6 +30,8 @@
/// </summary>
public object CustomData { get; set; }
//TODO: Add Properties dictionary for custom stuff (and remove CustomData)
public SettingDefinition(
string name,
string defaultValue = null,

@ -33,17 +33,17 @@ namespace Volo.Abp.Settings
{
Check.NotNull(name, nameof(name));
var settingDefinition = GetOrNull(name);
var setting = GetOrNull(name);
if (settingDefinition == null)
if (setting == null)
{
throw new AbpException("Undefined setting: " + name);
}
return settingDefinition;
return setting;
}
public IReadOnlyList<SettingDefinition> GetAll()
public virtual IReadOnlyList<SettingDefinition> GetAll()
{
return SettingDefinitions.Value.Values.ToImmutableList();
}
@ -53,7 +53,7 @@ namespace Volo.Abp.Settings
return SettingDefinitions.Value.GetOrDefault(name);
}
private List<ISettingDefinitionProvider> CreateSettingProviders()
protected virtual List<ISettingDefinitionProvider> CreateSettingProviders()
{
return Options
.DefinitionProviders
@ -61,7 +61,7 @@ namespace Volo.Abp.Settings
.ToList();
}
private IDictionary<string, SettingDefinition> CreateSettingDefinitions()
protected virtual IDictionary<string, SettingDefinition> CreateSettingDefinitions()
{
var settings = new Dictionary<string, SettingDefinition>();

@ -16,15 +16,11 @@ namespace Volo.Abp.Settings
protected SettingOptions Options { get; }
protected ISettingStore SettingStore { get; }
public SettingManager(
IOptions<SettingOptions> options,
IServiceProvider serviceProvider,
ISettingDefinitionManager settingDefinitionManager,
ISettingStore settingStore)
ISettingDefinitionManager settingDefinitionManager)
{
SettingStore = settingStore;
SettingDefinitionManager = settingDefinitionManager;
Options = options.Value;

Loading…
Cancel
Save