mirror of
https://github.com/esiur/esiur-dotnet.git
synced 2026-07-30 17:30:40 +00:00
Managers
This commit is contained in:
@@ -7,7 +7,10 @@ namespace Esiur.Resource;
|
||||
/// Associates a registered auditing-manager implementation with a resource type.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
|
||||
public sealed class AuditingManagerAttribute<T> : Attribute
|
||||
public sealed class AuditingManagerAttribute<T> : ResourceManagerAttribute
|
||||
where T : IAuditingManager
|
||||
{
|
||||
public AuditingManagerAttribute() : base(typeof(T))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,10 @@ namespace Esiur.Resource;
|
||||
/// Associates a registered permissions-manager implementation with a resource type.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
|
||||
public sealed class PermissionsManagerAttribute<T> : Attribute
|
||||
public sealed class PermissionsManagerAttribute<T> : ResourceManagerAttribute
|
||||
where T : IPermissionsManager
|
||||
{
|
||||
public PermissionsManagerAttribute() : base(typeof(T))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,10 @@ namespace Esiur.Resource;
|
||||
/// Associates a registered rate-control-manager implementation with a resource type.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
|
||||
public sealed class RateControlManagerAttribute<T> : Attribute
|
||||
public sealed class RateControlManagerAttribute<T> : ResourceManagerAttribute
|
||||
where T : IRateControlManager
|
||||
{
|
||||
public RateControlManagerAttribute() : base(typeof(T))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
using Esiur.Security.Management;
|
||||
using System;
|
||||
|
||||
namespace Esiur.Resource;
|
||||
|
||||
/// <summary>
|
||||
/// Base metadata used to resolve a resource manager from its owning Warehouse.
|
||||
/// Manager attributes never create instances directly; the declared type must be
|
||||
/// registered with the Warehouse before the resource is created.
|
||||
/// </summary>
|
||||
public abstract class ResourceManagerAttribute : Attribute
|
||||
{
|
||||
public Type ManagerType { get; }
|
||||
|
||||
protected ResourceManagerAttribute(Type managerType)
|
||||
{
|
||||
ManagerType = managerType ?? throw new ArgumentNullException(nameof(managerType));
|
||||
|
||||
if (!typeof(IResourceManager).IsAssignableFrom(managerType))
|
||||
throw new ArgumentException(
|
||||
$"Manager type `{managerType}` must implement {nameof(IResourceManager)}.",
|
||||
nameof(managerType));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using Esiur.Security.Management;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Esiur.Resource;
|
||||
|
||||
/// <summary>
|
||||
/// Optional trusted creation context that binds registered managers to a resource.
|
||||
/// Keeping this separate from <see cref="IResourceContext"/> preserves compatibility
|
||||
/// with existing context implementations.
|
||||
/// </summary>
|
||||
public interface IResourceManagersContext
|
||||
{
|
||||
IReadOnlyList<IResourceManager> ResourceManagers { get; }
|
||||
}
|
||||
@@ -8,6 +8,7 @@ using System.Runtime.CompilerServices;
|
||||
using System.Reflection;
|
||||
using Esiur.Misc;
|
||||
using Esiur.Security.Permissions;
|
||||
using Esiur.Security.Management;
|
||||
using Esiur.Security.Authority;
|
||||
using Esiur.Proxy;
|
||||
using Esiur.Core;
|
||||
@@ -30,7 +31,7 @@ public class Instance
|
||||
WeakReference<IResource> resource;
|
||||
IStore store;
|
||||
TypeDef definition;
|
||||
AutoList<IPermissionsManager, Instance> managers;
|
||||
AutoList<IResourceManager, Instance> managers;
|
||||
|
||||
|
||||
public event PropertyModifiedEvent PropertyModified;
|
||||
@@ -696,36 +697,55 @@ public class Instance
|
||||
/// <returns>Ruling.</returns>
|
||||
public Ruling Applicable(Session session, ActionType action, MemberDef member, object inquirer = null)
|
||||
{
|
||||
IResource res;
|
||||
if (this.resource.TryGetTarget(out res))
|
||||
{
|
||||
//return store.Applicable(res, session, action, member, inquirer);
|
||||
var context = MakeManagerContext(session, action, member, inquirer);
|
||||
return Warehouse.EvaluatePermissions(context, managers.ToArray());
|
||||
}
|
||||
|
||||
foreach (IPermissionsManager manager in managers)
|
||||
{
|
||||
var r = manager.Applicable(res, session, action, member, inquirer);
|
||||
if (r != Ruling.DontCare)
|
||||
return r;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Apply default permissions if no manager is applicable or if the resource is not available.
|
||||
if (action == ActionType.GetProperty
|
||||
|| action == ActionType.ViewTypeDef
|
||||
|| action == ActionType.ReceiveEvent
|
||||
|| action == ActionType.Attach
|
||||
|| action == ActionType.Execute)
|
||||
return Ruling.Allowed;
|
||||
else
|
||||
return Ruling.Denied;
|
||||
/// <summary>
|
||||
/// Evaluates the Warehouse defaults and this resource's manager snapshot.
|
||||
/// </summary>
|
||||
public ResourceManagerEvaluation EvaluateManagers(
|
||||
Session session,
|
||||
ActionType action,
|
||||
MemberDef member,
|
||||
object inquirer = null)
|
||||
{
|
||||
var context = MakeManagerContext(session, action, member, inquirer);
|
||||
return Warehouse.EvaluateManagers(context, managers.ToArray());
|
||||
}
|
||||
|
||||
ResourceManagerContext MakeManagerContext(
|
||||
Session session,
|
||||
ActionType action,
|
||||
MemberDef member,
|
||||
object inquirer)
|
||||
{
|
||||
resource.TryGetTarget(out var res);
|
||||
return new ResourceManagerContext(
|
||||
Warehouse,
|
||||
inquirer as EpConnection,
|
||||
session,
|
||||
res,
|
||||
member,
|
||||
action,
|
||||
inquirer,
|
||||
member?.MemberPolicyAttributes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execution managers.
|
||||
/// </summary>
|
||||
public AutoList<IPermissionsManager, Instance> Managers => managers;
|
||||
public AutoList<IResourceManager, Instance> Managers => managers;
|
||||
|
||||
void ManagerAdded(Instance instance, IResourceManager manager)
|
||||
{
|
||||
if (manager != null && Warehouse.IsRegisteredManager(manager))
|
||||
return;
|
||||
|
||||
managers.Remove(manager);
|
||||
throw new InvalidOperationException(
|
||||
$"Resource manager `{manager?.GetType()}` must be registered with this Warehouse before it is attached.");
|
||||
}
|
||||
|
||||
public readonly Warehouse Warehouse;
|
||||
/// <summary>
|
||||
@@ -747,7 +767,8 @@ public class Instance
|
||||
//this.attributes = new KeyList<string, object>(this);
|
||||
//children = new AutoList<IResource, Instance>(this);
|
||||
//parents = new AutoList<IResource, Instance>(this);
|
||||
managers = new AutoList<IPermissionsManager, Instance>(this);
|
||||
managers = new AutoList<IResourceManager, Instance>(this);
|
||||
managers.OnAdd += ManagerAdded;
|
||||
//children.OnAdd += Children_OnAdd;
|
||||
//children.OnRemoved += Children_OnRemoved;
|
||||
//parents.OnAdd += Parents_OnAdd;
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
using Esiur.Data;
|
||||
using Esiur.Security.Authority;
|
||||
using Esiur.Security.Permissions;
|
||||
using Esiur.Security.Management;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
|
||||
namespace Esiur.Resource
|
||||
{
|
||||
public class ResourceContext:IResourceContext
|
||||
public class ResourceContext : IResourceContext, IResourceManagersContext
|
||||
{
|
||||
public ulong Age { get; }
|
||||
public Map<string, object> Attributes { get; }
|
||||
public Map<string, object> Properties { get; }
|
||||
public IPermissionsManager PermissionsManager { get; }
|
||||
public IReadOnlyList<IResourceManager> ResourceManagers { get; }
|
||||
|
||||
public ResourceContext(ulong age, Map<string, object> attributes, Map<string, object> properties, IPermissionsManager permissionsManager)
|
||||
{
|
||||
@@ -21,6 +24,35 @@ namespace Esiur.Resource
|
||||
Attributes = attributes;
|
||||
Properties = properties;
|
||||
PermissionsManager = permissionsManager;
|
||||
ResourceManagers = permissionsManager is null
|
||||
? Array.Empty<IResourceManager>()
|
||||
: new IResourceManager[] { permissionsManager };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a context with one or more locally supplied managers. Every manager
|
||||
/// must already be registered with the target Warehouse.
|
||||
/// </summary>
|
||||
public ResourceContext(
|
||||
IEnumerable<IResourceManager> resourceManagers,
|
||||
ulong age = 0,
|
||||
Map<string, object> attributes = null,
|
||||
Map<string, object> properties = null)
|
||||
{
|
||||
if (resourceManagers == null)
|
||||
throw new ArgumentNullException(nameof(resourceManagers));
|
||||
|
||||
var managers = resourceManagers.ToArray();
|
||||
if (managers.Any(manager => manager == null))
|
||||
throw new ArgumentException(
|
||||
"Resource managers cannot contain null values.",
|
||||
nameof(resourceManagers));
|
||||
|
||||
Age = age;
|
||||
Attributes = attributes;
|
||||
Properties = properties;
|
||||
ResourceManagers = Array.AsReadOnly(managers);
|
||||
PermissionsManager = managers.OfType<IPermissionsManager>().FirstOrDefault();
|
||||
}
|
||||
|
||||
//public virtual void Build()
|
||||
|
||||
@@ -31,6 +31,7 @@ using Esiur.Protocol;
|
||||
using Esiur.Proxy;
|
||||
using Esiur.Security.Authority;
|
||||
using Esiur.Security.Cryptography;
|
||||
using Esiur.Security.Management;
|
||||
using Esiur.Security.Permissions;
|
||||
using Esiur.Security.RateLimiting;
|
||||
using Org.BouncyCastle.Asn1.Cms;
|
||||
@@ -91,7 +92,10 @@ public class Warehouse
|
||||
Map<string, IAuthenticationProvider> _authenticationProviders = new Map<string, IAuthenticationProvider>();
|
||||
readonly ConcurrentDictionary<string, IEncryptionProvider> _encryptionProviders
|
||||
= new ConcurrentDictionary<string, IEncryptionProvider>(StringComparer.Ordinal);
|
||||
List<IPermissionsManager> _permissionsManagers = new List<IPermissionsManager>();
|
||||
readonly ConcurrentDictionary<Type, IResourceManager> _resourceManagers
|
||||
= new ConcurrentDictionary<Type, IResourceManager>();
|
||||
readonly ConcurrentDictionary<Type, byte> _defaultResourceManagerTypes
|
||||
= new ConcurrentDictionary<Type, byte>();
|
||||
readonly ConcurrentDictionary<string, RatePolicy> _ratePolicies
|
||||
= new ConcurrentDictionary<string, RatePolicy>(StringComparer.Ordinal);
|
||||
|
||||
@@ -151,11 +155,374 @@ public class Warehouse
|
||||
}
|
||||
|
||||
|
||||
public void RegisterPermissionsManager(IPermissionsManager manager)
|
||||
/// <summary>
|
||||
/// Registers a manager instance by its concrete type. Type attributes and
|
||||
/// ResourceContext bindings can only reference instances registered here.
|
||||
/// </summary>
|
||||
public void RegisterManager(IResourceManager manager, bool useAsDefault = false)
|
||||
{
|
||||
_permissionsManagers.Add(manager);
|
||||
if (manager == null)
|
||||
throw new ArgumentNullException(nameof(manager));
|
||||
|
||||
var managerType = manager.GetType();
|
||||
var categoryCount =
|
||||
(manager is IPermissionsManager ? 1 : 0) +
|
||||
(manager is IRateControlManager ? 1 : 0) +
|
||||
(manager is IAuditingManager ? 1 : 0);
|
||||
|
||||
if (categoryCount == 0)
|
||||
throw new ArgumentException(
|
||||
$"Manager `{managerType}` does not implement a supported manager category.",
|
||||
nameof(manager));
|
||||
if (categoryCount > 1)
|
||||
throw new ArgumentException(
|
||||
$"Manager `{managerType}` must implement exactly one manager category.",
|
||||
nameof(manager));
|
||||
|
||||
if (!_resourceManagers.TryAdd(managerType, manager))
|
||||
throw new InvalidOperationException(
|
||||
$"A resource manager of type `{managerType}` is already registered.");
|
||||
|
||||
if (useAsDefault)
|
||||
_defaultResourceManagerTypes.TryAdd(managerType, 0);
|
||||
}
|
||||
|
||||
public void RegisterManager<TManager>(TManager manager, bool useAsDefault = false)
|
||||
where TManager : class, IResourceManager
|
||||
=> RegisterManager((IResourceManager)manager, useAsDefault);
|
||||
|
||||
public TManager RegisterManager<TManager>(bool useAsDefault = false)
|
||||
where TManager : class, IResourceManager, new()
|
||||
{
|
||||
var manager = new TManager();
|
||||
RegisterManager(manager, useAsDefault);
|
||||
return manager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compatibility registration for Warehouse-wide permissions. Registered
|
||||
/// permission managers are defaults, matching the original API's intent.
|
||||
/// </summary>
|
||||
public void RegisterPermissionsManager(IPermissionsManager manager)
|
||||
=> RegisterManager(manager, true);
|
||||
|
||||
public void RegisterPermissionsManager(
|
||||
IPermissionsManager manager,
|
||||
bool useAsDefault)
|
||||
=> RegisterManager(manager, useAsDefault);
|
||||
|
||||
public void RegisterRateControlManager(IRateControlManager manager, bool useAsDefault = false)
|
||||
=> RegisterManager(manager, useAsDefault);
|
||||
|
||||
public void RegisterAuditingManager(IAuditingManager manager, bool useAsDefault = false)
|
||||
=> RegisterManager(manager, useAsDefault);
|
||||
|
||||
/// <summary>
|
||||
/// Enables or disables a registered manager as a Warehouse-wide default.
|
||||
/// Multiple defaults may be enabled for the same manager category.
|
||||
/// </summary>
|
||||
public void SetDefaultManager(Type managerType, bool enabled = true)
|
||||
{
|
||||
if (managerType == null)
|
||||
throw new ArgumentNullException(nameof(managerType));
|
||||
if (!_resourceManagers.ContainsKey(managerType))
|
||||
throw new InvalidOperationException(
|
||||
$"Resource manager `{managerType}` is not registered.");
|
||||
if (!enabled && typeof(NamedRateControlManager).IsAssignableFrom(managerType))
|
||||
throw new InvalidOperationException(
|
||||
"The built-in named rate-control manager cannot be disabled.");
|
||||
|
||||
if (enabled)
|
||||
_defaultResourceManagerTypes.TryAdd(managerType, 0);
|
||||
else
|
||||
_defaultResourceManagerTypes.TryRemove(managerType, out _);
|
||||
}
|
||||
|
||||
public void SetDefaultManager<TManager>(bool enabled = true)
|
||||
where TManager : IResourceManager
|
||||
=> SetDefaultManager(typeof(TManager), enabled);
|
||||
|
||||
public IResourceManager? TryGetManager(Type managerType)
|
||||
=> managerType != null && _resourceManagers.TryGetValue(managerType, out var manager)
|
||||
? manager
|
||||
: null;
|
||||
|
||||
public TManager? TryGetManager<TManager>() where TManager : class, IResourceManager
|
||||
=> TryGetManager(typeof(TManager)) as TManager;
|
||||
|
||||
public bool RemoveManager(Type managerType)
|
||||
{
|
||||
if (managerType == null)
|
||||
return false;
|
||||
if (typeof(NamedRateControlManager).IsAssignableFrom(managerType))
|
||||
return false;
|
||||
|
||||
_defaultResourceManagerTypes.TryRemove(managerType, out _);
|
||||
return _resourceManagers.TryRemove(managerType, out _);
|
||||
}
|
||||
|
||||
public Type[] GetRegisteredManagerTypes()
|
||||
=> _resourceManagers.Keys.OrderBy(type => type.FullName, StringComparer.Ordinal).ToArray();
|
||||
|
||||
public IResourceManager[] GetDefaultManagers()
|
||||
=> _defaultResourceManagerTypes.Keys
|
||||
.OrderBy(type => type.FullName, StringComparer.Ordinal)
|
||||
.Select(type => TryGetManager(type))
|
||||
.Where(manager => manager != null)
|
||||
.ToArray()!;
|
||||
|
||||
internal bool IsRegisteredManager(IResourceManager manager)
|
||||
=> manager != null &&
|
||||
_resourceManagers.TryGetValue(manager.GetType(), out var registered) &&
|
||||
ReferenceEquals(manager, registered);
|
||||
|
||||
internal IResourceManager[] ResolveResourceManagers(
|
||||
Type resourceType,
|
||||
IResourceContext resourceContext)
|
||||
{
|
||||
if (resourceType == null)
|
||||
throw new ArgumentNullException(nameof(resourceType));
|
||||
|
||||
var resolved = new List<IResourceManager>();
|
||||
var baseType = ResourceProxy.GetBaseType(resourceType);
|
||||
|
||||
foreach (var attribute in baseType
|
||||
.GetCustomAttributes(typeof(ResourceManagerAttribute), true)
|
||||
.OfType<ResourceManagerAttribute>())
|
||||
{
|
||||
var manager = TryGetManager(attribute.ManagerType);
|
||||
if (manager == null)
|
||||
throw new InvalidOperationException(
|
||||
$"Resource manager `{attribute.ManagerType}` declared by `{baseType}` is not registered.");
|
||||
|
||||
if (!resolved.Any(existing => ReferenceEquals(existing, manager)))
|
||||
resolved.Add(manager);
|
||||
}
|
||||
|
||||
if (resourceContext is IResourceManagersContext managerContext)
|
||||
{
|
||||
foreach (var manager in managerContext.ResourceManagers ?? Array.Empty<IResourceManager>())
|
||||
{
|
||||
if (manager == null)
|
||||
throw new InvalidOperationException("A ResourceContext supplied a null manager.");
|
||||
if (!IsRegisteredManager(manager))
|
||||
throw new InvalidOperationException(
|
||||
$"Resource manager `{manager.GetType()}` supplied by ResourceContext is not registered with this Warehouse.");
|
||||
|
||||
if (!resolved.Any(existing => ReferenceEquals(existing, manager)))
|
||||
resolved.Add(manager);
|
||||
}
|
||||
}
|
||||
|
||||
return resolved.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asks every applicable manager using independent deny-overrides aggregation
|
||||
/// for permissions, rate control and auditing.
|
||||
/// </summary>
|
||||
public ResourceManagerEvaluation EvaluateManagers(
|
||||
ResourceManagerContext context,
|
||||
IEnumerable<IResourceManager>? resourceManagers = null)
|
||||
{
|
||||
if (context == null)
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
if (!ReferenceEquals(context.Warehouse, this))
|
||||
throw new ArgumentException(
|
||||
"The manager context belongs to another Warehouse.",
|
||||
nameof(context));
|
||||
|
||||
var localManagers = resourceManagers?.ToArray()
|
||||
?? context.Resource?.Instance?.Managers.ToArray()
|
||||
?? Array.Empty<IResourceManager>();
|
||||
|
||||
var managers = new List<IResourceManager>();
|
||||
foreach (var manager in GetDefaultManagers().Concat(localManagers))
|
||||
if (manager != null && !managers.Any(existing => ReferenceEquals(existing, manager)))
|
||||
managers.Add(manager);
|
||||
|
||||
var permissionsAllowed = false;
|
||||
var permissionsDenied = false;
|
||||
var rateAllowed = false;
|
||||
var rateDenied = false;
|
||||
var auditingAllowed = false;
|
||||
var auditingDenied = false;
|
||||
var delay = TimeSpan.Zero;
|
||||
string permissionsReason = null;
|
||||
string rateReason = null;
|
||||
string auditingReason = null;
|
||||
|
||||
foreach (var manager in managers)
|
||||
{
|
||||
var registered = IsRegisteredManager(manager);
|
||||
context.Delay = TimeSpan.Zero;
|
||||
context.DenialReason = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (!registered)
|
||||
throw new InvalidOperationException(
|
||||
$"Resource manager `{manager.GetType()}` is not registered with this Warehouse.");
|
||||
|
||||
if (manager is IPermissionsManager permissionsManager)
|
||||
{
|
||||
var ruling = permissionsManager.Applicable(
|
||||
context.Resource,
|
||||
context.Session,
|
||||
context.Action,
|
||||
context.Member,
|
||||
context.Inquirer);
|
||||
|
||||
permissionsDenied |= ruling == Ruling.Denied;
|
||||
permissionsAllowed |= ruling == Ruling.Allowed;
|
||||
if (ruling == Ruling.Denied && permissionsReason == null)
|
||||
permissionsReason = context.DenialReason
|
||||
?? $"Permissions manager `{manager.GetType().Name}` denied the operation.";
|
||||
}
|
||||
else if (manager is IRateControlManager rateControlManager)
|
||||
{
|
||||
var ruling = rateControlManager.Applicable(context);
|
||||
rateDenied |= ruling == Ruling.Denied;
|
||||
rateAllowed |= ruling == Ruling.Allowed;
|
||||
if (context.Delay > delay)
|
||||
delay = context.Delay;
|
||||
if (ruling == Ruling.Denied && rateReason == null)
|
||||
rateReason = context.DenialReason
|
||||
?? $"Rate-control manager `{manager.GetType().Name}` denied the operation.";
|
||||
}
|
||||
else if (manager is IAuditingManager auditingManager)
|
||||
{
|
||||
var ruling = auditingManager.Applicable(context);
|
||||
auditingDenied |= ruling == Ruling.Denied;
|
||||
auditingAllowed |= ruling == Ruling.Allowed;
|
||||
if (ruling == Ruling.Denied && auditingReason == null)
|
||||
auditingReason = context.DenialReason
|
||||
?? $"Auditing manager `{manager.GetType().Name}` denied the operation.";
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Global.Log(
|
||||
"ResourceManager",
|
||||
LogType.Error,
|
||||
$"Manager `{manager.GetType()}` failed while evaluating `{context.Action}`: {exception}");
|
||||
|
||||
if (manager is IPermissionsManager)
|
||||
{
|
||||
permissionsDenied = true;
|
||||
permissionsReason ??= "A permissions manager failed while evaluating the operation.";
|
||||
}
|
||||
else if (manager is IRateControlManager)
|
||||
{
|
||||
rateDenied = true;
|
||||
rateReason ??= "A rate-control manager failed while evaluating the operation.";
|
||||
}
|
||||
else if (manager is IAuditingManager)
|
||||
{
|
||||
auditingDenied = true;
|
||||
auditingReason ??= "An auditing manager failed while evaluating the operation.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var permissions = permissionsDenied
|
||||
? Ruling.Denied
|
||||
: permissionsAllowed
|
||||
? Ruling.Allowed
|
||||
: DefaultPermissions(context.Action);
|
||||
var rateControl = rateDenied
|
||||
? Ruling.Denied
|
||||
: rateAllowed ? Ruling.Allowed : Ruling.DontCare;
|
||||
var auditing = auditingDenied
|
||||
? Ruling.Denied
|
||||
: auditingAllowed ? Ruling.Allowed : Ruling.DontCare;
|
||||
|
||||
context.Delay = delay;
|
||||
context.DenialReason = permissions == Ruling.Denied
|
||||
? permissionsReason
|
||||
: auditing == Ruling.Denied
|
||||
? auditingReason
|
||||
: rateReason;
|
||||
|
||||
return new ResourceManagerEvaluation(
|
||||
permissions,
|
||||
rateControl,
|
||||
auditing,
|
||||
delay,
|
||||
permissionsReason,
|
||||
rateReason,
|
||||
auditingReason);
|
||||
}
|
||||
|
||||
internal Ruling EvaluatePermissions(
|
||||
ResourceManagerContext context,
|
||||
IEnumerable<IResourceManager> resourceManagers)
|
||||
{
|
||||
if (context == null)
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
if (!ReferenceEquals(context.Warehouse, this))
|
||||
throw new ArgumentException(
|
||||
"The manager context belongs to another Warehouse.",
|
||||
nameof(context));
|
||||
|
||||
var managers = new List<IPermissionsManager>();
|
||||
foreach (var manager in GetDefaultManagers()
|
||||
.Concat(resourceManagers ?? Array.Empty<IResourceManager>())
|
||||
.OfType<IPermissionsManager>())
|
||||
if (!managers.Any(existing => ReferenceEquals(existing, manager)))
|
||||
managers.Add(manager);
|
||||
|
||||
var allowed = false;
|
||||
var denied = false;
|
||||
|
||||
foreach (var manager in managers)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!IsRegisteredManager(manager))
|
||||
throw new InvalidOperationException(
|
||||
$"Resource manager `{manager.GetType()}` is not registered with this Warehouse.");
|
||||
|
||||
var ruling = manager.Applicable(
|
||||
context.Resource,
|
||||
context.Session,
|
||||
context.Action,
|
||||
context.Member,
|
||||
context.Inquirer);
|
||||
denied |= ruling == Ruling.Denied;
|
||||
allowed |= ruling == Ruling.Allowed;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
denied = true;
|
||||
Global.Log(
|
||||
"ResourceManager",
|
||||
LogType.Error,
|
||||
$"Permissions manager `{manager.GetType()}` failed while evaluating `{context.Action}`: {exception}");
|
||||
}
|
||||
}
|
||||
|
||||
return denied
|
||||
? Ruling.Denied
|
||||
: allowed ? Ruling.Allowed : DefaultPermissions(context.Action);
|
||||
}
|
||||
|
||||
internal static Ruling DefaultPermissions(ActionType action)
|
||||
=> action == ActionType.GetProperty
|
||||
|| action == ActionType.ViewTypeDef
|
||||
|| action == ActionType.ReceiveEvent
|
||||
|| action == ActionType.Attach
|
||||
|| action == ActionType.Execute
|
||||
|| action == ActionType.Detach
|
||||
|| action == ActionType.Subscribe
|
||||
|| action == ActionType.Unsubscribe
|
||||
|| action == ActionType.PullStream
|
||||
|| action == ActionType.TerminateExecution
|
||||
|| action == ActionType.HaltExecution
|
||||
|| action == ActionType.ResumeExecution
|
||||
? Ruling.Allowed
|
||||
: Ruling.Denied;
|
||||
|
||||
/// <summary>
|
||||
/// Registers a named rate policy referenced by RateControl attributes.
|
||||
/// </summary>
|
||||
@@ -241,6 +608,8 @@ public class Warehouse
|
||||
{
|
||||
Configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
|
||||
|
||||
RegisterManager(new NamedRateControlManager(), true);
|
||||
|
||||
Protocols.Add("EP",
|
||||
async (name, context)
|
||||
=> await New<EpConnection>(name, context));
|
||||
@@ -540,11 +909,14 @@ public class Warehouse
|
||||
}
|
||||
|
||||
var resourceReference = new WeakReference<IResource>(resource);
|
||||
var resourceManagers = ResolveResourceManagers(resource.GetType(), resourceContext);
|
||||
|
||||
var resourceId = (uint)Interlocked.Increment(ref _resourceCounter);
|
||||
|
||||
resource.Instance = new Instance(this, resourceId, instanceName, resource, store, resourceContext?.Age ?? 0);
|
||||
|
||||
resource.Instance.Managers.AddRange(resourceManagers);
|
||||
|
||||
if (resourceContext?.Attributes != null)
|
||||
resource.Instance.SetAttributes(resourceContext.Attributes);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user