diff options
| -rw-r--r-- | HBContext.cs | 14 | ||||
| -rw-r--r-- | LocalPrincipal.cs | 49 | ||||
| -rw-r--r-- | Principal.cs | 13 | ||||
| -rw-r--r-- | PrincipalProviders/LocalPrincipalProvider.cs | 49 | ||||
| -rw-r--r-- | Services/PrincipalProvider.cs | 22 | ||||
| -rw-r--r-- | Services/SecurityService.cs | 14 |
6 files changed, 135 insertions, 26 deletions
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> OcrData { get; set; } // Security-related tables - public DbSet<HBPrincipal> Principals { get; set; } - public DbSet<User> Users { get; set; } - public DbSet<Group> Groups { get; set; } - public DbSet<Acl> Acls { get; set; } - public DbSet<AclRule> AclRules { get; set; } + public DbSet<LocalPrincipal> Principals { get; set; } + public DbSet<LocalUser> Users { get; set; } + public DbSet<LocalGroup> Groups { get; set; } + public DbSet<Acl> Acls { get; set; } + public DbSet<AclRule> AclRules { get; set; } private IConfigService config; @@ -50,7 +50,7 @@ public class HBContext : DbContext { modelBuilder.Entity<Tag>().ToTable("Tags"); modelBuilder.Entity<Media>().ToTable("Media"); modelBuilder.Entity<UploadedFile>().ToTable("UploadedFiles"); - modelBuilder.Entity<HBPrincipal>().ToTable("SecurityPrincipals"); + modelBuilder.Entity<Principal>().ToTable("SecurityPrincipals"); // Seed internal tag definitions // These should NEVER change @@ -70,7 +70,7 @@ public class HBContext : DbContext { }); // Seed initial admin user - modelBuilder.Entity<User>().HasData(new User[] { + modelBuilder.Entity<LocalUser>().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<LocalGroup> 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<Group> 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<HBContext> dbFactory; + + public LocalPrincipalProvider(IDbContextFactory<HBContext> 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<HBContext> dbFactory; - private MemoryCache<SidStruct, HBPrincipal> principalCache; - private MemoryCache<int, Acl> aclCache; + private MemoryCache<SidStruct, Principal> principalCache; + private MemoryCache<int, Acl> aclCache; public SecurityService(IDbContextFactory<HBContext> dbFactory) { this.dbFactory = dbFactory; @@ -39,7 +39,7 @@ public class SecurityService { public IEnumerable<HBObject> Filter( IEnumerable<HBObject> objects, - HBPrincipal principal, + Principal principal, ulong permissions) { foreach(var obj in objects) { @@ -51,7 +51,7 @@ public class SecurityService { public IEnumerable<HBObject> Filter<T>( IEnumerable<HBObject> objects, - HBPrincipal principal, + Principal principal, T permissions) where T : Enum => Filter(objects, principal, permissions); @@ -62,14 +62,14 @@ public class SecurityService { /// <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) { + private ulong GetPermissions(Acl? acl, Principal principal) { if(acl is null) return ulong.MaxValue; ulong permissions = 0; var principals = GetGroupMemberShip(principal) - .Cast<HBPrincipal>() + .Cast<Principal>() .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. /// </summary> - private List<Group> GetGroupMemberShip(HBPrincipal principal) { + private List<Group> GetGroupMemberShip(Principal principal) { var groups = principal.MemberOf.ToList(); while(true) { |
