| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381 |
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Linq;
- using System.Reflection;
- using System.Security;
- using System.Threading.Tasks;
- using InABox.Clients;
- namespace InABox.Core
- {
- public static class Security
- {
- private static ISecurityDescriptor[]? _descriptors;
- private static GlobalSecurityToken[]? _globaltokens;
- private static Dictionary<Guid, SecurityToken[]> _grouptokens = new Dictionary<Guid, SecurityToken[]>();
- private static Dictionary<Guid, UserSecurityToken[]> _usertokens = new Dictionary<Guid, UserSecurityToken[]>();
- public static IEnumerable<ISecurityDescriptor> Descriptors
- {
- get
- {
- if (_descriptors == null)
- {
- ISecurityDescriptor[] GetTokens(params Task<ISecurityDescriptor[]>[] tasks)
- {
- Task.WaitAll(tasks);
- return CoreUtils.Concatenate(tasks.ToArray(x => x.Result));
- }
- var custom = Task.Run(() =>
- {
- return CoreUtils.Entities.Where(x => !x.IsGenericType && x.HasInterface<ISecurityDescriptor>())
- .Select(x => Activator.CreateInstance(x) as ISecurityDescriptor)
- .NotNull()
- .ToArray();
- });
- bool Overridden(Type @class, Func<EntitySecurityAttribute, Type?> getToken)
- {
- return @class.GetCustomAttribute<EntitySecurityAttribute>() is EntitySecurityAttribute attr && getToken(attr) != null;
- }
- var auto = Task.Run(() =>
- {
- var entities = CoreUtils.Entities.Where( x => !x.IsGenericType && x.IsSubclassOf(typeof(Entity))).ToArray();
- var view = Task.Run(() =>
- {
- return entities
- .Where(x => !Overridden(x, x => x.CanView))
- .Select(x => GetAutoToken(x, typeof(CanView<>)))
- .NotNull()
- .ToArray();
- });
- var edit = Task.Run(() =>
- {
- return entities
- .Where(x => !Overridden(x, x => x.CanEdit))
- .Select(x => GetAutoToken(x, typeof(CanEdit<>)))
- .NotNull()
- .ToArray();
- });
- var delete = Task.Run(() =>
- {
- return entities
- .Where(x => !Overridden(x, x => x.CanDelete))
- .Select(x => GetAutoToken(x, typeof(CanDelete<>)))
- .NotNull()
- .ToArray();
- });
- var issues = Task.Run(() =>
- {
- return entities.Where(x => x.GetInterfaces().Contains(typeof(IIssues)))
- .Select(x => GetAutoToken(x, typeof(CanManageIssues<>)))
- .NotNull()
- .ToArray();
- });
- var exports = Task.Run(() =>
- {
- return entities.Where(x => x.GetInterfaces().Contains(typeof(IExportable)))
- .Select(x => GetAutoToken(x, typeof(CanExport<>)))
- .NotNull()
- .ToArray();
- });
- var imports = Task.Run(() =>
- {
- return entities.Where(x => x.GetInterfaces().Contains(typeof(IImportable)))
- .Select(x => GetAutoToken(x, typeof(CanImport<>)))
- .NotNull()
- .ToArray();
- });
- var merges = Task.Run(() =>
- {
- return entities.Where(x => x.GetInterfaces().Contains(typeof(IMergeable)))
- .Select(x => GetAutoToken(x, typeof(CanMerge<>)))
- .NotNull()
- .ToArray();
- });
- var posts = Task.Run(() =>
- {
- return entities.Where(x => x.GetInterfaces().Contains(typeof(IPostable)))
- .Select(x => GetAutoToken(x, typeof(CanPost<>)))
- .NotNull()
- .ToArray();
- });
- var configPosts = Task.Run(() =>
- {
- return entities.Where(x => x.GetInterfaces().Contains(typeof(IPostable)))
- .Select(x => GetAutoToken(x, typeof(CanConfigurePost<>)))
- .NotNull()
- .ToArray();
- });
- return GetTokens(view, edit, delete, issues, exports, merges, posts, configPosts);
- });
- _descriptors = GetTokens(custom, auto);
- Array.Sort(_descriptors, CoreUtils.OrderBy((ISecurityDescriptor x) => x.Type).ThenBy(x => x.Code));
- }
- return _descriptors;
- }
- }
- public static void Reset()
- {
- _globaltokens = null;
- _grouptokens.Clear();
- _usertokens.Clear();
- _descriptors = null;
- }
- public static void CheckTokens(Guid userId, Guid securityID)
- {
- var userTask = !_usertokens.ContainsKey(userId)
- ? Client.QueryAsync(
- Filter<UserSecurityToken>.Where(x => x.User.ID).IsEqualTo(ClientFactory.UserGuid),
- Columns.None<UserSecurityToken>().Add(x => x.Descriptor).Add(x => x.Enabled))
- : null;
- var groupTask = !_grouptokens.ContainsKey(securityID)
- ? Client.QueryAsync(
- Filter<SecurityToken>.Where(x => x.Group.ID).IsEqualTo(ClientFactory.UserSecurityID),
- Columns.None<SecurityToken>().Add(x => x.Descriptor).Add(x => x.Enabled))
- : null;
- var globalTask = _globaltokens is null
- ? Client.QueryAsync(
- null,
- Columns.None<GlobalSecurityToken>().Add(x => x.Descriptor).Add(x => x.Enabled))
- : null;
- if (userTask is null && groupTask is null && globalTask is null) return;
- CoreUtils.WaitAllNotNull(userTask, groupTask, globalTask);
- if(userTask != null)
- {
- _usertokens.Add(userId, userTask.Result.ToArray<UserSecurityToken>());
- }
- if(groupTask != null)
- {
- _grouptokens.Add(securityID, groupTask.Result.ToArray<SecurityToken>());
- }
- if(globalTask != null)
- {
- _globaltokens = globalTask.Result.ToArray<GlobalSecurityToken>();
- }
- }
-
- private static ISecurityDescriptor? GetAutoToken(Type _class, Type type)
- {
- var basetype = typeof(AutoSecurityDescriptor<,>);
- var actiontype = type.MakeGenericType(_class);
- var descriptortype = basetype.MakeGenericType(_class, actiontype);
- var descriptor = (Activator.CreateInstance(descriptortype) as ISecurityDescriptor)!;
- return descriptor;
- // if (!_descriptors.Any(x => string.Equals(x.Code, descriptor.Code)))
- // _descriptors.Add(descriptor);
- }
- private static bool IsAllowedInternal(ISecurityDescriptor descriptor, Guid userGuid, Guid securityId)
- {
- // If you're not logged in, you can't do jack!
- if (userGuid == Guid.Empty)
- return false;
- CheckTokens(userGuid, securityId);
-
- // First Check for a matching User Token (override)
- var usertoken = _usertokens[userGuid].FirstOrDefault(x => x.Descriptor.Equals(descriptor.Code));
- if (usertoken != null)
- return usertoken.Enabled;
- // If not found, fall back to the Group Token
- var grouptoken = _grouptokens[securityId].FirstOrDefault(x => x.Descriptor.Equals(descriptor.Code));
- if (grouptoken != null)
- return grouptoken.Enabled;
- // Still not found? fall back to the Global Token
- var globaltoken = _globaltokens.FirstOrDefault(x => x.Descriptor.Equals(descriptor.Code));
- if (globaltoken != null)
- return globaltoken.Enabled;
- // Aaand finally, just return the default for the descriptor
- return descriptor.Value;
- }
- public static bool IsAllowed(Type T, Guid userGuid, Guid securityId)
- {
- var descriptor = (Activator.CreateInstance(T) as ISecurityDescriptor)!;
- try
- {
- if(IsAllowedInternal(descriptor, userGuid, securityId))
- {
- if(descriptor is IDependentSecurityDescriptor dependent)
- {
- return dependent.DependsOn.All(x => IsAllowed(x, userGuid, securityId));
- }
- else
- {
- return true;
- }
- }
- else
- {
- return false;
- }
- }
- catch (Exception e)
- {
- Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
- return false;
- }
- }
- public static bool IsAllowed<T>(Guid userGuid, Guid securityId) where T : ISecurityDescriptor, new()
- => IsAllowed(typeof(T), userGuid, securityId);
- public static bool IsAllowed<T>() where T : ISecurityDescriptor, new()
- => IsAllowed<T>(ClientFactory.UserGuid, ClientFactory.UserSecurityID);
- public static bool IsAllowed(Type T)
- => IsAllowed(T, ClientFactory.UserGuid, ClientFactory.UserSecurityID);
- private static Type CreateAutoDescriptor(Type TAction, Type TEntity)
- {
- return typeof(AutoSecurityDescriptor<,>).MakeGenericType(TEntity, TAction.MakeGenericType(TEntity));
- }
- #region CanView
- private static Type CanViewSecurityDescriptor(Type T)
- {
- var security = T.GetCustomAttribute<EntitySecurityAttribute>();
- return security?.CanView ?? CreateAutoDescriptor(typeof(CanView<>), T);
- }
- private static Type CanViewSecurityDescriptor<T>()
- where T : Entity, new()
- {
- var security = typeof(T).GetCustomAttribute<EntitySecurityAttribute>();
- return security?.CanView ?? typeof(AutoSecurityDescriptor<T, CanView<T>>);
- }
- public static bool CanView<TEntity>(Guid userGuid, Guid securityId) where TEntity : Entity, new()
- {
- return IsAllowed(CanViewSecurityDescriptor<TEntity>(), userGuid, securityId);
- }
- public static bool CanView(Type TEntity)
- {
- return IsAllowed(CanViewSecurityDescriptor(TEntity));
- }
- public static bool CanView<TEntity>() where TEntity : Entity, new()
- {
- return IsAllowed(CanViewSecurityDescriptor<TEntity>());
- }
- #endregion
- #region CanEdit
- private static Type CanEditSecurityDescriptor(Type T)
- {
- var security = T.GetCustomAttribute<EntitySecurityAttribute>();
- return security?.CanEdit ?? CreateAutoDescriptor(typeof(CanEdit<>), T);
- }
- private static Type CanEditSecurityDescriptor<T>()
- where T : Entity, new()
- {
- var security = typeof(T).GetCustomAttribute<EntitySecurityAttribute>();
- return security?.CanEdit ?? typeof(AutoSecurityDescriptor<T, CanEdit<T>>);
- }
- public static bool CanEdit(Type TEntity, Guid userGuid, Guid securityId)
- {
- return IsAllowed(CanEditSecurityDescriptor(TEntity), userGuid, securityId);
- }
- public static bool CanEdit<TEntity>(Guid userGuid, Guid securityId) where TEntity : Entity, new()
- {
- return IsAllowed(CanEditSecurityDescriptor<TEntity>(), userGuid, securityId);
- }
- public static bool CanEdit(Type TEntity)
- {
- return IsAllowed(CanEditSecurityDescriptor(TEntity));
- }
- public static bool CanEdit<TEntity>() where TEntity : Entity, new()
- {
- return IsAllowed(CanEditSecurityDescriptor<TEntity>());
- }
- #endregion
- public static bool CanImport<TEntity>() where TEntity : Entity, new()
- {
- return IsAllowed<AutoSecurityDescriptor<TEntity, CanImport<TEntity>>>();
- }
- public static bool CanExport<TEntity>() where TEntity : Entity, new()
- {
- return IsAllowed<AutoSecurityDescriptor<TEntity, CanExport<TEntity>>>();
- }
- public static bool CanMerge<TEntity>() where TEntity : Entity, new()
- {
- return IsAllowed<AutoSecurityDescriptor<TEntity, CanMerge<TEntity>>>();
- }
- public static bool CanPost<TEntity>() where TEntity : Entity, new()
- {
- return IsAllowed<AutoSecurityDescriptor<TEntity, CanPost<TEntity>>>();
- }
- public static bool CanConfigurePost<TEntity>() where TEntity : Entity, new()
- {
- return IsAllowed<AutoSecurityDescriptor<TEntity, CanConfigurePost<TEntity>>>();
- }
- #region CanDelete
- private static Type CanDeleteSecurityDescriptor(Type T)
- {
- var security = T.GetCustomAttribute<EntitySecurityAttribute>();
- return security?.CanDelete ?? CreateAutoDescriptor(typeof(CanDelete<>), T);
- }
- private static Type CanDeleteSecurityDescriptor<T>()
- where T : Entity, new()
- {
- var security = typeof(T).GetCustomAttribute<EntitySecurityAttribute>();
- return security?.CanDelete ?? typeof(AutoSecurityDescriptor<T, CanDelete<T>>);
- }
- public static bool CanDelete<TEntity>() where TEntity : Entity, new()
- {
- return IsAllowed(CanDeleteSecurityDescriptor<TEntity>());
- }
-
- public static bool CanDelete(Type TEntity)
- {
- return IsAllowed(CanDeleteSecurityDescriptor(TEntity));
- }
- #endregion
- public static bool CanManageIssues(Type TEntity)
- {
- return IsAllowed(typeof(AutoSecurityDescriptor<,>).MakeGenericType(TEntity, typeof(CanManageIssues<>).MakeGenericType(TEntity)));
- }
- public static bool CanManageIssues<TEntity>() where TEntity : Entity, IIssues, new()
- {
- return IsAllowed<AutoSecurityDescriptor<TEntity, CanManageIssues<TEntity>>>();
- }
-
- public static bool CanManageProblems(Type TEntity)
- {
- return IsAllowed(typeof(AutoSecurityDescriptor<,>).MakeGenericType(TEntity, typeof(CanManageProblems<>).MakeGenericType(TEntity)));
- }
- public static bool CanManageProblems<TEntity>() where TEntity : Entity, IProblems, new()
- {
- return IsAllowed<AutoSecurityDescriptor<TEntity, CanManageProblems<TEntity>>>();
- }
- }
- }
|