Security.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.ComponentModel;
  5. using System.Linq;
  6. using System.Reflection;
  7. using System.Threading.Tasks;
  8. using InABox.Clients;
  9. namespace InABox.Core
  10. {
  11. public static class Security
  12. {
  13. private static ConcurrentBag<ISecurityDescriptor>? _descriptors;
  14. private static GlobalSecurityToken[]? _globaltokens;
  15. private static SecurityToken[]? _grouptokens;
  16. private static UserSecurityToken[]? _usertokens;
  17. public static IEnumerable<ISecurityDescriptor> Descriptors
  18. {
  19. get
  20. {
  21. if (_descriptors == null)
  22. {
  23. _descriptors = new ConcurrentBag<ISecurityDescriptor>();
  24. var custom = Task.Run(() =>
  25. {
  26. var tokens = CoreUtils.TypeList(
  27. AppDomain.CurrentDomain.GetAssemblies(),
  28. x => !x.IsAbstract && !x.IsGenericType &&
  29. x.GetInterfaces().Any(i => i == typeof(ISecurityDescriptor))
  30. );
  31. foreach (var _class in tokens)
  32. {
  33. var token = (Activator.CreateInstance(_class) as ISecurityDescriptor)!;
  34. _descriptors.Add(token);
  35. }
  36. });
  37. var auto = Task.Run(() =>
  38. {
  39. var tokens = CoreUtils.TypeList(
  40. AppDomain.CurrentDomain.GetAssemblies(),
  41. x => !x.IsAbstract && !x.IsGenericType && x.IsSubclassOf(typeof(Entity))
  42. );
  43. var view = Task.Run(() =>
  44. {
  45. foreach (var _class in tokens)
  46. CheckAutoToken(_class, typeof(CanView<>));
  47. });
  48. var edit = Task.Run(() =>
  49. {
  50. foreach (var _class in tokens.Where(x => x.GetCustomAttribute<AutoEntity>() == null))
  51. CheckAutoToken(_class, typeof(CanEdit<>));
  52. });
  53. var delete = Task.Run(() =>
  54. {
  55. foreach (var _class in tokens.Where(x => x.GetCustomAttribute<AutoEntity>() == null))
  56. CheckAutoToken(_class, typeof(CanDelete<>));
  57. });
  58. var issues = Task.Run(() =>
  59. {
  60. foreach (var _class in tokens.Where(x => x.GetInterfaces().Contains(typeof(IIssues))))
  61. CheckAutoToken(_class, typeof(CanManageIssues<>));
  62. });
  63. var exports = Task.Run(() =>
  64. {
  65. foreach (var _class in tokens.Where(x => x.GetInterfaces().Contains(typeof(IExportable))))
  66. CheckAutoToken(_class, typeof(CanExport<>));
  67. });
  68. var imports = Task.Run(() =>
  69. {
  70. foreach (var _class in tokens.Where(x => x.GetInterfaces().Contains(typeof(IImportable))))
  71. CheckAutoToken(_class, typeof(CanImport<>));
  72. });
  73. var merges = Task.Run(() =>
  74. {
  75. foreach (var _class in tokens.Where(x => x.GetInterfaces().Contains(typeof(IMergeable))))
  76. CheckAutoToken(_class, typeof(CanMerge<>));
  77. });
  78. Task.WaitAll(view, edit, delete, issues, exports, merges);
  79. });
  80. Task.WaitAll(custom, auto);
  81. }
  82. return _descriptors.OrderBy(x => x.Type).ThenBy(x => x.Code);
  83. }
  84. }
  85. public static void Reset()
  86. {
  87. _globaltokens = null;
  88. _grouptokens = null;
  89. _usertokens = null;
  90. _descriptors = null;
  91. }
  92. public static void CheckTokens()
  93. {
  94. var tasks = new Task[] {
  95. Task.Run(() =>
  96. {
  97. _usertokens ??= new Client<UserSecurityToken>().Load(
  98. new Filter<UserSecurityToken>(x => x.User.ID).IsEqualTo(ClientFactory.UserGuid)
  99. );
  100. }),
  101. Task.Run(() =>
  102. {
  103. _grouptokens ??= new Client<SecurityToken>().Load(
  104. new Filter<SecurityToken>(x => x.Group.ID).IsEqualTo(ClientFactory.UserSecurityID));
  105. }),
  106. Task.Run(() =>
  107. {
  108. _globaltokens ??= new Client<GlobalSecurityToken>().Load();
  109. }),
  110. };
  111. Task.WaitAll(tasks);
  112. }
  113. private static void CheckAutoToken(Type _class, Type type)
  114. {
  115. var basetype = typeof(AutoSecurityDescriptor<,>);
  116. var actiontype = type.MakeGenericType(_class);
  117. var descriptortype = basetype.MakeGenericType(_class, actiontype);
  118. var descriptor = (Activator.CreateInstance(descriptortype) as ISecurityDescriptor)!;
  119. if (!_descriptors.Any(x => string.Equals(x.Code, descriptor.Code)))
  120. _descriptors.Add(descriptor);
  121. }
  122. public static bool IsAllowed(Type T, Guid userGuid, Guid securityId)
  123. {
  124. var descriptor = (Activator.CreateInstance(T) as ISecurityDescriptor)!;
  125. try
  126. {
  127. // If you're not logged in, you can't do jack!
  128. if (userGuid == Guid.Empty)
  129. return false;
  130. CheckTokens();
  131. // First Check for a matching User Token (override)
  132. var usertoken = _usertokens.FirstOrDefault(x => x.Descriptor.Equals(descriptor.Code));
  133. if (usertoken != null)
  134. return usertoken.Enabled;
  135. // If not found, fall back to the Group Token
  136. var grouptoken = _grouptokens.FirstOrDefault(x => x.Descriptor.Equals(descriptor.Code));
  137. if (grouptoken != null)
  138. return grouptoken.Enabled;
  139. // Still not found? fall back to the Global Token
  140. var globaltoken = _globaltokens.FirstOrDefault(x => x.Descriptor.Equals(descriptor.Code));
  141. if (globaltoken != null)
  142. return globaltoken.Enabled;
  143. }
  144. catch (Exception e)
  145. {
  146. Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
  147. }
  148. // Aaand finally, just return the default for the descriptor
  149. return descriptor.Value;
  150. }
  151. public static bool IsAllowed<T>(Guid userGuid, Guid securityId) where T : ISecurityDescriptor, new()
  152. => IsAllowed(typeof(T), userGuid, securityId);
  153. public static bool IsAllowed<T>() where T : ISecurityDescriptor, new()
  154. => IsAllowed<T>(ClientFactory.UserGuid, ClientFactory.UserSecurityID);
  155. public static bool IsAllowed(Type T)
  156. => IsAllowed(T, ClientFactory.UserGuid, ClientFactory.UserSecurityID);
  157. public static bool CanView<TEntity>(Guid userGuid, Guid securityId) where TEntity : Entity, new()
  158. {
  159. return ClientFactory.IsSupported<TEntity>()
  160. && IsAllowed<AutoSecurityDescriptor<TEntity, CanView<TEntity>>>(userGuid, securityId);
  161. }
  162. public static bool CanView(Type TEntity)
  163. {
  164. return ClientFactory.IsSupported(TEntity) &&
  165. IsAllowed(typeof(AutoSecurityDescriptor<,>).MakeGenericType(TEntity, typeof(CanView<>).MakeGenericType(TEntity)));
  166. }
  167. public static bool CanView<TEntity>() where TEntity : Entity, new()
  168. {
  169. return ClientFactory.IsSupported<TEntity>() && IsAllowed<AutoSecurityDescriptor<TEntity, CanView<TEntity>>>();
  170. }
  171. public static bool CanEdit(Type TEntity, Guid userGuid, Guid securityId)
  172. {
  173. return ClientFactory.IsSupported(TEntity) &&
  174. IsAllowed(typeof(AutoSecurityDescriptor<,>).MakeGenericType(TEntity, typeof(CanEdit<>).MakeGenericType(TEntity)), userGuid, securityId);
  175. }
  176. public static bool CanEdit<TEntity>(Guid userGuid, Guid securityId) where TEntity : Entity, new()
  177. {
  178. return ClientFactory.IsSupported<TEntity>() && IsAllowed<AutoSecurityDescriptor<TEntity, CanEdit<TEntity>>>(userGuid, securityId);
  179. }
  180. public static bool CanEdit(Type TEntity)
  181. {
  182. return ClientFactory.IsSupported(TEntity) &&
  183. IsAllowed(typeof(AutoSecurityDescriptor<,>).MakeGenericType(TEntity, typeof(CanEdit<>).MakeGenericType(TEntity)));
  184. }
  185. public static bool CanEdit<TEntity>() where TEntity : Entity, new()
  186. {
  187. return ClientFactory.IsSupported<TEntity>() && IsAllowed<AutoSecurityDescriptor<TEntity, CanEdit<TEntity>>>();
  188. }
  189. public static bool CanImport<TEntity>() where TEntity : Entity, new()
  190. {
  191. return ClientFactory.IsSupported<TEntity>() && IsAllowed<AutoSecurityDescriptor<TEntity, CanImport<TEntity>>>();
  192. }
  193. public static bool CanExport<TEntity>() where TEntity : Entity, new()
  194. {
  195. return ClientFactory.IsSupported<TEntity>() && IsAllowed<AutoSecurityDescriptor<TEntity, CanExport<TEntity>>>();
  196. }
  197. public static bool CanMerge<TEntity>() where TEntity : Entity, new()
  198. {
  199. return ClientFactory.IsSupported<TEntity>() && IsAllowed<AutoSecurityDescriptor<TEntity, CanMerge<TEntity>>>();
  200. }
  201. public static bool CanDelete<TEntity>() where TEntity : Entity, new()
  202. {
  203. return ClientFactory.IsSupported<TEntity>() && IsAllowed<AutoSecurityDescriptor<TEntity, CanDelete<TEntity>>>();
  204. }
  205. public static bool CanManageIssues<TEntity>() where TEntity : Entity, IIssues, new()
  206. {
  207. return ClientFactory.IsSupported<TEntity>() && IsAllowed<AutoSecurityDescriptor<TEntity, CanManageIssues<TEntity>>>();
  208. }
  209. }
  210. }