up
Some checks failed
Build Test Deploy / build-test (push) Has been cancelled
Build Test Deploy / authority-container (push) Has been cancelled
Build Test Deploy / docs (push) Has been cancelled
Build Test Deploy / deploy (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled

This commit is contained in:
root
2025-10-10 06:53:40 +00:00
parent 3aed135fb5
commit df5984d07e
1081 changed files with 97764 additions and 61389 deletions

View File

@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.5" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../../../../__Libraries/Ablera.Serdica.Plugin/Ablera.Serdica.Plugin.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,7 @@
namespace Ablera.Serdica.Authority.Plugins.Base.Constants;
public static class ConstantsClass
{
public const string YesKey = "Y";
public const string NoKey = "N";
}

View File

@@ -0,0 +1,10 @@
using Ablera.Serdica.Authority.Plugins.Base.Models;
namespace Ablera.Serdica.Authority.Plugins.Base.Contracts;
public interface IAccountLockManager<TUser>
where TUser : class
{
Task<OperationResult> LockAsync(TUser user, CancellationToken ct = default);
Task<OperationResult> UnlockAsync(TUser user, CancellationToken ct = default);
}

View File

@@ -0,0 +1,12 @@
using Ablera.Serdica.Authority.Plugins.Base.Models;
namespace Ablera.Serdica.Authority.Plugins.Base.Contracts;
public interface IAuthService<TUser>
where TUser : class
{
/// <summary>
/// Authenticates a user given a login identifier (email/username) and password.
/// </summary>
Task<AuthenticationResult> AuthenticateAsync(TUser user, string password, bool lockoutOnFailure = false, CancellationToken ct = default);
}

View File

@@ -0,0 +1,10 @@
using System.Security.Claims;
namespace Ablera.Serdica.Authority.Plugins.Base.Contracts;
public interface IClaimStore<TUser>
where TUser : class
{
Task<IReadOnlyCollection<Claim>> GetBaseClaimsAsync(TUser user, CancellationToken ct = default);
Task<IReadOnlyCollection<Claim>?> GetRolesClaimsAsync(TUser user, CancellationToken ct = default);
}

View File

@@ -0,0 +1,10 @@
using Ablera.Serdica.Authority.Plugins.Base.Models;
namespace Ablera.Serdica.Authority.Plugins.Base.Contracts;
public interface IPasswordManager<TUser>
where TUser : class
{
Task<OperationResult> ChangePasswordAsync(TUser user, string currentPassword, string newPassword, CancellationToken ct = default);
Task<OperationResult> ResetPasswordAsync(TUser user, string resetToken, string newPassword, CancellationToken ct = default);
}

View File

@@ -0,0 +1,15 @@
namespace Ablera.Serdica.Authority.Plugins.Base.Contracts;
/*===========================================================*/
/* Facade for legacy code that expects a single user manager */
/*===========================================================*/
public interface IUserManagementFacade<TUser> :
IUserRepository<TUser>,
IPasswordManager<TUser>,
IClaimStore<TUser>,
IAccountLockManager<TUser>,
IAuthService<TUser>
where TUser : class
{
}

View File

@@ -0,0 +1,18 @@
using Ablera.Serdica.Authority.Plugins.Base.Models;
namespace Ablera.Serdica.Authority.Plugins.Base.Contracts;
/*====================================================================*/
/* Core, storageagnostic responsibilities are split across focused */
/* contracts. Implementations can cherrypick or aggregate as needed */
/*====================================================================*/
public interface IUserRepository<TUser>
where TUser : class
{
Task<OperationResult> CreateAsync(TUser user, string password, CancellationToken ct = default);
Task<OperationResult> UpdateAsync(TUser user, CancellationToken ct = default);
Task<TUser?> FindByIdAsync(string id, CancellationToken ct = default);
Task<TUser?> FindByEmailAsync(string email, CancellationToken ct = default);
Task<TUser?> FindByNameAsync(string username, CancellationToken ct = default);
}

View File

@@ -0,0 +1,43 @@
using System.Security.Claims;
namespace Ablera.Serdica.Authority.Plugins.Base.Models;
public enum AuthenticationCode
{
GenericError,
AccountIsNotFound,
AccountIsLocked,
AccountIsNotActive,
EmptyCredentials,
InvalidPassword,
NoAuthBackend,
ClientIsUnknown,
ClientWithNoSecretDoesNotMatchAllowedMask,
ClientSecretIsInvalid,
InvalidCredentials,
AccountIsNotAuthenticaAble
}
/// <summary>
/// Result of an authentication attempt. Use the static helpers for convenience.
/// </summary>
public sealed class AuthenticationResult
{
private AuthenticationResult(bool succeeded, string? errorCode, ClaimsPrincipal? claimsPrincipal)
{
Succeeded = succeeded;
ErrorCode = errorCode;
ClaimsPrincipal = claimsPrincipal;
}
public bool Succeeded { get; }
public string? ErrorCode { get; }
public ClaimsPrincipal? ClaimsPrincipal { get; }
public static AuthenticationResult Success(ClaimsPrincipal? claimsPrincipal) =>
new AuthenticationResult(true, null, claimsPrincipal);
public static AuthenticationResult Fail(string errorCode) =>
new AuthenticationResult(false, errorCode, null);
}

View File

@@ -0,0 +1,19 @@
namespace Ablera.Serdica.Authority.Plugins.Base.Models;
/// <summary>
/// Generic result wrapper for write operations that need more detail than a boolean.
/// </summary>
public sealed class OperationResult
{
private OperationResult(bool succeeded, string? errorCode)
{
Succeeded = succeeded;
ErrorCode = errorCode;
}
public bool Succeeded { get; }
public string? ErrorCode { get; }
public static OperationResult Success() => new OperationResult(true, null);
public static OperationResult Fail(string errorCode) => new OperationResult(false, errorCode);
}