From 76e4bf609c3d196bd20619188a317fca66f4a04a Mon Sep 17 00:00:00 2001 From: Jake Mannens Date: Fri, 29 Sep 2023 05:01:45 +1000 Subject: Separated Principal and LocalPrincipal types --- HBContext.cs | 14 ++++---- LocalPrincipal.cs | 49 ++++++++++++++++++++++++++++ Principal.cs | 13 +++----- PrincipalProviders/LocalPrincipalProvider.cs | 49 ++++++++++++++++++++++++++++ Services/PrincipalProvider.cs | 22 ++++++++++--- Services/SecurityService.cs | 14 ++++---- 6 files changed, 135 insertions(+), 26 deletions(-) create mode 100644 LocalPrincipal.cs create mode 100644 PrincipalProviders/LocalPrincipalProvider.cs diff --git a/HBContext.cs b/HBContext.cs index 2bb477e..2d44bc5 100644 --- a/HBContext.cs +++ b/HBContext.cs @@ -24,11 +24,11 @@ public class HBContext : DbContext { public DbSet OcrData { get; set; } // Security-related tables - public DbSet Principals { get; set; } - public DbSet Users { get; set; } - public DbSet Groups { get; set; } - public DbSet Acls { get; set; } - public DbSet AclRules { get; set; } + public DbSet Principals { get; set; } + public DbSet Users { get; set; } + public DbSet Groups { get; set; } + public DbSet Acls { get; set; } + public DbSet AclRules { get; set; } private IConfigService config; @@ -50,7 +50,7 @@ public class HBContext : DbContext { modelBuilder.Entity().ToTable("Tags"); modelBuilder.Entity().ToTable("Media"); modelBuilder.Entity().ToTable("UploadedFiles"); - modelBuilder.Entity().ToTable("SecurityPrincipals"); + modelBuilder.Entity().ToTable("SecurityPrincipals"); // Seed internal tag definitions // These should NEVER change @@ -70,7 +70,7 @@ public class HBContext : DbContext { }); // Seed initial admin user - modelBuilder.Entity().HasData(new User[] { + modelBuilder.Entity().HasData(new LocalUser[] { new() { ObjectId = (int) HBObjectId.AdminUser, Guid = HBObjectGuid.AdminUser, diff --git a/LocalPrincipal.cs b/LocalPrincipal.cs new file mode 100644 index 0000000..28a2721 --- /dev/null +++ b/LocalPrincipal.cs @@ -0,0 +1,49 @@ +namespace HyperBooru; + +public class LocalPrincipal : HBObject { + public string Name { get; set; } + public SecurityIdentifier Sid { get; set; } + public List MemberOf { get; set; } + + public static implicit operator Principal(LocalPrincipal principal) => + new() { + Name = principal.Name, + Sid = principal.Sid, + }; + + public static implicit operator LocalPrincipal(Principal principal) => + new() { + Name = principal.Name, + Sid = principal.Sid + }; +} + +public class LocalUser : LocalPrincipal { + public string PasswordHash { get; set; } + + public static implicit operator User(LocalUser user) => + new() { + Name = user.Name, + Sid = user.Sid, + }; + + public static implicit operator LocalUser(User user) => + new() { + Name = user.Name, + Sid = user.Sid + }; +} + +public class LocalGroup : LocalPrincipal { + public static implicit operator Group(LocalGroup group) => + new() { + Name = group.Name, + Sid = group.Sid, + }; + + public static implicit operator LocalGroup(Group group) => + new() { + Name = group.Name, + Sid = group.Sid + }; +} diff --git a/Principal.cs b/Principal.cs index 553fbec..677f926 100644 --- a/Principal.cs +++ b/Principal.cs @@ -4,14 +4,11 @@ using System.Security.Principal; namespace HyperBooru; [Index(nameof(Name))] -public class HBPrincipal : HBObject { - public string Name { get; set; } - public SecurityIdentifier Sid { get; set; } - public List MemberOf { get; set; } +public class Principal { + public string Name { get; set; } + public SecurityIdentifier Sid { get; set; } } -public class User : HBPrincipal { - public string PasswordHash { get; set; } -} +public class User : Principal {} -public class Group : HBPrincipal {} \ No newline at end of file +public class Group : Principal {} \ No newline at end of file diff --git a/PrincipalProviders/LocalPrincipalProvider.cs b/PrincipalProviders/LocalPrincipalProvider.cs new file mode 100644 index 0000000..7bee800 --- /dev/null +++ b/PrincipalProviders/LocalPrincipalProvider.cs @@ -0,0 +1,49 @@ +using HyperBooru.Services; +using Microsoft.EntityFrameworkCore; + +namespace HyperBooru.PrincipalProviders; + +public class LocalPrincipalProvider : PrincipalProvider { + private IDbContextFactory dbFactory; + + public LocalPrincipalProvider(IDbContextFactory dbFactory) => + this.dbFactory = dbFactory; + + public override Principal? GetPrincipal(string name) { + using var db = dbFactory.CreateDbContext(); + + LocalPrincipal? principal = db.Principals.FirstOrDefault(p => p.Name == name); + if(principal is null) + return null; + + return principal; + } + + public override User? GetUser(string name) { + using var db = dbFactory.CreateDbContext(); + + LocalUser? user = db.Users.FirstOrDefault(p => p.Name == name); + if(user is null) + return null; + + return user; + } + + public override Group? GetGroup(string name) { + using var db = dbFactory.CreateDbContext(); + + LocalGroup? group = db.Groups.FirstOrDefault(p => p.Name == name); + if(group is null) + return null; + + return group; + } + + public override Group[] GetGroups(Principal principal, bool recurse) { + throw new NotImplementedException(); + } + + public override bool ValidatePassword(User principal, string password) { + throw new NotImplementedException(); + } +} diff --git a/Services/PrincipalProvider.cs b/Services/PrincipalProvider.cs index e75c6c7..6991c64 100644 --- a/Services/PrincipalProvider.cs +++ b/Services/PrincipalProvider.cs @@ -1,9 +1,23 @@ namespace HyperBooru.Services; -public abstract class PrincipalProvider { - public abstract bool ValidatePassword(HBPrincipal principal, string password); +public interface IPrincipalProvider { + public Principal? GetPrincipal(string name); + public User? GetUser(string name); + public Group? GetGroup(string name); - public abstract HBPrincipal GetPrincipal(string username); + public Group[] GetGroups(Principal principal); + public Group[] GetGroups(Principal principal, bool recurse); - public abstract Group[] GetAllGroups(HBPrincipal principal); + public bool ValidatePassword(User user, string password); +} + +public abstract class PrincipalProvider : IPrincipalProvider { + public abstract Principal? GetPrincipal(string name); + public abstract User? GetUser(string name); + public abstract Group? GetGroup(string name); + + public Group[] GetGroups(Principal principal) => GetGroups(principal, false); + public abstract Group[] GetGroups(Principal principal, bool recurse); + + public abstract bool ValidatePassword(User user, string password); } diff --git a/Services/SecurityService.cs b/Services/SecurityService.cs index f1444c1..8c97c7b 100644 --- a/Services/SecurityService.cs +++ b/Services/SecurityService.cs @@ -7,8 +7,8 @@ namespace HyperBooru.Services; public class SecurityService { private IDbContextFactory dbFactory; - private MemoryCache principalCache; - private MemoryCache aclCache; + private MemoryCache principalCache; + private MemoryCache aclCache; public SecurityService(IDbContextFactory dbFactory) { this.dbFactory = dbFactory; @@ -39,7 +39,7 @@ public class SecurityService { public IEnumerable Filter( IEnumerable objects, - HBPrincipal principal, + Principal principal, ulong permissions) { foreach(var obj in objects) { @@ -51,7 +51,7 @@ public class SecurityService { public IEnumerable Filter( IEnumerable objects, - HBPrincipal principal, + Principal principal, T permissions) where T : Enum => Filter(objects, principal, permissions); @@ -62,14 +62,14 @@ public class SecurityService { /// /// ACL to resolve (returns a bitmask consisting of all 1's if this field is null) /// - private ulong GetPermissions(Acl? acl, HBPrincipal principal) { + private ulong GetPermissions(Acl? acl, Principal principal) { if(acl is null) return ulong.MaxValue; ulong permissions = 0; var principals = GetGroupMemberShip(principal) - .Cast() + .Cast() .Concat(new[] { principal }) .Select(p => p.Sid) .ToArray(); @@ -96,7 +96,7 @@ public class SecurityService { /// Recursively get all groups of which the specified principal /// is a member, including implicit memberships. /// - private List GetGroupMemberShip(HBPrincipal principal) { + private List GetGroupMemberShip(Principal principal) { var groups = principal.MemberOf.ToList(); while(true) { -- cgit v1.3