refactor: distribute the domain folder
This commit is contained in:
parent
43edab2912
commit
36026b3afb
@ -1,17 +1,17 @@
|
||||
using Mirea.Api.Dto.Common;
|
||||
using PasswordPolicy = Mirea.Api.Dto.Common.PasswordPolicy;
|
||||
|
||||
namespace Mirea.Api.Endpoint.Common.MapperDto;
|
||||
|
||||
public static class PasswordPolicyConverter
|
||||
{
|
||||
public static Security.Common.Domain.PasswordPolicy ConvertFromDto(this PasswordPolicy policy) =>
|
||||
public static Security.Common.Model.PasswordPolicy ConvertFromDto(this PasswordPolicy policy) =>
|
||||
new(policy.MinimumLength,
|
||||
policy.RequireLetter,
|
||||
policy.RequireLettersDifferentCase,
|
||||
policy.RequireDigit,
|
||||
policy.RequireSpecialCharacter);
|
||||
|
||||
public static PasswordPolicy ConvertToDto(this Security.Common.Domain.PasswordPolicy policy) =>
|
||||
public static PasswordPolicy ConvertToDto(this Security.Common.Model.PasswordPolicy policy) =>
|
||||
new()
|
||||
{
|
||||
MinimumLength = policy.MinimumLength,
|
||||
|
@ -1,24 +1,23 @@
|
||||
using Mirea.Api.Dto.Common;
|
||||
using Mirea.Api.Security.Common.Domain;
|
||||
using System;
|
||||
|
||||
namespace Mirea.Api.Endpoint.Common.MapperDto;
|
||||
|
||||
public static class TwoFactorAuthenticationConverter
|
||||
{
|
||||
public static TwoFactorAuthentication ConvertToDto(this TwoFactorAuthenticator authenticator) =>
|
||||
public static TwoFactorAuthentication ConvertToDto(this Security.Common.Model.TwoFactorAuthenticator authenticator) =>
|
||||
authenticator switch
|
||||
{
|
||||
TwoFactorAuthenticator.None => TwoFactorAuthentication.None,
|
||||
TwoFactorAuthenticator.Totp => TwoFactorAuthentication.TotpRequired,
|
||||
Security.Common.Model.TwoFactorAuthenticator.None => TwoFactorAuthentication.None,
|
||||
Security.Common.Model.TwoFactorAuthenticator.Totp => TwoFactorAuthentication.TotpRequired,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(authenticator), authenticator, null)
|
||||
};
|
||||
|
||||
public static TwoFactorAuthenticator ConvertFromDto(this TwoFactorAuthentication authentication) =>
|
||||
public static Security.Common.Model.TwoFactorAuthenticator ConvertFromDto(this TwoFactorAuthentication authentication) =>
|
||||
authentication switch
|
||||
{
|
||||
TwoFactorAuthentication.None => TwoFactorAuthenticator.None,
|
||||
TwoFactorAuthentication.TotpRequired => TwoFactorAuthenticator.Totp,
|
||||
TwoFactorAuthentication.None => Security.Common.Model.TwoFactorAuthenticator.None,
|
||||
TwoFactorAuthentication.TotpRequired => Security.Common.Model.TwoFactorAuthenticator.Totp,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(authentication), authentication, null)
|
||||
};
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
using Mirea.Api.Endpoint.Common.Services;
|
||||
using Mirea.Api.Security.Common.Domain;
|
||||
using Mirea.Api.Security.Common.Model;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
|
@ -1,6 +1,6 @@
|
||||
using Mirea.Api.Endpoint.Common.Services;
|
||||
using Mirea.Api.Endpoint.Configuration.Model.GeneralSettings;
|
||||
using Mirea.Api.Security.Common.Domain;
|
||||
using Mirea.Api.Security.Common.Model;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
@ -18,7 +18,7 @@ using Mirea.Api.Endpoint.Common.Services;
|
||||
using Mirea.Api.Endpoint.Configuration.Model;
|
||||
using Mirea.Api.Endpoint.Configuration.Model.GeneralSettings;
|
||||
using Mirea.Api.Endpoint.Configuration.Validation.Validators;
|
||||
using Mirea.Api.Security.Common.Domain;
|
||||
using Mirea.Api.Security.Common.Model;
|
||||
using Mirea.Api.Security.Services;
|
||||
using MySqlConnector;
|
||||
using Npgsql;
|
||||
@ -32,6 +32,7 @@ using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Security.Cryptography;
|
||||
using CookieOptions = Microsoft.AspNetCore.Http.CookieOptions;
|
||||
using PasswordPolicy = Mirea.Api.Dto.Common.PasswordPolicy;
|
||||
|
||||
namespace Mirea.Api.Endpoint.Controllers.Configuration;
|
||||
@ -539,7 +540,7 @@ public class SetupController(
|
||||
[TokenAuthentication]
|
||||
public ActionResult<bool> SetPasswordPolicy([FromBody] PasswordPolicy? policy = null)
|
||||
{
|
||||
GeneralConfig.PasswordPolicy = policy?.ConvertFromDto() ?? new Security.Common.Domain.PasswordPolicy();
|
||||
GeneralConfig.PasswordPolicy = policy?.ConvertFromDto() ?? new Security.Common.Model.PasswordPolicy();
|
||||
cache.Set("password", true);
|
||||
return true;
|
||||
}
|
||||
|
@ -11,13 +11,14 @@ using Mirea.Api.Endpoint.Common.Exceptions;
|
||||
using Mirea.Api.Endpoint.Common.MapperDto;
|
||||
using Mirea.Api.Endpoint.Common.Services;
|
||||
using Mirea.Api.Endpoint.Configuration.Model;
|
||||
using Mirea.Api.Security.Common.Domain;
|
||||
using Mirea.Api.Security.Common.Model;
|
||||
using Mirea.Api.Security.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using CookieOptions = Mirea.Api.Security.Common.Model.CookieOptions;
|
||||
using OAuthProvider = Mirea.Api.Security.Common.Domain.OAuthProvider;
|
||||
|
||||
namespace Mirea.Api.Endpoint.Controllers.V1;
|
||||
@ -26,7 +27,7 @@ namespace Mirea.Api.Endpoint.Controllers.V1;
|
||||
public class AuthController(IOptionsSnapshot<Admin> user, IOptionsSnapshot<GeneralConfig> generalConfig, AuthService auth,
|
||||
PasswordHashService passwordService, OAuthService oAuthService) : BaseController
|
||||
{
|
||||
private CookieOptionsParameters GetCookieParams() =>
|
||||
private CookieOptions GetCookieParams() =>
|
||||
new()
|
||||
{
|
||||
Domain = HttpContext.GetCurrentDomain(),
|
||||
@ -53,6 +54,19 @@ public class AuthController(IOptionsSnapshot<Admin> user, IOptionsSnapshot<Gener
|
||||
return $"<!DOCTYPE html><html lang=ru><head><meta charset=UTF-8><meta content=\"width=device-width,initial-scale=1\"name=viewport><link href=\"https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap\"rel=stylesheet><style>body{{background-color:#121212;color:#fff;font-family:Roboto,sans-serif;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;text-align:center}}.container{{max-width:600px;padding:20px;border-radius:8px;background-color:#1e1e1e;box-shadow:0 4px 20px rgba(0,0,0,.5)}}h1{{font-size:24px;margin-bottom:20px}}</style><title>{title}</title></head><body><div class=container><h1>{title}</h1>{blockInfo}<p style=font-size:14px;color:silver;>{message}</p><code style=font-size:12px;color:gray;>TraceId={traceId}</code></div>{script}</body></html>";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the callback from an OAuth2 provider and finalizes the authorization process.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method processes the response from an OAuth provider after the user authorizes the application.
|
||||
/// Upon successful authorization, it redirects the user back to the specified callback URL.
|
||||
/// </remarks>
|
||||
/// <param name="code">The authorization code returned by the OAuth provider.</param>
|
||||
/// <param name="state">The state parameter to ensure the request's integrity and prevent CSRF attacks.</param>
|
||||
/// <returns>
|
||||
/// An HTML response indicating the success or failure of the authorization process.
|
||||
/// If a callback URL is provided, the user will be redirected to it.
|
||||
/// </returns>
|
||||
[HttpGet("OAuth2")]
|
||||
[BadRequestResponse]
|
||||
[Produces("text/html")]
|
||||
@ -163,6 +177,7 @@ public class AuthController(IOptionsSnapshot<Admin> user, IOptionsSnapshot<Gener
|
||||
|
||||
var tokenResult = await auth.LoginAsync(
|
||||
GetCookieParams(),
|
||||
HttpContext,
|
||||
new User
|
||||
{
|
||||
Id = 1.ToString(),
|
||||
@ -174,7 +189,7 @@ public class AuthController(IOptionsSnapshot<Admin> user, IOptionsSnapshot<Gener
|
||||
SecondFactorToken = userEntity.Secret,
|
||||
OAuthProviders = userEntity.OAuthProviders
|
||||
},
|
||||
HttpContext, request.Password, request.Username);
|
||||
request.Password, request.Username);
|
||||
|
||||
return Ok(tokenResult.ConvertToDto());
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
namespace Mirea.Api.Security.Common.Domain.Caching;
|
||||
using Mirea.Api.Security.Common.Model;
|
||||
|
||||
namespace Mirea.Api.Security.Common.Domain.Caching;
|
||||
|
||||
internal class FirstAuthToken
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace Mirea.Api.Security.Common.Domain.OAuth2;
|
||||
namespace Mirea.Api.Security.Common.Domain;
|
||||
|
||||
public class OAuthPayload
|
||||
internal class OAuthPayload
|
||||
{
|
||||
public required OAuthProvider Provider { get; set; }
|
||||
public required string Callback { get; set; }
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Mirea.Api.Security.Common.Domain.OAuth2;
|
||||
namespace Mirea.Api.Security.Common.Domain;
|
||||
|
||||
internal readonly struct OAuthProviderUrisData
|
||||
{
|
@ -7,7 +7,7 @@ namespace Mirea.Api.Security.Common.Domain;
|
||||
|
||||
internal class RequestContextInfo
|
||||
{
|
||||
public RequestContextInfo(HttpContext context, CookieOptionsParameters cookieOptions)
|
||||
public RequestContextInfo(HttpContext context, Model.CookieOptions cookieOptions)
|
||||
{
|
||||
var ipEntity = context.Connection.RemoteIpAddress;
|
||||
|
||||
|
@ -1,16 +1,16 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System;
|
||||
|
||||
namespace Mirea.Api.Security.Common.Domain;
|
||||
namespace Mirea.Api.Security.Common.Model;
|
||||
|
||||
public class CookieOptionsParameters
|
||||
public class CookieOptions
|
||||
{
|
||||
public required string Domain { get; set; }
|
||||
public required string Path { get; set; }
|
||||
|
||||
internal void SetCookie(HttpContext context, string name, string value, DateTimeOffset? expires = null)
|
||||
{
|
||||
var cookieOptions = new CookieOptions
|
||||
var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions
|
||||
{
|
||||
Expires = expires,
|
||||
Path = Path,
|
@ -1,4 +1,4 @@
|
||||
namespace Mirea.Api.Security.Common.Domain;
|
||||
namespace Mirea.Api.Security.Common.Model;
|
||||
|
||||
public class PasswordPolicy(
|
||||
int minimumLength = 8,
|
@ -1,4 +1,4 @@
|
||||
namespace Mirea.Api.Security.Common.Domain;
|
||||
namespace Mirea.Api.Security.Common.Model;
|
||||
|
||||
public enum TwoFactorAuthenticator
|
||||
{
|
@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Mirea.Api.Security.Common.Domain;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Mirea.Api.Security.Common.Domain;
|
||||
namespace Mirea.Api.Security.Common.Model;
|
||||
|
||||
public class User
|
||||
{
|
@ -1,8 +1,8 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Mirea.Api.Security.Common.Domain.OAuth2;
|
||||
namespace Mirea.Api.Security.Common.OAuth2;
|
||||
|
||||
public class OAuthTokenResponse
|
||||
internal class OAuthTokenResponse
|
||||
{
|
||||
[JsonPropertyName("access_token")]
|
||||
public required string AccessToken { get; set; }
|
@ -1,7 +1,8 @@
|
||||
using Mirea.Api.Security.Common.Interfaces;
|
||||
using Mirea.Api.Security.Common.Domain;
|
||||
using Mirea.Api.Security.Common.Interfaces;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Mirea.Api.Security.Common.Domain.OAuth2.UserInfo;
|
||||
namespace Mirea.Api.Security.Common.OAuth2.UserInfo;
|
||||
|
||||
internal class GoogleUserInfo : IUserInfo
|
||||
{
|
@ -1,7 +1,8 @@
|
||||
using Mirea.Api.Security.Common.Interfaces;
|
||||
using Mirea.Api.Security.Common.Domain;
|
||||
using Mirea.Api.Security.Common.Interfaces;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Mirea.Api.Security.Common.Domain.OAuth2.UserInfo;
|
||||
namespace Mirea.Api.Security.Common.OAuth2.UserInfo;
|
||||
|
||||
internal class MailRuUserInfo : IUserInfo
|
||||
{
|
@ -1,7 +1,8 @@
|
||||
using Mirea.Api.Security.Common.Interfaces;
|
||||
using Mirea.Api.Security.Common.Domain;
|
||||
using Mirea.Api.Security.Common.Interfaces;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Mirea.Api.Security.Common.Domain.OAuth2.UserInfo;
|
||||
namespace Mirea.Api.Security.Common.OAuth2.UserInfo;
|
||||
|
||||
internal class YandexUserInfo : IUserInfo
|
||||
{
|
@ -1,8 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace Mirea.Api.Security.Common.Domain;
|
||||
namespace Mirea.Api.Security.Common.ViewModel;
|
||||
|
||||
public class LoginOAuthResult
|
||||
public class LoginOAuth
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public required string Token { get; set; }
|
@ -4,11 +4,13 @@ using Mirea.Api.Security.Common;
|
||||
using Mirea.Api.Security.Common.Domain;
|
||||
using Mirea.Api.Security.Common.Domain.Caching;
|
||||
using Mirea.Api.Security.Common.Interfaces;
|
||||
using Mirea.Api.Security.Common.Model;
|
||||
using System;
|
||||
using System.Security;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CookieOptions = Mirea.Api.Security.Common.Model.CookieOptions;
|
||||
|
||||
namespace Mirea.Api.Security.Services;
|
||||
|
||||
@ -94,7 +96,7 @@ public class AuthService(ICacheService cache, IAccessToken accessTokenService, I
|
||||
throw new SecurityException("Authentication failed. Please check your credentials.");
|
||||
}
|
||||
|
||||
private async Task GenerateAuthTokensAsync(CookieOptionsParameters cookieOptions, HttpContext context,
|
||||
private async Task GenerateAuthTokensAsync(CookieOptions cookieOptions, HttpContext context,
|
||||
RequestContextInfo requestContext, string userId, CancellationToken cancellation = default)
|
||||
{
|
||||
var refreshToken = GenerateRefreshToken();
|
||||
@ -118,23 +120,7 @@ public class AuthService(ICacheService cache, IAccessToken accessTokenService, I
|
||||
authToken.Fingerprint);
|
||||
}
|
||||
|
||||
public async Task<TwoFactorAuthenticator> LoginOAuthAsync(CookieOptionsParameters cookieOptions, HttpContext context, User user,
|
||||
CancellationToken cancellation = default)
|
||||
{
|
||||
var requestContext = new RequestContextInfo(context, cookieOptions);
|
||||
|
||||
if (user.TwoFactorAuthenticator == TwoFactorAuthenticator.None)
|
||||
{
|
||||
await GenerateAuthTokensAsync(cookieOptions, context, requestContext, user.Id, cancellation);
|
||||
return TwoFactorAuthenticator.None;
|
||||
}
|
||||
|
||||
await StoreFirstAuthTokenInCache(user, requestContext, cancellation);
|
||||
|
||||
return user.TwoFactorAuthenticator;
|
||||
}
|
||||
|
||||
public async Task<bool> LoginAsync(CookieOptionsParameters cookieOptions, HttpContext context, TwoFactorAuthenticator authenticator, string code,
|
||||
public async Task<bool> LoginAsync(CookieOptions cookieOptions, HttpContext context, TwoFactorAuthenticator authenticator, string code,
|
||||
CancellationToken cancellation = default)
|
||||
{
|
||||
var requestContext = new RequestContextInfo(context, cookieOptions);
|
||||
@ -176,12 +162,12 @@ public class AuthService(ICacheService cache, IAccessToken accessTokenService, I
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<TwoFactorAuthenticator> LoginAsync(CookieOptionsParameters cookieOptions, User user, HttpContext context, string password,
|
||||
string username, CancellationToken cancellation = default)
|
||||
private async Task<TwoFactorAuthenticator> LoginAsync(CookieOptions cookieOptions,
|
||||
HttpContext context,
|
||||
User user,
|
||||
CancellationToken cancellation = default)
|
||||
{
|
||||
var requestContext = new RequestContextInfo(context, cookieOptions);
|
||||
username = username.Trim();
|
||||
await VerifyUserOrThrowError(requestContext, user, password, username, cancellation);
|
||||
|
||||
if (user.TwoFactorAuthenticator == TwoFactorAuthenticator.None)
|
||||
{
|
||||
@ -194,7 +180,27 @@ public class AuthService(ICacheService cache, IAccessToken accessTokenService, I
|
||||
return user.TwoFactorAuthenticator;
|
||||
}
|
||||
|
||||
public async Task RefreshTokenAsync(CookieOptionsParameters cookieOptions, HttpContext context, CancellationToken cancellation = default)
|
||||
public Task<TwoFactorAuthenticator> LoginOAuthAsync(CookieOptions cookieOptions,
|
||||
HttpContext context,
|
||||
User user,
|
||||
CancellationToken cancellation = default) =>
|
||||
LoginAsync(cookieOptions, context, user, cancellation);
|
||||
|
||||
public async Task<TwoFactorAuthenticator> LoginAsync(CookieOptions cookieOptions,
|
||||
HttpContext context,
|
||||
User user,
|
||||
string password,
|
||||
string username,
|
||||
CancellationToken cancellation = default)
|
||||
{
|
||||
var requestContext = new RequestContextInfo(context, cookieOptions);
|
||||
username = username.Trim();
|
||||
await VerifyUserOrThrowError(requestContext, user, password, username, cancellation);
|
||||
|
||||
return await LoginAsync(cookieOptions, context, user, cancellation);
|
||||
}
|
||||
|
||||
public async Task RefreshTokenAsync(CookieOptions cookieOptions, HttpContext context, CancellationToken cancellation = default)
|
||||
{
|
||||
const string defaultMessageError = "The session time has expired";
|
||||
var requestContext = new RequestContextInfo(context, cookieOptions);
|
||||
@ -271,7 +277,7 @@ public class AuthService(ICacheService cache, IAccessToken accessTokenService, I
|
||||
cookieOptions.SetCookie(context, CookieNames.RefreshToken, authToken.RefreshToken, DateTime.UtcNow.Add(Lifetime));
|
||||
}
|
||||
|
||||
public async Task LogoutAsync(CookieOptionsParameters cookieOptions, HttpContext context, CancellationToken cancellation = default)
|
||||
public async Task LogoutAsync(CookieOptions cookieOptions, HttpContext context, CancellationToken cancellation = default)
|
||||
{
|
||||
var requestContext = new RequestContextInfo(context, cookieOptions);
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Mirea.Api.Security.Common.Domain;
|
||||
using Mirea.Api.Security.Common.Domain.OAuth2;
|
||||
using Mirea.Api.Security.Common.Domain.OAuth2.UserInfo;
|
||||
using Mirea.Api.Security.Common.Interfaces;
|
||||
using Mirea.Api.Security.Common.OAuth2;
|
||||
using Mirea.Api.Security.Common.OAuth2.UserInfo;
|
||||
using Mirea.Api.Security.Common.ViewModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@ -15,6 +16,7 @@ using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CookieOptions = Mirea.Api.Security.Common.Model.CookieOptions;
|
||||
|
||||
namespace Mirea.Api.Security.Services;
|
||||
|
||||
@ -165,6 +167,7 @@ public class OAuthService(ILogger<OAuthService> logger, Dictionary<OAuthProvider
|
||||
}
|
||||
|
||||
public Uri GetProviderRedirect(HttpContext context, CookieOptionsParameters cookieOptions, string redirectUri,
|
||||
public Uri GetProviderRedirect(HttpContext context, CookieOptions cookieOptions, string redirectUri,
|
||||
OAuthProvider provider, Uri callback)
|
||||
{
|
||||
var (clientId, _) = providers[provider];
|
||||
@ -195,10 +198,10 @@ public class OAuthService(ILogger<OAuthService> logger, Dictionary<OAuthProvider
|
||||
public (OAuthProvider Provider, Uri Redirect)[] GetAvailableProviders(string redirectUri) =>
|
||||
[.. providers.Select(x => (x.Key, new Uri(redirectUri.TrimEnd('/') + "/?provider=" + (int)x.Key)))];
|
||||
|
||||
public async Task<LoginOAuthResult> LoginOAuth(HttpContext context, CookieOptionsParameters cookieOptions,
|
||||
public async Task<LoginOAuth> LoginOAuth(HttpContext context, CookieOptions cookieOptions,
|
||||
string redirectUrl, string code, string state, CancellationToken cancellation = default)
|
||||
{
|
||||
var result = new LoginOAuthResult()
|
||||
var result = new LoginOAuth()
|
||||
{
|
||||
Token = GeneratorKey.GenerateBase64(32)
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
using Mirea.Api.Security.Common.Domain;
|
||||
using Mirea.Api.Security.Common.Model;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user