mirror of
https://github.com/bitwarden/mobile
synced 2026-01-21 03:43:17 +00:00
[PM-6466] Implement passkeys User Verification (#3044)
* PM-6441 Implement passkeys User Verification * PM-6441 Reorganized UserVerificationMediatorService so everything is not in the same file * PM-6441 Fix Unit tests * PM-6441 Refactor UserVerification on Fido2Authenticator and Client services to be of an enum type so we can see which specific preference the RP sent and to be passed into the user verification mediator service to perform the correct flow depending on that. Also updated Unit tests. * PM-6441 Changed user verification logic a bit so if preference is Preferred and the app has the ability to verify the user then enforce required UV and fix issue on on Discouraged to take into account MP reprompt
This commit is contained in:
committed by
GitHub
parent
e41abf5003
commit
4292542155
@@ -11,9 +11,9 @@
|
||||
public PublicKeyCredentialDescriptor[] AllowCredentialDescriptorList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Instructs the authenticator to require a user-verifying gesture in order to complete the request. Examples of such gestures are fingerprint scan or a PIN.
|
||||
/// Instructs the authenticator the user verification preference in order to complete the request. Examples of UV gestures are fingerprint scan or a PIN.
|
||||
/// </summary>
|
||||
public bool RequireUserVerification { get; set; }
|
||||
public Fido2UserVerificationPreference UserVerificationPreference { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The challenge to be signed by the authenticator.
|
||||
|
||||
@@ -33,9 +33,9 @@ namespace Bit.Core.Utilities.Fido2
|
||||
public bool RequireResidentKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The effective user verification requirement for assertion, a Boolean value provided by the client.
|
||||
/// The effective user verification preference for assertion, provided by the client.
|
||||
/// </summary>
|
||||
public bool RequireUserVerification { get; set; }
|
||||
public Fido2UserVerificationPreference UserVerificationPreference { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// CTAP2 authenticators support setting this to false, but we only support the WebAuthn authenticator model which does not have that option.
|
||||
|
||||
@@ -15,19 +15,27 @@ namespace Bit.Core.Utilities.Fido2
|
||||
private readonly string _cipherId;
|
||||
private readonly bool _userVerified = false;
|
||||
private readonly Func<Task> _ensureUnlockedVaultCallback;
|
||||
private readonly Func<Task<bool>> _verifyUserCallback;
|
||||
private readonly Func<bool> _hasVaultBeenUnlockedInThisTransaction;
|
||||
private readonly Func<string, Fido2UserVerificationPreference, Task<bool>> _verifyUserCallback;
|
||||
|
||||
/// <param name="cipherId">The cipherId for the credential that the user has already picker</param>
|
||||
/// <param name="userVerified">True if the user has already been verified by the operating system</param>
|
||||
public Fido2GetAssertionUserInterface(string cipherId, bool userVerified, Func<Task> ensureUnlockedVaultCallback, Func<Task<bool>> verifyUserCallback)
|
||||
public Fido2GetAssertionUserInterface(string cipherId,
|
||||
bool userVerified,
|
||||
Func<Task> ensureUnlockedVaultCallback,
|
||||
Func<bool> hasVaultBeenUnlockedInThisTransaction,
|
||||
Func<string, Fido2UserVerificationPreference, Task<bool>> verifyUserCallback)
|
||||
{
|
||||
_cipherId = cipherId;
|
||||
_userVerified = userVerified;
|
||||
_ensureUnlockedVaultCallback = ensureUnlockedVaultCallback;
|
||||
_hasVaultBeenUnlockedInThisTransaction = hasVaultBeenUnlockedInThisTransaction;
|
||||
_verifyUserCallback = verifyUserCallback;
|
||||
}
|
||||
|
||||
public async Task<(string CipherId, bool UserVerified)> PickCredentialAsync(Fido2GetAssertionUserInterfaceCredential[] credentials)
|
||||
public bool HasVaultBeenUnlockedInThisTransaction { get; private set; }
|
||||
|
||||
public async Task<(string CipherId, bool UserVerified)> PickCredentialAsync(Fido2GetAssertionUserInterfaceCredential[] credentials)
|
||||
{
|
||||
if (credentials.Length == 0 || !credentials.Any(c => c.CipherId == _cipherId))
|
||||
{
|
||||
@@ -35,18 +43,16 @@ namespace Bit.Core.Utilities.Fido2
|
||||
}
|
||||
|
||||
var credential = credentials.First(c => c.CipherId == _cipherId);
|
||||
var verified = _userVerified;
|
||||
if (credential.RequireUserVerification && !verified)
|
||||
{
|
||||
verified = await _verifyUserCallback();
|
||||
}
|
||||
var verified = _userVerified || await _verifyUserCallback(_cipherId, credential.UserVerificationPreference);
|
||||
|
||||
return (CipherId: _cipherId, UserVerified: verified);
|
||||
}
|
||||
|
||||
public Task EnsureUnlockedVaultAsync()
|
||||
public async Task EnsureUnlockedVaultAsync()
|
||||
{
|
||||
return _ensureUnlockedVaultCallback();
|
||||
await _ensureUnlockedVaultCallback();
|
||||
|
||||
HasVaultBeenUnlockedInThisTransaction = _hasVaultBeenUnlockedInThisTransaction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
24
src/Core/Utilities/Fido2/Fido2UserVerificationOptions.cs
Normal file
24
src/Core/Utilities/Fido2/Fido2UserVerificationOptions.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace Bit.Core.Utilities.Fido2
|
||||
{
|
||||
public readonly struct Fido2UserVerificationOptions
|
||||
{
|
||||
public Fido2UserVerificationOptions(bool shouldCheckMasterPasswordReprompt,
|
||||
Fido2UserVerificationPreference userVerificationPreference,
|
||||
bool hasVaultBeenUnlockedInTransaction,
|
||||
string rpId = null,
|
||||
Action onNeedUI = null)
|
||||
{
|
||||
ShouldCheckMasterPasswordReprompt = shouldCheckMasterPasswordReprompt;
|
||||
UserVerificationPreference = userVerificationPreference;
|
||||
HasVaultBeenUnlockedInTransaction = hasVaultBeenUnlockedInTransaction;
|
||||
RpId = rpId;
|
||||
OnNeedUI = onNeedUI;
|
||||
}
|
||||
|
||||
public bool ShouldCheckMasterPasswordReprompt { get; }
|
||||
public Fido2UserVerificationPreference UserVerificationPreference { get; }
|
||||
public bool HasVaultBeenUnlockedInTransaction { get; }
|
||||
public string RpId { get; }
|
||||
public Action OnNeedUI { get; }
|
||||
}
|
||||
}
|
||||
39
src/Core/Utilities/Fido2/Fido2UserVerificationPreference.cs
Normal file
39
src/Core/Utilities/Fido2/Fido2UserVerificationPreference.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
#nullable enable
|
||||
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.Utilities.Fido2
|
||||
{
|
||||
public enum Fido2UserVerificationPreference
|
||||
{
|
||||
Discouraged,
|
||||
Preferred,
|
||||
Required
|
||||
}
|
||||
|
||||
public static class Fido2UserVerificationPreferenceExtensions
|
||||
{
|
||||
public static Fido2UserVerificationPreference ToFido2UserVerificationPreference(string? preference)
|
||||
{
|
||||
switch (preference)
|
||||
{
|
||||
case "required":
|
||||
return Fido2UserVerificationPreference.Required;
|
||||
case "discouraged":
|
||||
return Fido2UserVerificationPreference.Discouraged;
|
||||
default:
|
||||
return Fido2UserVerificationPreference.Preferred;
|
||||
}
|
||||
}
|
||||
|
||||
public static Fido2UserVerificationPreference GetUserVerificationPreferenceFrom(Fido2UserVerificationPreference preference, CipherRepromptType repromptType)
|
||||
{
|
||||
if (repromptType != CipherRepromptType.None)
|
||||
{
|
||||
return Fido2UserVerificationPreference.Required;
|
||||
}
|
||||
|
||||
return preference;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user