Skip to content

Commit

Permalink
FEAT: Adding new logic to reset password and send email confirmation …
Browse files Browse the repository at this point in the history
…to validate user
  • Loading branch information
fmattioli committed Jul 8, 2024
1 parent 3f0912f commit f974055
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class CreateUserCommandHandler(IUserRepository userRepository) : IRequest

public async Task<Result> Handle(CreateUserCommand request, CancellationToken cancellationToken)
{
var resultUserCreated = await _userRepository.DoNewUserCreationActions(request. AddUserRequest.Tenant!, request.AddUserRequest.ToDomain());
var resultUserCreated = await _userRepository.CreateNewUserActions(request. AddUserRequest.Tenant!, request.AddUserRequest.ToDomain());
if (resultUserCreated.IsSuccess)
{
return Result.Success();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public static class UserMapper
public static User ToDomain(this AddUserRequest userRequest)
{
var attributes = userRequest.Attributes!.ToDomain(userRequest.Tenant!);
return new User(userRequest.Username!, userRequest.Email!, userRequest.FirstName!, userRequest.LastName!, attributes);
return new User(userRequest.Username!, userRequest.Password, userRequest.Email!, userRequest.FirstName!, userRequest.LastName!, attributes);
}

public static Attributes ToDomain(this AttributesRequest attributes, string tenant)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace TokenManager.Application.Services.Requests.User
{
public record AddUserRequest(string? Username, string? Email, string? FirstName, string? LastName, AttributesRequest? Attributes)
public record AddUserRequest(string Username, string Password, string Email, string FirstName, string LastName, AttributesRequest? Attributes)
{
[JsonIgnore]
public string? Tenant { get; set; }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
namespace TokenManager.Domain.Entities
using Newtonsoft.Json;

namespace TokenManager.Domain.Entities
{
public class User
{
[JsonIgnore]
public string Password { get; set; } = null!;
public string? Id { get; set; }
public bool Enabled { get; set; }
public bool EmailVerified { get; set; }
public string? Username { get; set; } = null!;
public string? Email { get; set; }
public string? Password { get; set; }
public string? Email { get; set; }
public string? FirstName { get; set; }
public string? LastName { get; set; }
public bool Totp { get; set; }
Expand All @@ -29,11 +32,12 @@ public User(string userName, string password)
Password = password;
}

public User(string userName, string email, string firstName, string lastName, Attributes attributes)
public User(string userName, string password, string email, string firstName, string lastName, Attributes attributes)
{
Enabled = true;
EmailVerified = false;
EmailVerified = true;
Email = email;
Password = password;
FirstName = firstName;
Username = userName;
LastName = lastName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ public static class UserErrors
$"An error occurred while trying to get JWT token. Please check username and password. {TechnicalMessage}"
);

public static Error WrongPasswordDefinition => new(
"User.WrongPasswordDefinition",
$"An error occurred while trying to add a new password to the user. {TechnicalMessage}"
);

public static void SetTechnicalMessage(string technicalMessage)
{
TechnicalMessage = technicalMessage;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ namespace TokenManager.Domain.Interfaces
public interface IUserRepository
{
Task<Result<TokenDetails>> GetAccessTokenAsync(string tenant);
Task<Result> DoNewUserCreationActions(string tenant, User user);
Task<Result> CreateNewUserActions(string tenant, User user);
Task<HttpResponseMessage> CreateNewUserAsync(User user);
Task<Result<User>> GetUserAsync(string userName);
Task<Result> ResetPasswordAsync(string userId, string password);
Task<Result> SendEmailVerificationAsync(string userId);
Task<Result<TokenDetails>> LoginAsync(User user);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public async Task<Result<TokenDetails>> GetAccessTokenAsync(string tenant)
return Result<TokenDetails>.Failure(UserErrors.TokenGenerationError);
}

public async Task<Result> DoNewUserCreationActions(string tenant, User user)
public async Task<Result> CreateNewUserActions(string tenant, User user)
{
var tokenBearerResult = await GetAccessTokenAsync(tenant);
if (tokenBearerResult.IsSuccess)
Expand All @@ -75,7 +75,8 @@ public async Task<Result> DoNewUserCreationActions(string tenant, User user)

if (response.IsSuccessStatusCode)
{
var userName = await GetUserAsync(user.Username);
var keycloakUser = await GetUserAsync(user.Username!);
await ResetPasswordAsync(keycloakUser.Value.Id!, user.Password!);
return Result.Success();
}

Expand Down Expand Up @@ -115,6 +116,59 @@ public async Task<Result<User>> GetUserAsync(string userName)
return Result<User>.Success(user[0]);
}

public async Task<Result> ResetPasswordAsync(string userId, string password)
{
var url = urlUserActions
.AppendPathSegment(userId)
.AppendPathSegment("reset-password");

var passwordData = new
{
type = "password",
temporary = false,
value = password
};

var json = JsonConvert.SerializeObject(passwordData, Settings);
var httpContent = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _httpClient.PutAsync(url, httpContent);

if (response.IsSuccessStatusCode)
{
return Result.Success();
}

var responseMessage = await response.Content.ReadAsStringAsync();
UserErrors.SetTechnicalMessage(responseMessage);
return Result.Failure(UserErrors.InvalidUserNameOrPasswordError);
}

public async Task<Result> SendEmailVerificationAsync(string userId)
{
var url = urlUserActions
.AppendPathSegment(userId);

var requestData = new
{
requiredActions = new string[] { "VERIFY_EMAIL" }
};

var json = JsonConvert.SerializeObject(requestData, Settings);
var httpContent = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _httpClient.PutAsync(url, httpContent);

if (response.IsSuccessStatusCode)
{
url = url.AppendPathSegment("send-verify-email");
await _httpClient.PutAsync(url, default!);
return Result.Success();
}

var responseMessage = await response.Content.ReadAsStringAsync();
UserErrors.SetTechnicalMessage(responseMessage);
return Result.Failure(UserErrors.InvalidUserNameOrPasswordError);
}

public async Task<Result<TokenDetails>> LoginAsync(User user)
{
var requestData = new FormUrlEncodedContent(
Expand Down

0 comments on commit f974055

Please sign in to comment.