diff --git a/README.md b/README.md
index 92c5bd4..5faf44d 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,12 @@
# Wilcommerce.Auth
-Wilcommerce Authentication and Authorization package
+Wilcommerce Authentication and Authorization package.
+It uses AspNetCore Identity framework to manage sign in and user persistence.
## Installation
Nuget package available here [https://www.nuget.org/packages/Wilcommerce.Auth](https://www.nuget.org/packages/Wilcommerce.Auth)
## Models
-The **Models** namespace contains all the classes representing the components used for creating authentication tokens.
+The **Models** namespace contains the user class.
## Read models
This namespace contains the interface which gives a readonly access to the components.
@@ -16,9 +17,6 @@ The **Services** namespace contains a set of components which gives a simple acc
## Commands
**Commands** namespace contains all the actions available on this package.
-## Repository
-This namespace contains the interface which defines the persistence of the components.
-
## Events
In the **Events** namespace are defined all the events that could happen after an action made.
diff --git a/Wilcommerce.Auth.Test/Models/UserTest.cs b/Wilcommerce.Auth.Test/Models/UserTest.cs
new file mode 100644
index 0000000..b2896a9
--- /dev/null
+++ b/Wilcommerce.Auth.Test/Models/UserTest.cs
@@ -0,0 +1,129 @@
+using System;
+using Wilcommerce.Auth.Models;
+using Xunit;
+
+namespace Wilcommerce.Auth.Test.Models
+{
+ public class UserTest
+ {
+ #region Administrator tests
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ public void AdministratorFactory_Should_Throw_ArgumentNull_Exception_If_Name_IsEmpty(string value)
+ {
+ var ex = Assert.Throws(() => User.CreateAsAdministrator(
+ value,
+ "admin@email.com",
+ true));
+
+ Assert.Equal("name", ex.ParamName);
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ public void AdministratorFactory_Should_Throw_ArgumentNull_Exception_If_Email_IsEmpty(string value)
+ {
+ var ex = Assert.Throws(() => User.CreateAsAdministrator(
+ "Administrator",
+ value,
+ true));
+
+ Assert.Equal("email", ex.ParamName);
+ }
+
+ #endregion
+
+ #region Customer tests
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ public void CustomerFactory_Should_Throw_ArgumentNull_Exception_If_Name_IsEmpty(string value)
+ {
+ var ex = Assert.Throws(() => User.CreateAsCustomer(
+ value,
+ "customer@email.com"));
+
+ Assert.Equal("name", ex.ParamName);
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ public void CustomerFactory_Should_Throw_ArgumentNull_Exception_If_Email_IsEmpty(string value)
+ {
+ var ex = Assert.Throws(() => User.CreateAsCustomer(
+ "Customer",
+ value));
+
+ Assert.Equal("email", ex.ParamName);
+ }
+ #endregion
+
+ [Fact]
+ public void Enable_Should_Active_User_And_Set_Date_To_Null()
+ {
+ var user = User.CreateAsAdministrator(
+ "Admin",
+ "admin@email.com",
+ false);
+
+ user.Enable();
+
+ Assert.True(user.IsActive);
+ Assert.Null(user.DisabledOn);
+ }
+
+ [Fact]
+ public void Disable_Should_Set_Date_To_Now()
+ {
+ var user = User.CreateAsAdministrator(
+ "Admin",
+ "admin@email.com",
+ true);
+
+ user.Disable();
+
+ Assert.False(user.IsActive);
+ Assert.Equal(DateTime.Today, ((DateTime)user.DisabledOn).Date);
+ }
+
+ [Theory]
+ [InlineData("")]
+ [InlineData(null)]
+ public void ChangeName_Should_Throw_ArgumentNullException_If_Name_IsEmpty(string value)
+ {
+ var user = User.CreateAsAdministrator(
+ "Admin",
+ "admin@email.com",
+ true);
+
+ var ex = Assert.Throws(() => user.ChangeName(value));
+ Assert.Equal("name", ex.ParamName);
+ }
+
+ [Fact]
+ public void SetProfileImage_Should_Throw_ArgumentNullException_If_Image_IsNull()
+ {
+ var user = User.CreateAsAdministrator(
+ "Admin",
+ "admin@email.com",
+ true);
+
+ var ex = Assert.Throws(() => user.SetProfileImage(null));
+ Assert.Equal("profileImage", ex.ParamName);
+ }
+
+ [Fact]
+ public void Constructor_Should_Initialize_Empty_ProfileImage()
+ {
+ var admin = User.CreateAsAdministrator(
+ "Administrator",
+ "admin@email.com",
+ true);
+
+ Assert.NotNull(admin.ProfileImage);
+ }
+ }
+}
diff --git a/Wilcommerce.Auth.Test/Models/UserTokenTest.cs b/Wilcommerce.Auth.Test/Models/UserTokenTest.cs
deleted file mode 100644
index 35063b5..0000000
--- a/Wilcommerce.Auth.Test/Models/UserTokenTest.cs
+++ /dev/null
@@ -1,118 +0,0 @@
-using Microsoft.AspNetCore.Identity;
-using Moq;
-using System;
-using Wilcommerce.Auth.Models;
-using Wilcommerce.Core.Common.Domain.Models;
-using Xunit;
-
-namespace Wilcommerce.Auth.Test.Models
-{
- public class UserTokenTest
- {
- [Fact]
- public void PasswordRecovery_Should_Throw_ArgumentNullException_If_User_IsNull()
- {
- var ex = Assert.Throws(() => UserToken.PasswordRecovery(null, "", DateTime.Now));
- Assert.Equal("user", ex.ParamName);
- }
-
- [Theory]
- [InlineData(null)]
- [InlineData("")]
- public void PasswordRecovery_Should_Throw_ArgumentNullException_If_Token_IsEmpty(string value)
- {
- var user = User.CreateAsAdministrator("Admin", "admin@admin.com", "password", new Mock>().Object);
-
- var ex = Assert.Throws(() => UserToken.PasswordRecovery(user, value, DateTime.Now));
- Assert.Equal("token", ex.ParamName);
- }
-
- [Fact]
- public void PasswordRecovery_Should_Throw_ArgumentException_If_ExpirationDate_IsPreviousThan_Now()
- {
- var user = User.CreateAsAdministrator("Admin", "admin@admin.com", "password", new Mock>().Object);
- string token = "token";
-
- var ex = Assert.Throws(() => UserToken.PasswordRecovery(user, token, DateTime.Now.AddDays(-1)));
- Assert.Equal("expirationDate", ex.ParamName);
- }
-
- [Fact]
- public void PasswordRecovery_Should_Create_A_PasswordRecovery_Token()
- {
- var user = User.CreateAsAdministrator("Admin", "admin@admin.com", "password", new Mock>().Object);
- string token = "token";
- var expirationDate = DateTime.Now.AddDays(10);
-
- var userToken = UserToken.PasswordRecovery(user, token, expirationDate);
- Assert.Equal(TokenTypes.PasswordRecovery, userToken.TokenType);
- }
-
- [Fact]
- public void Registration_Should_Throw_ArgumentNullException_If_User_IsNull()
- {
- var ex = Assert.Throws(() => UserToken.Registration(null, "", DateTime.Now));
- Assert.Equal("user", ex.ParamName);
- }
-
- [Theory]
- [InlineData(null)]
- [InlineData("")]
- public void Registration_Should_Throw_ArgumentNullException_If_Token_IsEmpty(string value)
- {
- var user = User.CreateAsAdministrator("Admin", "admin@admin.com", "password", new Mock>().Object);
-
- var ex = Assert.Throws(() => UserToken.Registration(user, value, DateTime.Now));
- Assert.Equal("token", ex.ParamName);
- }
-
- [Fact]
- public void Registration_Should_Throw_ArgumentException_If_ExpirationDate_IsPreviousThan_Now()
- {
- var user = User.CreateAsAdministrator("Admin", "admin@admin.com", "password", new Mock>().Object);
- string token = "token";
-
- var ex = Assert.Throws(() => UserToken.Registration(user, token, DateTime.Now.AddDays(-1)));
- Assert.Equal("expirationDate", ex.ParamName);
- }
-
- [Fact]
- public void Registration_Should_Create_A_Registration_Token()
- {
- var user = User.CreateAsAdministrator("Admin", "admin@admin.com", "password", new Mock>().Object);
- string token = "token";
- var expirationDate = DateTime.Now.AddDays(10);
-
- var userToken = UserToken.Registration(user, token, expirationDate);
- Assert.Equal(TokenTypes.Registration, userToken.TokenType);
- }
-
- [Fact]
- public void SetAsExpired_Should_Throw_InvalidOperationException_If_Token_Is_Already_Expired()
- {
- var user = User.CreateAsAdministrator("Admin", "admin@admin.com", "password", new Mock>().Object);
- string token = "token";
- var expirationDate = DateTime.Now.AddDays(10);
-
- var userToken = UserToken.Registration(user, token, expirationDate);
- userToken.SetAsExpired();
-
- var ex = Assert.Throws(() => userToken.SetAsExpired());
- Assert.Equal($"Token already expired on {userToken.ExpirationDate.ToString()}", ex.Message);
- }
-
- [Fact]
- public void SetAsExpired_Should_Set_ExpirationDate_To_Today()
- {
- var user = User.CreateAsAdministrator("Admin", "admin@admin.com", "password", new Mock>().Object);
- string token = "token";
- var expirationDate = DateTime.Now.AddDays(10);
-
- var userToken = UserToken.Registration(user, token, expirationDate);
- userToken.SetAsExpired();
-
- Assert.True(userToken.IsExpired);
- Assert.Equal(DateTime.Now.ToString("yyyy-MM-dd"), userToken.ExpirationDate.ToString("yyyy-MM-dd"));
- }
- }
-}
diff --git a/Wilcommerce.Auth.Test/Services/IdentityFactoryTest.cs b/Wilcommerce.Auth.Test/Services/IdentityFactoryTest.cs
deleted file mode 100644
index dd4846c..0000000
--- a/Wilcommerce.Auth.Test/Services/IdentityFactoryTest.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using Microsoft.AspNetCore.Identity;
-using Moq;
-using System.Security.Claims;
-using Wilcommerce.Auth.Services;
-using Wilcommerce.Auth.Services.Interfaces;
-using Wilcommerce.Core.Common.Domain.Models;
-using Xunit;
-
-namespace Wilcommerce.Auth.Test.Services
-{
- public class IdentityFactoryTest
- {
- private IIdentityFactory _factory;
-
- public IdentityFactoryTest()
- {
- _factory = new IdentityFactory();
- }
-
- [Fact]
- public void CreateIdentity_Identity_Name_Must_Match_User_Email()
- {
- var user = User.CreateAsAdministrator("User", "admin@admin.com", "1234", new Mock>().Object);
- var principal = _factory.CreateIdentity(user);
-
- Assert.Equal(user.Email, principal.Identity.Name);
- }
-
- [Fact]
- public void AdministratorUser_Must_Have_Administrator_As_Role()
- {
- var user = User.CreateAsAdministrator("User", "admin@admin.com", "1234", new Mock>().Object);
- var principal = _factory.CreateIdentity(user);
-
- Assert.True(principal.IsInRole(AuthenticationDefaults.AdministratorRole));
- }
-
- [Fact]
- public void CustomerUser_Must_Have_Customer_As_Role()
- {
- var user = User.CreateAsCustomer("Customer", "customer@customer.com", "1234", new Mock>().Object);
- var principal = _factory.CreateIdentity(user);
-
- Assert.True(principal.IsInRole(AuthenticationDefaults.CustomerRole));
- }
-
- [Fact]
- public void CreateIdentity_NameIdentifier_Must_Match_User_Id()
- {
- var user = User.CreateAsAdministrator("User", "admin@admin.com", "1234", new Mock>().Object);
- var principal = _factory.CreateIdentity(user);
-
- Assert.Equal(principal.FindFirstValue(ClaimTypes.NameIdentifier), user.Id.ToString());
- }
-
- [Fact]
- public void CreateIdentity_Email_Must_Match_User_Email()
- {
- var user = User.CreateAsAdministrator("User", "admin@admin.com", "1234", new Mock>().Object);
- var principal = _factory.CreateIdentity(user);
-
- Assert.Equal(principal.FindFirstValue(ClaimTypes.Email), user.Email);
- }
-
- [Fact]
- public void CreateIdentity_GivenName_Must_Match_User_Name()
- {
- var user = User.CreateAsAdministrator("User", "admin@admin.com", "1234", new Mock>().Object);
- var principal = _factory.CreateIdentity(user);
-
- Assert.Equal(principal.FindFirstValue(ClaimTypes.GivenName), user.Name);
- }
- }
-}
diff --git a/Wilcommerce.Auth.Test/Wilcommerce.Auth.Test.csproj b/Wilcommerce.Auth.Test/Wilcommerce.Auth.Test.csproj
index 5f6743a..edd7f44 100644
--- a/Wilcommerce.Auth.Test/Wilcommerce.Auth.Test.csproj
+++ b/Wilcommerce.Auth.Test/Wilcommerce.Auth.Test.csproj
@@ -17,10 +17,10 @@
-
-
-
-
+
+
+
+
diff --git a/src/Wilcommerce.Auth/Commands/Handlers/Interfaces/IRecoverPasswordCommandHandler.cs b/src/Wilcommerce.Auth/Commands/Handlers/Interfaces/IRecoverPasswordCommandHandler.cs
deleted file mode 100644
index 00e2b62..0000000
--- a/src/Wilcommerce.Auth/Commands/Handlers/Interfaces/IRecoverPasswordCommandHandler.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using Wilcommerce.Core.Infrastructure;
-
-namespace Wilcommerce.Auth.Commands.Handlers.Interfaces
-{
- ///
- /// Performs the password recovery action
- ///
- public interface IRecoverPasswordCommandHandler : ICommandHandlerAsync
- {
- }
-}
diff --git a/src/Wilcommerce.Auth/Commands/Handlers/Interfaces/IValidatePasswordRecoveryCommandHandler.cs b/src/Wilcommerce.Auth/Commands/Handlers/Interfaces/IValidatePasswordRecoveryCommandHandler.cs
deleted file mode 100644
index cbbadad..0000000
--- a/src/Wilcommerce.Auth/Commands/Handlers/Interfaces/IValidatePasswordRecoveryCommandHandler.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using Wilcommerce.Core.Infrastructure;
-
-namespace Wilcommerce.Auth.Commands.Handlers.Interfaces
-{
- ///
- /// Performs the validation for the password recovery request
- ///
- public interface IValidatePasswordRecoveryCommandHandler : ICommandHandlerAsync
- {
- }
-}
diff --git a/src/Wilcommerce.Auth/Commands/Handlers/RecoverPasswordCommandHandler.cs b/src/Wilcommerce.Auth/Commands/Handlers/RecoverPasswordCommandHandler.cs
deleted file mode 100644
index a6a2717..0000000
--- a/src/Wilcommerce.Auth/Commands/Handlers/RecoverPasswordCommandHandler.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-using System;
-using System.Threading.Tasks;
-using Wilcommerce.Auth.Events.User;
-using Wilcommerce.Auth.Models;
-using Wilcommerce.Auth.Repository;
-
-namespace Wilcommerce.Auth.Commands.Handlers
-{
- ///
- /// Implementation of
- ///
- public class RecoverPasswordCommandHandler : Interfaces.IRecoverPasswordCommandHandler
- {
- ///
- /// Get the event bus
- ///
- public Core.Infrastructure.IEventBus EventBus { get; }
-
- ///
- /// Get the authentication repository
- ///
- public IRepository Repository { get; }
-
- ///
- /// Construct the command handler
- ///
- /// The repository instance
- /// The event bus instance
- public RecoverPasswordCommandHandler(IRepository repository, Core.Infrastructure.IEventBus eventBus)
- {
- Repository = repository ?? throw new ArgumentNullException(nameof(repository));
- EventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
- }
-
- ///
- /// Recover the password for the user
- ///
- /// The command to execute
- ///
- public async Task Handle(RecoverPasswordCommand command)
- {
- try
- {
- var userToken = UserToken.PasswordRecovery(command.UserInfo, command.Token, DateTime.Now.AddDays(AuthenticationDefaults.ExpirationDays));
-
- Repository.Add(userToken);
- await Repository.SaveChangesAsync();
-
- var @event = new PasswordRecoveryRequestedEvent(userToken.UserId, command.UserInfo.Email, userToken.Id, userToken.Token, userToken.ExpirationDate);
- EventBus.RaiseEvent(@event);
- }
- catch
- {
- throw;
- }
- }
- }
-}
diff --git a/src/Wilcommerce.Auth/Commands/Handlers/ValidatePasswordRecoveryCommandHandler.cs b/src/Wilcommerce.Auth/Commands/Handlers/ValidatePasswordRecoveryCommandHandler.cs
deleted file mode 100644
index af624f1..0000000
--- a/src/Wilcommerce.Auth/Commands/Handlers/ValidatePasswordRecoveryCommandHandler.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using System;
-using System.Linq;
-using System.Threading.Tasks;
-using Wilcommerce.Auth.Events.User;
-using Wilcommerce.Auth.Models;
-using Wilcommerce.Auth.ReadModels;
-using Wilcommerce.Auth.Repository;
-
-namespace Wilcommerce.Auth.Commands.Handlers
-{
- ///
- /// Implementation of
- ///
- public class ValidatePasswordRecoveryCommandHandler : Interfaces.IValidatePasswordRecoveryCommandHandler
- {
- ///
- /// Get the authentication database
- ///
- public IAuthDatabase Database { get; }
-
- ///
- /// Get the authentication repository
- ///
- public IRepository Repository { get; }
-
- ///
- /// Get the event bus
- ///
- public Core.Infrastructure.IEventBus EventBus { get; }
-
- ///
- /// Construct the command handler
- ///
- /// The database instance
- /// The repository instance
- /// The event bus instance
- public ValidatePasswordRecoveryCommandHandler(IAuthDatabase database, IRepository repository, Core.Infrastructure.IEventBus eventBus)
- {
- Database = database ?? throw new ArgumentNullException(nameof(database));
- Repository = repository ?? throw new ArgumentNullException(nameof(repository));
- EventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
- }
-
- ///
- /// Validate the password recovery request
- ///
- /// The command to execute
- ///
- public async Task Handle(ValidatePasswordRecoveryCommand command)
- {
- try
- {
- var userToken = Database.Tokens
- .NotExpired()
- .ByTokenType(TokenTypes.PasswordRecovery)
- .FirstOrDefault(t => t.Token == command.Token);
-
- if (userToken == null)
- {
- throw new InvalidOperationException("Invalid token");
- }
-
- var token = await Repository.GetByKeyAsync(userToken.Id);
- token.SetAsExpired();
-
- await Repository.SaveChangesAsync();
-
- var @event = new PasswordRecoveryValidatedEvent(userToken.UserId, userToken.Token);
- EventBus.RaiseEvent(@event);
- }
- catch
- {
- throw;
- }
- }
- }
-}
diff --git a/src/Wilcommerce.Auth/Commands/RecoverPasswordCommand.cs b/src/Wilcommerce.Auth/Commands/RecoverPasswordCommand.cs
deleted file mode 100644
index fbd8066..0000000
--- a/src/Wilcommerce.Auth/Commands/RecoverPasswordCommand.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using Wilcommerce.Core.Common.Domain.Models;
-using Wilcommerce.Core.Infrastructure;
-
-namespace Wilcommerce.Auth.Commands
-{
- ///
- /// Recover the user password
- ///
- public class RecoverPasswordCommand : ICommand
- {
- ///
- /// Get the user information
- ///
- public User UserInfo { get; }
-
- ///
- /// Get the recovery token
- ///
- public string Token { get; }
-
- ///
- /// Construct the command
- ///
- /// The user information
- /// The recovery token
- public RecoverPasswordCommand(User user, string token)
- {
- UserInfo = user;
- Token = token;
- }
- }
-}
diff --git a/src/Wilcommerce.Auth/Commands/User/ChangeUserInfoCommand.cs b/src/Wilcommerce.Auth/Commands/User/ChangeUserInfoCommand.cs
new file mode 100644
index 0000000..389756a
--- /dev/null
+++ b/src/Wilcommerce.Auth/Commands/User/ChangeUserInfoCommand.cs
@@ -0,0 +1,40 @@
+using System;
+using Wilcommerce.Core.Common.Models;
+using Wilcommerce.Core.Infrastructure;
+
+namespace Wilcommerce.Auth.Commands.User
+{
+ ///
+ /// Update the user information
+ ///
+ public class ChangeUserInfoCommand : ICommand
+ {
+ ///
+ /// Get the user's id
+ ///
+ public Guid UserId { get; }
+
+ ///
+ /// Get the user's name
+ ///
+ public string Name { get; }
+
+ ///
+ /// Get the user's profile image
+ ///
+ public Image ProfileImage { get; }
+
+ ///
+ /// Construct the change user info command
+ ///
+ /// The user id
+ /// The user name
+ /// The user profile image
+ public ChangeUserInfoCommand(Guid userId, string name, Image profileImage)
+ {
+ UserId = userId;
+ Name = name;
+ ProfileImage = profileImage;
+ }
+ }
+}
diff --git a/src/Wilcommerce.Auth/Commands/User/CreateNewAdministratorCommand.cs b/src/Wilcommerce.Auth/Commands/User/CreateNewAdministratorCommand.cs
new file mode 100644
index 0000000..f635cab
--- /dev/null
+++ b/src/Wilcommerce.Auth/Commands/User/CreateNewAdministratorCommand.cs
@@ -0,0 +1,45 @@
+using Wilcommerce.Core.Infrastructure;
+
+namespace Wilcommerce.Auth.Commands.User
+{
+ ///
+ /// Create a new administrator
+ ///
+ public class CreateNewAdministratorCommand : ICommand
+ {
+ ///
+ /// Get the administrator name
+ ///
+ public string Name { get; }
+
+ ///
+ /// Get the administrator email
+ ///
+ public string Email { get; }
+
+ ///
+ /// Get the administrator password
+ ///
+ public string Password { get; }
+
+ ///
+ /// Get whether the administrator is active
+ ///
+ public bool IsActive { get; }
+
+ ///
+ /// Construct the command
+ ///
+ /// The adminsitrator name
+ /// The adminsitrator email
+ /// The adminsitrator password
+ /// Whether the user is active
+ public CreateNewAdministratorCommand(string name, string email, string password, bool isActive)
+ {
+ Name = name;
+ Email = email;
+ Password = password;
+ IsActive = isActive;
+ }
+ }
+}
diff --git a/src/Wilcommerce.Auth/Commands/User/DisableUserCommand.cs b/src/Wilcommerce.Auth/Commands/User/DisableUserCommand.cs
new file mode 100644
index 0000000..c7fd932
--- /dev/null
+++ b/src/Wilcommerce.Auth/Commands/User/DisableUserCommand.cs
@@ -0,0 +1,25 @@
+using System;
+using Wilcommerce.Core.Infrastructure;
+
+namespace Wilcommerce.Auth.Commands.User
+{
+ ///
+ /// Disable the user
+ ///
+ public class DisableUserCommand : ICommand
+ {
+ ///
+ /// Get the user id
+ ///
+ public Guid UserId { get; }
+
+ ///
+ /// Construct the command
+ ///
+ /// The user id
+ public DisableUserCommand(Guid userId)
+ {
+ UserId = UserId;
+ }
+ }
+}
diff --git a/src/Wilcommerce.Auth/Commands/User/EnableUserCommand.cs b/src/Wilcommerce.Auth/Commands/User/EnableUserCommand.cs
new file mode 100644
index 0000000..4d7bede
--- /dev/null
+++ b/src/Wilcommerce.Auth/Commands/User/EnableUserCommand.cs
@@ -0,0 +1,25 @@
+using System;
+using Wilcommerce.Core.Infrastructure;
+
+namespace Wilcommerce.Auth.Commands.User
+{
+ ///
+ /// Enable the user
+ ///
+ public class EnableUserCommand : ICommand
+ {
+ ///
+ /// Get the user id
+ ///
+ public Guid UserId { get; }
+
+ ///
+ /// Construct the command
+ ///
+ /// The user id
+ public EnableUserCommand(Guid userId)
+ {
+ UserId = UserId;
+ }
+ }
+}
diff --git a/src/Wilcommerce.Auth/Commands/User/Handlers/ChangeUserInfoCommandHandler.cs b/src/Wilcommerce.Auth/Commands/User/Handlers/ChangeUserInfoCommandHandler.cs
new file mode 100644
index 0000000..aac497b
--- /dev/null
+++ b/src/Wilcommerce.Auth/Commands/User/Handlers/ChangeUserInfoCommandHandler.cs
@@ -0,0 +1,70 @@
+using Microsoft.AspNetCore.Identity;
+using System;
+using System.Threading.Tasks;
+using Wilcommerce.Auth.Events.User;
+using Wilcommerce.Core.Infrastructure;
+
+namespace Wilcommerce.Auth.Commands.User.Handlers
+{
+ ///
+ /// Implementation of
+ ///
+ public class ChangeUserInfoCommandHandler : Interfaces.IChangeUserInfoCommandHandler
+ {
+ ///
+ /// Get the user manager instance
+ ///
+ public UserManager UserManager { get; }
+
+ ///
+ /// Get the event bus instance
+ ///
+ public IEventBus EventBus { get; }
+
+ ///
+ /// Construct the command handler
+ ///
+ /// The user manager
+ /// The event bus
+ public ChangeUserInfoCommandHandler(UserManager userManager, IEventBus eventBus)
+ {
+ UserManager = userManager ?? throw new ArgumentNullException(nameof(userManager));
+ EventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
+ }
+
+ ///
+ /// Change the user's information
+ ///
+ /// The command to execute
+ ///
+ public async Task Handle(ChangeUserInfoCommand command)
+ {
+ try
+ {
+ var user = await UserManager.FindByIdAsync(command.UserId.ToString());
+ if (command.Name != user.Name)
+ {
+ user.ChangeName(command.Name);
+ }
+
+ if (command.ProfileImage != user.ProfileImage)
+ {
+ user.SetProfileImage(command.ProfileImage);
+ }
+
+ var result = await UserManager.UpdateAsync(user);
+ if (!result.Succeeded)
+ {
+ throw new ApplicationException("Error while changing the user's info");
+ }
+
+ var @event = new UserInfoChangedEvent(command.UserId, command.Name, command.ProfileImage);
+ EventBus.RaiseEvent(@event);
+ }
+ catch
+ {
+ throw;
+ }
+ }
+ }
+}
diff --git a/src/Wilcommerce.Auth/Commands/User/Handlers/CreateNewAdministratorCommandHandler.cs b/src/Wilcommerce.Auth/Commands/User/Handlers/CreateNewAdministratorCommandHandler.cs
new file mode 100644
index 0000000..70495c0
--- /dev/null
+++ b/src/Wilcommerce.Auth/Commands/User/Handlers/CreateNewAdministratorCommandHandler.cs
@@ -0,0 +1,70 @@
+using Microsoft.AspNetCore.Identity;
+using System;
+using System.Threading.Tasks;
+using Wilcommerce.Auth.Events.User;
+using Wilcommerce.Auth.Services.Interfaces;
+
+namespace Wilcommerce.Auth.Commands.User.Handlers
+{
+ ///
+ /// Implementation of
+ ///
+ public class CreateNewAdministratorCommandHandler : Interfaces.ICreateNewAdministratorCommandHandler
+ {
+ ///
+ /// Get the user mananager instance
+ ///
+ public UserManager UserManager { get; }
+
+ ///
+ /// The event bus instance
+ ///
+ public Core.Infrastructure.IEventBus EventBus { get; }
+
+ ///
+ /// Get the role factory instance
+ ///
+ public IRoleFactory RoleFactory { get; }
+
+ ///
+ /// Construct the command handler
+ ///
+ /// The user manager
+ /// The event bus
+ /// The role factory
+ public CreateNewAdministratorCommandHandler(UserManager userManager, Core.Infrastructure.IEventBus eventBus, IRoleFactory roleFactory)
+ {
+ UserManager = userManager ?? throw new ArgumentNullException(nameof(userManager));
+ EventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
+ RoleFactory = roleFactory ?? throw new ArgumentNullException(nameof(roleFactory));
+ }
+
+ ///
+ /// Create a new administrator
+ ///
+ /// The command to execute
+ ///
+ public async Task Handle(CreateNewAdministratorCommand command)
+ {
+ try
+ {
+ var administrator = Models.User.CreateAsAdministrator(command.Name, command.Email, command.IsActive);
+ var result = await UserManager.CreateAsync(administrator, command.Password);
+ if (!result.Succeeded)
+ {
+ throw new InvalidOperationException(string.Join(",", result.Errors));
+ }
+
+ var role = await RoleFactory.Administrator();
+ await UserManager.AddToRoleAsync(administrator, role.Name);
+
+ var @event = new NewAdministratorCreatedEvent(administrator.Id, administrator.Name, administrator.Email);
+ EventBus.RaiseEvent(@event);
+ }
+ catch
+ {
+ throw;
+ }
+ }
+ }
+}
diff --git a/src/Wilcommerce.Auth/Commands/User/Handlers/DisableUserCommandHandler.cs b/src/Wilcommerce.Auth/Commands/User/Handlers/DisableUserCommandHandler.cs
new file mode 100644
index 0000000..a7a8746
--- /dev/null
+++ b/src/Wilcommerce.Auth/Commands/User/Handlers/DisableUserCommandHandler.cs
@@ -0,0 +1,62 @@
+using Microsoft.AspNetCore.Identity;
+using System;
+using System.Threading.Tasks;
+using Wilcommerce.Auth.Events.User;
+using Wilcommerce.Core.Infrastructure;
+
+namespace Wilcommerce.Auth.Commands.User.Handlers
+{
+ ///
+ /// Implementation of
+ ///
+ public class DisableUserCommandHandler : Interfaces.IDisableUserCommandHandler
+ {
+ ///
+ /// Get the user manager instance
+ ///
+ public UserManager UserManager { get; }
+
+ ///
+ /// Get the event bus instance
+ ///
+ public IEventBus EventBus { get; }
+
+ ///
+ /// Construct the command handler
+ ///
+ /// The user manager
+ /// The event bus
+ public DisableUserCommandHandler(UserManager userManager, IEventBus eventBus)
+ {
+ UserManager = userManager ?? throw new ArgumentNullException(nameof(userManager));
+ EventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
+ }
+
+ ///
+ /// Disable the user
+ ///
+ /// The command to execute
+ ///
+ public async Task Handle(DisableUserCommand command)
+ {
+ try
+ {
+ var user = await UserManager.FindByIdAsync(command.UserId.ToString());
+ user.Disable();
+
+ var result = await UserManager.UpdateAsync(user);
+ if (!result.Succeeded)
+ {
+ throw new ApplicationException("Error while disabling the user");
+ }
+
+ var @event = new UserDisabledEvent(user.Id);
+ EventBus.RaiseEvent(@event);
+ }
+ catch
+ {
+ throw;
+ }
+ }
+ }
+}
diff --git a/src/Wilcommerce.Auth/Commands/User/Handlers/EnableUserCommandHandler.cs b/src/Wilcommerce.Auth/Commands/User/Handlers/EnableUserCommandHandler.cs
new file mode 100644
index 0000000..46ed5b2
--- /dev/null
+++ b/src/Wilcommerce.Auth/Commands/User/Handlers/EnableUserCommandHandler.cs
@@ -0,0 +1,62 @@
+using Microsoft.AspNetCore.Identity;
+using System;
+using System.Threading.Tasks;
+using Wilcommerce.Auth.Events.User;
+using Wilcommerce.Core.Infrastructure;
+
+namespace Wilcommerce.Auth.Commands.User.Handlers
+{
+ ///
+ /// Implementation of
+ ///
+ public class EnableUserCommandHandler : Interfaces.IEnableUserCommandHandler
+ {
+ ///
+ /// Get the user manager instance
+ ///
+ public UserManager UserManager { get; }
+
+ ///
+ /// Get the event bus instance
+ ///
+ public IEventBus EventBus { get; }
+
+ ///
+ /// Construct the command handler
+ ///
+ /// The user manager
+ /// The event bus
+ public EnableUserCommandHandler(UserManager userManager, IEventBus eventBus)
+ {
+ UserManager = userManager ?? throw new ArgumentNullException(nameof(userManager));
+ EventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
+ }
+
+ ///
+ /// Enable the user
+ ///
+ /// The command to execute
+ ///
+ public async Task Handle(EnableUserCommand command)
+ {
+ try
+ {
+ var user = await UserManager.FindByIdAsync(command.UserId.ToString());
+ user.Enable();
+
+ var result = await UserManager.UpdateAsync(user);
+ if (!result.Succeeded)
+ {
+ throw new ApplicationException("Error while enabling the user");
+ }
+
+ var @event = new UserEnabledEvent(user.Id);
+ EventBus.RaiseEvent(@event);
+ }
+ catch
+ {
+ throw;
+ }
+ }
+ }
+}
diff --git a/src/Wilcommerce.Auth/Commands/User/Handlers/Interfaces/IChangeUserInfoCommandHandler.cs b/src/Wilcommerce.Auth/Commands/User/Handlers/Interfaces/IChangeUserInfoCommandHandler.cs
new file mode 100644
index 0000000..aa06cfb
--- /dev/null
+++ b/src/Wilcommerce.Auth/Commands/User/Handlers/Interfaces/IChangeUserInfoCommandHandler.cs
@@ -0,0 +1,11 @@
+using Wilcommerce.Core.Infrastructure;
+
+namespace Wilcommerce.Auth.Commands.User.Handlers.Interfaces
+{
+ ///
+ /// Handles the change of user's information
+ ///
+ public interface IChangeUserInfoCommandHandler : ICommandHandlerAsync
+ {
+ }
+}
diff --git a/src/Wilcommerce.Auth/Commands/User/Handlers/Interfaces/ICreateNewAdministratorCommandHandler.cs b/src/Wilcommerce.Auth/Commands/User/Handlers/Interfaces/ICreateNewAdministratorCommandHandler.cs
new file mode 100644
index 0000000..0ea3de7
--- /dev/null
+++ b/src/Wilcommerce.Auth/Commands/User/Handlers/Interfaces/ICreateNewAdministratorCommandHandler.cs
@@ -0,0 +1,11 @@
+using Wilcommerce.Core.Infrastructure;
+
+namespace Wilcommerce.Auth.Commands.User.Handlers.Interfaces
+{
+ ///
+ /// Handles the creation of a new administrator
+ ///
+ public interface ICreateNewAdministratorCommandHandler : ICommandHandlerAsync
+ {
+ }
+}
diff --git a/src/Wilcommerce.Auth/Commands/User/Handlers/Interfaces/IDisableUserCommandHandler.cs b/src/Wilcommerce.Auth/Commands/User/Handlers/Interfaces/IDisableUserCommandHandler.cs
new file mode 100644
index 0000000..8457e6c
--- /dev/null
+++ b/src/Wilcommerce.Auth/Commands/User/Handlers/Interfaces/IDisableUserCommandHandler.cs
@@ -0,0 +1,11 @@
+using Wilcommerce.Core.Infrastructure;
+
+namespace Wilcommerce.Auth.Commands.User.Handlers.Interfaces
+{
+ ///
+ /// Handles the disabling of the user
+ ///
+ public interface IDisableUserCommandHandler : ICommandHandlerAsync
+ {
+ }
+}
diff --git a/src/Wilcommerce.Auth/Commands/User/Handlers/Interfaces/IEnableUserCommandHandler.cs b/src/Wilcommerce.Auth/Commands/User/Handlers/Interfaces/IEnableUserCommandHandler.cs
new file mode 100644
index 0000000..f0751b6
--- /dev/null
+++ b/src/Wilcommerce.Auth/Commands/User/Handlers/Interfaces/IEnableUserCommandHandler.cs
@@ -0,0 +1,11 @@
+using Wilcommerce.Core.Infrastructure;
+
+namespace Wilcommerce.Auth.Commands.User.Handlers.Interfaces
+{
+ ///
+ /// Handles the enabling of the user
+ ///
+ public interface IEnableUserCommandHandler : ICommandHandlerAsync
+ {
+ }
+}
diff --git a/src/Wilcommerce.Auth/Commands/User/Handlers/Interfaces/IResetPasswordCommandHandler.cs b/src/Wilcommerce.Auth/Commands/User/Handlers/Interfaces/IResetPasswordCommandHandler.cs
new file mode 100644
index 0000000..655b74f
--- /dev/null
+++ b/src/Wilcommerce.Auth/Commands/User/Handlers/Interfaces/IResetPasswordCommandHandler.cs
@@ -0,0 +1,11 @@
+using Wilcommerce.Core.Infrastructure;
+
+namespace Wilcommerce.Auth.Commands.User.Handlers.Interfaces
+{
+ ///
+ /// Handles the reset of user's password
+ ///
+ public interface IResetPasswordCommandHandler : ICommandHandlerAsync
+ {
+ }
+}
diff --git a/src/Wilcommerce.Auth/Commands/User/Handlers/ResetPasswordCommandHandler.cs b/src/Wilcommerce.Auth/Commands/User/Handlers/ResetPasswordCommandHandler.cs
new file mode 100644
index 0000000..9e868d2
--- /dev/null
+++ b/src/Wilcommerce.Auth/Commands/User/Handlers/ResetPasswordCommandHandler.cs
@@ -0,0 +1,61 @@
+using Microsoft.AspNetCore.Identity;
+using System;
+using System.Threading.Tasks;
+using Wilcommerce.Auth.Events.User;
+using Wilcommerce.Core.Infrastructure;
+
+namespace Wilcommerce.Auth.Commands.User.Handlers
+{
+ ///
+ /// Implementation of
+ ///
+ public class ResetPasswordCommandHandler : Interfaces.IResetPasswordCommandHandler
+ {
+ ///
+ /// Get the user manager instance
+ ///
+ public UserManager UserManager { get; }
+
+ ///
+ /// Get the event bus
+ ///
+ public IEventBus EventBus { get; }
+
+ ///
+ /// Construct the command handler
+ ///
+ /// The user manager
+ /// The event bus
+ public ResetPasswordCommandHandler(UserManager userManager, IEventBus eventBus)
+ {
+ UserManager = userManager ?? throw new ArgumentNullException(nameof(userManager));
+ EventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
+ }
+
+ ///
+ /// Reset the user's password
+ ///
+ /// The command to execute
+ ///
+ public async Task Handle(ResetPasswordCommand command)
+ {
+ try
+ {
+ var user = await UserManager.FindByIdAsync(command.UserId.ToString());
+ var result = await UserManager.ResetPasswordAsync(user, command.ResetToken, command.NewPassword);
+
+ if (!result.Succeeded)
+ {
+ throw new ApplicationException("There was an error resetting the user password");
+ }
+
+ var @event = new UserPasswordResetEvent(command.UserId);
+ EventBus.RaiseEvent(@event);
+ }
+ catch
+ {
+ throw;
+ }
+ }
+ }
+}
diff --git a/src/Wilcommerce.Auth/Commands/User/ResetPasswordCommand.cs b/src/Wilcommerce.Auth/Commands/User/ResetPasswordCommand.cs
new file mode 100644
index 0000000..b5d6e0f
--- /dev/null
+++ b/src/Wilcommerce.Auth/Commands/User/ResetPasswordCommand.cs
@@ -0,0 +1,39 @@
+using System;
+using Wilcommerce.Core.Infrastructure;
+
+namespace Wilcommerce.Auth.Commands.User
+{
+ ///
+ /// Reset the user password
+ ///
+ public class ResetPasswordCommand : ICommand
+ {
+ ///
+ /// Get the user's id
+ ///
+ public Guid UserId { get; }
+
+ ///
+ /// Get the reset token for the user
+ ///
+ public string ResetToken { get; }
+
+ ///
+ /// Get the new user's password
+ ///
+ public string NewPassword { get; }
+
+ ///
+ /// Construct the reset password command
+ ///
+ /// The user's id
+ /// The reset token
+ /// The new password
+ public ResetPasswordCommand(Guid userId, string resetToken, string newPassword)
+ {
+ UserId = userId;
+ ResetToken = resetToken;
+ NewPassword = newPassword;
+ }
+ }
+}
diff --git a/src/Wilcommerce.Auth/Commands/ValidatePasswordRecoveryCommand.cs b/src/Wilcommerce.Auth/Commands/ValidatePasswordRecoveryCommand.cs
deleted file mode 100644
index addae1f..0000000
--- a/src/Wilcommerce.Auth/Commands/ValidatePasswordRecoveryCommand.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using Wilcommerce.Core.Infrastructure;
-
-namespace Wilcommerce.Auth.Commands
-{
- ///
- /// Validate the password recovery request
- ///
- public class ValidatePasswordRecoveryCommand : ICommand
- {
- ///
- /// Get the recovery token
- ///
- public string Token { get; }
-
- ///
- /// Construct the command
- ///
- /// The recovery token
- public ValidatePasswordRecoveryCommand(string token)
- {
- Token = token;
- }
- }
-}
diff --git a/src/Wilcommerce.Auth/Events/User/Handlers/UserEventHandler.cs b/src/Wilcommerce.Auth/Events/User/Handlers/UserEventHandler.cs
index 38c7261..3420300 100644
--- a/src/Wilcommerce.Auth/Events/User/Handlers/UserEventHandler.cs
+++ b/src/Wilcommerce.Auth/Events/User/Handlers/UserEventHandler.cs
@@ -1,9 +1,4 @@
-using Microsoft.AspNetCore.Authentication;
-using Microsoft.AspNetCore.Http;
-using System;
-using System.Linq;
-using Wilcommerce.Auth.Services.Interfaces;
-using Wilcommerce.Core.Common.Domain.ReadModels;
+using System;
using Wilcommerce.Core.Infrastructure;
namespace Wilcommerce.Auth.Events.User.Handlers
@@ -13,8 +8,11 @@ namespace Wilcommerce.Auth.Events.User.Handlers
///
public class UserEventHandler :
IHandleEvent,
- IHandleEvent,
- IHandleEvent
+ IHandleEvent,
+ IHandleEvent,
+ IHandleEvent,
+ IHandleEvent,
+ IHandleEvent
{
///
/// Get the event store
@@ -22,55 +20,83 @@ public class UserEventHandler :
public IEventStore EventStore { get; }
///
- /// Get the identity factory
+ /// Construct the event handler
///
- public IIdentityFactory IdentityFactory { get; }
+ /// The event store instance
+ public UserEventHandler(IEventStore eventStore)
+ {
+ EventStore = eventStore ?? throw new ArgumentNullException(nameof(eventStore));
+ }
///
- /// Get the database of the common context
+ ///
///
- public ICommonDatabase CommonDatabase { get; }
+ ///
+ public void Handle(UserSignedInEvent @event)
+ {
+ try
+ {
+ EventStore.Save(@event);
+ }
+ catch
+ {
+ throw;
+ }
+ }
///
- /// Get the http context
+ ///
///
- public HttpContext Context { get; }
+ ///
+ public void Handle(NewAdministratorCreatedEvent @event)
+ {
+ try
+ {
+ EventStore.Save(@event);
+ }
+ catch
+ {
+ throw;
+ }
+ }
///
- /// Construct the event handler
+ ///
///
- /// The event store instance
- /// The identity factory instance
- /// The common database instance
- /// The http context accessor instance
- public UserEventHandler(IEventStore eventStore, IIdentityFactory identityFactory, ICommonDatabase commonDatabase, IHttpContextAccessor httpContextAccessor)
+ ///
+ public void Handle(UserDisabledEvent @event)
{
- if (httpContextAccessor == null)
+ try
+ {
+ EventStore.Save(@event);
+ }
+ catch
{
- throw new ArgumentNullException(nameof(httpContextAccessor));
+ throw;
}
-
- EventStore = eventStore ?? throw new ArgumentNullException(nameof(eventStore));
- IdentityFactory = identityFactory ?? throw new ArgumentNullException(nameof(identityFactory));
- CommonDatabase = commonDatabase ?? throw new ArgumentNullException(nameof(commonDatabase));
- Context = httpContextAccessor.HttpContext;
}
- ///
- public void Handle(UserSignedInEvent @event)
+ ///
+ ///
+ ///
+ ///
+ public void Handle(UserEnabledEvent @event)
{
try
{
EventStore.Save(@event);
}
- catch
+ catch
{
throw;
}
}
- ///
- public void Handle(PasswordRecoveryRequestedEvent @event)
+ ///
+ ///
+ ///
+ ///
+ public void Handle(UserInfoChangedEvent @event)
{
try
{
@@ -82,23 +108,15 @@ public void Handle(PasswordRecoveryRequestedEvent @event)
}
}
- ///
- public void Handle(PasswordRecoveryValidatedEvent @event)
+ ///
+ ///
+ ///
+ ///
+ public void Handle(UserPasswordResetEvent @event)
{
try
{
EventStore.Save(@event);
-
- var user = CommonDatabase.Users
- .FirstOrDefault(u => u.Id == @event.AggregateId);
-
- if (user == null)
- {
- throw new Exception("User not found");
- }
-
- var principal = IdentityFactory.CreateIdentity(user);
- Context.SignInAsync(AuthenticationDefaults.AuthenticationScheme, principal);
}
catch
{
diff --git a/src/Wilcommerce.Auth/Events/User/NewAdministratorCreatedEvent.cs b/src/Wilcommerce.Auth/Events/User/NewAdministratorCreatedEvent.cs
new file mode 100644
index 0000000..9885379
--- /dev/null
+++ b/src/Wilcommerce.Auth/Events/User/NewAdministratorCreatedEvent.cs
@@ -0,0 +1,49 @@
+using System;
+using Wilcommerce.Core.Infrastructure;
+
+namespace Wilcommerce.Auth.Events.User
+{
+ ///
+ /// New administrator created
+ ///
+ public class NewAdministratorCreatedEvent : DomainEvent
+ {
+ ///
+ /// Get the administrator id
+ ///
+ public Guid AdministratorId { get; private set; }
+
+ ///
+ /// Get the administrator name
+ ///
+ public string Name { get; private set; }
+
+ ///
+ /// Get the administrator email
+ ///
+ public string Email { get; private set; }
+
+ ///
+ /// Construct the event
+ ///
+ /// The administrator id
+ /// The administrator name
+ /// The administrator email
+ public NewAdministratorCreatedEvent(Guid administratorId, string name, string email)
+ : base(administratorId, typeof(Models.User))
+ {
+ AdministratorId = administratorId;
+ Name = name;
+ Email = email;
+ }
+
+ ///
+ /// Convert the event to string
+ ///
+ /// The converted string
+ public override string ToString()
+ {
+ return $"{FiredOn} - The administrator {Name}, {Email} [{AdministratorId}] was created";
+ }
+ }
+}
diff --git a/src/Wilcommerce.Auth/Events/User/PasswordRecoveryRequestedEvent.cs b/src/Wilcommerce.Auth/Events/User/PasswordRecoveryRequestedEvent.cs
deleted file mode 100644
index a6bb562..0000000
--- a/src/Wilcommerce.Auth/Events/User/PasswordRecoveryRequestedEvent.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-using System;
-using Wilcommerce.Core.Infrastructure;
-
-namespace Wilcommerce.Auth.Events.User
-{
- ///
- /// Password recovery validated
- ///
- public class PasswordRecoveryRequestedEvent : DomainEvent
- {
- ///
- /// Get the username
- ///
- public string Username { get; }
-
- ///
- /// Get the token id
- ///
- public Guid TokenId { get; }
-
- ///
- /// Get the password recovery token
- ///
- public string Token { get; }
-
- ///
- /// Get the token expiration date
- ///
- public DateTime ExpirationDate { get; }
-
- ///
- /// Construct the event
- ///
- /// The user id
- /// The username
- /// The token id
- /// The password recovery token
- /// The token expiration date
- public PasswordRecoveryRequestedEvent(Guid userId, string username, Guid tokenId, string token, DateTime expirationDate)
- : base(userId, typeof(Core.Common.Domain.Models.User))
- {
- Username = username;
- TokenId = tokenId;
- Token = token;
- ExpirationDate = expirationDate;
- }
- }
-}
diff --git a/src/Wilcommerce.Auth/Events/User/PasswordRecoveryValidatedEvent.cs b/src/Wilcommerce.Auth/Events/User/PasswordRecoveryValidatedEvent.cs
deleted file mode 100644
index ecc5815..0000000
--- a/src/Wilcommerce.Auth/Events/User/PasswordRecoveryValidatedEvent.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using System;
-using Wilcommerce.Core.Infrastructure;
-
-namespace Wilcommerce.Auth.Events.User
-{
- ///
- /// Password recovery validated
- ///
- public class PasswordRecoveryValidatedEvent : DomainEvent
- {
- ///
- /// Get the password recovery token
- ///
- public string Token { get; }
-
- ///
- /// Construct the event
- ///
- /// The user id
- /// The password recovery token
- public PasswordRecoveryValidatedEvent(Guid userId, string token)
- : base(userId, typeof(Core.Common.Domain.Models.User))
- {
- Token = token;
- }
- }
-}
diff --git a/src/Wilcommerce.Auth/Events/User/UserDisabledEvent.cs b/src/Wilcommerce.Auth/Events/User/UserDisabledEvent.cs
new file mode 100644
index 0000000..6c14761
--- /dev/null
+++ b/src/Wilcommerce.Auth/Events/User/UserDisabledEvent.cs
@@ -0,0 +1,35 @@
+using System;
+using Wilcommerce.Core.Infrastructure;
+
+namespace Wilcommerce.Auth.Events.User
+{
+ ///
+ /// User disabled
+ ///
+ public class UserDisabledEvent : DomainEvent
+ {
+ ///
+ /// Get the user id
+ ///
+ public Guid UserId { get; private set; }
+
+ ///
+ /// Construct the event
+ ///
+ /// The user id
+ public UserDisabledEvent(Guid userId)
+ : base(userId, typeof(Models.User))
+ {
+ UserId = userId;
+ }
+
+ ///
+ /// Convert the event to string
+ ///
+ /// The converted string
+ public override string ToString()
+ {
+ return $"{FiredOn} - User {UserId} disabled";
+ }
+ }
+}
diff --git a/src/Wilcommerce.Auth/Events/User/UserEnabledEvent.cs b/src/Wilcommerce.Auth/Events/User/UserEnabledEvent.cs
new file mode 100644
index 0000000..bad6c9b
--- /dev/null
+++ b/src/Wilcommerce.Auth/Events/User/UserEnabledEvent.cs
@@ -0,0 +1,35 @@
+using System;
+using Wilcommerce.Core.Infrastructure;
+
+namespace Wilcommerce.Auth.Events.User
+{
+ ///
+ /// User enabled
+ ///
+ public class UserEnabledEvent : DomainEvent
+ {
+ ///
+ /// Get the user id
+ ///
+ public Guid UserId { get; private set; }
+
+ ///
+ /// Construct the event
+ ///
+ /// The user id
+ public UserEnabledEvent(Guid userId)
+ : base(userId, typeof(Models.User))
+ {
+ UserId = userId;
+ }
+
+ ///
+ /// Convert the event to string
+ ///
+ /// The converted string
+ public override string ToString()
+ {
+ return $"{FiredOn} - User {UserId} enabled";
+ }
+ }
+}
diff --git a/src/Wilcommerce.Auth/Events/User/UserInfoChangedEvent.cs b/src/Wilcommerce.Auth/Events/User/UserInfoChangedEvent.cs
new file mode 100644
index 0000000..7cd4fe3
--- /dev/null
+++ b/src/Wilcommerce.Auth/Events/User/UserInfoChangedEvent.cs
@@ -0,0 +1,41 @@
+using System;
+using Wilcommerce.Core.Common.Models;
+using Wilcommerce.Core.Infrastructure;
+
+namespace Wilcommerce.Auth.Events.User
+{
+ ///
+ /// User information changed
+ ///
+ public class UserInfoChangedEvent : DomainEvent
+ {
+ ///
+ /// Get the user id
+ ///
+ public Guid UserId { get; private set; }
+
+ ///
+ /// Get the user name
+ ///
+ public string Name { get; private set; }
+
+ ///
+ /// Get the user profile image
+ ///
+ public Image ProfileImage { get; private set; }
+
+ ///
+ /// Construct the event
+ ///
+ /// The user id
+ /// The new user name
+ /// The new user profile image
+ public UserInfoChangedEvent(Guid userId, string name, Image profileImage)
+ : base(userId, typeof(Models.User))
+ {
+ UserId = userId;
+ Name = name;
+ ProfileImage = profileImage;
+ }
+ }
+}
diff --git a/src/Wilcommerce.Auth/Events/User/UserPasswordResetEvent.cs b/src/Wilcommerce.Auth/Events/User/UserPasswordResetEvent.cs
new file mode 100644
index 0000000..338c05e
--- /dev/null
+++ b/src/Wilcommerce.Auth/Events/User/UserPasswordResetEvent.cs
@@ -0,0 +1,26 @@
+using System;
+using Wilcommerce.Core.Infrastructure;
+
+namespace Wilcommerce.Auth.Events.User
+{
+ ///
+ /// User password reset
+ ///
+ public class UserPasswordResetEvent : DomainEvent
+ {
+ ///
+ /// Get the user id
+ ///
+ public Guid UserId { get; private set; }
+
+ ///
+ /// Construct the event
+ ///
+ ///
+ public UserPasswordResetEvent(Guid userId)
+ : base(userId, typeof(Models.User))
+ {
+ UserId = userId;
+ }
+ }
+}
diff --git a/src/Wilcommerce.Auth/Events/User/UserSignedInEvent.cs b/src/Wilcommerce.Auth/Events/User/UserSignedInEvent.cs
index ff0ae32..6382c70 100644
--- a/src/Wilcommerce.Auth/Events/User/UserSignedInEvent.cs
+++ b/src/Wilcommerce.Auth/Events/User/UserSignedInEvent.cs
@@ -19,7 +19,7 @@ public class UserSignedInEvent : DomainEvent
/// The user id
/// The username
public UserSignedInEvent(Guid userId, string username)
- : base(userId, typeof(Core.Common.Domain.Models.User))
+ : base(userId, typeof(Models.User))
{
Username = username;
}
diff --git a/src/Wilcommerce.Auth/Extensions/UserManagerExtensions.cs b/src/Wilcommerce.Auth/Extensions/UserManagerExtensions.cs
new file mode 100644
index 0000000..38d06dc
--- /dev/null
+++ b/src/Wilcommerce.Auth/Extensions/UserManagerExtensions.cs
@@ -0,0 +1,29 @@
+using Microsoft.AspNetCore.Identity;
+using System;
+using System.Security.Claims;
+using Wilcommerce.Auth.Models;
+
+namespace Wilcommerce.Auth
+{
+ ///
+ /// Defines the extension methods for the UserManager class
+ ///
+ public static class UserManagerExtensions
+ {
+ ///
+ /// Get the user's full name or the user's name if not exists
+ ///
+ /// The UserManager instance
+ /// The claims principal instance
+ /// The user's full name
+ public static string GetUserFullName(this UserManager userManager, ClaimsPrincipal principal)
+ {
+ if (principal == null)
+ {
+ throw new ArgumentNullException(nameof(principal));
+ }
+
+ return principal.FindFirstValue(ClaimTypes.GivenName) ?? userManager.GetUserName(principal);
+ }
+ }
+}
diff --git a/src/Wilcommerce.Auth/Models/TokenTypes.cs b/src/Wilcommerce.Auth/Models/TokenTypes.cs
deleted file mode 100644
index 35d3ce4..0000000
--- a/src/Wilcommerce.Auth/Models/TokenTypes.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using System;
-using System.Linq;
-using System.Reflection;
-
-namespace Wilcommerce.Auth.Models
-{
- ///
- /// Defines the available token types
- ///
- public static class TokenTypes
- {
- ///
- /// Password recovery token
- ///
- public static string PasswordRecovery => "PASSWORD_RECOVERY";
-
- ///
- /// Registration token
- ///
- public static string Registration => "REGISTRATION";
-
- ///
- /// Check whether the specified type is valid
- ///
- /// The token type to check
- /// true if the type is valid, false otherwise
- public static bool IsValidType(string type)
- {
- if (string.IsNullOrEmpty(type))
- {
- throw new ArgumentNullException("type");
- }
-
- bool isValid = typeof(TokenTypes).GetProperties(BindingFlags.Static).Any(p => p.GetValue(null).ToString() == type);
- return isValid;
- }
- }
-}
diff --git a/src/Wilcommerce.Auth/Models/User.cs b/src/Wilcommerce.Auth/Models/User.cs
new file mode 100644
index 0000000..5174d0e
--- /dev/null
+++ b/src/Wilcommerce.Auth/Models/User.cs
@@ -0,0 +1,162 @@
+using Microsoft.AspNetCore.Identity;
+using System;
+using Wilcommerce.Core.Common.Models;
+using Wilcommerce.Core.Infrastructure;
+
+namespace Wilcommerce.Auth.Models
+{
+ ///
+ /// Represents the user
+ ///
+ public class User : IdentityUser, IAggregateRoot
+ {
+ ///
+ /// Get the user's id in Guid format
+ ///
+ public new Guid Id => Guid.Parse(base.Id);
+
+ #region Constructor
+ ///
+ /// Construct the user
+ ///
+ protected User()
+ : base()
+ {
+ ProfileImage = new Image();
+ }
+ #endregion
+
+ #region Properties
+ ///
+ /// Get or set the user full name
+ ///
+ public string Name { get; protected set; }
+
+ ///
+ /// Get or set the user profile image
+ ///
+ public Image ProfileImage { get; protected set; }
+
+ ///
+ /// Get or set whether the user is active
+ ///
+ public bool IsActive { get; protected set; }
+
+ ///
+ /// Get or set the date and time of when the user was disabled
+ ///
+ public DateTime? DisabledOn { get; set; }
+ #endregion
+
+ #region Behaviors
+ ///
+ /// Enable the user
+ ///
+ public virtual void Enable()
+ {
+ IsActive = true;
+ if (DisabledOn != null)
+ {
+ DisabledOn = null;
+ }
+ }
+
+ ///
+ /// Disable the user
+ ///
+ public virtual void Disable()
+ {
+ IsActive = false;
+ DisabledOn = DateTime.Now;
+ }
+
+ ///
+ /// Change the user's name
+ ///
+ /// The new user's name
+ public virtual void ChangeName(string name)
+ {
+ if (string.IsNullOrWhiteSpace(name))
+ {
+ throw new ArgumentException("value cannot be empty", nameof(name));
+ }
+
+ Name = name;
+ }
+
+ ///
+ /// Set the user's profile image
+ ///
+ /// The profile image to set
+ public virtual void SetProfileImage(Image profileImage)
+ {
+ ProfileImage = profileImage ?? throw new ArgumentNullException(nameof(profileImage));
+ }
+ #endregion
+
+ #region Factory Methods
+ ///
+ /// Creates a new administrator user
+ ///
+ /// The user full name
+ /// The user username
+ /// Whether the user is active
+ /// The created administrator user
+ public static User CreateAsAdministrator(string name, string email, bool active)
+ {
+ if (string.IsNullOrWhiteSpace(name))
+ {
+ throw new ArgumentException("value cannot be empty", nameof(name));
+ }
+
+ if (string.IsNullOrWhiteSpace(email))
+ {
+ throw new ArgumentException("value cannot be empty", nameof(email));
+ }
+
+ var user = new User
+ {
+ UserName = email,
+ Email = email,
+ NormalizedEmail = email.ToUpper(),
+ NormalizedUserName = email.ToUpper(),
+ Name = name,
+ IsActive = active,
+ EmailConfirmed = true
+ };
+
+ return user;
+ }
+
+ ///
+ /// Creates a new customer user
+ ///
+ /// The user full name
+ /// The user username
+ /// The created customer user
+ public static User CreateAsCustomer(string name, string email)
+ {
+ if (string.IsNullOrWhiteSpace(name))
+ {
+ throw new ArgumentException("value cannot be empty", nameof(name));
+ }
+
+ if (string.IsNullOrWhiteSpace(email))
+ {
+ throw new ArgumentException("value cannot be empty", nameof(email));
+ }
+
+ var user = new User
+ {
+ UserName = email,
+ Email = email,
+ NormalizedEmail = email.ToUpper(),
+ NormalizedUserName = email.ToUpper(),
+ Name = name
+ };
+
+ return user;
+ }
+ #endregion
+ }
+}
diff --git a/src/Wilcommerce.Auth/Models/UserToken.cs b/src/Wilcommerce.Auth/Models/UserToken.cs
deleted file mode 100644
index 535b33b..0000000
--- a/src/Wilcommerce.Auth/Models/UserToken.cs
+++ /dev/null
@@ -1,143 +0,0 @@
-using System;
-using Wilcommerce.Core.Common.Domain.Models;
-using Wilcommerce.Core.Infrastructure;
-
-namespace Wilcommerce.Auth.Models
-{
- ///
- /// Represents a token created for a specific user
- ///
- public class UserToken : IAggregateRoot
- {
- ///
- /// Get the entity id
- ///
- public Guid Id { get; protected set; }
-
- #region Properties
- ///
- /// Get the related user id
- ///
- public Guid UserId { get; protected set; }
-
- ///
- /// Get the token type
- ///
- public string TokenType { get; protected set; }
-
- ///
- /// Get the token
- ///
- public string Token { get; protected set; }
-
- ///
- /// Get the date and time of token creation
- ///
- public DateTime CreationDate { get; protected set; }
-
- ///
- /// Get the date and time of token expiration
- ///
- public DateTime ExpirationDate { get; protected set; }
-
- ///
- /// Get whether the token is expired
- ///
- public bool IsExpired { get; protected set; }
- #endregion
-
- #region Public Methods
- ///
- /// Set the current token as expired
- ///
- public virtual void SetAsExpired()
- {
- if (IsExpired)
- {
- throw new InvalidOperationException($"Token already expired on {ExpirationDate.ToString()}");
- }
-
- IsExpired = true;
- ExpirationDate = DateTime.Now;
- }
- #endregion
-
- #region Factory
- ///
- /// Create a new password recovery token
- ///
- /// The user
- /// The token string
- /// The token expiration date
- /// The token created
- public static UserToken PasswordRecovery(User user, string token, DateTime expirationDate)
- {
- if (user == null)
- {
- throw new ArgumentNullException(nameof(user));
- }
-
- if (string.IsNullOrEmpty(token))
- {
- throw new ArgumentNullException(nameof(token));
- }
-
- var now = DateTime.Now;
- if (expirationDate < now)
- {
- throw new ArgumentException("Invalid expiration date", nameof(expirationDate));
- }
-
- var userToken = new UserToken
- {
- UserId = user.Id,
- TokenType = TokenTypes.PasswordRecovery,
- Token = token,
- CreationDate = now,
- ExpirationDate = expirationDate,
- IsExpired = false
- };
-
- return userToken;
- }
-
- ///
- /// Create a new registration token
- ///
- /// The user
- /// The token string
- /// The token expiration date
- /// The token created
- public static UserToken Registration(User user, string token, DateTime expirationDate)
- {
- if (user == null)
- {
- throw new ArgumentNullException("user");
- }
-
- if (string.IsNullOrEmpty(token))
- {
- throw new ArgumentNullException("token");
- }
-
- var now = DateTime.Now;
- if (expirationDate < now)
- {
- throw new ArgumentException("Invalid expiration date", "expirationDate");
- }
-
- var userToken = new UserToken
- {
- UserId = user.Id,
- TokenType = TokenTypes.Registration,
- Token = token,
- CreationDate = now,
- ExpirationDate = expirationDate,
- IsExpired = false
- };
-
- return userToken;
- }
- #endregion
- }
-}
diff --git a/src/Wilcommerce.Auth/ReadModels/Extensions/UserExtensions.cs b/src/Wilcommerce.Auth/ReadModels/Extensions/UserExtensions.cs
new file mode 100644
index 0000000..38a016c
--- /dev/null
+++ b/src/Wilcommerce.Auth/ReadModels/Extensions/UserExtensions.cs
@@ -0,0 +1,36 @@
+using System.Linq;
+using Wilcommerce.Auth.Models;
+
+namespace Wilcommerce.Auth.ReadModels
+{
+ ///
+ /// Defines the extension methods for the user read model
+ ///
+ public static class UserExtensions
+ {
+ ///
+ /// Retrieve all active users
+ ///
+ /// The instance to which attach this method
+ /// A list of users
+ public static IQueryable Actives(this IQueryable users)
+ {
+ return from u in users
+ where u.IsActive && u.DisabledOn == null
+ select u;
+ }
+
+ ///
+ /// Retrieve the users with the specified username
+ ///
+ /// The instance to which attach this method
+ /// The user's username
+ /// A list of users
+ public static IQueryable WithUsername(this IQueryable users, string username)
+ {
+ return from u in users
+ where u.UserName == username
+ select u;
+ }
+ }
+}
diff --git a/src/Wilcommerce.Auth/ReadModels/Extensions/UserTokenExtensions.cs b/src/Wilcommerce.Auth/ReadModels/Extensions/UserTokenExtensions.cs
deleted file mode 100644
index 998974c..0000000
--- a/src/Wilcommerce.Auth/ReadModels/Extensions/UserTokenExtensions.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-using System;
-using System.Linq;
-using Wilcommerce.Auth.Models;
-
-namespace Wilcommerce.Auth.ReadModels
-{
- ///
- /// Defines the extension methods for the read models
- ///
- public static class UserTokenExtensions
- {
- ///
- /// Retrieve all the user tokens by the user id
- ///
- /// The instance to which attach this method
- /// The user id
- /// A list of user tokens
- public static IQueryable ByUser(this IQueryable tokens, Guid userId)
- {
- return from t in tokens
- where t.UserId == userId
- select t;
- }
-
- ///
- /// Retrieve all the expired tokens
- ///
- /// The instance to which attach this method
- /// A list of user tokens
- public static IQueryable Expired(this IQueryable tokens)
- {
- return from t in tokens
- where t.IsExpired || t.ExpirationDate <= DateTime.Now
- select t;
- }
-
- ///
- /// Retrieve all the user tokens which are not expired
- ///
- /// The instance to which attach this method
- /// A list of user tokens
- public static IQueryable NotExpired(this IQueryable tokens)
- {
- return from t in tokens
- where !t.IsExpired && t.ExpirationDate > DateTime.Now
- select t;
- }
-
- ///
- /// Retrieve all the user tokens filtered by the type
- ///
- /// The instance to which attach this method
- /// The token type
- /// A list of user tokens
- public static IQueryable ByTokenType(this IQueryable tokens, string type)
- {
- return from t in tokens
- where t.TokenType == type
- select t;
- }
- }
-}
diff --git a/src/Wilcommerce.Auth/ReadModels/IAuthDatabase.cs b/src/Wilcommerce.Auth/ReadModels/IAuthDatabase.cs
index 803ae8f..8f6968b 100644
--- a/src/Wilcommerce.Auth/ReadModels/IAuthDatabase.cs
+++ b/src/Wilcommerce.Auth/ReadModels/IAuthDatabase.cs
@@ -9,8 +9,8 @@ namespace Wilcommerce.Auth.ReadModels
public interface IAuthDatabase
{
///
- /// Get the tokens created by the platform
+ /// Get the users list
///
- IQueryable Tokens { get; }
+ IQueryable Users { get; }
}
}
diff --git a/src/Wilcommerce.Auth/Repository/IRepository.cs b/src/Wilcommerce.Auth/Repository/IRepository.cs
deleted file mode 100644
index 95a527c..0000000
--- a/src/Wilcommerce.Auth/Repository/IRepository.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace Wilcommerce.Auth.Repository
-{
- ///
- public interface IRepository : Core.Infrastructure.IRepository
- {
- }
-}
diff --git a/src/Wilcommerce.Auth/Services/AuthenticationService.cs b/src/Wilcommerce.Auth/Services/AuthenticationService.cs
index 06489cf..b9c4fb6 100644
--- a/src/Wilcommerce.Auth/Services/AuthenticationService.cs
+++ b/src/Wilcommerce.Auth/Services/AuthenticationService.cs
@@ -1,120 +1,76 @@
using System;
using System.Linq;
using System.Threading.Tasks;
-using Wilcommerce.Core.Common.Domain.Models;
-using Wilcommerce.Core.Common.Domain.ReadModels;
using Microsoft.AspNetCore.Identity;
using Wilcommerce.Auth.Services.Interfaces;
-using Wilcommerce.Auth.Commands.Handlers.Interfaces;
-using Wilcommerce.Auth.Commands;
using Wilcommerce.Core.Infrastructure;
using Wilcommerce.Auth.Events.User;
-using Microsoft.AspNetCore.Http;
+using Wilcommerce.Auth.ReadModels;
+using Wilcommerce.Auth.Models;
using Microsoft.AspNetCore.Authentication;
+using System.Security.Claims;
namespace Wilcommerce.Auth.Services
{
///
- /// Implementation of
+ /// Implementation of
///
public class AuthenticationService : Interfaces.IAuthenticationService
{
- ///
- /// Get the http context
- ///
- public HttpContext Context { get; }
-
///
/// Get the common context database
///
- public ICommonDatabase CommonDatabase { get; }
-
- ///
- /// Get the password hasher service
- ///
- public IPasswordHasher PasswordHasher { get; }
-
- ///
- /// Get the token generator service
- ///
- public ITokenGenerator TokenGenerator { get; }
-
- ///
- /// Get the identity factory
- ///
- public IIdentityFactory IdentityFactory { get; }
+ public IAuthDatabase AuthDatabase { get; }
///
- /// Get the password recovery handler
- ///
- public IRecoverPasswordCommandHandler RecoverPasswordHandler { get; }
-
- ///
- /// Get the password recovery validation handler
+ /// Get the event bus
///
- public IValidatePasswordRecoveryCommandHandler ValidatePasswordRecoveryHandler { get; }
+ public IEventBus EventBus { get; }
///
- /// Get the event bus
+ /// Get the signin manager instance
///
- public IEventBus EventBus { get; }
+ public SignInManager SignInManager { get; }
///
/// Construct the authentication service
///
- /// The http context accessor instance
- /// The common database instance
- /// The password hasher instance
- /// The token generator instance
- /// The password recover handler instance
- /// The password recovery validation handler instance
+ /// The common database instance
/// The event bus instance
- /// The identity factory instance
- public AuthenticationService(IHttpContextAccessor httpContextAccessor, ICommonDatabase commonDatabase, IPasswordHasher passwordHasher, ITokenGenerator tokenGenerator, IRecoverPasswordCommandHandler recoverPasswordHandler, IValidatePasswordRecoveryCommandHandler validatePasswordRecoveryHandler, IEventBus eventBus, IIdentityFactory identityFactory)
+ ///
+ public AuthenticationService(IAuthDatabase authDatabase, IEventBus eventBus, SignInManager signInManager)
{
- if (httpContextAccessor == null)
- {
- throw new ArgumentNullException(nameof(httpContextAccessor));
- }
-
- Context = httpContextAccessor.HttpContext;
- CommonDatabase = commonDatabase ?? throw new ArgumentNullException(nameof(commonDatabase));
- PasswordHasher = passwordHasher ?? throw new ArgumentNullException(nameof(passwordHasher));
- TokenGenerator = tokenGenerator ?? throw new ArgumentNullException(nameof(tokenGenerator));
- RecoverPasswordHandler = recoverPasswordHandler ?? throw new ArgumentNullException(nameof(recoverPasswordHandler));
- ValidatePasswordRecoveryHandler = validatePasswordRecoveryHandler ?? throw new ArgumentNullException(nameof(validatePasswordRecoveryHandler));
+ AuthDatabase = authDatabase ?? throw new ArgumentNullException(nameof(authDatabase));
EventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
- IdentityFactory = identityFactory ?? throw new ArgumentNullException(nameof(identityFactory));
+ SignInManager = signInManager ?? throw new ArgumentNullException(nameof(signInManager));
}
- ///
- public Task SignIn(string email, string password, bool isPersistent)
+ ///
+ /// Implementation of
+ ///
+ ///
+ ///
+ ///
+ ///
+ public virtual async Task SignIn(string email, string password, bool isPersistent)
{
try
{
- var user = CommonDatabase.Users
- .Where(u => u.IsActive && u.DisabledOn == null)
- .FirstOrDefault(u => u.Email == email);
+ var user = AuthDatabase.Users
+ .Actives()
+ .WithUsername(email)
+ .Single();
- if (user == null)
+ var signin = await SignInManager.PasswordSignInAsync(user, password, isPersistent, false);
+ if (signin.Succeeded)
{
- throw new InvalidOperationException($"User {email} not found");
- }
+ var claimsPrincipal = await AddCustomClaimsForUser(user);
+ await RefreshAuthenticationWithClaimsPrincipal(claimsPrincipal, isPersistent);
- if (!IsPasswordValid(user, password))
- {
- throw new InvalidOperationException("Bad credentials");
+ var @event = new UserSignedInEvent(user.Id, user.Email);
+ EventBus.RaiseEvent(@event);
}
- var principal = IdentityFactory.CreateIdentity(user);
- var signin = Context.SignInAsync(
- AuthenticationDefaults.AuthenticationScheme,
- principal,
- new AuthenticationProperties { IsPersistent = isPersistent });
-
- var @event = new UserSignedInEvent(user.Id, user.Email);
- EventBus.RaiseEvent(@event);
-
return signin;
}
catch
@@ -123,12 +79,15 @@ public Task SignIn(string email, string password, bool isPersistent)
}
}
- ///
- public Task SignOut()
+ ///
+ /// Implementation of
+ ///
+ ///
+ public virtual Task SignOut()
{
try
{
- return Context.SignOutAsync(AuthenticationDefaults.AuthenticationScheme);
+ return SignInManager.SignOutAsync();
}
catch
{
@@ -136,61 +95,36 @@ public Task SignOut()
}
}
- ///
- public Task RecoverPassword(string email)
+ #region Protected methods
+ ///
+ /// Add custom claims for the specified user
+ ///
+ /// The current user
+ /// The claims principal for the authenticated user
+ protected virtual async Task AddCustomClaimsForUser(User user)
{
- try
- {
- var user = CommonDatabase.Users
- .Where(u => u.IsActive && u.DisabledOn == null)
- .FirstOrDefault(u => u.Email == email);
+ var claimsPrincipal = await SignInManager.CreateUserPrincipalAsync(user);
+ var claimsIdentity = claimsPrincipal.Identity as ClaimsIdentity;
+ claimsIdentity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()));
+ claimsIdentity.AddClaim(new Claim(ClaimTypes.Email, user.Email));
+ claimsIdentity.AddClaim(new Claim(ClaimTypes.GivenName, user.Name));
- if (user == null)
- {
- throw new InvalidOperationException($"User {email} not found");
- }
-
- var command = new RecoverPasswordCommand(user, TokenGenerator.GenerateForUser(user));
- return RecoverPasswordHandler.Handle(command);
- }
- catch
- {
- throw;
- }
- }
-
- ///
- public Task ValidatePasswordRecovery(string token)
- {
- try
- {
- var command = new ValidatePasswordRecoveryCommand(token);
- return ValidatePasswordRecoveryHandler.Handle(command);
- }
- catch
- {
- throw;
- }
+ return claimsPrincipal;
}
- #region Protected methods
///
- /// Check whether the password is valid
+ /// Refresh the authentication using the specified claims principal
///
- /// The user instance
- /// The password to check
- /// true if the password is valid, false otherwise
- protected virtual bool IsPasswordValid(User user, string password)
+ /// The claims principal instance to perform authentication
+ /// Whether the authentication is persistent
+ ///
+ protected virtual async Task RefreshAuthenticationWithClaimsPrincipal(ClaimsPrincipal claimsPrincipal, bool isPersistent)
{
- try
- {
- var result = PasswordHasher.VerifyHashedPassword(user, user.Password, password);
- return result != PasswordVerificationResult.Failed;
- }
- catch
- {
- throw;
- }
+ await SignInManager.Context.SignOutAsync();
+ await SignInManager.Context.SignInAsync(
+ IdentityConstants.ApplicationScheme,
+ claimsPrincipal,
+ new AuthenticationProperties { IsPersistent = isPersistent });
}
#endregion
}
diff --git a/src/Wilcommerce.Auth/Services/IdentityFactory.cs b/src/Wilcommerce.Auth/Services/IdentityFactory.cs
deleted file mode 100644
index 3f88d6e..0000000
--- a/src/Wilcommerce.Auth/Services/IdentityFactory.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-using System;
-using System.Security.Claims;
-using Wilcommerce.Auth.Services.Interfaces;
-using Wilcommerce.Core.Common.Domain.Models;
-
-namespace Wilcommerce.Auth.Services
-{
- ///
- /// Implementation of
- ///
- public class IdentityFactory : IIdentityFactory
- {
- ///
- public virtual ClaimsPrincipal CreateIdentity(User user)
- {
- try
- {
- if (user == null)
- {
- throw new ArgumentNullException(nameof(user));
- }
-
- var identity = new ClaimsIdentity();
- identity.AddClaim(new Claim(ClaimTypes.Name, user.Email));
- identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()));
- identity.AddClaim(new Claim(ClaimTypes.Email, user.Email));
- identity.AddClaim(new Claim(ClaimTypes.Role, GetUserRoleAsString(user)));
- identity.AddClaim(new Claim(ClaimTypes.GivenName, user.Name));
-
- return new ClaimsPrincipal(identity);
- }
- catch
- {
- throw;
- }
- }
-
- ///
- /// Get the string representing the user's role
- ///
- /// The user instance
- /// The user's role as a string
- protected virtual string GetUserRoleAsString(User user)
- {
- var role = user.Role;
- switch (role)
- {
- case User.Roles.CUSTOMER:
- return AuthenticationDefaults.CustomerRole;
- case User.Roles.ADMINISTRATOR:
- return AuthenticationDefaults.AdministratorRole;
- default:
- return null;
- }
- }
- }
-}
diff --git a/src/Wilcommerce.Auth/Services/Interfaces/IAuthenticationService.cs b/src/Wilcommerce.Auth/Services/Interfaces/IAuthenticationService.cs
index ed8dc27..92a3520 100644
--- a/src/Wilcommerce.Auth/Services/Interfaces/IAuthenticationService.cs
+++ b/src/Wilcommerce.Auth/Services/Interfaces/IAuthenticationService.cs
@@ -1,4 +1,5 @@
-using System.Threading.Tasks;
+using Microsoft.AspNetCore.Identity;
+using System.Threading.Tasks;
namespace Wilcommerce.Auth.Services.Interfaces
{
@@ -14,26 +15,12 @@ public interface IAuthenticationService
/// The password
/// Whether the authentication is persistent
///
- Task SignIn(string username, string password, bool isPersistent);
+ Task SignIn(string username, string password, bool isPersistent);
///
/// Sign out the authenticated user
///
///
Task SignOut();
-
- ///
- /// Perform the password recovery request
- ///
- ///
- ///
- Task RecoverPassword(string email);
-
- ///
- /// Validate the password recovery request by the specified token
- ///
- ///
- ///
- Task ValidatePasswordRecovery(string token);
}
}
diff --git a/src/Wilcommerce.Auth/Services/Interfaces/IIdentityFactory.cs b/src/Wilcommerce.Auth/Services/Interfaces/IIdentityFactory.cs
deleted file mode 100644
index 6e89690..0000000
--- a/src/Wilcommerce.Auth/Services/Interfaces/IIdentityFactory.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System.Security.Claims;
-using Wilcommerce.Core.Common.Domain.Models;
-
-namespace Wilcommerce.Auth.Services.Interfaces
-{
- ///
- /// Represents the factory to create the indentity
- ///
- public interface IIdentityFactory
- {
- ///
- /// Create the claims principal by the user
- ///
- /// The user for which creates the identity
- /// The claims principal
- ClaimsPrincipal CreateIdentity(User user);
- }
-}
diff --git a/src/Wilcommerce.Auth/Services/Interfaces/IRoleFactory.cs b/src/Wilcommerce.Auth/Services/Interfaces/IRoleFactory.cs
new file mode 100644
index 0000000..a686220
--- /dev/null
+++ b/src/Wilcommerce.Auth/Services/Interfaces/IRoleFactory.cs
@@ -0,0 +1,23 @@
+using Microsoft.AspNetCore.Identity;
+using System.Threading.Tasks;
+
+namespace Wilcommerce.Auth.Services.Interfaces
+{
+ ///
+ /// Represents the factory to create the available roles
+ ///
+ public interface IRoleFactory
+ {
+ ///
+ /// Create an administrator role if not exists and returns it
+ ///
+ /// The administrator role
+ Task Administrator();
+
+ ///
+ /// Create a customer role if not exists and returns it
+ ///
+ /// The customer role
+ Task Customer();
+ }
+}
diff --git a/src/Wilcommerce.Auth/Services/Interfaces/ITokenGenerator.cs b/src/Wilcommerce.Auth/Services/Interfaces/ITokenGenerator.cs
index bed1ddf..f155c76 100644
--- a/src/Wilcommerce.Auth/Services/Interfaces/ITokenGenerator.cs
+++ b/src/Wilcommerce.Auth/Services/Interfaces/ITokenGenerator.cs
@@ -1,4 +1,5 @@
-using Wilcommerce.Core.Common.Domain.Models;
+using System.Threading.Tasks;
+using Wilcommerce.Auth.Models;
namespace Wilcommerce.Auth.Services.Interfaces
{
@@ -8,10 +9,17 @@ namespace Wilcommerce.Auth.Services.Interfaces
public interface ITokenGenerator
{
///
- /// Generate a token string for the specified user
+ /// Generate an email confirmation token string for the specified user
///
/// The current user
/// The token string
- string GenerateForUser(User user);
+ Task GenerateEmailConfirmationTokenForUser(User user);
+
+ ///
+ /// Generate a password recovery token string for the specified user
+ ///
+ /// The current user
+ /// The token string
+ Task GeneratePasswordRecoveryTokenForUser(User user);
}
}
diff --git a/src/Wilcommerce.Auth/Services/RoleFactory.cs b/src/Wilcommerce.Auth/Services/RoleFactory.cs
new file mode 100644
index 0000000..08248c3
--- /dev/null
+++ b/src/Wilcommerce.Auth/Services/RoleFactory.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Identity;
+using Wilcommerce.Auth.Services.Interfaces;
+
+namespace Wilcommerce.Auth.Services
+{
+ ///
+ /// Implementation of
+ ///
+ public class RoleFactory : IRoleFactory
+ {
+ private readonly RoleManager _roleManager;
+
+ ///
+ /// Construct the role factory
+ ///
+ /// The role manager instance
+ public RoleFactory(RoleManager roleManager)
+ {
+ _roleManager = roleManager ?? throw new ArgumentNullException(nameof(roleManager));
+ }
+
+ ///
+ /// Implementation of
+ ///
+ ///
+ public virtual async Task Administrator()
+ {
+ return await CreateRoleIfNotExists(AuthenticationDefaults.CustomerRole);
+ }
+
+ ///
+ /// Implementation of
+ ///
+ ///
+ public virtual async Task Customer()
+ {
+ return await CreateRoleIfNotExists(AuthenticationDefaults.CustomerRole);
+ }
+
+ #region Protected Methods
+ ///
+ /// Create the role with the specified name if not exists and returns it
+ ///
+ /// The role name
+ /// The role instance
+ protected virtual async Task CreateRoleIfNotExists(string roleName)
+ {
+ var role = await _roleManager.FindByNameAsync(roleName);
+ if (role == null)
+ {
+ return new IdentityRole(roleName);
+ }
+
+ return role;
+ }
+ #endregion
+ }
+}
diff --git a/src/Wilcommerce.Auth/Services/TokenGenerator.cs b/src/Wilcommerce.Auth/Services/TokenGenerator.cs
index f7d73f9..a070072 100644
--- a/src/Wilcommerce.Auth/Services/TokenGenerator.cs
+++ b/src/Wilcommerce.Auth/Services/TokenGenerator.cs
@@ -1,7 +1,8 @@
using System;
-using System.Text;
using Wilcommerce.Auth.Services.Interfaces;
-using Wilcommerce.Core.Common.Domain.Models;
+using Wilcommerce.Auth.Models;
+using Microsoft.AspNetCore.Identity;
+using System.Threading.Tasks;
namespace Wilcommerce.Auth.Services
{
@@ -10,13 +11,54 @@ namespace Wilcommerce.Auth.Services
///
public class TokenGenerator : ITokenGenerator
{
- ///
- public string GenerateForUser(User user)
+ private readonly UserManager _userManager;
+
+ ///
+ /// Construct the token generator class
+ ///
+ /// The identity user manager
+ public TokenGenerator(UserManager userManager)
+ {
+ _userManager = userManager ?? throw new ArgumentNullException(nameof(userManager));
+ }
+
+ ///
+ /// Implementation of
+ ///
+ ///
+ ///
+ public virtual async Task GenerateEmailConfirmationTokenForUser(User user)
+ {
+ try
+ {
+ if (user == null)
+ {
+ throw new ArgumentNullException(nameof(user));
+ }
+
+ return await _userManager.GenerateEmailConfirmationTokenAsync(user);
+ }
+ catch
+ {
+ throw;
+ }
+ }
+
+ ///
+ /// Implementation of
+ ///
+ ///
+ ///
+ public virtual async Task GeneratePasswordRecoveryTokenForUser(User user)
{
try
{
- var tokenBytes = Encoding.UTF8.GetBytes($"{user.Email}{Guid.NewGuid().ToString("N")}");
- return Convert.ToBase64String(tokenBytes);
+ if (user == null)
+ {
+ throw new ArgumentNullException(nameof(user));
+ }
+
+ return await _userManager.GeneratePasswordResetTokenAsync(user);
}
catch
{
diff --git a/src/Wilcommerce.Auth/Wilcommerce.Auth.csproj b/src/Wilcommerce.Auth/Wilcommerce.Auth.csproj
index c482d9c..9674da2 100644
--- a/src/Wilcommerce.Auth/Wilcommerce.Auth.csproj
+++ b/src/Wilcommerce.Auth/Wilcommerce.Auth.csproj
@@ -15,7 +15,7 @@
false
false
false
- 1.0.0-rc4
+ 1.0.0-rc5
Wilcommerce Authentication and Authorization library
@@ -29,15 +29,12 @@
-
-
-
-
-
+
-
+
+
-
+