From 834fcbbbcdd73c1cbe91e5d13f5aadbc21d6e729 Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Thu, 24 Jul 2025 17:37:16 -0700 Subject: [PATCH] Start OAuth required endpoints --- database/mistox.sql | 1 + src/Server/Controllers/OAuth.cs | 36 +++++++++++++++++++ src/Server/Entities/Account.cs | 1 + src/Server/Entities/AuthorizationRequest.cs | 29 +++++++++++++++ src/Server/Entities/TokenRequest.cs | 28 +++++++++++++++ .../Services/DatabaseService/Account.cs | 14 ++++++-- 6 files changed, 107 insertions(+), 2 deletions(-) create mode 100755 src/Server/Controllers/OAuth.cs create mode 100644 src/Server/Entities/AuthorizationRequest.cs create mode 100644 src/Server/Entities/TokenRequest.cs diff --git a/database/mistox.sql b/database/mistox.sql index 274e50b..08ba404 100755 --- a/database/mistox.sql +++ b/database/mistox.sql @@ -9,6 +9,7 @@ CREATE TABLE IF NOT EXISTS `Account` ( `Email` varchar(255) NOT NULL, `EmailVerified` boolean DEFAULT 0, `PasswordHash` char(60) DEFAULT NULL, + `LoginToken` binary(16) DEFAULT NULL, `FailedPasswordLock` boolean DEFAULT 0, `PasswordAttempts` int(11) DEFAULT NULL, `CurrentPasswordAttempts` int(11) DEFAULT NULL, diff --git a/src/Server/Controllers/OAuth.cs b/src/Server/Controllers/OAuth.cs new file mode 100755 index 0000000..7a7d289 --- /dev/null +++ b/src/Server/Controllers/OAuth.cs @@ -0,0 +1,36 @@ +using Microsoft.AspNetCore.Mvc; +using Auth.Services.DatabaseService; +using System.Web.Http; +using Auth.Entities; + +namespace Auth.Controllers { + [ApiController] + [Route("api/oauth/")] + public class OAuthController : MistoxControllerBase { + + public OAuthController(DatabaseService db) : base(db) {} + + [HttpGet("/authorize")] + public async Task Authorize([FromQuery] AuthorizationRequest request) { + try { + + return NotFound("User is not logged in"); + } catch (Exception ex) { + Console.WriteLine("Delete Error: " + ex.Message); + return NotFound("An internal server error has occured"); + } + } + + [HttpGet("/token")] + public async Task Token([FromForm] TokenRequest request) { + try { + + return NotFound("User is not logged in"); + } catch (Exception ex) { + Console.WriteLine("Delete Error: " + ex.Message); + return NotFound("An internal server error has occured"); + } + } + + } +} diff --git a/src/Server/Entities/Account.cs b/src/Server/Entities/Account.cs index a59a3d6..d2b431e 100644 --- a/src/Server/Entities/Account.cs +++ b/src/Server/Entities/Account.cs @@ -5,6 +5,7 @@ namespace Auth.Entities { public string Email { get; set; } = ""; public bool EmailVerified { get; set; } = false; public string PasswordHash { get; set; } = ""; + public Guid LoginToken { get; set; } = new Guid(); public bool FailedPasswordLock { get; set; } = false; public int PasswordAttempts { get; set; } = 5; public int CurrentPasswordAttempts { get; set; } = 0; diff --git a/src/Server/Entities/AuthorizationRequest.cs b/src/Server/Entities/AuthorizationRequest.cs new file mode 100644 index 0000000..d68163f --- /dev/null +++ b/src/Server/Entities/AuthorizationRequest.cs @@ -0,0 +1,29 @@ +using System.ComponentModel.DataAnnotations; +using Microsoft.AspNetCore.Mvc; + +namespace Auth.Entities { + public class AuthorizationRequest { + [Required] + [FromQuery(Name = "response_type")] + public required string ResponseType { get; set; } + + [Required] + [FromQuery(Name = "client_id")] + public required string ClientId { get; set; } + + [FromQuery(Name = "redirect_uri")] + public string RedirectUri { get; set; } = ""; + + [FromQuery(Name = "scope")] + public string Scope { get; set; } = ""; + + [FromQuery(Name = "state")] + public string State { get; set; } = ""; + + [FromQuery(Name = "code_challenge")] + public string CodeChallenge { get; set; } = ""; + + [FromQuery(Name = "code_challenge_method")] + public string CodeChallengeMethod { get; set; } = ""; + } +} \ No newline at end of file diff --git a/src/Server/Entities/TokenRequest.cs b/src/Server/Entities/TokenRequest.cs new file mode 100644 index 0000000..b0e7842 --- /dev/null +++ b/src/Server/Entities/TokenRequest.cs @@ -0,0 +1,28 @@ +using System.ComponentModel.DataAnnotations; +using Microsoft.AspNetCore.Mvc; + +namespace Auth.Entities { + public class TokenRequest { + [Required] + [FromForm(Name = "grant_type")] + public required string GrantType { get; set; } = ""; + + [FromForm(Name = "code")] + public string Code { get; set; } = ""; + + [FromForm(Name = "redirect_uri")] + public string RedirectUri { get; set; } = ""; + + [FromForm(Name = "client_id")] + public string ClientId { get; set; } = ""; + + [FromForm(Name = "client_secret")] + public string ClientSecret { get; set; } = ""; + + [FromForm(Name = "code_verifier")] + public string CodeVerifier { get; set; } = ""; + + [FromForm(Name = "refresh_token")] + public string RefreshToken { get; set; } = ""; + } +} \ No newline at end of file diff --git a/src/Server/Services/DatabaseService/Account.cs b/src/Server/Services/DatabaseService/Account.cs index ca8ae93..5196c1b 100755 --- a/src/Server/Services/DatabaseService/Account.cs +++ b/src/Server/Services/DatabaseService/Account.cs @@ -34,12 +34,16 @@ namespace Auth.Services.DatabaseService { string _emailtoken = reader.GetString( "EmailToken" ); string _dataserver = reader.GetString( "DataServer" ); + byte[] _loginToken = new byte[16]; + reader.GetBytes( reader.GetOrdinal("LoginToken"), 0, _loginToken, 0, 16); + account = new Account() { ID = _id, UserName = _username, Email = _email, EmailVerified = _emailVerified, PasswordHash = _passwordhash, + LoginToken = new Guid(_loginToken), CurrentPasswordAttempts = _curpasswordattempts, PasswordAttempts = _passwordattempts, EmailToken = _emailtoken, @@ -83,12 +87,16 @@ namespace Auth.Services.DatabaseService { string _emailtoken = reader.GetString( "EmailToken" ); string _dataserver = reader.GetString("DataServer"); + byte[] _loginToken = new byte[16]; + reader.GetBytes( reader.GetOrdinal("LoginToken"), 0, _loginToken, 0, 16); + account = new Account() { ID = _id, UserName = _username, Email = _email, EmailVerified = _emailVerified, PasswordHash = _passwordhash, + LoginToken = new Guid(_loginToken), CurrentPasswordAttempts = _passwordattempts, PasswordAttempts = _passwordattempts, EmailToken = _emailtoken, @@ -108,14 +116,15 @@ namespace Auth.Services.DatabaseService { string command = @" INSERT INTO Account - (ID,UserName,Email,EmailVerified,PasswordHash,FailedPasswordLock,PasswordAttempts,CurrentPasswordAttempts,Role,EmailToken,DataServer) + (ID,UserName,Email,EmailVerified,PasswordHash,LoginToken,FailedPasswordLock,PasswordAttempts,CurrentPasswordAttempts,Role,EmailToken,DataServer) VALUES - (@ID,@UserName,@Email,@EmailVerified,@PasswordHash,@FailedPasswordLock,@PasswordAttempts,@CurrentPasswordAttempts,@Role,@EmailToken,@DataServer) + (@ID,@UserName,@Email,@EmailVerified,@PasswordHash,@LoginToken,@FailedPasswordLock,@PasswordAttempts,@CurrentPasswordAttempts,@Role,@EmailToken,@DataServer) ON DUPLICATE KEY UPDATE UserName = @UserName, Email = @Email, EmailVerified = @EmailVerified, PasswordHash = @PasswordHash, + LoginToken = @LoginToken, FailedPasswordLock = @FailedPasswordLock, PasswordAttempts = @PasswordAttempts, CurrentPasswordAttempts = @CurrentPasswordAttempts, @@ -130,6 +139,7 @@ namespace Auth.Services.DatabaseService { cmd.Parameters.AddWithValue("@Email", Profile.Email); cmd.Parameters.AddWithValue("@EmailVerified", Profile.EmailVerified); cmd.Parameters.AddWithValue("@PasswordHash", Profile.PasswordHash); + cmd.Parameters.AddWithValue("@LoginToken", Profile.LoginToken.ToByteArray()); cmd.Parameters.AddWithValue("@FailedPasswordLock", Profile.FailedPasswordLock); cmd.Parameters.AddWithValue("@PasswordAttempts", Profile.PasswordAttempts); cmd.Parameters.AddWithValue("@CurrentPasswordAttempts", Profile.CurrentPasswordAttempts);