From 333cf66cb4c7c872abdfdf36520439026126e6ad Mon Sep 17 00:00:00 2001 From: max Date: Sun, 18 May 2025 22:36:12 +0200 Subject: [PATCH] [WIP] --- .../AuthorityLoginAuthenticationHandler.cs | 81 ++++++++++++++++++- .../Managers/AuthorityUserManager.cs | 16 ++++ TestWebApi/Program.cs | 1 + TestWebApi/TestWebApi.csproj | 4 + 4 files changed, 99 insertions(+), 3 deletions(-) diff --git a/DotBased.AspNet.Authority/Handlers/AuthorityLoginAuthenticationHandler.cs b/DotBased.AspNet.Authority/Handlers/AuthorityLoginAuthenticationHandler.cs index 8923473..8818041 100644 --- a/DotBased.AspNet.Authority/Handlers/AuthorityLoginAuthenticationHandler.cs +++ b/DotBased.AspNet.Authority/Handlers/AuthorityLoginAuthenticationHandler.cs @@ -1,3 +1,5 @@ +using System.Buffers.Text; +using System.Net.Http.Headers; using System.Security.Claims; using System.Text.Encodings.Web; using DotBased.AspNet.Authority.Managers; @@ -5,6 +7,7 @@ using DotBased.AspNet.Authority.Models.Options.Auth; using Microsoft.AspNetCore.Authentication; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Microsoft.Extensions.Primitives; namespace DotBased.AspNet.Authority.Handlers; @@ -19,9 +22,81 @@ public class AuthorityLoginAuthenticationHandler(IOptionsMonitor HandleAuthenticateAsync() { - //TODO: Check headers for login credentials. - /*var ticket = new AuthenticationTicket(new ClaimsPrincipal(), Scheme.Name);*/ - var result = AuthenticateResult.Fail("No login found!"); + var authResult = GetBasicAuthorization(out var email, out var password); + if (authResult != null || string.IsNullOrEmpty(email) || string.IsNullOrEmpty(password)) + { + return AuthenticateResult.Fail(authResult ?? "Failed to get basic authorization from header."); + } + + var userResult = await manager.GetUserByEmailAsync(email); + if (userResult is { IsSuccess: false, Error: not null }) + { + return AuthenticateResult.Fail(userResult.Error.Description); + } + var user = userResult.Value; + + var passwordValidateResult = await manager.ValidatePasswordAsync(user, password); + if (!passwordValidateResult.IsSuccess) + { + return AuthenticateResult.Fail(passwordValidateResult.Error?.Description ?? "Failed to validate password."); + } + + var identityClaims = new List(); + var rolesResult = await manager.GetAllUserRolesAsync(user); + if (rolesResult.IsSuccess) + { + var roles = rolesResult.Value; + foreach (var authorityRole in roles) + { + identityClaims.Add(new Claim(ClaimTypes.Role, authorityRole.Name)); + } + } + + var principal = new ClaimsPrincipal(new ClaimsIdentity(identityClaims, Scheme.Name)); + var ticket = new AuthenticationTicket(principal, Scheme.Name); + var result = AuthenticateResult.Success(ticket); return result; } + + private string? GetBasicAuthorization(out string? email, out string? password) + { + email = null; + password = null; + + if (StringValues.IsNullOrEmpty(Context.Request.Headers.Authorization)) + { + return "Missing authorization header"; + } + + var basicAuth = string.Empty; + foreach (var authorizationValue in Context.Request.Headers.Authorization) + { + if (string.IsNullOrWhiteSpace(authorizationValue)) + { + continue; + } + + if (AuthenticationHeaderValue.TryParse(authorizationValue, out var basicAuthHeader) && !string.IsNullOrWhiteSpace(basicAuthHeader.Parameter)) + { + basicAuth = basicAuthHeader.Parameter; + } + } + + if (!Base64.IsValid(basicAuth)) + { + return "Invalid basic authorization data!"; + } + + var base64Auth = Convert.FromBase64String(basicAuth); + var decodedAuth = System.Text.Encoding.UTF8.GetString(base64Auth); + var parts = decodedAuth.Split(':'); + if (parts.Length != 2) + { + return "No email and/or password found!"; + } + + email = parts[0]; + password = parts[1]; + return null; + } } \ No newline at end of file diff --git a/DotBased.AspNet.Authority/Managers/AuthorityUserManager.cs b/DotBased.AspNet.Authority/Managers/AuthorityUserManager.cs index abc3b4e..19db9a9 100755 --- a/DotBased.AspNet.Authority/Managers/AuthorityUserManager.cs +++ b/DotBased.AspNet.Authority/Managers/AuthorityUserManager.cs @@ -36,6 +36,22 @@ public partial class AuthorityManager return errors.Count > 0 ? ValidationResult.Fail(errors) : ValidationResult.Success(); } + public async Task> GetUserByEmailAsync(string email) + { + if (string.IsNullOrEmpty(email)) + { + return ResultError.Fail("No email given."); + } + + var user = await userRepository.GetUserByEmailAsync(email); + if (user == null) + { + return ResultError.Fail("No user found with given email."); + } + + return user; + } + public async Task>> SearchUsersAsync(string query, int maxResults = 20, int offset = 0, CancellationToken cancellationToken = default) { var result = await UserRepository.GetUsersAsync(maxResults, offset, query, cancellationToken); diff --git a/TestWebApi/Program.cs b/TestWebApi/Program.cs index 02aab28..029d901 100755 --- a/TestWebApi/Program.cs +++ b/TestWebApi/Program.cs @@ -34,6 +34,7 @@ builder.Services.AddAuthority() .AddAuthorityAuth(options => { options.DefaultScheme = AuthorityDefaults.Scheme.Authority.AuthenticationScheme; + options.DefaultAuthenticateScheme = AuthorityDefaults.Scheme.Authority.AuthenticationScheme; options.DefaultSignInScheme = AuthorityDefaults.Scheme.Cookie.AuthenticationScheme; options.DefaultSignOutScheme = AuthorityDefaults.Scheme.Cookie.AuthenticationScheme; options.SchemeInfoMap = [ diff --git a/TestWebApi/TestWebApi.csproj b/TestWebApi/TestWebApi.csproj index 673fe48..8cf2412 100755 --- a/TestWebApi/TestWebApi.csproj +++ b/TestWebApi/TestWebApi.csproj @@ -25,4 +25,8 @@ + + + +