Compare commits

..

No commits in common. "3ccd3106c14ac735150e65399ccfdda320d62eb5" and "12efc92ac4605a8c68783f217d64c1f33bf08dd1" have entirely different histories.

17 changed files with 157 additions and 128 deletions

View File

@ -1,5 +1,6 @@
using DotBased.AspNet.Authority.Crypto; using DotBased.AspNet.Authority.Crypto;
using DotBased.AspNet.Authority.Managers; using DotBased.AspNet.Authority.Managers;
using DotBased.AspNet.Authority.Models.Authority;
using DotBased.AspNet.Authority.Models.Options; using DotBased.AspNet.Authority.Models.Options;
using DotBased.AspNet.Authority.Validators; using DotBased.AspNet.Authority.Validators;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -10,6 +11,10 @@ namespace DotBased.AspNet.Authority;
public static class AuthorityProviderExtensions public static class AuthorityProviderExtensions
{ {
public static AuthorityBuilder AddAuthority(this IServiceCollection services, Action<AuthorityOptions>? optionsAction = null) public static AuthorityBuilder AddAuthority(this IServiceCollection services, Action<AuthorityOptions>? optionsAction = null)
=> services.AddAuthority<AuthorityUser, AuthorityGroup, AuthorityRole>(optionsAction);
public static AuthorityBuilder AddAuthority<TUser, TGroup, TRole>(this IServiceCollection services, Action<AuthorityOptions>? optionsAction = null)
where TUser : class where TGroup : class where TRole : class
{ {
if (optionsAction != null) if (optionsAction != null)
{ {
@ -19,13 +24,16 @@ public static class AuthorityProviderExtensions
services.TryAddScoped<ICryptographer, Cryptographer>(); services.TryAddScoped<ICryptographer, Cryptographer>();
services.TryAddScoped<IPasswordHasher, PasswordHasher>(); services.TryAddScoped<IPasswordHasher, PasswordHasher>();
services.TryAddScoped<IPasswordValidator, PasswordOptionsValidator>(); services.TryAddScoped<IPasswordValidator<TUser>, PasswordOptionsValidator<TUser>>();
services.TryAddScoped<IPasswordValidator, PasswordEqualsValidator>(); services.TryAddScoped<IPasswordValidator<TUser>, PasswordEqualsValidator<TUser>>();
services.TryAddScoped<IUserValidator, UserValidator>(); services.TryAddScoped<IUserValidator<TUser>, UserValidator<TUser>>();
/*services.TryAddScoped<IEmailVerifier, EmailVerifier>(); /*services.TryAddScoped<IEmailVerifier, EmailVerifier>();
services.TryAddScoped<IPhoneNumberVerifier, PhoneNumberVerifier>(); services.TryAddScoped<IPhoneNumberVerifier, PhoneNumberVerifier>();
services.TryAddScoped<IUserVerifier, UserVerifier>();*/ services.TryAddScoped<IUserVerifier, UserVerifier>();*/
services.TryAddScoped<AuthorityManager>(); services.TryAddScoped<AuthorityManager>();
services.TryAddScoped<AuthorityUserManager<TUser>>();
services.TryAddScoped<AuthorityGroupManager<TGroup>>();
services.TryAddScoped<AuthorityRoleManager<TRole>>();
return new AuthorityBuilder(services); return new AuthorityBuilder(services);
} }

View File

@ -1,6 +1,6 @@
namespace DotBased.AspNet.Authority.Managers; namespace DotBased.AspNet.Authority.Managers;
public partial class AuthorityManager public class AuthorityGroupManager<TGroup>
{ {
} }

View File

@ -2,30 +2,22 @@ using System.Reflection;
using DotBased.AspNet.Authority.Attributes; using DotBased.AspNet.Authority.Attributes;
using DotBased.AspNet.Authority.Crypto; using DotBased.AspNet.Authority.Crypto;
using DotBased.AspNet.Authority.Models.Options; using DotBased.AspNet.Authority.Models.Options;
using DotBased.AspNet.Authority.Repositories;
using DotBased.AspNet.Authority.Validators;
using DotBased.Logging; using DotBased.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
namespace DotBased.AspNet.Authority.Managers; namespace DotBased.AspNet.Authority.Managers;
public partial class AuthorityManager public class AuthorityManager
{ {
public AuthorityManager( public AuthorityManager(
IOptions<AuthorityOptions> options, IOptions<AuthorityOptions> options,
IServiceProvider services, IServiceProvider services,
ICryptographer cryptographer, ICryptographer cryptographer)
IUserRepository userRepository,
IRoleRepository roleRepository,
IPasswordHasher passwordHasher)
{ {
_logger = LogService.RegisterLogger<AuthorityManager>(); _logger = LogService.RegisterLogger<AuthorityManager>();
Options = options.Value; Options = options.Value ?? new AuthorityOptions();
Services = services; Services = services;
Cryptographer = cryptographer; Cryptographer = cryptographer;
UserRepository = userRepository;
RoleRepository = roleRepository;
PasswordHasher = passwordHasher;
} }
private readonly ILogger _logger; private readonly ILogger _logger;
@ -34,14 +26,6 @@ public partial class AuthorityManager
public AuthorityOptions Options { get; } public AuthorityOptions Options { get; }
public ICryptographer Cryptographer { get; } public ICryptographer Cryptographer { get; }
public IUserRepository UserRepository { get; }
public IRoleRepository RoleRepository { get; }
public IPasswordHasher PasswordHasher { get; }
public IEnumerable<IPasswordValidator> PasswordValidators { get; } = [];
public IEnumerable<IUserValidator> UserValidators { get; } = [];
public long GenerateVersion() => DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); public long GenerateVersion() => DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
@ -54,7 +38,12 @@ public partial class AuthorityManager
/// <typeparam name="TModel">The class with the properties to protect.</typeparam> /// <typeparam name="TModel">The class with the properties to protect.</typeparam>
public async Task HandlePropertyProtection<TModel>(TModel data, bool protection) public async Task HandlePropertyProtection<TModel>(TModel data, bool protection)
{ {
var props = GetProtectedPropertiesValues(data); var props = GetProtectedPropertiesValues<TModel>(data);
if (Cryptographer == null)
{
_logger.Warning("No cryptographer specified! Cannot encrypt/decrypt properties.");
return;
}
if (props.Count == 0) if (props.Count == 0)
{ {
return; return;

View File

@ -1,34 +1,6 @@
using DotBased.AspNet.Authority.Models.Authority;
namespace DotBased.AspNet.Authority.Managers; namespace DotBased.AspNet.Authority.Managers;
public partial class AuthorityManager public class AuthorityRoleManager<TRole>
{
public async Task<Result<AuthorityRole>> CreateRoleAsync(AuthorityRole role, CancellationToken? cancellationToken = null)
{
return Result<AuthorityRole>.Failed("Not implemented!");
}
public async Task<Result> DeleteRoleAsync(AuthorityRole role, CancellationToken? cancellationToken = null)
{
return Result.Failed("Not implemented!");
}
public async Task<Result<AuthorityRole>> UpdateRoleAsync(AuthorityRole role, CancellationToken? cancellationToken = null)
{
return Result<AuthorityRole>.Failed("Not implemented!");
}
public async Task AddRoleToUserAsync(AuthorityUser user, AuthorityRole role, CancellationToken? cancellationToken = null)
{ {
} }
public async Task RemoveRoleFromUserAsync(AuthorityRole role, AuthorityUser user, CancellationToken? cancellationToken = null)
{
}
public async Task AddRoleToGroupAsync(AuthorityRole role, AuthorityGroup group, CancellationToken? cancellationToken = null)
{
}
}

View File

@ -1,12 +1,42 @@
using DotBased.AspNet.Authority.Crypto;
using DotBased.AspNet.Authority.Models; using DotBased.AspNet.Authority.Models;
using DotBased.AspNet.Authority.Models.Authority; using DotBased.AspNet.Authority.Models.Authority;
using DotBased.AspNet.Authority.Models.Validation; using DotBased.AspNet.Authority.Models.Validation;
using DotBased.AspNet.Authority.Repositories;
using DotBased.AspNet.Authority.Validators;
using DotBased.Logging;
namespace DotBased.AspNet.Authority.Managers; namespace DotBased.AspNet.Authority.Managers;
public partial class AuthorityManager public class AuthorityUserManager<TUser> where TUser : class
{ {
public async Task<ValidationResult> ValidatePasswordAsync(AuthorityUser user, string password) public AuthorityUserManager(
AuthorityManager manager,
IUserRepository<TUser> userRepository,
IPasswordHasher passwordHasher,
IEnumerable<IPasswordValidator<TUser>>? passwordValidators,
IEnumerable<IUserValidator<TUser>>? userValidators)
{
_logger = LogService.RegisterLogger<AuthorityUserManager<TUser>>();
AuthorityManager = manager;
UserRepository = userRepository;
PasswordHasher = passwordHasher;
if (passwordValidators != null)
PasswordValidators = passwordValidators;
if (userValidators != null)
UserValidators = userValidators;
}
private readonly ILogger _logger;
public AuthorityManager AuthorityManager { get; }
public IUserRepository<TUser> UserRepository { get; }
public IPasswordHasher PasswordHasher { get; }
public IEnumerable<IPasswordValidator<TUser>> PasswordValidators { get; } = [];
public IEnumerable<IUserValidator<TUser>> UserValidators { get; } = [];
public async Task<ValidationResult> ValidatePasswordAsync(TUser user, string password)
{ {
List<ValidationError> errors = []; List<ValidationError> errors = [];
foreach (var validator in PasswordValidators) foreach (var validator in PasswordValidators)
@ -20,7 +50,7 @@ public partial class AuthorityManager
return errors.Count > 0 ? ValidationResult.Failed(errors) : ValidationResult.Ok(); return errors.Count > 0 ? ValidationResult.Failed(errors) : ValidationResult.Ok();
} }
public async Task<ValidationResult> ValidateUserAsync(AuthorityUser user) public async Task<ValidationResult> ValidateUserAsync(TUser user)
{ {
List<ValidationError> errors = []; List<ValidationError> errors = [];
foreach (var userValidator in UserValidators) foreach (var userValidator in UserValidators)
@ -34,31 +64,41 @@ public partial class AuthorityManager
return errors.Count > 0 ? ValidationResult.Failed(errors) : ValidationResult.Ok(); return errors.Count > 0 ? ValidationResult.Failed(errors) : ValidationResult.Ok();
} }
public async Task<ListResult<AuthorityUser>> SearchUsersAsync(string query, int maxResults = 20, int offset = 0, CancellationToken? cancellationToken = null) public async Task<ListResult<TUser>> SearchUsersAsync(string query, int maxResults = 20, int offset = 0)
{ {
var searchResult = await UserRepository.GetAuthorityUsersAsync(query, maxResults, offset, cancellationToken); var searchResult = await UserRepository.GetUsersAsync(query, maxResults, offset);
return searchResult.Item1 == null ? ListResult<AuthorityUser>.Failed("No results!") : ListResult<AuthorityUser>.Ok(searchResult.Item1, searchResult.Item2); return searchResult.Item1 == null ? ListResult<TUser>.Failed("No results!") : ListResult<TUser>.Ok(searchResult.Item1, searchResult.Item2);
} }
public async Task<AuthorityResult<AuthorityUser>> UpdatePasswordAsync(AuthorityUser user, string password, CancellationToken? cancellationToken = null) public async Task<AuthorityResult<TUser>> UpdatePasswordAsync(TUser user, string password)
{ {
if (user is not AuthorityUserBase userBase)
{
return AuthorityResult<TUser>.Error($"Given user is not of base type {nameof(AuthorityUserBase)}!");
}
var passwordValidation = await ValidatePasswordAsync(user, password); var passwordValidation = await ValidatePasswordAsync(user, password);
if (!passwordValidation.Success) if (!passwordValidation.Success)
{ {
List<ValidationError> errors = []; List<ValidationError> errors = [];
errors.AddRange(passwordValidation.Errors); errors.AddRange(passwordValidation.Errors);
return AuthorityResult<AuthorityUser>.Failed(errors, ResultFailReason.Validation); return AuthorityResult<TUser>.Failed(errors, ResultFailReason.Validation);
} }
user.PasswordHash = await PasswordHasher.HashPasswordAsync(password); userBase.PasswordHash = await PasswordHasher.HashPasswordAsync(password);
user.SecurityVersion = GenerateVersion(); userBase.SecurityVersion = AuthorityManager.GenerateVersion();
var updateResult = await UserRepository.UpdateUserAsync(user, cancellationToken); var updateResult = await UserRepository.UpdateUserAsync(user);
return updateResult == null ? AuthorityResult<AuthorityUser>.Error("Failed to save updates!") : AuthorityResult<AuthorityUser>.Ok(updateResult); return updateResult == null ? AuthorityResult<TUser>.Error("Failed to save updates!") : AuthorityResult<TUser>.Ok(updateResult);
} }
public async Task<AuthorityResult<AuthorityUser>> CreateUserAsync(AuthorityUser userModel, string password, CancellationToken? cancellationToken = null) public async Task<AuthorityResult<TUser>> CreateUserAsync(TUser userModel, string password)
{ {
if (userModel is not AuthorityUserBase userBase)
{
return AuthorityResult<TUser>.Error($"Given user is not of base type {nameof(AuthorityUserBase)}!");
}
var userValidation = await ValidateUserAsync(userModel); var userValidation = await ValidateUserAsync(userModel);
var passwordValidation = await ValidatePasswordAsync(userModel, password); var passwordValidation = await ValidatePasswordAsync(userModel, password);
if (!userValidation.Success || !passwordValidation.Success) if (!userValidation.Success || !passwordValidation.Success)
@ -66,30 +106,30 @@ public partial class AuthorityManager
List<ValidationError> errors = []; List<ValidationError> errors = [];
errors.AddRange(userValidation.Errors); errors.AddRange(userValidation.Errors);
errors.AddRange(passwordValidation.Errors); errors.AddRange(passwordValidation.Errors);
return AuthorityResult<AuthorityUser>.Failed(errors, ResultFailReason.Validation); return AuthorityResult<TUser>.Failed(errors, ResultFailReason.Validation);
} }
userModel.Version = GenerateVersion(); userBase.Version = AuthorityManager.GenerateVersion();
userModel.SecurityVersion = GenerateVersion(); userBase.SecurityVersion = AuthorityManager.GenerateVersion();
var hashedPassword = await PasswordHasher.HashPasswordAsync(password); var hashedPassword = await PasswordHasher.HashPasswordAsync(password);
userModel.PasswordHash = hashedPassword; userBase.PasswordHash = hashedPassword;
var userCreationResult = await UserRepository.CreateUserAsync(userModel, cancellationToken); var userCreationResult = await UserRepository.CreateUserAsync(userModel);
return userCreationResult != null return userCreationResult != null
? AuthorityResult<AuthorityUser>.Ok(userCreationResult) ? AuthorityResult<TUser>.Ok(userCreationResult)
: AuthorityResult<AuthorityUser>.Error("Failed to create user in repository!"); : AuthorityResult<TUser>.Error("Failed to create user in repository!");
} }
public async Task<Result<AuthorityUser>> UpdateUserAsync(AuthorityUser model, CancellationToken? cancellationToken = null) public async Task<Result<TUser>> UpdateUserAsync(TUser model)
{ {
var updateResult = await UserRepository.UpdateUserAsync(model, cancellationToken); var updateResult = await UserRepository.UpdateUserAsync(model);
return updateResult != null ? Result<AuthorityUser>.Ok(updateResult) : Result<AuthorityUser>.Failed("Failed to update user in repository!"); return updateResult != null ? Result<TUser>.Ok(updateResult) : Result<TUser>.Failed("Failed to update user in repository!");
} }
public async Task<bool> DeleteUserAsync(AuthorityUser model, CancellationToken? cancellationToken = null) public async Task<bool> DeleteUserAsync(TUser model)
{ {
var deleteResult = await UserRepository.DeleteUserAsync(model, cancellationToken); var deleteResult = await UserRepository.DeleteUserAsync(model);
return deleteResult; return deleteResult;
} }

View File

@ -1,6 +1,6 @@
namespace DotBased.AspNet.Authority.Models.Authority; namespace DotBased.AspNet.Authority.Models.Authority;
public class AuthorityGroup public class AuthorityGroup : AuthorityGroup<Guid>
{ {
public AuthorityGroup(string name) : this() public AuthorityGroup(string name) : this()
{ {
@ -12,8 +12,11 @@ public class AuthorityGroup
Id = Guid.NewGuid(); Id = Guid.NewGuid();
CreatedDate = DateTime.Now; CreatedDate = DateTime.Now;
} }
}
public Guid Id { get; set; } public abstract class AuthorityGroup<TKey> where TKey : IEquatable<TKey>
{
public TKey Id { get; set; }
public string? Name { get; set; } public string? Name { get; set; }

View File

@ -1,6 +1,6 @@
namespace DotBased.AspNet.Authority.Models.Authority; namespace DotBased.AspNet.Authority.Models.Authority;
public abstract class AuthorityRole public class AuthorityRole : AuthorityRole<Guid>
{ {
public AuthorityRole(string name) : this() public AuthorityRole(string name) : this()
{ {
@ -12,8 +12,11 @@ public abstract class AuthorityRole
Id = Guid.NewGuid(); Id = Guid.NewGuid();
CreatedDate = DateTime.Now; CreatedDate = DateTime.Now;
} }
}
public Guid Id { get; set; } public abstract class AuthorityRole<TKey> where TKey : IEquatable<TKey>
{
public TKey Id { get; set; }
public string? Name { get; set; } public string? Name { get; set; }

View File

@ -2,7 +2,7 @@ using DotBased.AspNet.Authority.Attributes;
namespace DotBased.AspNet.Authority.Models.Authority; namespace DotBased.AspNet.Authority.Models.Authority;
public class AuthorityUser public class AuthorityUser : AuthorityUser<Guid>
{ {
public AuthorityUser(string userName) : this() public AuthorityUser(string userName) : this()
{ {
@ -14,9 +14,15 @@ public class AuthorityUser
Id = Guid.NewGuid(); Id = Guid.NewGuid();
CreatedDate = DateTime.Now; CreatedDate = DateTime.Now;
} }
}
public Guid Id { get; set; } public abstract class AuthorityUser<TKey> : AuthorityUserBase where TKey : IEquatable<TKey>
{
public TKey Id { get; set; }
}
public abstract class AuthorityUserBase
{
public bool Enabled { get; set; } public bool Enabled { get; set; }
public bool Confirmed { get; set; } public bool Confirmed { get; set; }

View File

@ -1,6 +1,6 @@
namespace DotBased.AspNet.Authority.Repositories; namespace DotBased.AspNet.Authority.Repositories;
public interface IAttributeRepository public interface IAttributeRepository<TAttribute, TId> where TAttribute : class where TId : IEquatable<TId>
{ {
} }

View File

@ -1,6 +1,6 @@
namespace DotBased.AspNet.Authority.Repositories; namespace DotBased.AspNet.Authority.Repositories;
public interface IGroupRepository public interface IGroupRepository<TGroup> where TGroup : class
{ {
} }

View File

@ -1,6 +1,6 @@
namespace DotBased.AspNet.Authority.Repositories; namespace DotBased.AspNet.Authority.Repositories;
public interface IRoleRepository public interface IRoleRepository<TRole, TId> where TRole : class where TId : IEquatable<TId>
{ {
} }

View File

@ -1,18 +1,16 @@
using DotBased.AspNet.Authority.Models.Authority;
namespace DotBased.AspNet.Authority.Repositories; namespace DotBased.AspNet.Authority.Repositories;
public interface IUserRepository public interface IUserRepository<TUser> where TUser : class
{ {
public Task<AuthorityUser?> GetAuthorityUserByIdAsync(string id, CancellationToken? cancellationToken = null); public Task<TUser?> GetUserByIdAsync(string id, CancellationToken? cancellationToken = null);
public Task<string> GetAuthorityUserIdAsync(AuthorityUser user, CancellationToken? cancellationToken = null); public Task<string> GetUserIdAsync(TUser user, CancellationToken? cancellationToken = null);
public Task<Tuple<List<AuthorityUser>?, int>> GetAuthorityUsersAsync(string query, int maxResults = 20, int offset = 0, CancellationToken? cancellationToken = null); public Task<Tuple<List<TUser>?, int>> GetUsersAsync(string query, int maxResults = 20, int offset = 0, CancellationToken? cancellationToken = null);
public Task<AuthorityUser?> GetAuthorityUserByEmailAsync(string email, CancellationToken? cancellationToken = null); public Task<TUser?> GetUserByEmailAsync(string email, CancellationToken? cancellationToken = null);
public Task SetVersionAsync(AuthorityUser user, long version, CancellationToken? cancellationToken = null); public Task SetVersionAsync(TUser user, long version, CancellationToken? cancellationToken = null);
public Task<long> GetVersionAsync(AuthorityUser user, CancellationToken? cancellationToken = null); public Task<long> GetVersionAsync(TUser user, CancellationToken? cancellationToken = null);
public Task SetSecurityVersionAsync(AuthorityUser user, long version, CancellationToken? cancellationToken = null); public Task SetSecurityVersionAsync(TUser user, long version, CancellationToken? cancellationToken = null);
public Task<long> GetSecurityVersionAsync(AuthorityUser user, CancellationToken? cancellationToken = null); public Task<long> GetSecurityVersionAsync(TUser user, CancellationToken? cancellationToken = null);
public Task<AuthorityUser?> CreateUserAsync(AuthorityUser user, CancellationToken? cancellationToken = null); public Task<TUser?> CreateUserAsync(TUser user, CancellationToken? cancellationToken = null);
public Task<AuthorityUser?> UpdateUserAsync(AuthorityUser user, CancellationToken? cancellationToken = null); public Task<TUser?> UpdateUserAsync(TUser user, CancellationToken? cancellationToken = null);
public Task<bool> DeleteUserAsync(AuthorityUser user, CancellationToken? cancellationToken = null); public Task<bool> DeleteUserAsync(TUser user, CancellationToken? cancellationToken = null);
} }

View File

@ -1,10 +1,9 @@
using DotBased.AspNet.Authority.Managers; using DotBased.AspNet.Authority.Managers;
using DotBased.AspNet.Authority.Models.Authority;
using DotBased.AspNet.Authority.Models.Validation; using DotBased.AspNet.Authority.Models.Validation;
namespace DotBased.AspNet.Authority.Validators; namespace DotBased.AspNet.Authority.Validators;
public interface IPasswordValidator public interface IPasswordValidator<TUser> where TUser : class
{ {
public Task<ValidationResult> ValidatePasswordAsync(AuthorityManager manager, AuthorityUser user, string password); public Task<ValidationResult> ValidatePasswordAsync(AuthorityUserManager<TUser> userManager, TUser user, string password);
} }

View File

@ -1,10 +1,9 @@
using DotBased.AspNet.Authority.Managers; using DotBased.AspNet.Authority.Managers;
using DotBased.AspNet.Authority.Models.Authority;
using DotBased.AspNet.Authority.Models.Validation; using DotBased.AspNet.Authority.Models.Validation;
namespace DotBased.AspNet.Authority.Validators; namespace DotBased.AspNet.Authority.Validators;
public interface IUserValidator public interface IUserValidator<TUser> where TUser : class
{ {
public Task<ValidationResult> ValidateUserAsync(AuthorityManager manager, AuthorityUser user); public Task<ValidationResult> ValidateUserAsync(AuthorityUserManager<TUser> manager, TUser user);
} }

View File

@ -4,15 +4,20 @@ using DotBased.AspNet.Authority.Models.Validation;
namespace DotBased.AspNet.Authority.Validators; namespace DotBased.AspNet.Authority.Validators;
public class PasswordEqualsValidator : IPasswordValidator public class PasswordEqualsValidator<TUser> : IPasswordValidator<TUser> where TUser : class
{ {
private const string ValidatorId = "Authority.Validator.Password.Equals"; private const string ValidatorId = "Authority.Validator.Password.Equals";
private const string ValidationBase = "Authority.Validation.Password"; private const string ValidationBase = "Authority.Validation.Password";
public async Task<ValidationResult> ValidatePasswordAsync(AuthorityManager userManager, AuthorityUser user, string password) public async Task<ValidationResult> ValidatePasswordAsync(AuthorityUserManager<TUser> userManager, TUser user, string password)
{ {
if (user is not AuthorityUserBase authorityUser)
{
throw new ArgumentException($"User is not type of {nameof(AuthorityUserBase)}!", nameof(user));
}
List<ValidationError> errors = []; List<ValidationError> errors = [];
var hashedPassword = await userManager.PasswordHasher.HashPasswordAsync(password); var hashedPassword = await userManager.PasswordHasher.HashPasswordAsync(password);
if (user.PasswordHash != null && user.PasswordHash.Equals(hashedPassword, StringComparison.Ordinal)) if (authorityUser.PasswordHash != null && authorityUser.PasswordHash.Equals(hashedPassword, StringComparison.Ordinal))
{ {
errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.InUse", "User uses this password already!")); errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.InUse", "User uses this password already!"));
} }

View File

@ -1,5 +1,4 @@
using DotBased.AspNet.Authority.Managers; using DotBased.AspNet.Authority.Managers;
using DotBased.AspNet.Authority.Models.Authority;
using DotBased.AspNet.Authority.Models.Validation; using DotBased.AspNet.Authority.Models.Validation;
using DotBased.Extensions; using DotBased.Extensions;
@ -8,18 +7,19 @@ namespace DotBased.AspNet.Authority.Validators;
/// <summary> /// <summary>
/// Validates the password against the options that is configured. /// Validates the password against the options that is configured.
/// </summary> /// </summary>
public class PasswordOptionsValidator : IPasswordValidator /// <typeparam name="TUser">The user model used.</typeparam>
public class PasswordOptionsValidator<TUser> : IPasswordValidator<TUser> where TUser : class
{ {
private const string ValidatorId = "Authority.Validator.Password.Options"; private const string ValidatorId = "Authority.Validator.Password.Options";
private const string ValidationBase = "Authority.Validation.Password"; private const string ValidationBase = "Authority.Validation.Password";
public async Task<ValidationResult> ValidatePasswordAsync(AuthorityManager userManager, AuthorityUser user, string password) public async Task<ValidationResult> ValidatePasswordAsync(AuthorityUserManager<TUser> userManager, TUser user, string password)
{ {
if (userManager == null) if (userManager == null)
{ {
throw new ArgumentNullException(nameof(userManager), "User manager is not provided!"); throw new ArgumentNullException(nameof(userManager), "User manager is not provided!");
} }
var passwordOptions = userManager.Options.Password; var passwordOptions = userManager.AuthorityManager.Options.Password;
var errors = new List<ValidationError>(); var errors = new List<ValidationError>();
if (password.IsNullOrEmpty() || password.Length < passwordOptions.RequiredLength) if (password.IsNullOrEmpty() || password.Length < passwordOptions.RequiredLength)

View File

@ -5,27 +5,34 @@ using DotBased.AspNet.Authority.Models.Validation;
namespace DotBased.AspNet.Authority.Validators; namespace DotBased.AspNet.Authority.Validators;
public class UserValidator : IUserValidator public class UserValidator<TUser> : IUserValidator<TUser> where TUser : class
{ {
private const string ValidatorId = "Authority.Validator.User"; private const string ValidatorId = "Authority.Validator.User";
private const string ValidationBase = "Authority.Validation.User"; private const string ValidationBase = "Authority.Validation.User";
public async Task<ValidationResult> ValidateUserAsync(AuthorityManager manager, AuthorityUser user) public async Task<ValidationResult> ValidateUserAsync(AuthorityUserManager<TUser> manager, TUser user)
{ {
List<ValidationError> errors = []; List<ValidationError> errors = [];
var userOptions = manager.Options.User; var userOptions = manager.AuthorityManager.Options.User;
if (user is not AuthorityUserBase userBase)
{
errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.NotAuthorityUser",
$"Given user model is not an type of {nameof(AuthorityUserBase)}"));
return ValidationResult.Failed(errors);
}
if (userOptions.RequireUniqueEmail) if (userOptions.RequireUniqueEmail)
{ {
if (string.IsNullOrWhiteSpace(user.EmailAddress)) if (string.IsNullOrWhiteSpace(userBase.EmailAddress))
{ {
errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.NoEmail", errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.NoEmail",
$"Option {nameof(UserOptions.RequireUniqueEmail)} is set to true but given user does not have an email address!")); $"Option {nameof(UserOptions.RequireUniqueEmail)} is set to true but given user does not have an email address!"));
} }
else else
{ {
var userEmailResult = await manager.UserRepository.GetAuthorityUserByEmailAsync(user.EmailAddress); var userEmailResult = await manager.UserRepository.GetUserByEmailAsync(userBase.EmailAddress);
if (userEmailResult != null) if (userEmailResult != null)
{ {
errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.EmailExists", errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.EmailExists",
@ -34,9 +41,9 @@ public class UserValidator : IUserValidator
} }
} }
if (!string.IsNullOrWhiteSpace(user.UserName)) if (!string.IsNullOrWhiteSpace(userBase.UserName))
{ {
if (userOptions.UserNameBlackList.Count != 0 && userOptions.UserNameBlackList.Contains(user.UserName, userOptions.UserNameBlackListComparer)) if (userOptions.UserNameBlackList.Count != 0 && userOptions.UserNameBlackList.Contains(userBase.UserName, userOptions.UserNameBlackListComparer))
{ {
errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.Blacklisted", "Given username is not allowed (blacklisted)")); errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.Blacklisted", "Given username is not allowed (blacklisted)"));
} }
@ -46,11 +53,11 @@ public class UserValidator : IUserValidator
List<char> chars = []; List<char> chars = [];
if (userOptions.UserNameCharacterListType == ListOption.Whitelist) if (userOptions.UserNameCharacterListType == ListOption.Whitelist)
{ {
chars.AddRange(user.UserName.Where(userNameChar => !userOptions.UserNameCharacters.Contains(userNameChar))); chars.AddRange(userBase.UserName.Where(userNameChar => !userOptions.UserNameCharacters.Contains(userNameChar)));
} }
if (userOptions.UserNameCharacterListType == ListOption.Blacklist) if (userOptions.UserNameCharacterListType == ListOption.Blacklist)
{ {
chars.AddRange(user.UserName.Where(userNameChar => userOptions.UserNameCharacters.Contains(userNameChar))); chars.AddRange(userBase.UserName.Where(userNameChar => userOptions.UserNameCharacters.Contains(userNameChar)));
} }
if (chars.Count <= 0) return errors.Count > 0 ? ValidationResult.Failed(errors) : ValidationResult.Ok(); if (chars.Count <= 0) return errors.Count > 0 ? ValidationResult.Failed(errors) : ValidationResult.Ok();