mirror of
https://github.com/bitwarden/server
synced 2026-01-08 03:23:20 +00:00
refactor(DeviceValidator): [Auth/PM-24362] Misc improvements (#6152)
* PM-24362 - DeviceValidator - (1) refactor name of NewDeviceOtpRequest --> RequestHasNewDeviceVerificationOtp (2) Move auth request rejection check above normal NDV check and remove auth request check from NDV check * PM-24362 - Update DeviceValidatorTests + add new scenario
This commit is contained in:
@@ -13,6 +13,7 @@ using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Identity.IdentityServer.Enums;
|
||||
using Duende.IdentityServer.Models;
|
||||
using Duende.IdentityServer.Validation;
|
||||
using Microsoft.Extensions.Caching.Distributed;
|
||||
|
||||
@@ -55,8 +56,10 @@ public class DeviceValidator(
|
||||
return false;
|
||||
}
|
||||
|
||||
// if not a new device request then check if the device is known
|
||||
if (!NewDeviceOtpRequest(request))
|
||||
// Check if the request has a NewDeviceOtp, if it does we can assume it is an unknown device
|
||||
// that has already been prompted for new device verification so we don't
|
||||
// have to hit the database to check if the device is known to avoid unnecessary database calls.
|
||||
if (!RequestHasNewDeviceVerificationOtp(request))
|
||||
{
|
||||
var knownDevice = await GetKnownDeviceAsync(context.User, requestDevice);
|
||||
// if the device is know then we return the device fetched from the database
|
||||
@@ -69,14 +72,23 @@ public class DeviceValidator(
|
||||
}
|
||||
}
|
||||
|
||||
// We have established that the device is unknown at this point; begin new device verification
|
||||
// for standard password grant type requests
|
||||
// Note: the auth request flow re-uses the resource owner password flow but new device verification
|
||||
// is not required for auth requests
|
||||
// The device is either unknown or the request has a NewDeviceOtp (implies unknown device)
|
||||
|
||||
var rawAuthRequestId = request.Raw["AuthRequest"]?.ToLowerInvariant();
|
||||
var isAuthRequest = !string.IsNullOrEmpty(rawAuthRequestId);
|
||||
if (request.GrantType == PasswordGrantType &&
|
||||
!isAuthRequest &&
|
||||
|
||||
// Device unknown, but if we are in an auth request flow, this is not valid
|
||||
// as we only support auth request authN requests on known devices
|
||||
// Note: we re-use the resource owner password flow for auth requests
|
||||
if (request.GrantType == GrantType.ResourceOwnerPassword && isAuthRequest)
|
||||
{
|
||||
(context.ValidationErrorResult, context.CustomResponse) =
|
||||
BuildDeviceErrorResult(DeviceValidationResultType.AuthRequestFlowUnknownDevice);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Enforce new device verification for resource owner password flow (just normal password flow)
|
||||
if (request.GrantType == GrantType.ResourceOwnerPassword &&
|
||||
context is { TwoFactorRequired: false, SsoRequired: false } &&
|
||||
_globalSettings.EnableNewDeviceVerification)
|
||||
{
|
||||
@@ -93,15 +105,6 @@ public class DeviceValidator(
|
||||
}
|
||||
}
|
||||
|
||||
// Device still unknown, but if we are in an auth request flow, this is not valid
|
||||
// as we only support auth request authN requests on known devices
|
||||
if (request.GrantType == PasswordGrantType && isAuthRequest)
|
||||
{
|
||||
(context.ValidationErrorResult, context.CustomResponse) =
|
||||
BuildDeviceErrorResult(DeviceValidationResultType.AuthRequestFlowUnknownDevice);
|
||||
return false;
|
||||
}
|
||||
|
||||
// At this point we have established either new device verification is not required or the NewDeviceOtp is valid,
|
||||
// so we save the device to the database and proceed with authentication
|
||||
requestDevice.UserId = context.User.Id;
|
||||
@@ -247,7 +250,7 @@ public class DeviceValidator(
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
public static bool NewDeviceOtpRequest(ValidatedRequest request)
|
||||
public static bool RequestHasNewDeviceVerificationOtp(ValidatedRequest request)
|
||||
{
|
||||
return !string.IsNullOrEmpty(request.Raw["NewDeviceOtp"]?.ToString());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user