summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJake Mannens <jake@asger.xyz>2023-09-29 17:46:47 +1000
committerJake Mannens <jake@asger.xyz>2023-09-29 17:57:21 +1000
commite0cf80a5d0e2d6898b611892a331aa917b9370d9 (patch)
tree75809891d57e687a246233f52feead273a1eca7d
parentc5ff0b57a12b605a5ae5ae8a92ce7a4e8eaec77a (diff)
Finalised security service
-rw-r--r--Controllers/LoginController.cs16
-rw-r--r--PrincipalProviders/LocalPrincipalProvider.cs4
-rw-r--r--Program.cs7
-rw-r--r--Services/PrincipalProvider.cs12
-rw-r--r--Services/SecurityService.cs29
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)
diff --git a/Program.cs b/Program.cs
index e78f0d4..5cc7839 100644
--- a/Program.cs
+++ b/Program.cs
@@ -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);