Security.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  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. var posts = Task.Run(() =>
  79. {
  80. foreach (var _class in tokens.Where(x => x.GetInterfaces().Contains(typeof(IPostable))))
  81. CheckAutoToken(_class, typeof(CanPost<>));
  82. });
  83. var configPosts = Task.Run(() =>
  84. {
  85. foreach (var _class in tokens.Where(x => x.GetInterfaces().Contains(typeof(IPostable))))
  86. CheckAutoToken(_class, typeof(CanConfigurePost<>));
  87. });
  88. Task.WaitAll(view, edit, delete, issues, exports, merges, posts, configPosts);
  89. });
  90. Task.WaitAll(custom, auto);
  91. }
  92. return _descriptors.OrderBy(x => x.Type).ThenBy(x => x.Code);
  93. }
  94. }
  95. public static void Reset()
  96. {
  97. _globaltokens = null;
  98. _grouptokens = null;
  99. _usertokens = null;
  100. _descriptors = null;
  101. }
  102. public static void CheckTokens()
  103. {
  104. _usertokens ??= Client.Query(
  105. new Filter<UserSecurityToken>(x => x.User.ID).IsEqualTo(ClientFactory.UserGuid),
  106. Columns.None<UserSecurityToken>().Add(x => x.Descriptor).Add(x => x.Enabled)
  107. ).ToArray<UserSecurityToken>();
  108. _grouptokens ??= Client.Query(
  109. new Filter<SecurityToken>(x => x.Group.ID).IsEqualTo(ClientFactory.UserSecurityID),
  110. Columns.None<SecurityToken>().Add(x => x.Descriptor).Add(x => x.Enabled)
  111. ).ToArray<SecurityToken>();
  112. _globaltokens ??= Client.Query(
  113. null,
  114. Columns.None<GlobalSecurityToken>().Add(x => x.Descriptor).Add(x => x.Enabled))
  115. .ToArray<GlobalSecurityToken>();
  116. }
  117. private static void CheckAutoToken(Type _class, Type type)
  118. {
  119. var basetype = typeof(AutoSecurityDescriptor<,>);
  120. var actiontype = type.MakeGenericType(_class);
  121. var descriptortype = basetype.MakeGenericType(_class, actiontype);
  122. var descriptor = (Activator.CreateInstance(descriptortype) as ISecurityDescriptor)!;
  123. if (!_descriptors.Any(x => string.Equals(x.Code, descriptor.Code)))
  124. _descriptors.Add(descriptor);
  125. }
  126. public static bool IsAllowed(Type T, Guid userGuid, Guid securityId)
  127. {
  128. var descriptor = (Activator.CreateInstance(T) as ISecurityDescriptor)!;
  129. try
  130. {
  131. // If you're not logged in, you can't do jack!
  132. if (userGuid == Guid.Empty)
  133. return false;
  134. CheckTokens();
  135. // First Check for a matching User Token (override)
  136. var usertoken = _usertokens.FirstOrDefault(x => x.Descriptor.Equals(descriptor.Code));
  137. if (usertoken != null)
  138. return usertoken.Enabled;
  139. // If not found, fall back to the Group Token
  140. var grouptoken = _grouptokens.FirstOrDefault(x => x.Descriptor.Equals(descriptor.Code));
  141. if (grouptoken != null)
  142. return grouptoken.Enabled;
  143. // Still not found? fall back to the Global Token
  144. var globaltoken = _globaltokens.FirstOrDefault(x => x.Descriptor.Equals(descriptor.Code));
  145. if (globaltoken != null)
  146. return globaltoken.Enabled;
  147. }
  148. catch (Exception e)
  149. {
  150. Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
  151. }
  152. // Aaand finally, just return the default for the descriptor
  153. return descriptor.Value;
  154. }
  155. public static bool IsAllowed<T>(Guid userGuid, Guid securityId) where T : ISecurityDescriptor, new()
  156. => IsAllowed(typeof(T), userGuid, securityId);
  157. public static bool IsAllowed<T>() where T : ISecurityDescriptor, new()
  158. => IsAllowed<T>(ClientFactory.UserGuid, ClientFactory.UserSecurityID);
  159. public static bool IsAllowed(Type T)
  160. => IsAllowed(T, ClientFactory.UserGuid, ClientFactory.UserSecurityID);
  161. public static bool CanView<TEntity>(Guid userGuid, Guid securityId) where TEntity : Entity, new()
  162. {
  163. return ClientFactory.IsSupported<TEntity>()
  164. && IsAllowed<AutoSecurityDescriptor<TEntity, CanView<TEntity>>>(userGuid, securityId);
  165. }
  166. public static bool CanView(Type TEntity)
  167. {
  168. return ClientFactory.IsSupported(TEntity) &&
  169. IsAllowed(typeof(AutoSecurityDescriptor<,>).MakeGenericType(TEntity, typeof(CanView<>).MakeGenericType(TEntity)));
  170. }
  171. public static bool CanView<TEntity>() where TEntity : Entity, new()
  172. {
  173. return ClientFactory.IsSupported<TEntity>() && IsAllowed<AutoSecurityDescriptor<TEntity, CanView<TEntity>>>();
  174. }
  175. public static bool CanEdit(Type TEntity, Guid userGuid, Guid securityId)
  176. {
  177. return ClientFactory.IsSupported(TEntity) &&
  178. IsAllowed(typeof(AutoSecurityDescriptor<,>).MakeGenericType(TEntity, typeof(CanEdit<>).MakeGenericType(TEntity)), userGuid, securityId);
  179. }
  180. public static bool CanEdit<TEntity>(Guid userGuid, Guid securityId) where TEntity : Entity, new()
  181. {
  182. return ClientFactory.IsSupported<TEntity>() && IsAllowed<AutoSecurityDescriptor<TEntity, CanEdit<TEntity>>>(userGuid, securityId);
  183. }
  184. public static bool CanEdit(Type TEntity)
  185. {
  186. return ClientFactory.IsSupported(TEntity) &&
  187. IsAllowed(typeof(AutoSecurityDescriptor<,>).MakeGenericType(TEntity, typeof(CanEdit<>).MakeGenericType(TEntity)));
  188. }
  189. public static bool CanEdit<TEntity>() where TEntity : Entity, new()
  190. {
  191. return ClientFactory.IsSupported<TEntity>() && IsAllowed<AutoSecurityDescriptor<TEntity, CanEdit<TEntity>>>();
  192. }
  193. public static bool CanImport<TEntity>() where TEntity : Entity, new()
  194. {
  195. return ClientFactory.IsSupported<TEntity>() && IsAllowed<AutoSecurityDescriptor<TEntity, CanImport<TEntity>>>();
  196. }
  197. public static bool CanExport<TEntity>() where TEntity : Entity, new()
  198. {
  199. return ClientFactory.IsSupported<TEntity>() && IsAllowed<AutoSecurityDescriptor<TEntity, CanExport<TEntity>>>();
  200. }
  201. public static bool CanMerge<TEntity>() where TEntity : Entity, new()
  202. {
  203. return ClientFactory.IsSupported<TEntity>() && IsAllowed<AutoSecurityDescriptor<TEntity, CanMerge<TEntity>>>();
  204. }
  205. public static bool CanPost<TEntity>() where TEntity : Entity, new()
  206. {
  207. return ClientFactory.IsSupported<TEntity>() && IsAllowed<AutoSecurityDescriptor<TEntity, CanPost<TEntity>>>();
  208. }
  209. public static bool CanConfigurePost<TEntity>() where TEntity : Entity, new()
  210. {
  211. return ClientFactory.IsSupported<TEntity>() && IsAllowed<AutoSecurityDescriptor<TEntity, CanConfigurePost<TEntity>>>();
  212. }
  213. public static bool CanDelete<TEntity>() where TEntity : Entity, new()
  214. {
  215. return ClientFactory.IsSupported<TEntity>() && IsAllowed<AutoSecurityDescriptor<TEntity, CanDelete<TEntity>>>();
  216. }
  217. public static bool CanManageIssues(Type TEntity)
  218. {
  219. return ClientFactory.IsSupported(TEntity)
  220. && IsAllowed(typeof(AutoSecurityDescriptor<,>).MakeGenericType(TEntity, typeof(CanManageIssues<>).MakeGenericType(TEntity)));
  221. }
  222. public static bool CanManageIssues<TEntity>() where TEntity : Entity, IIssues, new()
  223. {
  224. return ClientFactory.IsSupported<TEntity>() && IsAllowed<AutoSecurityDescriptor<TEntity, CanManageIssues<TEntity>>>();
  225. }
  226. }
  227. }