mirror of
https://github.com/hmaxnl/DotBased.git
synced 2025-04-20 04:28:12 +02:00
Compare commits
1 Commits
2b76f79f24
...
39077ef0ee
Author | SHA1 | Date | |
---|---|---|---|
|
39077ef0ee |
0
Blazor.Wasm/App.razor
Executable file → Normal file
0
Blazor.Wasm/App.razor
Executable file → Normal file
0
Blazor.Wasm/Blazor.Wasm.csproj
Executable file → Normal file
0
Blazor.Wasm/Blazor.Wasm.csproj
Executable file → Normal file
0
Blazor.Wasm/Layout/MainLayout.razor
Executable file → Normal file
0
Blazor.Wasm/Layout/MainLayout.razor
Executable file → Normal file
0
Blazor.Wasm/Layout/MainLayout.razor.css
Executable file → Normal file
0
Blazor.Wasm/Layout/MainLayout.razor.css
Executable file → Normal file
0
Blazor.Wasm/Layout/NavMenu.razor
Executable file → Normal file
0
Blazor.Wasm/Layout/NavMenu.razor
Executable file → Normal file
0
Blazor.Wasm/Layout/NavMenu.razor.css
Executable file → Normal file
0
Blazor.Wasm/Layout/NavMenu.razor.css
Executable file → Normal file
0
Blazor.Wasm/Pages/Counter.razor
Executable file → Normal file
0
Blazor.Wasm/Pages/Counter.razor
Executable file → Normal file
0
Blazor.Wasm/Pages/Home.razor
Executable file → Normal file
0
Blazor.Wasm/Pages/Home.razor
Executable file → Normal file
0
Blazor.Wasm/Pages/Weather.razor
Executable file → Normal file
0
Blazor.Wasm/Pages/Weather.razor
Executable file → Normal file
0
Blazor.Wasm/Program.cs
Executable file → Normal file
0
Blazor.Wasm/Program.cs
Executable file → Normal file
0
Blazor.Wasm/Properties/launchSettings.json
Executable file → Normal file
0
Blazor.Wasm/Properties/launchSettings.json
Executable file → Normal file
0
Blazor.Wasm/_Imports.razor
Executable file → Normal file
0
Blazor.Wasm/_Imports.razor
Executable file → Normal file
0
Blazor.Wasm/wwwroot/css/app.css
Executable file → Normal file
0
Blazor.Wasm/wwwroot/css/app.css
Executable file → Normal file
0
Blazor.Wasm/wwwroot/css/bootstrap/bootstrap.min.css
vendored
Executable file → Normal file
0
Blazor.Wasm/wwwroot/css/bootstrap/bootstrap.min.css
vendored
Executable file → Normal file
0
Blazor.Wasm/wwwroot/css/bootstrap/bootstrap.min.css.map
Executable file → Normal file
0
Blazor.Wasm/wwwroot/css/bootstrap/bootstrap.min.css.map
Executable file → Normal file
0
Blazor.Wasm/wwwroot/favicon.png
Executable file → Normal file
0
Blazor.Wasm/wwwroot/favicon.png
Executable file → Normal file
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
0
Blazor.Wasm/wwwroot/icon-192.png
Executable file → Normal file
0
Blazor.Wasm/wwwroot/icon-192.png
Executable file → Normal file
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
0
Blazor.Wasm/wwwroot/index.html
Executable file → Normal file
0
Blazor.Wasm/wwwroot/index.html
Executable file → Normal file
0
Blazor.Wasm/wwwroot/sample-data/weather.json
Executable file → Normal file
0
Blazor.Wasm/wwwroot/sample-data/weather.json
Executable file → Normal file
0
DotBased.ASP.Auth/AuthDataCache.cs
Executable file → Normal file
0
DotBased.ASP.Auth/AuthDataCache.cs
Executable file → Normal file
0
DotBased.ASP.Auth/AuthenticationService.cs
Executable file → Normal file
0
DotBased.ASP.Auth/AuthenticationService.cs
Executable file → Normal file
0
DotBased.ASP.Auth/BasedAuthConfiguration.cs
Executable file → Normal file
0
DotBased.ASP.Auth/BasedAuthConfiguration.cs
Executable file → Normal file
0
DotBased.ASP.Auth/BasedAuthDefaults.cs
Executable file → Normal file
0
DotBased.ASP.Auth/BasedAuthDefaults.cs
Executable file → Normal file
0
DotBased.ASP.Auth/BasedServerAuthenticationStateProvider.cs
Executable file → Normal file
0
DotBased.ASP.Auth/BasedServerAuthenticationStateProvider.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Domains/Auth/AuthenticationStateModel.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Domains/Auth/AuthenticationStateModel.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Domains/Auth/PermissionModel.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Domains/Auth/PermissionModel.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Domains/Auth/RoleModel.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Domains/Auth/RoleModel.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Domains/Identity/GroupItemModel.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Domains/Identity/GroupItemModel.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Domains/Identity/GroupModel.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Domains/Identity/GroupModel.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Domains/Identity/UserItemModel.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Domains/Identity/UserItemModel.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Domains/Identity/UserModel.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Domains/Identity/UserModel.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Domains/LoginModel.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Domains/LoginModel.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Domains/RegisterModel.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Domains/RegisterModel.cs
Executable file → Normal file
0
DotBased.ASP.Auth/DotBased.ASP.Auth.csproj
Executable file → Normal file
0
DotBased.ASP.Auth/DotBased.ASP.Auth.csproj
Executable file → Normal file
0
DotBased.ASP.Auth/DotBasedAuthDependencyInjection.cs
Executable file → Normal file
0
DotBased.ASP.Auth/DotBasedAuthDependencyInjection.cs
Executable file → Normal file
0
DotBased.ASP.Auth/IAuthDataRepository.cs
Executable file → Normal file
0
DotBased.ASP.Auth/IAuthDataRepository.cs
Executable file → Normal file
0
DotBased.ASP.Auth/ISessionStateProvider.cs
Executable file → Normal file
0
DotBased.ASP.Auth/ISessionStateProvider.cs
Executable file → Normal file
0
DotBased.ASP.Auth/MemoryAuthDataRepository.cs
Executable file → Normal file
0
DotBased.ASP.Auth/MemoryAuthDataRepository.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Models/Configuration/AuthConfiguration.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Models/Configuration/AuthConfiguration.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Models/Configuration/CacheConfiguration.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Models/Configuration/CacheConfiguration.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Models/Configuration/LockoutConfiguration.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Models/Configuration/LockoutConfiguration.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Models/Configuration/PasswordConfiguration.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Models/Configuration/PasswordConfiguration.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Models/Configuration/ProviderConfiguration.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Models/Configuration/ProviderConfiguration.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Models/Configuration/RepositoryConfiguration.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Models/Configuration/RepositoryConfiguration.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Models/Configuration/UserConfiguration.cs
Executable file → Normal file
0
DotBased.ASP.Auth/Models/Configuration/UserConfiguration.cs
Executable file → Normal file
0
DotBased.ASP.Auth/SecurityManager.cs
Executable file → Normal file
0
DotBased.ASP.Auth/SecurityManager.cs
Executable file → Normal file
0
DotBased.ASP.Auth/SecurityService.cs
Executable file → Normal file
0
DotBased.ASP.Auth/SecurityService.cs
Executable file → Normal file
2
DotBased.AspNet.Authority/Attributes/ProtectAttribute.cs
Executable file → Normal file
2
DotBased.AspNet.Authority/Attributes/ProtectAttribute.cs
Executable file → Normal file
|
@ -1,7 +1,7 @@
|
||||||
namespace DotBased.AspNet.Authority.Attributes;
|
namespace DotBased.AspNet.Authority.Attributes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates to protect the property before saving/loading to the repository.
|
/// Indicates that the property should be protected.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.Property)]
|
[AttributeUsage(AttributeTargets.Property)]
|
||||||
public class ProtectAttribute : Attribute
|
public class ProtectAttribute : Attribute
|
||||||
|
|
0
DotBased.AspNet.Authority/AuthorityBuilder.cs
Executable file → Normal file
0
DotBased.AspNet.Authority/AuthorityBuilder.cs
Executable file → Normal file
0
DotBased.AspNet.Authority/AuthorityDefaults.cs
Executable file → Normal file
0
DotBased.AspNet.Authority/AuthorityDefaults.cs
Executable file → Normal file
46
DotBased.AspNet.Authority/AuthorityProviderExtensions.cs
Executable file → Normal file
46
DotBased.AspNet.Authority/AuthorityProviderExtensions.cs
Executable file → Normal file
|
@ -1,57 +1,17 @@
|
||||||
using DotBased.AspNet.Authority.Crypto;
|
using DotBased.AspNet.Authority.Interfaces;
|
||||||
using DotBased.AspNet.Authority.Managers;
|
|
||||||
using DotBased.AspNet.Authority.Models.Options;
|
|
||||||
using DotBased.AspNet.Authority.Validators;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
|
||||||
|
|
||||||
namespace DotBased.AspNet.Authority;
|
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 AddAuthorityProvider<TModel>(this IServiceCollection services) where TModel : class
|
||||||
{
|
{
|
||||||
if (optionsAction != null)
|
|
||||||
{
|
|
||||||
services.AddOptions();
|
|
||||||
services.Configure<AuthorityOptions>(optionsAction);
|
|
||||||
}
|
|
||||||
|
|
||||||
services.TryAddScoped<ICryptographer, Cryptographer>();
|
|
||||||
services.TryAddScoped<IPasswordHasher, PasswordHasher>();
|
|
||||||
services.TryAddScoped<IPasswordValidator, PasswordOptionsValidator>();
|
|
||||||
services.TryAddScoped<IPasswordValidator, PasswordEqualsValidator>();
|
|
||||||
services.TryAddScoped<IUserValidator, UserValidator>();
|
|
||||||
/*services.TryAddScoped<IEmailVerifier, EmailVerifier>();
|
|
||||||
services.TryAddScoped<IPhoneNumberVerifier, PhoneNumberVerifier>();
|
|
||||||
services.TryAddScoped<IUserVerifier, UserVerifier>();*/
|
|
||||||
services.TryAddScoped<AuthorityManager>();
|
|
||||||
return new AuthorityBuilder(services);
|
return new AuthorityBuilder(services);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AuthorityBuilder AddAuthorityRepository<TRepository>(this AuthorityBuilder authorityBuilder) where TRepository : class
|
public static AuthorityBuilder AddAuthorityStore<TStore>(this AuthorityBuilder authorityBuilder) where TStore : IAuthorityRepository
|
||||||
{
|
{
|
||||||
return authorityBuilder;
|
return authorityBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AuthorityBuilder MapAuthorityEndpoints(this AuthorityBuilder builder)
|
|
||||||
{
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Type GetBaseGenericArgumentType<TModel>(Type baseType)
|
|
||||||
{
|
|
||||||
var userGenericBaseTypeDefinition = typeof(TModel).BaseType?.GetGenericTypeDefinition();
|
|
||||||
if (userGenericBaseTypeDefinition != null && userGenericBaseTypeDefinition == baseType)
|
|
||||||
{
|
|
||||||
var userBaseGenericArguments = userGenericBaseTypeDefinition.GetGenericArguments();
|
|
||||||
if (userBaseGenericArguments.Length <= 0)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Base implementation does not have the required generic argument.", nameof(TModel));
|
|
||||||
}
|
|
||||||
|
|
||||||
return userBaseGenericArguments[0];
|
|
||||||
}
|
|
||||||
throw new ArgumentException($"Given object {typeof(TModel).Name} does not have the base implementation type of: {baseType.Name}", nameof(TModel));
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,14 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Crypto;
|
|
||||||
|
|
||||||
public class Cryptographer : ICryptographer
|
|
||||||
{
|
|
||||||
public Task<string?> EncryptAsync(string data)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<string?> DecryptAsync(string data)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Crypto;
|
|
||||||
|
|
||||||
public interface ICryptographer
|
|
||||||
{
|
|
||||||
public Task<string?> EncryptAsync(string data);
|
|
||||||
public Task<string?> DecryptAsync(string data);
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Crypto;
|
|
||||||
|
|
||||||
public interface IPasswordHasher
|
|
||||||
{
|
|
||||||
public Task<string> HashPasswordAsync(string password);
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Crypto;
|
|
||||||
|
|
||||||
public class PasswordHasher : IPasswordHasher
|
|
||||||
{
|
|
||||||
public async Task<string> HashPasswordAsync(string password)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
6
DotBased.AspNet.Authority/DotBased.AspNet.Authority.csproj
Executable file → Normal file
6
DotBased.AspNet.Authority/DotBased.AspNet.Authority.csproj
Executable file → Normal file
|
@ -17,11 +17,9 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Folder Include="Authentication\" />
|
||||||
<Folder Include="Models\Security\" />
|
<Folder Include="Models\Security\" />
|
||||||
</ItemGroup>
|
<Folder Include="Repositories\" />
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.0" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
namespace DotBased.AspNet.Authority.Interfaces;
|
||||||
|
|
||||||
|
public interface IAttributeRepository
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
namespace DotBased.AspNet.Authority.Interfaces;
|
||||||
|
|
||||||
|
public interface IAuthorityRepository
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
6
DotBased.AspNet.Authority/Interfaces/IRoleRepository.cs
Normal file
6
DotBased.AspNet.Authority/Interfaces/IRoleRepository.cs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
namespace DotBased.AspNet.Authority.Interfaces;
|
||||||
|
|
||||||
|
public interface IRoleRepository
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
6
DotBased.AspNet.Authority/Interfaces/IUserRepository.cs
Normal file
6
DotBased.AspNet.Authority/Interfaces/IUserRepository.cs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
namespace DotBased.AspNet.Authority.Interfaces;
|
||||||
|
|
||||||
|
public interface IUserRepository
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -1,10 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Managers;
|
|
||||||
|
|
||||||
public partial class AuthorityManager
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* - Validate User & Group
|
|
||||||
* - Check if user is already in group (if already in group return)
|
|
||||||
* - Add to UsersGroups table
|
|
||||||
*/
|
|
||||||
}
|
|
|
@ -1,97 +0,0 @@
|
||||||
using System.Reflection;
|
|
||||||
using DotBased.AspNet.Authority.Attributes;
|
|
||||||
using DotBased.AspNet.Authority.Crypto;
|
|
||||||
using DotBased.AspNet.Authority.Models.Options;
|
|
||||||
using DotBased.AspNet.Authority.Repositories;
|
|
||||||
using DotBased.AspNet.Authority.Validators;
|
|
||||||
using DotBased.Logging;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
|
|
||||||
namespace DotBased.AspNet.Authority.Managers;
|
|
||||||
|
|
||||||
public partial class AuthorityManager(
|
|
||||||
IOptions<AuthorityOptions> options,
|
|
||||||
IServiceProvider services,
|
|
||||||
ICryptographer cryptographer,
|
|
||||||
IUserRepository userRepository,
|
|
||||||
IRoleRepository roleRepository,
|
|
||||||
IPasswordHasher passwordHasher)
|
|
||||||
{
|
|
||||||
private readonly ILogger _logger = LogService.RegisterLogger<AuthorityManager>();
|
|
||||||
|
|
||||||
public IServiceProvider Services { get; } = services;
|
|
||||||
public AuthorityOptions Options { get; } = options.Value;
|
|
||||||
public ICryptographer Cryptographer { get; } = cryptographer;
|
|
||||||
|
|
||||||
public IUserRepository UserRepository { get; } = userRepository;
|
|
||||||
public IRoleRepository RoleRepository { get; } = roleRepository;
|
|
||||||
|
|
||||||
public IPasswordHasher PasswordHasher { get; } = passwordHasher;
|
|
||||||
|
|
||||||
public IEnumerable<IPasswordValidator> PasswordValidators { get; } = [];
|
|
||||||
public IEnumerable<IUserValidator> UserValidators { get; } = [];
|
|
||||||
|
|
||||||
|
|
||||||
public long GenerateVersion() => DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Protect or unprotect the properties with the <see cref="ProtectAttribute"/>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">The data model</param>
|
|
||||||
/// <param name="protection">True for protect false for unprotect.</param>
|
|
||||||
/// <typeparam name="TModel">The class with the properties to protect.</typeparam>
|
|
||||||
public async Task HandlePropertyProtection<TModel>(TModel data, bool protection)
|
|
||||||
{
|
|
||||||
var props = GetProtectedPropertiesValues(data);
|
|
||||||
if (props.Count == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var handledProperties = 0;
|
|
||||||
foreach (var property in props)
|
|
||||||
{
|
|
||||||
if (property.PropertyType != typeof(string))
|
|
||||||
{
|
|
||||||
_logger.Warning("Property({PropName}) with type: {PropType} detected, encrypting only supports strings! Skipping property!", property.Name, property.PropertyType);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
string? cryptString;
|
|
||||||
if (protection)
|
|
||||||
{
|
|
||||||
cryptString = await Cryptographer.EncryptAsync(property.GetValue(data)?.ToString() ?? string.Empty);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cryptString = await Cryptographer.DecryptAsync(property.GetValue(data)?.ToString() ?? string.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cryptString == null)
|
|
||||||
{
|
|
||||||
_logger.Warning("{Protection} failed for property {PropName}", protection ? "Encryption" : "Decryption", property.Name);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
property.SetValue(data, cryptString);
|
|
||||||
handledProperties++;
|
|
||||||
}
|
|
||||||
_logger.Debug("{HandledPropCount}/{TotalPropCount} protection properties handled!", handledProperties, props.Count);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsPropertyProtected<TModel>(string propertyName)
|
|
||||||
{
|
|
||||||
var protectedProperties = GetProtectedProperties<TModel>();
|
|
||||||
var propertyFound = protectedProperties.Where(propInfo => propInfo.Name == propertyName);
|
|
||||||
return propertyFound.Any();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<PropertyInfo> GetProtectedPropertiesValues<TModel>(TModel model)
|
|
||||||
{
|
|
||||||
var protectedProperties = GetProtectedProperties<TModel>();
|
|
||||||
return protectedProperties.Count != 0 ? protectedProperties : [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<PropertyInfo> GetProtectedProperties<TModel>()
|
|
||||||
=> typeof(TModel).GetProperties().Where(p => Attribute.IsDefined(p, typeof(ProtectAttribute))).ToList();
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
using DotBased.AspNet.Authority.Models.Authority;
|
|
||||||
|
|
||||||
namespace DotBased.AspNet.Authority.Managers;
|
|
||||||
|
|
||||||
public partial class AuthorityManager
|
|
||||||
{
|
|
||||||
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<ListResult<AuthorityRole>> GetRolesAsync(int limit = 20, int offset = 0, string search = "", CancellationToken? cancellationToken = null)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Search by role name & id
|
|
||||||
* Order by name, created date, creator? (paging)
|
|
||||||
*/
|
|
||||||
return ListResult<AuthorityRole>.Failed("Not implemented!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task AddRoleToUserAsync(AuthorityUser user, AuthorityRole role, CancellationToken? cancellationToken = null)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
- Validate User & Role
|
|
||||||
- Check if role is already in linked to user (if user already has the role, return)
|
|
||||||
- Add to UsersRoles table
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task RemoveRoleFromUserAsync(AuthorityRole role, AuthorityUser user, CancellationToken? cancellationToken = null)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task AddRoleToGroupAsync(AuthorityRole role, AuthorityGroup group, CancellationToken? cancellationToken = null)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get all roles (including group roles) that the user has.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="user">The user to get the roles from</param>
|
|
||||||
/// <param name="cancellationToken"></param>
|
|
||||||
public async Task<ListResult<AuthorityRole>> GetUserRolesAsync(AuthorityUser user, CancellationToken? cancellationToken = null)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* - Validate user
|
|
||||||
* - Get user groups (id)
|
|
||||||
* - Get roles contained from user
|
|
||||||
* - Get roles contained from groups (if any)
|
|
||||||
* - Order by (for paging)
|
|
||||||
*/
|
|
||||||
|
|
||||||
return ListResult<AuthorityRole>.Failed("Not implemented!");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,97 +0,0 @@
|
||||||
using DotBased.AspNet.Authority.Models;
|
|
||||||
using DotBased.AspNet.Authority.Models.Authority;
|
|
||||||
using DotBased.AspNet.Authority.Models.Validation;
|
|
||||||
|
|
||||||
namespace DotBased.AspNet.Authority.Managers;
|
|
||||||
|
|
||||||
public partial class AuthorityManager
|
|
||||||
{
|
|
||||||
public async Task<ValidationResult> ValidatePasswordAsync(AuthorityUser user, string password)
|
|
||||||
{
|
|
||||||
List<ValidationError> errors = [];
|
|
||||||
foreach (var validator in PasswordValidators)
|
|
||||||
{
|
|
||||||
var validatorResult = await validator.ValidatePasswordAsync(this, user, password);
|
|
||||||
if (!validatorResult.Success)
|
|
||||||
{
|
|
||||||
errors.AddRange(validatorResult.Errors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errors.Count > 0 ? ValidationResult.Failed(errors) : ValidationResult.Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<ValidationResult> ValidateUserAsync(AuthorityUser user)
|
|
||||||
{
|
|
||||||
List<ValidationError> errors = [];
|
|
||||||
foreach (var userValidator in UserValidators)
|
|
||||||
{
|
|
||||||
var validationResult = await userValidator.ValidateUserAsync(this, user);
|
|
||||||
if (!validationResult.Success)
|
|
||||||
{
|
|
||||||
errors.AddRange(validationResult.Errors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
var searchResult = await UserRepository.GetAuthorityUsersAsync(query, maxResults, offset, cancellationToken);
|
|
||||||
return searchResult.Item1 == null ? ListResult<AuthorityUser>.Failed("No results!") : ListResult<AuthorityUser>.Ok(searchResult.Item1, searchResult.Item2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<AuthorityResult<AuthorityUser>> UpdatePasswordAsync(AuthorityUser user, string password, CancellationToken? cancellationToken = null)
|
|
||||||
{
|
|
||||||
var passwordValidation = await ValidatePasswordAsync(user, password);
|
|
||||||
if (!passwordValidation.Success)
|
|
||||||
{
|
|
||||||
List<ValidationError> errors = [];
|
|
||||||
errors.AddRange(passwordValidation.Errors);
|
|
||||||
return AuthorityResult<AuthorityUser>.Failed(errors, ResultFailReason.Validation);
|
|
||||||
}
|
|
||||||
|
|
||||||
user.PasswordHash = await PasswordHasher.HashPasswordAsync(password);
|
|
||||||
user.SecurityVersion = GenerateVersion();
|
|
||||||
|
|
||||||
var updateResult = await UserRepository.UpdateUserAsync(user, cancellationToken);
|
|
||||||
return updateResult == null ? AuthorityResult<AuthorityUser>.Error("Failed to save updates!") : AuthorityResult<AuthorityUser>.Ok(updateResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<AuthorityResult<AuthorityUser>> CreateUserAsync(AuthorityUser userModel, string password, CancellationToken? cancellationToken = null)
|
|
||||||
{
|
|
||||||
var userValidation = await ValidateUserAsync(userModel);
|
|
||||||
var passwordValidation = await ValidatePasswordAsync(userModel, password);
|
|
||||||
if (!userValidation.Success || !passwordValidation.Success)
|
|
||||||
{
|
|
||||||
List<ValidationError> errors = [];
|
|
||||||
errors.AddRange(userValidation.Errors);
|
|
||||||
errors.AddRange(passwordValidation.Errors);
|
|
||||||
return AuthorityResult<AuthorityUser>.Failed(errors, ResultFailReason.Validation);
|
|
||||||
}
|
|
||||||
|
|
||||||
userModel.Version = GenerateVersion();
|
|
||||||
userModel.SecurityVersion = GenerateVersion();
|
|
||||||
var hashedPassword = await PasswordHasher.HashPasswordAsync(password);
|
|
||||||
userModel.PasswordHash = hashedPassword;
|
|
||||||
|
|
||||||
var userCreationResult = await UserRepository.CreateUserAsync(userModel, cancellationToken);
|
|
||||||
|
|
||||||
return userCreationResult != null
|
|
||||||
? AuthorityResult<AuthorityUser>.Ok(userCreationResult)
|
|
||||||
: AuthorityResult<AuthorityUser>.Error("Failed to create user in repository!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Result<AuthorityUser>> UpdateUserAsync(AuthorityUser model, CancellationToken? cancellationToken = null)
|
|
||||||
{
|
|
||||||
var updateResult = await UserRepository.UpdateUserAsync(model, cancellationToken);
|
|
||||||
return updateResult != null ? Result<AuthorityUser>.Ok(updateResult) : Result<AuthorityUser>.Failed("Failed to update user in repository!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> DeleteUserAsync(AuthorityUser model, CancellationToken? cancellationToken = null)
|
|
||||||
{
|
|
||||||
var deleteResult = await UserRepository.DeleteUserAsync(model, cancellationToken);
|
|
||||||
return deleteResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Models.Authority;
|
|
||||||
|
|
||||||
public class AuthorityAttribute
|
|
||||||
{
|
|
||||||
public AuthorityAttribute(string attributeKey, string bound)
|
|
||||||
{
|
|
||||||
AttributeKey = attributeKey;
|
|
||||||
BoundId = bound;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AuthorityAttribute()
|
|
||||||
{
|
|
||||||
AttributeKey = string.Empty;
|
|
||||||
BoundId = string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string AttributeKey { get; set; } // ClaimType/Authority.attribute.enabled
|
|
||||||
|
|
||||||
public string BoundId { get; set; } // Bound to User, Group, Role id
|
|
||||||
|
|
||||||
public object? AttributeValue { get; set; }
|
|
||||||
|
|
||||||
public string? Type { get; set; } // AspNet.Claim.Role/Property/Data.JSON, Data.Raw, Data.Base64 etc.
|
|
||||||
|
|
||||||
public long Version { get; set; }
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Models.Authority;
|
|
||||||
|
|
||||||
public class AuthorityGroup
|
|
||||||
{
|
|
||||||
public AuthorityGroup(string name) : this()
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AuthorityGroup()
|
|
||||||
{
|
|
||||||
Id = Guid.NewGuid();
|
|
||||||
CreatedDate = DateTime.Now;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
|
|
||||||
public string? Name { get; set; }
|
|
||||||
|
|
||||||
public long Version { get; set; }
|
|
||||||
|
|
||||||
public DateTime CreatedDate { get; set; }
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Models.Authority;
|
|
||||||
|
|
||||||
public abstract class AuthorityRole()
|
|
||||||
{
|
|
||||||
public AuthorityRole(string name) : this()
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Guid Id { get; set; } = Guid.NewGuid();
|
|
||||||
|
|
||||||
public string? Name { get; set; }
|
|
||||||
|
|
||||||
public long Version { get; set; }
|
|
||||||
|
|
||||||
public DateTime CreatedDate { get; set; } = DateTime.Now;
|
|
||||||
|
|
||||||
public override string ToString() => Name ?? string.Empty;
|
|
||||||
}
|
|
43
DotBased.AspNet.Authority/Models/Authority/AuthorityUser.cs
Executable file → Normal file
43
DotBased.AspNet.Authority/Models/Authority/AuthorityUser.cs
Executable file → Normal file
|
@ -1,45 +1,10 @@
|
||||||
using DotBased.AspNet.Authority.Attributes;
|
|
||||||
|
|
||||||
namespace DotBased.AspNet.Authority.Models.Authority;
|
namespace DotBased.AspNet.Authority.Models.Authority;
|
||||||
|
|
||||||
public class AuthorityUser()
|
public class AuthorityUser : AuthorityUserBase<Guid>
|
||||||
{
|
{
|
||||||
public AuthorityUser(string userName) : this()
|
public AuthorityUser()
|
||||||
{
|
{
|
||||||
UserName = userName;
|
Id = Guid.NewGuid();
|
||||||
|
CreatedDate = DateTime.Now;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Guid Id { get; set; } = Guid.NewGuid();
|
|
||||||
|
|
||||||
public bool Enabled { get; set; }
|
|
||||||
|
|
||||||
public bool Confirmed { get; set; }
|
|
||||||
|
|
||||||
public bool Locked { get; set; }
|
|
||||||
|
|
||||||
public DateTime LockedDate { get; set; }
|
|
||||||
|
|
||||||
public string? UserName { get; set; }
|
|
||||||
|
|
||||||
public string? PasswordHash { get; set; }
|
|
||||||
|
|
||||||
public DateTime CreatedDate { get; set; } = DateTime.Now;
|
|
||||||
|
|
||||||
public bool TwoFactorEnabled { get; set; }
|
|
||||||
|
|
||||||
public long Version { get; set; }
|
|
||||||
|
|
||||||
public long SecurityVersion { get; set; }
|
|
||||||
|
|
||||||
[Protect]
|
|
||||||
public string? EmailAddress { get; set; }
|
|
||||||
|
|
||||||
public bool EmailConfirmed { get; set; }
|
|
||||||
|
|
||||||
[Protect]
|
|
||||||
public string? PhoneNumber { get; set; }
|
|
||||||
|
|
||||||
public bool PhoneNumberConfirmed { get; set; }
|
|
||||||
|
|
||||||
public override string ToString() => UserName ?? EmailAddress ?? string.Empty;
|
|
||||||
}
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
using DotBased.AspNet.Authority.Attributes;
|
||||||
|
|
||||||
|
namespace DotBased.AspNet.Authority.Models.Authority;
|
||||||
|
|
||||||
|
public abstract class AuthorityUserBase<TKey> where TKey : IEquatable<TKey>
|
||||||
|
{
|
||||||
|
public TKey Id { get; set; }
|
||||||
|
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
|
||||||
|
public bool Locked { get; set; }
|
||||||
|
|
||||||
|
public string UserName { get; set; }
|
||||||
|
|
||||||
|
public string PasswordHash { get; set; }
|
||||||
|
|
||||||
|
public DateTime CreatedDate { get; set; }
|
||||||
|
|
||||||
|
public bool TwoFactorEnabled { get; set; }
|
||||||
|
|
||||||
|
public string ConcurrencyStamp { get; set; }
|
||||||
|
public string SecurityStamp { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[Protect]
|
||||||
|
public string EmailAddress { get; set; }
|
||||||
|
|
||||||
|
public bool EmailConfirmed { get; set; }
|
||||||
|
|
||||||
|
[Protect]
|
||||||
|
public string PhoneNumber { get; set; }
|
||||||
|
|
||||||
|
public bool PhoneNumberConfirmed { get; set; }
|
||||||
|
|
||||||
|
}
|
|
@ -1,38 +0,0 @@
|
||||||
using DotBased.AspNet.Authority.Models.Validation;
|
|
||||||
|
|
||||||
namespace DotBased.AspNet.Authority.Models;
|
|
||||||
|
|
||||||
public class AuthorityResult<TResultValue>
|
|
||||||
{
|
|
||||||
public AuthorityResult(bool success, string errorMessage = "", TResultValue? value = default, ResultFailReason reason = ResultFailReason.None, List<ValidationError>? errors = null)
|
|
||||||
{
|
|
||||||
Success = success;
|
|
||||||
ErrorMessage = errorMessage;
|
|
||||||
Value = value;
|
|
||||||
Reason = reason;
|
|
||||||
ValidationErrors = errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Success { get; }
|
|
||||||
public string ErrorMessage { get; }
|
|
||||||
public TResultValue? Value { get; }
|
|
||||||
public ResultFailReason Reason { get; }
|
|
||||||
public List<ValidationError>? ValidationErrors { get; }
|
|
||||||
|
|
||||||
|
|
||||||
public static AuthorityResult<TResultValue> Ok(TResultValue? value) => new AuthorityResult<TResultValue>(true, value:value);
|
|
||||||
|
|
||||||
public static AuthorityResult<TResultValue> Error(string errorMessage, ResultFailReason reason = ResultFailReason.Error) =>
|
|
||||||
new AuthorityResult<TResultValue>(false, errorMessage, reason:reason);
|
|
||||||
|
|
||||||
public static AuthorityResult<TResultValue> Failed(List<ValidationError> errors, ResultFailReason reason = ResultFailReason.None)
|
|
||||||
=> new AuthorityResult<TResultValue>(false, errors:errors, reason:reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ResultFailReason
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
Unknown,
|
|
||||||
Validation,
|
|
||||||
Error
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Models.Options;
|
|
||||||
|
|
||||||
public class AuthorityOptions
|
|
||||||
{
|
|
||||||
public LockdownOptions Lockdown { get; set; } = new();
|
|
||||||
public LockoutOptions Lockout { get; set; } = new();
|
|
||||||
public PasswordOptions Password { get; set; } = new();
|
|
||||||
public ProviderOptions Provider { get; set; } = new();
|
|
||||||
public RepositoryOptions Repository { get; set; } = new();
|
|
||||||
public UserOptions User { get; set; } = new();
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Models.Options;
|
|
||||||
|
|
||||||
public enum ListOption
|
|
||||||
{
|
|
||||||
Blacklist,
|
|
||||||
Whitelist
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Models.Options;
|
|
||||||
|
|
||||||
public class LockdownOptions
|
|
||||||
{
|
|
||||||
public bool EnableLockout { get; set; }
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Models.Options;
|
|
||||||
|
|
||||||
public class LockoutOptions
|
|
||||||
{
|
|
||||||
public bool EnableLockout { get; set; } = true;
|
|
||||||
public int FailedAttempts { get; set; } = 3;
|
|
||||||
public TimeSpan LockoutTimeout { get; set; } = TimeSpan.FromMinutes(30);
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Models.Options;
|
|
||||||
|
|
||||||
public class PasswordOptions
|
|
||||||
{
|
|
||||||
public int RequiredLength { get; set; } = 10;
|
|
||||||
public int MinimalUniqueChars { get; set; } = 1;
|
|
||||||
public bool RequireLowercase { get; set; }
|
|
||||||
public bool RequireUppercase { get; set; }
|
|
||||||
public bool RequireDigit { get; set; }
|
|
||||||
public bool RequireNonAlphanumeric { get; set; }
|
|
||||||
|
|
||||||
public List<string> PasswordBlackList { get; set; } = ["password", "1234"];
|
|
||||||
public StringComparer PasswordBlackListComparer { get; set; } = StringComparer.OrdinalIgnoreCase;
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Models.Options;
|
|
||||||
|
|
||||||
public class ProviderOptions
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Models.Options;
|
|
||||||
|
|
||||||
public class RepositoryOptions
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Use data encryption when a property has the <see cref="DotBased.AspNet.Authority.Attributes.ProtectAttribute"/> defined.
|
|
||||||
/// <value>Default: true</value>
|
|
||||||
/// </summary>
|
|
||||||
public bool UseDataProtection { get; set; } = true;
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Models.Options;
|
|
||||||
|
|
||||||
public class SignInOptions
|
|
||||||
{
|
|
||||||
public bool RequireVerifiedEmail { get; set; }
|
|
||||||
public bool RequireVerifiedPhoneNumber { get; set; }
|
|
||||||
public bool RequireConfirmedAccount { get; set; }
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Models.Options;
|
|
||||||
|
|
||||||
public class UserOptions
|
|
||||||
{
|
|
||||||
public bool EnableRegister { get; set; }
|
|
||||||
public bool RequireUniqueEmail { get; set; }
|
|
||||||
public string UserNameCharacters { get; set; } = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@";
|
|
||||||
public ListOption UserNameCharacterListType { get; set; } = ListOption.Whitelist;
|
|
||||||
|
|
||||||
public List<string> UserNameBlackList { get; set; } = ["admin", "administrator", "dev", "developer"];
|
|
||||||
public StringComparer UserNameBlackListComparer { get; set; } = StringComparer.OrdinalIgnoreCase;
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Models.Validation;
|
|
||||||
|
|
||||||
public class ValidationError
|
|
||||||
{
|
|
||||||
public ValidationError(string validator, string errorCode, string description)
|
|
||||||
{
|
|
||||||
Validator = validator;
|
|
||||||
ErrorCode = errorCode;
|
|
||||||
Description = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The validator name that generated this error.
|
|
||||||
/// </summary>
|
|
||||||
public string Validator { get; }
|
|
||||||
/// <summary>
|
|
||||||
/// The error code
|
|
||||||
/// </summary>
|
|
||||||
public string ErrorCode { get; }
|
|
||||||
/// <summary>
|
|
||||||
/// Error description
|
|
||||||
/// </summary>
|
|
||||||
public string Description { get; }
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Models.Validation;
|
|
||||||
|
|
||||||
public class ValidationResult
|
|
||||||
{
|
|
||||||
public ValidationResult(bool success, IEnumerable<ValidationError>? errors = null)
|
|
||||||
{
|
|
||||||
if (errors != null)
|
|
||||||
{
|
|
||||||
Errors = errors.ToList();
|
|
||||||
}
|
|
||||||
Success = success;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Success { get; }
|
|
||||||
public IReadOnlyList<ValidationError> Errors { get; } = [];
|
|
||||||
|
|
||||||
public static ValidationResult Failed(IEnumerable<ValidationError> errors) => new(false, errors);
|
|
||||||
public static ValidationResult Ok() => new(true);
|
|
||||||
|
|
||||||
public override string ToString() => Success ? "Success" : $"Failed ({Errors.Count} errors)";
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Repositories;
|
|
||||||
|
|
||||||
public interface IAttributeRepository
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Repositories;
|
|
||||||
|
|
||||||
public interface IGroupRepository
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Repositories;
|
|
||||||
|
|
||||||
public interface IRoleRepository
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
using DotBased.AspNet.Authority.Models.Authority;
|
|
||||||
|
|
||||||
namespace DotBased.AspNet.Authority.Repositories;
|
|
||||||
|
|
||||||
public interface IUserRepository
|
|
||||||
{
|
|
||||||
public Task<AuthorityUser?> GetAuthorityUserByIdAsync(string id, CancellationToken? cancellationToken = null);
|
|
||||||
public Task<string> GetAuthorityUserIdAsync(AuthorityUser user, CancellationToken? cancellationToken = null);
|
|
||||||
public Task<Tuple<List<AuthorityUser>?, int>> GetAuthorityUsersAsync(string query, int maxResults = 20, int offset = 0, CancellationToken? cancellationToken = null);
|
|
||||||
public Task<AuthorityUser?> GetAuthorityUserByEmailAsync(string email, CancellationToken? cancellationToken = null);
|
|
||||||
public Task SetVersionAsync(AuthorityUser user, long version, CancellationToken? cancellationToken = null);
|
|
||||||
public Task<long> GetVersionAsync(AuthorityUser user, CancellationToken? cancellationToken = null);
|
|
||||||
public Task SetSecurityVersionAsync(AuthorityUser user, long version, CancellationToken? cancellationToken = null);
|
|
||||||
public Task<long> GetSecurityVersionAsync(AuthorityUser user, CancellationToken? cancellationToken = null);
|
|
||||||
public Task<AuthorityUser?> CreateUserAsync(AuthorityUser user, CancellationToken? cancellationToken = null);
|
|
||||||
public Task<AuthorityUser?> UpdateUserAsync(AuthorityUser user, CancellationToken? cancellationToken = null);
|
|
||||||
public Task<bool> DeleteUserAsync(AuthorityUser user, CancellationToken? cancellationToken = null);
|
|
||||||
}
|
|
6
DotBased.AspNet.Authority/Services/AuthorityService.cs
Normal file
6
DotBased.AspNet.Authority/Services/AuthorityService.cs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
namespace DotBased.AspNet.Authority.Services;
|
||||||
|
|
||||||
|
public class AuthorityService
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -1,10 +0,0 @@
|
||||||
using DotBased.AspNet.Authority.Managers;
|
|
||||||
using DotBased.AspNet.Authority.Models.Authority;
|
|
||||||
using DotBased.AspNet.Authority.Models.Validation;
|
|
||||||
|
|
||||||
namespace DotBased.AspNet.Authority.Validators;
|
|
||||||
|
|
||||||
public interface IPasswordValidator
|
|
||||||
{
|
|
||||||
public Task<ValidationResult> ValidatePasswordAsync(AuthorityManager manager, AuthorityUser user, string password);
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
using DotBased.AspNet.Authority.Managers;
|
|
||||||
using DotBased.AspNet.Authority.Models.Authority;
|
|
||||||
using DotBased.AspNet.Authority.Models.Validation;
|
|
||||||
|
|
||||||
namespace DotBased.AspNet.Authority.Validators;
|
|
||||||
|
|
||||||
public interface IUserValidator
|
|
||||||
{
|
|
||||||
public Task<ValidationResult> ValidateUserAsync(AuthorityManager manager, AuthorityUser user);
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
using DotBased.AspNet.Authority.Managers;
|
|
||||||
using DotBased.AspNet.Authority.Models.Authority;
|
|
||||||
using DotBased.AspNet.Authority.Models.Validation;
|
|
||||||
|
|
||||||
namespace DotBased.AspNet.Authority.Validators;
|
|
||||||
|
|
||||||
public class PasswordEqualsValidator : IPasswordValidator
|
|
||||||
{
|
|
||||||
private const string ValidatorId = "Authority.Validator.Password.Equals";
|
|
||||||
private const string ValidationBase = "Authority.Validation.Password";
|
|
||||||
public async Task<ValidationResult> ValidatePasswordAsync(AuthorityManager userManager, AuthorityUser user, string password)
|
|
||||||
{
|
|
||||||
List<ValidationError> errors = [];
|
|
||||||
var hashedPassword = await userManager.PasswordHasher.HashPasswordAsync(password);
|
|
||||||
if (user.PasswordHash != null && user.PasswordHash.Equals(hashedPassword, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.InUse", "User uses this password already!"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors.Count > 0 ? ValidationResult.Failed(errors) : ValidationResult.Ok();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
using DotBased.AspNet.Authority.Managers;
|
|
||||||
using DotBased.AspNet.Authority.Models.Authority;
|
|
||||||
using DotBased.AspNet.Authority.Models.Validation;
|
|
||||||
using DotBased.Extensions;
|
|
||||||
|
|
||||||
namespace DotBased.AspNet.Authority.Validators;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Validates the password against the options that is configured.
|
|
||||||
/// </summary>
|
|
||||||
public class PasswordOptionsValidator : IPasswordValidator
|
|
||||||
{
|
|
||||||
private const string ValidatorId = "Authority.Validator.Password.Options";
|
|
||||||
private const string ValidationBase = "Authority.Validation.Password";
|
|
||||||
|
|
||||||
public async Task<ValidationResult> ValidatePasswordAsync(AuthorityManager userManager, AuthorityUser user, string password)
|
|
||||||
{
|
|
||||||
if (userManager == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(userManager), "User manager is not provided!");
|
|
||||||
}
|
|
||||||
var passwordOptions = userManager.Options.Password;
|
|
||||||
var errors = new List<ValidationError>();
|
|
||||||
|
|
||||||
if (password.IsNullOrEmpty() || password.Length < passwordOptions.RequiredLength)
|
|
||||||
{
|
|
||||||
errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.Required.Length", $"Password needs to have a minimum length of {passwordOptions.RequiredLength}"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (passwordOptions.RequireDigit && !ContainsDigit(password))
|
|
||||||
{
|
|
||||||
errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.Required.Digit", "Password must contain a digit!"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (passwordOptions.RequireNonAlphanumeric && ContainsNonAlphanumeric(password))
|
|
||||||
{
|
|
||||||
errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.Required.NonAlphanumeric", "Password must contain a non alphanumeric character."));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (passwordOptions.RequireLowercase && password.Any(char.IsLower))
|
|
||||||
{
|
|
||||||
errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.Required.Lowercase", "Password must contains at least one lowercase character."));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (passwordOptions.RequireUppercase && password.Any(char.IsUpper))
|
|
||||||
{
|
|
||||||
errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.Required.Uppercase", "Password must contains at least one uppercase character."));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (passwordOptions.PasswordBlackList.Count != 0 && passwordOptions.PasswordBlackList.Contains(password, passwordOptions.PasswordBlackListComparer))
|
|
||||||
{
|
|
||||||
errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.Blacklisted", "Given password is not allowed (blacklisted)"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (passwordOptions.MinimalUniqueChars > 0 && password.Distinct().Count() < passwordOptions.MinimalUniqueChars)
|
|
||||||
{
|
|
||||||
errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.UniqueChars", $"Password must contain at least {passwordOptions.MinimalUniqueChars} unique chars."));
|
|
||||||
}
|
|
||||||
|
|
||||||
return await Task.FromResult(errors.Count > 0 ? ValidationResult.Failed(errors) : ValidationResult.Ok());
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool ContainsDigit(string strVal) => strVal.Any(char.IsDigit);
|
|
||||||
|
|
||||||
private bool ContainsNonAlphanumeric(string strVal) => !strVal.Any(char.IsLetterOrDigit);
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
using DotBased.AspNet.Authority.Managers;
|
|
||||||
using DotBased.AspNet.Authority.Models.Authority;
|
|
||||||
using DotBased.AspNet.Authority.Models.Options;
|
|
||||||
using DotBased.AspNet.Authority.Models.Validation;
|
|
||||||
|
|
||||||
namespace DotBased.AspNet.Authority.Validators;
|
|
||||||
|
|
||||||
public class UserValidator : IUserValidator
|
|
||||||
{
|
|
||||||
private const string ValidatorId = "Authority.Validator.User";
|
|
||||||
private const string ValidationBase = "Authority.Validation.User";
|
|
||||||
|
|
||||||
public async Task<ValidationResult> ValidateUserAsync(AuthorityManager manager, AuthorityUser user)
|
|
||||||
{
|
|
||||||
List<ValidationError> errors = [];
|
|
||||||
|
|
||||||
var userOptions = manager.Options.User;
|
|
||||||
|
|
||||||
if (userOptions.RequireUniqueEmail)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(user.EmailAddress))
|
|
||||||
{
|
|
||||||
errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.NoEmail",
|
|
||||||
$"Option {nameof(UserOptions.RequireUniqueEmail)} is set to true but given user does not have an email address!"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var userEmailResult = await manager.UserRepository.GetAuthorityUserByEmailAsync(user.EmailAddress);
|
|
||||||
if (userEmailResult != null)
|
|
||||||
{
|
|
||||||
errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.EmailExists",
|
|
||||||
"Given email has already registered an account!"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(user.UserName))
|
|
||||||
{
|
|
||||||
if (userOptions.UserNameBlackList.Count != 0 && userOptions.UserNameBlackList.Contains(user.UserName, userOptions.UserNameBlackListComparer))
|
|
||||||
{
|
|
||||||
errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.Blacklisted", "Given username is not allowed (blacklisted)"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(userOptions.UserNameCharacters))
|
|
||||||
{
|
|
||||||
List<char> chars = [];
|
|
||||||
if (userOptions.UserNameCharacterListType == ListOption.Whitelist)
|
|
||||||
{
|
|
||||||
chars.AddRange(user.UserName.Where(userNameChar => !userOptions.UserNameCharacters.Contains(userNameChar)));
|
|
||||||
}
|
|
||||||
if (userOptions.UserNameCharacterListType == ListOption.Blacklist)
|
|
||||||
{
|
|
||||||
chars.AddRange(user.UserName.Where(userNameChar => userOptions.UserNameCharacters.Contains(userNameChar)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chars.Count <= 0) return errors.Count > 0 ? ValidationResult.Failed(errors) : ValidationResult.Ok();
|
|
||||||
var errorCode = "";
|
|
||||||
var description = "";
|
|
||||||
switch (userOptions.UserNameCharacterListType)
|
|
||||||
{
|
|
||||||
case ListOption.Whitelist:
|
|
||||||
errorCode = "CharactersNotOnWhitelist";
|
|
||||||
description = $"Found characters in username that were not on the whitelist! Chars: [{string.Join(',', chars)}]";
|
|
||||||
break;
|
|
||||||
case ListOption.Blacklist:
|
|
||||||
errorCode = "CharactersOnBlacklist";
|
|
||||||
description = $"Found characters in username that are on the blacklist! Chars: [{string.Join(',', chars)}]";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.UserName.{errorCode}", description));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.InvalidUserName", "No username given!"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors.Count > 0 ? ValidationResult.Failed(errors) : ValidationResult.Ok();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Verifiers;
|
|
||||||
|
|
||||||
public interface IEmailVerifier
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Verifiers;
|
|
||||||
|
|
||||||
public interface IPhoneNumberVerifier
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
namespace DotBased.AspNet.Authority.Verifiers;
|
|
||||||
|
|
||||||
public interface IUserVerifier
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>netstandard2.1</TargetFramework>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\DotBased\DotBased.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
0
DotBased.Logging.MEL/BasedLogger.cs
Executable file → Normal file
0
DotBased.Logging.MEL/BasedLogger.cs
Executable file → Normal file
0
DotBased.Logging.MEL/BasedLoggerProvider.cs
Executable file → Normal file
0
DotBased.Logging.MEL/BasedLoggerProvider.cs
Executable file → Normal file
0
DotBased.Logging.MEL/DotBased.Logging.MEL.csproj
Executable file → Normal file
0
DotBased.Logging.MEL/DotBased.Logging.MEL.csproj
Executable file → Normal file
0
DotBased.Logging.MEL/LoggerBuilderExtensions.cs
Executable file → Normal file
0
DotBased.Logging.MEL/LoggerBuilderExtensions.cs
Executable file → Normal file
0
DotBased.Logging.Serilog/BasedSerilog.cs
Executable file → Normal file
0
DotBased.Logging.Serilog/BasedSerilog.cs
Executable file → Normal file
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user