From f1222b4ec6d9e921fae6166db794a2d5f557c6e4 Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Tue, 9 Sep 2025 21:47:34 -0700 Subject: [PATCH] Update key store to validate account and site --- .../pages/account/login/login.component.ts | 2 +- src/Server/Controllers/MAuth.cs | 8 ++--- src/Server/Controllers/RedisController.cs | 24 +++++++++---- src/Server/DTO/AuthenticationDTO.cs | 2 +- src/Server/Entities/Account.cs | 1 + src/Server/Program.cs | 4 --- src/Server/Services/AuthJWT.cs | 34 +++++++++++++++---- 7 files changed, 52 insertions(+), 23 deletions(-) diff --git a/src/Client/src/app/pages/account/login/login.component.ts b/src/Client/src/app/pages/account/login/login.component.ts index d898e3f..ffd0baf 100644 --- a/src/Client/src/app/pages/account/login/login.component.ts +++ b/src/Client/src/app/pages/account/login/login.component.ts @@ -43,7 +43,7 @@ export class LoginComponent { } this.errorMsgs.push("Waiting for response from server"); - this.http.post( "api/auth/login", { "UserName": this.UserName, "Password": this.Password, "StayLoggedIn": this.StayLoggedIn, "SameSite": (this.returnURL == '/') }, { responseType: 'text' } ).subscribe({ + this.http.post( "api/auth/login", { "UserName": this.UserName, "Password": this.Password, "StayLoggedIn": this.StayLoggedIn, "Site": this.returnURL }, { responseType: 'text' } ).subscribe({ next: data => { this.errorMsgs = [ "Login Token: " + data ]; window.location.href = this.returnURL + "?LoginToken=" + data; diff --git a/src/Server/Controllers/MAuth.cs b/src/Server/Controllers/MAuth.cs index a01b499..baff5cd 100644 --- a/src/Server/Controllers/MAuth.cs +++ b/src/Server/Controllers/MAuth.cs @@ -52,14 +52,14 @@ namespace Auth.Controllers { test.CurrentPasswordAttempts = 0; await _databaseService.SetAccount(test); - if (request.SameSite) { - SignIn(Response, AuthJWT.GenereateJWTToken(test, request.StayLoggedIn)); + if (request.Site == "/") { + SignIn(Response, AuthJWT.GenereateJWTToken(test, request.Site, request.StayLoggedIn)); } else { string Ticket = Guid.NewGuid().ToString().Replace("-", ""); - string JWT = AuthJWT.GenereateJWTToken(test, request.StayLoggedIn); + string JWT = AuthJWT.GenereateJWTToken(test, request.Site, request.StayLoggedIn); AuthJWT.LoginSessions[Ticket] = new JWTMemCache { JWT = JWT, - ExpiresAt = DateTime.UtcNow.AddSeconds(30) + ExpiresAt = DateTime.UtcNow.AddSeconds(20) }; return Ok(Ticket); diff --git a/src/Server/Controllers/RedisController.cs b/src/Server/Controllers/RedisController.cs index 41c0488..25f6a75 100644 --- a/src/Server/Controllers/RedisController.cs +++ b/src/Server/Controllers/RedisController.cs @@ -2,6 +2,8 @@ using Microsoft.AspNetCore.Mvc; using System.Web.Http; using StackExchange.Redis; using Auth.Services.DatabaseService; +using Auth.Services; +using Auth.Entities; namespace Auth.Controllers { [ApiController] @@ -18,16 +20,26 @@ namespace Auth.Controllers { [Route("get")] [HttpGet] - public async Task> Get(string key) { - RedisValue result = await _redisdb.StringGetAsync(key); - return Ok(result.ToString()); + public async Task> Get(string JWT, string key) { + Account? account = AuthJWT.ValidateJWTToken(JWT); + if (account != null) { + RedisValue result = await _redisdb.StringGetAsync( account.Site + key); + return Ok(result.ToString()); + } else { + return BadRequest("JWT Not Valid"); + } } [Route("set")] [HttpGet] - public async Task Set(string key, string value) { - await _redisdb.StringSetAsync(key, value); - return Ok(); + public async Task Set(string JWT, string key, string value) { + Account? account = AuthJWT.ValidateJWTToken(JWT); + if (account != null) { + await _redisdb.StringSetAsync(account.Site + key, value); + return Ok(); + } else { + return BadRequest("JWT Not Valid"); + } } } diff --git a/src/Server/DTO/AuthenticationDTO.cs b/src/Server/DTO/AuthenticationDTO.cs index 6fab651..34621dd 100644 --- a/src/Server/DTO/AuthenticationDTO.cs +++ b/src/Server/DTO/AuthenticationDTO.cs @@ -3,8 +3,8 @@ namespace Auth.DTO { public class LoginRequest { public string UserName { get; set; } = ""; public string Password { get; set; } = ""; + public string Site { get; set; } = ""; public bool StayLoggedIn { get; set; } - public bool SameSite { get; set; } } public class JWTRenewRequest { diff --git a/src/Server/Entities/Account.cs b/src/Server/Entities/Account.cs index b56f9a3..4b246d9 100644 --- a/src/Server/Entities/Account.cs +++ b/src/Server/Entities/Account.cs @@ -14,5 +14,6 @@ namespace Auth.Entities { public string PasswordToken { get; set; } = ""; public DateTime PasswordTokenCreated { get; set; } public string DataServer { get; set; } = ""; + public string Site { get; set; } = ""; } } \ No newline at end of file diff --git a/src/Server/Program.cs b/src/Server/Program.cs index fb0e24f..062a0b9 100755 --- a/src/Server/Program.cs +++ b/src/Server/Program.cs @@ -1,10 +1,6 @@ using Auth.Services; using Auth.Services.DatabaseService; -using System.Security.Claims; using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.IdentityModel.Tokens; -using System.IdentityModel.Tokens.Jwt; -using System.Text; var builder = WebApplication.CreateBuilder(args); diff --git a/src/Server/Services/AuthJWT.cs b/src/Server/Services/AuthJWT.cs index d3be245..55e19a1 100644 --- a/src/Server/Services/AuthJWT.cs +++ b/src/Server/Services/AuthJWT.cs @@ -25,7 +25,7 @@ namespace Auth.Services { ClockSkew = TimeSpan.FromMinutes(1) }; - public static string GenereateJWTToken(Account account, bool StayLoggedIn) { + public static string GenereateJWTToken(Account account, string RequestedSite, bool StayLoggedIn) { JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler(); SecurityTokenDescriptor tokenDiscriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity([ @@ -34,6 +34,7 @@ namespace Auth.Services { new Claim(ClaimTypes.Email, account.Email), new Claim(ClaimTypes.Role, account.Role), new Claim(ClaimTypes.UserData, account.DataServer), + new Claim(ClaimTypes.Dns, RequestedSite), new Claim(ClaimTypes.IsPersistent, StayLoggedIn.ToString()), ]), Expires = DateTime.UtcNow.AddDays(7), @@ -47,14 +48,33 @@ namespace Auth.Services { return tokenHandler.WriteToken(token); } + public static Account? ValidateJWTToken(string Token) { + try { + JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler(); + ClaimsPrincipal principal = tokenHandler.ValidateToken( Token, TokenParameters, out SecurityToken validatedToken ); + return new Account { + ID = Convert.ToInt32(principal.FindFirstValue(ClaimTypes.NameIdentifier)), + UserName = principal.FindFirstValue(ClaimTypes.Name)!, + Email = principal.FindFirstValue(ClaimTypes.Email)!, + Role = principal.FindFirstValue(ClaimTypes.Role)!, + DataServer = principal.FindFirstValue(ClaimTypes.UserData)!, + Site = principal.FindFirstValue(ClaimTypes.Dns)! + }; + } catch (Exception) { + return null; + } + } + public static string RenewJWTToken(ClaimsPrincipal principal) { return GenereateJWTToken(new Account { - ID = Convert.ToInt32(principal.FindFirst(ClaimTypes.NameIdentifier)!.Value), - UserName = principal.FindFirst(ClaimTypes.Name)!.Value, - Email = principal.FindFirst(ClaimTypes.Email)!.Value, - Role = principal.FindFirst(ClaimTypes.Role)!.Value, - DataServer = principal.FindFirst(ClaimTypes.UserData)!.Value - }, Convert.ToBoolean(principal.FindFirst(ClaimTypes.IsPersistent)!.Value)); + ID = Convert.ToInt32(principal.FindFirstValue(ClaimTypes.NameIdentifier)), + UserName = principal.FindFirstValue(ClaimTypes.Name)!, + Email = principal.FindFirstValue(ClaimTypes.Email)!, + Role = principal.FindFirstValue(ClaimTypes.Role)!, + DataServer = principal.FindFirstValue(ClaimTypes.UserData)! + }, + principal.FindFirstValue(ClaimTypes.Dns)!, + Convert.ToBoolean(principal.FindFirstValue(ClaimTypes.IsPersistent)!)); } public static RsaSecurityKey LoadRSAKey(string KeyPath) {