aboutsummaryrefslogtreecommitdiff
path: root/plugins/VNLib.Plugins.Essentials.Accounts/src/Endpoints/LoginEndpoint.cs
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/VNLib.Plugins.Essentials.Accounts/src/Endpoints/LoginEndpoint.cs')
-rw-r--r--plugins/VNLib.Plugins.Essentials.Accounts/src/Endpoints/LoginEndpoint.cs60
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();