76 lines
2.8 KiB
C#
76 lines
2.8 KiB
C#
using LanguageExt.Common;
|
|
using MediatR;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Suspectus.Gandalf.Core.Abstractions.CQRS;
|
|
using Suspectus.Gandalf.Core.Abstractions.Extensions;
|
|
using Suspectus.Gandalf.Palantir.Api.Commands;
|
|
using Suspectus.Gandalf.Palantir.Api.Handlers.Commands;
|
|
using Suspectus.Gandalf.Palantir.Data.Database;
|
|
using Suspectus.Gandalf.Palantir.Data.Dto;
|
|
|
|
namespace Suspectus.Gandalf.Palantir.Api.Handlers.Security;
|
|
|
|
public class PasswordHashingHandler(ApplicationContext applicationContext, IMediator mediator, IPasswordHasher<object> passwordHasher) : ICommandHandler<HashPasswordCommand, string>, ICommandHandler<VerifyPasswordCommand, bool>
|
|
{
|
|
private static readonly object MicrosoftIsAMeme = new();
|
|
|
|
public Task<Result<string>> Handle(HashPasswordCommand command, CancellationToken cancellationToken)
|
|
{
|
|
try
|
|
{
|
|
var hash = passwordHasher.HashPassword(MicrosoftIsAMeme, command.RawPassword);
|
|
return Task.FromResult(hash.AsResult());
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return Task.FromResult("Something went wrong while hashing password.".AsErrorResult<string>());
|
|
}
|
|
|
|
}
|
|
|
|
public async Task<Result<bool>> Handle(VerifyPasswordCommand request, CancellationToken cancellationToken)
|
|
{
|
|
var signIn = await applicationContext.SignIns.SingleOrDefaultAsync(x => x.Id == request.SignInId, cancellationToken: cancellationToken);
|
|
|
|
if (signIn is null)
|
|
{
|
|
return "Sign-in method not found.".AsErrorResult<bool>();
|
|
}
|
|
|
|
if (signIn.PasswordHash is null)
|
|
{
|
|
return "Sign-in method does not have a password hash.".AsErrorResult<bool>();
|
|
}
|
|
|
|
var verification = passwordHasher.VerifyHashedPassword(MicrosoftIsAMeme, signIn.PasswordHash, request.RawPassword);
|
|
|
|
switch (verification)
|
|
{
|
|
case PasswordVerificationResult.Failed:
|
|
return false;
|
|
|
|
case PasswordVerificationResult.Success:
|
|
return true;
|
|
|
|
case PasswordVerificationResult.SuccessRehashNeeded:
|
|
var newHashResult = await mediator.Send(new HashPasswordCommand { RawPassword = request.RawPassword }, cancellationToken);
|
|
|
|
if (newHashResult.IsFaulted)
|
|
{
|
|
return newHashResult.AsErrorResult<bool, string>();
|
|
}
|
|
|
|
var newHash = newHashResult.GetValue();
|
|
|
|
signIn.PasswordHash = newHash;
|
|
|
|
await applicationContext.SaveChangesAsync(cancellationToken);
|
|
|
|
return true;
|
|
|
|
default:
|
|
return $"Password verification type not supported: {verification}".AsErrorResult<bool>();
|
|
}
|
|
}
|
|
} |