Security.cs 11 KB

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