diff options
Diffstat (limited to 'plugins/VNLib.Plugins.Essentials.Accounts/src/Endpoints/LoginEndpoint.cs')
-rw-r--r-- | plugins/VNLib.Plugins.Essentials.Accounts/src/Endpoints/LoginEndpoint.cs | 60 |
1 files changed, 32 insertions, 28 deletions
diff --git a/plugins/VNLib.Plugins.Essentials.Accounts/src/Endpoints/LoginEndpoint.cs b/plugins/VNLib.Plugins.Essentials.Accounts/src/Endpoints/LoginEndpoint.cs index 66a099e..2475f36 100644 --- a/plugins/VNLib.Plugins.Essentials.Accounts/src/Endpoints/LoginEndpoint.cs +++ b/plugins/VNLib.Plugins.Essentials.Accounts/src/Endpoints/LoginEndpoint.cs @@ -25,6 +25,7 @@ using System; using System.Net; using System.Text.Json; +using System.Threading; using System.Threading.Tasks; using System.Security.Cryptography; using System.Text.Json.Serialization; @@ -32,7 +33,6 @@ using System.Text.Json.Serialization; using FluentValidation; using VNLib.Utils; -using VNLib.Utils.Memory; using VNLib.Utils.Logging; using VNLib.Utils.Extensions; using VNLib.Plugins.Essentials.Users; @@ -45,6 +45,7 @@ using VNLib.Plugins.Extensions.Loading; using VNLib.Plugins.Extensions.Loading.Users; using static VNLib.Plugins.Essentials.Statics; + /* * Password only log-ins should be immune to repeat attacks on the same backend, because sessions are * guarunteed to be mutally exclusive on the same system, therefor a successful login cannot be repeated @@ -71,8 +72,7 @@ namespace VNLib.Plugins.Essentials.Accounts.Endpoints public const string MFA_ERROR_MESSAGE = "Invalid or expired request."; private static readonly LoginMessageValidation LmValidator = new(); - - private readonly IPasswordHashingProvider Passwords; + private readonly MFAConfig MultiFactor; private readonly IUserManager Users; private readonly FailedLoginLockout _lockout; @@ -84,8 +84,7 @@ namespace VNLib.Plugins.Essentials.Accounts.Endpoints uint maxLogins = config["max_login_attempts"].GetUInt32(); InitPathAndLog(path, pbase.Log); - - Passwords = pbase.GetOrCreateSingleton<ManagedPasswordHashing>(); + Users = pbase.GetOrCreateSingleton<UserManager>(); MultiFactor = pbase.GetConfigElement<MFAConfig>(); _lockout = new(maxLogins, duration); @@ -136,9 +135,8 @@ namespace VNLib.Plugins.Essentials.Accounts.Endpoints { return VirtualClose(entity, webm, HttpStatusCode.UnprocessableEntity); } - - //Time to get the user - using IUser? user = await Users.GetUserAndPassFromEmailAsync(loginMessage.UserName); + + using IUser? user = await Users.GetUserFromEmailAsync(loginMessage.UserName); //Make sure account exists if (webm.Assert(user != null, INVALID_MESSAGE)) @@ -155,15 +153,25 @@ namespace VNLib.Plugins.Essentials.Accounts.Endpoints } //Only allow local accounts - if (user.IsLocalAccount() && !PrivateString.IsNullOrEmpty(user.PassHash)) + if (!user.IsLocalAccount()) { - //If login return true, the response has been set and we should return - if (LoginUser(entity, loginMessage, user, webm)) - { - goto Cleanup; - } + goto Failed; + } + + //Validate password + if (await ValidatePasswordAsync(user, loginMessage, entity.EventCancellation) == false) + { + goto Failed; + } + + //If login return true, the response has been set and we should return + if (LoginUser(entity, loginMessage, user, webm)) + { + goto Cleanup; } + Failed: + //Inc failed login count _lockout.Increment(user, entity.RequestedTimeUtc); webm.Result = INVALID_MESSAGE; @@ -177,16 +185,19 @@ namespace VNLib.Plugins.Essentials.Accounts.Endpoints Log.Warn(uue); return VfReturnType.Error; } - } + } + + private async Task<bool> ValidatePasswordAsync(IUser user, LoginMessage login, CancellationToken cancellation) + { + //Validate password against store + ERRNO valResult = await Users.ValidatePasswordAsync(user, login.Password!, PassValidateFlags.None, cancellation); + + //Valid results are greater than 0; + return valResult > 0; + } private bool LoginUser(HttpEntity entity, LoginMessage loginMessage, IUser user, MfaUpgradeWebm webm) { - //Verify password before we tell the user the status of their account for security reasons - if (!Passwords.Verify(user.PassHash!, loginMessage.Password)) - { - return false; - } - //Only allow active users if (user.Status != UserStatus.Active) { @@ -195,13 +206,6 @@ namespace VNLib.Plugins.Essentials.Accounts.Endpoints return false; } - //Is the account restricted to a local network connection? - if (user.LocalOnly && !entity.IsLocalConnection) - { - Log.Information("User {uid} attempted a login from a non-local network with the correct password. Access was denied", user.UserID); - return false; - } - //Reset flc for account, either the user will be authorized, or the mfa will be triggered, but the flc should be reset user.ClearFailedLoginCount(); |