diff options
| author | Jake Mannens <jake@asger.xyz> | 2023-09-29 17:46:47 +1000 |
|---|---|---|
| committer | Jake Mannens <jake@asger.xyz> | 2023-09-29 17:57:21 +1000 |
| commit | e0cf80a5d0e2d6898b611892a331aa917b9370d9 (patch) | |
| tree | 75809891d57e687a246233f52feead273a1eca7d | |
| parent | c5ff0b57a12b605a5ae5ae8a92ce7a4e8eaec77a (diff) | |
Finalised security service
| -rw-r--r-- | Controllers/LoginController.cs | 16 | ||||
| -rw-r--r-- | PrincipalProviders/LocalPrincipalProvider.cs | 4 | ||||
| -rw-r--r-- | Program.cs | 7 | ||||
| -rw-r--r-- | Services/PrincipalProvider.cs | 12 | ||||
| -rw-r--r-- | Services/SecurityService.cs | 29 |
5 files changed, 48 insertions, 20 deletions
diff --git a/Controllers/LoginController.cs b/Controllers/LoginController.cs index bb31fe2..364bc5e 100644 --- a/Controllers/LoginController.cs +++ b/Controllers/LoginController.cs @@ -11,8 +11,15 @@ namespace HyperBooru.Controllers; [Route("/")] public class LoginController : Controller { private IHttpContextAccessor httpContextAccessor; - public LoginController(IHttpContextAccessor httpContextAccessor) => + private IPrincipalProvider principalProvider; + + public LoginController( + IHttpContextAccessor httpContextAccessor, + IPrincipalProvider principalProvider) { + this.httpContextAccessor = httpContextAccessor; + this.principalProvider = principalProvider; + } [HttpPost("Login")] public async Task<IActionResult> Login( @@ -20,17 +27,16 @@ public class LoginController : Controller { [FromForm] string password, HBContext db) { - var user = db.Users.FirstOrDefault(u => u.Name == username); + var user = principalProvider.GetUser(username); if(user is null) return StatusCode(403); - var hash = UserService.HashPassword(password); - if(hash != user.PasswordHash) + if(!principalProvider.ValidatePassword(user, password)) return StatusCode(403); var claims = new Claim[] { new Claim(ClaimTypes.Name, user.Name), - new Claim("ObjectId", user.ObjectId.ToString()) + new Claim("SID", user.Sid.ToString()) }; var claimsIdentity = new ClaimsIdentity( diff --git a/PrincipalProviders/LocalPrincipalProvider.cs b/PrincipalProviders/LocalPrincipalProvider.cs index 8035ce8..d480633 100644 --- a/PrincipalProviders/LocalPrincipalProvider.cs +++ b/PrincipalProviders/LocalPrincipalProvider.cs @@ -25,11 +25,11 @@ public class LocalPrincipalProvider : PrincipalProvider { return db.Groups.FirstOrDefault(p => p.Name == name); } - public override IGroup[] GetGroups(IPrincipal principal, bool recurse) { + public override IGroup[] GetGroups(SecurityIdentifier sid, bool recurse) { using var db = dbFactory.CreateDbContext(); List<LocalGroup> groups = db.Principals - .First(p => p.Sid == principal.Sid) + .First(p => p.Sid == sid) .MemberOf; if(!recurse) @@ -1,7 +1,8 @@ -using Microsoft.EntityFrameworkCore; -using System.Text.Json.Serialization; +using HyperBooru.PrincipalProviders; using HyperBooru.Services; using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.EntityFrameworkCore; +using System.Text.Json.Serialization; namespace HyperBooru; @@ -21,6 +22,8 @@ public class Program { // Add our custom services builder.Services.AddSingleton<IConfigService, ConfigService>(); builder.Services.AddDbContextFactory<HBContext>(); + builder.Services.AddSingleton<IPrincipalProvider, LocalPrincipalProvider>(); + builder.Services.AddSingleton<ISecurityService, SecurityService>(); builder.Services.AddScoped<ISearchService, SearchService>(); builder.Services.AddScoped<ITagService, TagService>(); builder.Services.AddScoped<IMediaService, MediaService>(); diff --git a/Services/PrincipalProvider.cs b/Services/PrincipalProvider.cs index 0c35007..d37e8c0 100644 --- a/Services/PrincipalProvider.cs +++ b/Services/PrincipalProvider.cs @@ -8,6 +8,9 @@ public interface IPrincipalProvider { public IGroup[] GetGroups(IPrincipal principal); public IGroup[] GetGroups(IPrincipal principal, bool recurse); + public IGroup[] GetGroups(SecurityIdentifier sid); + public IGroup[] GetGroups(SecurityIdentifier sid, bool recurse); + public bool ValidatePassword(IUser user, string password); } @@ -16,8 +19,13 @@ public abstract class PrincipalProvider : IPrincipalProvider { public abstract IUser? GetUser(string name); public abstract IGroup? GetGroup(string name); - public IGroup[] GetGroups(IPrincipal principal) => GetGroups(principal, false); - public abstract IGroup[] GetGroups(IPrincipal principal, bool recurse); + public IGroup[] GetGroups(IPrincipal principal) => + GetGroups(principal.Sid, false); + public IGroup[] GetGroups(IPrincipal principal, bool recurse) => + GetGroups(principal.Sid, recurse); + + public IGroup[] GetGroups(SecurityIdentifier sid) => GetGroups(sid, false); + public abstract IGroup[] GetGroups(SecurityIdentifier sid, bool recurse); public abstract bool ValidatePassword(IUser user, string password); } diff --git a/Services/SecurityService.cs b/Services/SecurityService.cs index 48f2d3e..e365266 100644 --- a/Services/SecurityService.cs +++ b/Services/SecurityService.cs @@ -4,7 +4,19 @@ using System.Data; namespace HyperBooru.Services; -public class SecurityService { +public interface ISecurityService { + public IEnumerable<HBObject> Filter( + IEnumerable<HBObject> objects, + IPrincipal principal, + ulong permissions); + + public IEnumerable<HBObject> Filter<T>( + IEnumerable<HBObject> objects, + IPrincipal principal, + T permissions) where T : Enum; +} + +public class SecurityService : ISecurityService { private IDbContextFactory<HBContext> dbFactory; private MemoryCache<SidStruct, IGroup[]> membershipCache; @@ -21,10 +33,10 @@ public class SecurityService { // TODO: preload the principal cache membershipCache = new() { - MaxItems = 1000, - MaxAge = TimeSpan.FromMinutes(10), - DataSource = (SidStruct sid) => { - } + MaxItems = 1000, + MaxAge = TimeSpan.FromMinutes(10), + DataSource = (SidStruct sid) => + principalProvider.GetGroups(new SecurityIdentifier(sid), true) }; aclCache = new() { @@ -70,10 +82,9 @@ public class SecurityService { ulong permissions = 0; - var principals = GetGroupMemberShip(principal) - .Cast<IPrincipal>() - .Concat(new[] { principal }) - .Select(p => p.Sid) + var principals = membershipCache[principal.Sid.SidStruct] + .Select(g => g.Sid) + .Concat(new[] { principal.Sid }) .ToArray(); var allowRules = acl.Rules.Where(r => r.Action == AclRuleAction.Allow); |
