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