diff options
| author | Jake Mannens <jake@asger.xyz> | 2023-09-27 03:38:58 +1000 |
|---|---|---|
| committer | Jake Mannens <jake@asger.xyz> | 2023-09-27 03:38:58 +1000 |
| commit | bc82b2dc2f7405c0fd4d179830412ea8209137b1 (patch) | |
| tree | 26fdaa8635a1487e3ae9fd112336be8df0f723ec /Services/SecurityService.cs | |
| parent | 39eead0052215d7be4f49906e987fef7fb0c700b (diff) | |
Added MemoryCache class and implemented principal/ACL cache in the security service
Diffstat (limited to 'Services/SecurityService.cs')
| -rw-r--r-- | Services/SecurityService.cs | 61 |
1 files changed, 42 insertions, 19 deletions
diff --git a/Services/SecurityService.cs b/Services/SecurityService.cs index 6e5ecb8..f0ebd70 100644 --- a/Services/SecurityService.cs +++ b/Services/SecurityService.cs @@ -1,5 +1,5 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Caching.Memory; +using HyperBooru.Util; +using Microsoft.EntityFrameworkCore; using System.Data; namespace HyperBooru.Services; @@ -7,25 +7,34 @@ namespace HyperBooru.Services; public class SecurityService { private IDbContextFactory<HBContext> dbFactory; - private Group[] groups; - private Acl[] acls; + private MemoryCache<int, HBPrincipal> principalCache; + private MemoryCache<int, Acl> aclCache; public SecurityService(IDbContextFactory<HBContext> dbFactory) { this.dbFactory = dbFactory; - Reload(); - } - - public void Reload() { - using var db = dbFactory.CreateDbContext(); - groups = db.Groups - .Include(g => g.MemberOf) - .ToArray(); + // TODO: preload the principal cache + principalCache = new() { + MaxItems = 10_000, + MaxAge = TimeSpan.FromMinutes(10), + DataSource = (int id) => { + using var db = dbFactory.CreateDbContext(); + return db.Principals + .Include(p => p.MemberOf) + .FirstOrDefault(p => p.ObjectId == id); + } + }; - acls = db.Acls - .Include(a => a.Rules) - .ThenInclude(r => r.Principal) - .ToArray(); + aclCache = new() { + MaxItems = 1000, + MaxAge = TimeSpan.FromMinutes(10), + DataSource = (int id) => { + using var db = dbFactory.CreateDbContext(); + return db.Acls + .Include(a => a.Rules) + .FirstOrDefault(a => a.ObjectId == id); + } + }; } public IEnumerable<HBObject> Filter( @@ -46,6 +55,13 @@ public class SecurityService { T permissions) where T : Enum => Filter(objects, principal, permissions); + /// <summary> + /// Resolve the specified ACL and return a bitmask representing + /// all the permissions the specified principal has. + /// </summary> + /// <param name="acl"> + /// ACL to resolve (returns a bitmask consisting of all 1's if this field is null) + /// </param> private ulong GetPermissions(Acl? acl, HBPrincipal principal) { if(acl is null) return ulong.MaxValue; @@ -75,18 +91,25 @@ public class SecurityService { return permissions; } + /// <summary> + /// Recursively get all groups of which the specified principal + /// is a member, including implicit memberships. + /// </summary> private List<Group> GetGroupMemberShip(HBPrincipal principal) { var groups = principal.MemberOf.ToList(); while(true) { - var toAdd = this.groups - .Where(g => !groups.Contains(g)) + var toAdd = groups + .SelectMany(g => g.MemberOf) + .Select(g => g.ObjectId) + .Where(id => !groups.Select(g => g.ObjectId).Contains(id)) .ToArray(); if(toAdd.Count() == 0) break; - groups.AddRange(toAdd); + foreach(var id in toAdd) + groups.Add((Group) principalCache[id]); } return groups; |
