diff --git a/Endpoint/Common/MapperDto/PasswordPolicyConverter.cs b/Endpoint/Common/MapperDto/PasswordPolicyConverter.cs index 85d27d4..a016c66 100644 --- a/Endpoint/Common/MapperDto/PasswordPolicyConverter.cs +++ b/Endpoint/Common/MapperDto/PasswordPolicyConverter.cs @@ -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, diff --git a/Endpoint/Common/MapperDto/TwoFactorAuthenticationConverter.cs b/Endpoint/Common/MapperDto/TwoFactorAuthenticationConverter.cs index 4086790..5239444 100644 --- a/Endpoint/Common/MapperDto/TwoFactorAuthenticationConverter.cs +++ b/Endpoint/Common/MapperDto/TwoFactorAuthenticationConverter.cs @@ -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) }; } \ No newline at end of file diff --git a/Endpoint/Configuration/Model/Admin.cs b/Endpoint/Configuration/Model/Admin.cs index 381981b..d9488f8 100644 --- a/Endpoint/Configuration/Model/Admin.cs +++ b/Endpoint/Configuration/Model/Admin.cs @@ -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; diff --git a/Endpoint/Configuration/Model/GeneralConfig.cs b/Endpoint/Configuration/Model/GeneralConfig.cs index f363517..331c681 100644 --- a/Endpoint/Configuration/Model/GeneralConfig.cs +++ b/Endpoint/Configuration/Model/GeneralConfig.cs @@ -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; diff --git a/Endpoint/Controllers/Configuration/SetupController.cs b/Endpoint/Controllers/Configuration/SetupController.cs index 2d64f7d..7c3441e 100644 --- a/Endpoint/Controllers/Configuration/SetupController.cs +++ b/Endpoint/Controllers/Configuration/SetupController.cs @@ -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 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; } diff --git a/Endpoint/Controllers/V1/AuthController.cs b/Endpoint/Controllers/V1/AuthController.cs index 8c0c7e8..7bf58f9 100644 --- a/Endpoint/Controllers/V1/AuthController.cs +++ b/Endpoint/Controllers/V1/AuthController.cs @@ -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 user, IOptionsSnapshot 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 user, IOptionsSnapshot{title}

{title}

{blockInfo}

{message}

TraceId={traceId}
{script}"; } + /// + /// Handles the callback from an OAuth2 provider and finalizes the authorization process. + /// + /// + /// 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. + /// + /// The authorization code returned by the OAuth provider. + /// The state parameter to ensure the request's integrity and prevent CSRF attacks. + /// + /// 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. + /// [HttpGet("OAuth2")] [BadRequestResponse] [Produces("text/html")] @@ -163,6 +177,7 @@ public class AuthController(IOptionsSnapshot user, IOptionsSnapshot user, IOptionsSnapshot 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 LoginAsync(CookieOptionsParameters cookieOptions, HttpContext context, TwoFactorAuthenticator authenticator, string code, + public async Task 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 LoginAsync(CookieOptionsParameters cookieOptions, User user, HttpContext context, string password, - string username, CancellationToken cancellation = default) + private async Task 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 LoginOAuthAsync(CookieOptions cookieOptions, + HttpContext context, + User user, + CancellationToken cancellation = default) => + LoginAsync(cookieOptions, context, user, cancellation); + + public async Task 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); diff --git a/Security/Services/OAuthService.cs b/Security/Services/OAuthService.cs index 8ba5018..cc0c3dc 100644 --- a/Security/Services/OAuthService.cs +++ b/Security/Services/OAuthService.cs @@ -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 logger, Dictionary logger, Dictionary [.. providers.Select(x => (x.Key, new Uri(redirectUri.TrimEnd('/') + "/?provider=" + (int)x.Key)))]; - public async Task LoginOAuth(HttpContext context, CookieOptionsParameters cookieOptions, + public async Task 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) }; diff --git a/Security/Services/PasswordPolicyService.cs b/Security/Services/PasswordPolicyService.cs index 63f421e..2179c9c 100644 --- a/Security/Services/PasswordPolicyService.cs +++ b/Security/Services/PasswordPolicyService.cs @@ -1,4 +1,4 @@ -using Mirea.Api.Security.Common.Domain; +using Mirea.Api.Security.Common.Model; using System.Linq; using System.Security;