From 2b9ddef0551b0dbb1cb4acd7ad5dce3ddbbee7d2 Mon Sep 17 00:00:00 2001 From: Mateusz Skoczek Date: Tue, 13 Jan 2026 02:47:34 +0100 Subject: [PATCH] PasswordHasher added --- .../API/Endpoints.cs | 11 +++--- .../Validators/RegisterRequestValidator.cs | 2 +- .../Commands/Register/RegisterCommand.cs | 2 +- .../Commands/Register/RegisterData.cs | 2 +- .../Commands/Register/RegisterHandler.cs | 10 +++-- .../Commands/Register/RegisterMappers.cs | 5 +-- .../Application/Helpers/IPasswordHasher.cs | 2 +- .../Application/Helpers/PasswordHashData.cs | 3 +- .../Application/Helpers/PasswordHasher.cs | 39 +++++++++++++++++-- .../Program.cs | 10 ++++- ...ner.Backend.Services.Authentication.csproj | 5 +-- 11 files changed, 66 insertions(+), 25 deletions(-) diff --git a/TimetableDesigner.Backend.Services.Authentication/API/Endpoints.cs b/TimetableDesigner.Backend.Services.Authentication/API/Endpoints.cs index 22b1607..9051499 100644 --- a/TimetableDesigner.Backend.Services.Authentication/API/Endpoints.cs +++ b/TimetableDesigner.Backend.Services.Authentication/API/Endpoints.cs @@ -19,18 +19,19 @@ public static class Endpoints return app; } - public static async Task, ProblemHttpResult>> Register(RegisterCommand command, IMediator mediator) + public static async Task, InternalServerError>> Register(RegisterRequest request, CancellationToken cancellationToken, IMediator mediator) { - await mediator.Send(command); - return Results.Created($"accounts/0", null); + RegisterCommand registerCommand = request.ToCommand(); + RegisterData data = await mediator.Send(registerCommand, cancellationToken); + return Results.Created($"accounts/0", null); } - public static async Task, ProblemHttpResult>> AuthenticatePassword(AuthenticatePasswordRequest request) + public static async Task, ProblemHttpResult>> AuthenticatePassword(AuthenticatePasswordRequest request, CancellationToken cancellationToken) { return null; } - public static async Task, ProblemHttpResult>> AuthenticateToken(AuthenticateTokenRequest request) + public static async Task, ProblemHttpResult>> AuthenticateToken(AuthenticateTokenRequest request, CancellationToken cancellationToken) { return null; } diff --git a/TimetableDesigner.Backend.Services.Authentication/API/Validators/RegisterRequestValidator.cs b/TimetableDesigner.Backend.Services.Authentication/API/Validators/RegisterRequestValidator.cs index 3091c72..0f07425 100644 --- a/TimetableDesigner.Backend.Services.Authentication/API/Validators/RegisterRequestValidator.cs +++ b/TimetableDesigner.Backend.Services.Authentication/API/Validators/RegisterRequestValidator.cs @@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore; using TimetableDesigner.Backend.Services.Authentication.Database; using TimetableDesigner.Backend.Services.Authentication.DTO.API; -namespace TimetableDesigner.Backend.Services.Authentication.DTO.Validators; +namespace TimetableDesigner.Backend.Services.Authentication.API.Validators; public class RegisterRequestValidator : AbstractValidator { diff --git a/TimetableDesigner.Backend.Services.Authentication/Application/Commands/Register/RegisterCommand.cs b/TimetableDesigner.Backend.Services.Authentication/Application/Commands/Register/RegisterCommand.cs index 21ce121..c6e47c5 100644 --- a/TimetableDesigner.Backend.Services.Authentication/Application/Commands/Register/RegisterCommand.cs +++ b/TimetableDesigner.Backend.Services.Authentication/Application/Commands/Register/RegisterCommand.cs @@ -2,4 +2,4 @@ namespace TimetableDesigner.Backend.Services.Authentication.Application.Commands.Register; -public record RegisterCommand(string Email, string Password) : IRequest; \ No newline at end of file +public record RegisterCommand(string Email, string Password) : IRequest; \ No newline at end of file diff --git a/TimetableDesigner.Backend.Services.Authentication/Application/Commands/Register/RegisterData.cs b/TimetableDesigner.Backend.Services.Authentication/Application/Commands/Register/RegisterData.cs index 5762b64..6afa321 100644 --- a/TimetableDesigner.Backend.Services.Authentication/Application/Commands/Register/RegisterData.cs +++ b/TimetableDesigner.Backend.Services.Authentication/Application/Commands/Register/RegisterData.cs @@ -1,6 +1,6 @@ namespace TimetableDesigner.Backend.Services.Authentication.Application.Commands.Register; -public class RegisterDto +public class RegisterData { } \ No newline at end of file diff --git a/TimetableDesigner.Backend.Services.Authentication/Application/Commands/Register/RegisterHandler.cs b/TimetableDesigner.Backend.Services.Authentication/Application/Commands/Register/RegisterHandler.cs index 49fbff7..30fe67d 100644 --- a/TimetableDesigner.Backend.Services.Authentication/Application/Commands/Register/RegisterHandler.cs +++ b/TimetableDesigner.Backend.Services.Authentication/Application/Commands/Register/RegisterHandler.cs @@ -1,19 +1,23 @@ using MediatR; +using TimetableDesigner.Backend.Services.Authentication.Application.Helpers; using TimetableDesigner.Backend.Services.Authentication.Database; namespace TimetableDesigner.Backend.Services.Authentication.Application.Commands.Register; -public class RegisterHandler : IRequestHandler +public class RegisterHandler : IRequestHandler { private readonly DatabaseContext _databaseContext; + private readonly IPasswordHasher _passwordHasher; - public RegisterHandler(DatabaseContext databaseContext) + public RegisterHandler(DatabaseContext databaseContext, IPasswordHasher passwordHasher) { _databaseContext = databaseContext; + _passwordHasher = passwordHasher; } - public async Task Handle(RegisterCommand command, CancellationToken cancellationToken) + public async Task Handle(RegisterCommand command, CancellationToken cancellationToken) { + PasswordHashData hash = _passwordHasher.CreateHash(command.Password); } } \ No newline at end of file diff --git a/TimetableDesigner.Backend.Services.Authentication/Application/Commands/Register/RegisterMappers.cs b/TimetableDesigner.Backend.Services.Authentication/Application/Commands/Register/RegisterMappers.cs index 3317d95..8d0b018 100644 --- a/TimetableDesigner.Backend.Services.Authentication/Application/Commands/Register/RegisterMappers.cs +++ b/TimetableDesigner.Backend.Services.Authentication/Application/Commands/Register/RegisterMappers.cs @@ -1,7 +1,6 @@ -using TimetableDesigner.Backend.Services.Authentication.Application.Commands.Register; -using TimetableDesigner.Backend.Services.Authentication.DTO.API; +using TimetableDesigner.Backend.Services.Authentication.DTO.API; -namespace TimetableDesigner.Backend.Services.Authentication.DTO.Mappers; +namespace TimetableDesigner.Backend.Services.Authentication.Application.Commands.Register; public static class RegisterMappers { diff --git a/TimetableDesigner.Backend.Services.Authentication/Application/Helpers/IPasswordHasher.cs b/TimetableDesigner.Backend.Services.Authentication/Application/Helpers/IPasswordHasher.cs index 36e1119..4c9ecd0 100644 --- a/TimetableDesigner.Backend.Services.Authentication/Application/Helpers/IPasswordHasher.cs +++ b/TimetableDesigner.Backend.Services.Authentication/Application/Helpers/IPasswordHasher.cs @@ -3,5 +3,5 @@ public interface IPasswordHasher { PasswordHashData CreateHash(string password); - byte[] ComputeHash(string password, string salt); + bool ValidatePassword(PasswordHashData hash, string password); } \ No newline at end of file diff --git a/TimetableDesigner.Backend.Services.Authentication/Application/Helpers/PasswordHashData.cs b/TimetableDesigner.Backend.Services.Authentication/Application/Helpers/PasswordHashData.cs index cb01f57..fb97d35 100644 --- a/TimetableDesigner.Backend.Services.Authentication/Application/Helpers/PasswordHashData.cs +++ b/TimetableDesigner.Backend.Services.Authentication/Application/Helpers/PasswordHashData.cs @@ -2,6 +2,5 @@ public record PasswordHashData( byte[] Hash, - string LeftSalt, - string RightSalt + string Salt ); \ No newline at end of file diff --git a/TimetableDesigner.Backend.Services.Authentication/Application/Helpers/PasswordHasher.cs b/TimetableDesigner.Backend.Services.Authentication/Application/Helpers/PasswordHasher.cs index 96f7d5c..2bebfc2 100644 --- a/TimetableDesigner.Backend.Services.Authentication/Application/Helpers/PasswordHasher.cs +++ b/TimetableDesigner.Backend.Services.Authentication/Application/Helpers/PasswordHasher.cs @@ -1,6 +1,39 @@ -namespace TimetableDesigner.Backend.Services.Authentication.Application.Helpers; +using System.Security.Cryptography; +using System.Text; +using Konscious.Security.Cryptography; -public class PasswordHasher +namespace TimetableDesigner.Backend.Services.Authentication.Application.Helpers; + +public class PasswordHasher : IPasswordHasher { - + private const string RandomPasswordCharacters = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890!@#$%^&*()-_=+[{]};:'\"\\|,<.>/?"; + + public PasswordHashData CreateHash(string password) + { + string salt = RandomNumberGenerator.GetString(RandomPasswordCharacters, 20); + byte[] hash = ComputeHash(password, salt); + PasswordHashData data = new PasswordHashData(hash, salt); + return data; + } + + public bool ValidatePassword(PasswordHashData hash, string password) + { + byte[] actualHash = hash.Hash; + byte[] checkedHash = ComputeHash(password, hash.Salt); + bool checkResult = checkedHash.SequenceEqual(actualHash); + return checkResult; + } + + protected byte[] ComputeHash(string password, string salt) + { + Argon2id hashFunction = new Argon2id(Encoding.UTF8.GetBytes(password)) + { + Salt = Encoding.UTF8.GetBytes(salt), + DegreeOfParallelism = 8, + MemorySize = 65536, + Iterations = 4 + }; + byte[] hash = hashFunction.GetBytes(32); + return hash; + } } \ No newline at end of file diff --git a/TimetableDesigner.Backend.Services.Authentication/Program.cs b/TimetableDesigner.Backend.Services.Authentication/Program.cs index 16b0d31..132ed8f 100644 --- a/TimetableDesigner.Backend.Services.Authentication/Program.cs +++ b/TimetableDesigner.Backend.Services.Authentication/Program.cs @@ -3,8 +3,9 @@ using FluentValidation; using Microsoft.AspNetCore.Identity.Data; using Microsoft.EntityFrameworkCore; using TimetableDesigner.Backend.Services.Authentication.API; +using TimetableDesigner.Backend.Services.Authentication.API.Validators; +using TimetableDesigner.Backend.Services.Authentication.Application.Helpers; using TimetableDesigner.Backend.Services.Authentication.Database; -using TimetableDesigner.Backend.Services.Authentication.DTO.Validators; namespace TimetableDesigner.Backend.Services.Authentication; @@ -16,6 +17,7 @@ public static class Program .SetupOpenApi() .SetupSecurity() .SetupDatabase() + .SetupHelpers() .SetupValidation() .SetupMediatR() .Build(); @@ -46,6 +48,12 @@ public static class Program builder.Services.AddDbContext(x => x.UseNpgsql(builder.Configuration.GetConnectionString("Database")), ServiceLifetime.Transient); return builder; } + + private static WebApplicationBuilder SetupHelpers(this WebApplicationBuilder builder) + { + builder.Services.AddSingleton(); + return builder; + } private static WebApplicationBuilder SetupValidation(this WebApplicationBuilder builder) { diff --git a/TimetableDesigner.Backend.Services.Authentication/TimetableDesigner.Backend.Services.Authentication.csproj b/TimetableDesigner.Backend.Services.Authentication/TimetableDesigner.Backend.Services.Authentication.csproj index 37d6399..2df7f22 100644 --- a/TimetableDesigner.Backend.Services.Authentication/TimetableDesigner.Backend.Services.Authentication.csproj +++ b/TimetableDesigner.Backend.Services.Authentication/TimetableDesigner.Backend.Services.Authentication.csproj @@ -10,6 +10,7 @@ + @@ -19,10 +20,6 @@ - - - -