From 6b6ac4eb7653a1001ffe641a3407d06fb33fa1c7 Mon Sep 17 00:00:00 2001
From: Oleksii Holub <1935960+Tyrrrz@users.noreply.github.com>
Date: Wed, 14 Aug 2024 20:30:36 +0300
Subject: [PATCH 1/3] Add support for credential hints to the register flow
---
src/AdminConsole/AdminConsole.csproj | 2 +-
.../Pages/App/Playground/NewAccount.cshtml | 10 ++++--
.../Pages/App/Playground/NewAccount.cshtml.cs | 34 +++++++------------
src/Service/Fido2Service.cs | 4 ++-
src/Service/Models/RegisterToken.cs | 14 ++++++--
src/Service/TokenService.cs | 22 +++++-------
6 files changed, 44 insertions(+), 42 deletions(-)
diff --git a/src/AdminConsole/AdminConsole.csproj b/src/AdminConsole/AdminConsole.csproj
index 2cc1a2ebc..fcb1cd589 100644
--- a/src/AdminConsole/AdminConsole.csproj
+++ b/src/AdminConsole/AdminConsole.csproj
@@ -23,7 +23,7 @@
-
+
diff --git a/src/AdminConsole/Pages/App/Playground/NewAccount.cshtml b/src/AdminConsole/Pages/App/Playground/NewAccount.cshtml
index 8fd1bd045..08bac95d1 100644
--- a/src/AdminConsole/Pages/App/Playground/NewAccount.cshtml
+++ b/src/AdminConsole/Pages/App/Playground/NewAccount.cshtml
@@ -12,7 +12,6 @@
var requestToken = Antiforgery.GetAndStoreTokens(Model.HttpContext).RequestToken;
}
-
@@ -85,6 +84,13 @@
}
+
+
+
+
+
+
+
@@ -127,7 +133,7 @@ const createNewAccount = async (e) => {
if (req.ok) {
const { token } = await req.json();
const nicknameForDevice = data.get("nickname");
- const { error } = await p.register(token , nicknameForDevice);
+ const { error } = await p.register(token, nicknameForDevice);
if (error) {
console.error(error);
diff --git a/src/AdminConsole/Pages/App/Playground/NewAccount.cshtml.cs b/src/AdminConsole/Pages/App/Playground/NewAccount.cshtml.cs
index ac2ed0e32..aec51b24e 100644
--- a/src/AdminConsole/Pages/App/Playground/NewAccount.cshtml.cs
+++ b/src/AdminConsole/Pages/App/Playground/NewAccount.cshtml.cs
@@ -5,33 +5,28 @@
namespace Passwordless.AdminConsole.Pages.App.Playground;
-public class NewAccountModel : PageModel
+public class NewAccountModel(IScopedPasswordlessClient passwordlessClient)
+ : PageModel
{
- private readonly ILogger
_logger;
- private readonly IScopedPasswordlessClient _passwordlessClient;
+ [MaxLength(64)]
+ public string Nickname { get; set; } = "";
- public NewAccountModel(ILogger logger, IScopedPasswordlessClient passwordlessClient)
- {
- _logger = logger;
- this._passwordlessClient = passwordlessClient;
- }
+ public string Attestation { get; set; } = "none";
- public void OnGet()
- {
+ public string Hints { get; set; } = "";
- }
-
- public async Task OnPostToken(string name, string email, string attestation)
+ public async Task OnPostToken(string name, string email, string attestation, string hints)
{
try
{
var userId = Guid.NewGuid().ToString();
- var token = await _passwordlessClient.CreateRegisterTokenAsync(new RegisterOptions(userId, $"Playground: {email}")
+ var token = await passwordlessClient.CreateRegisterTokenAsync(new RegisterOptions(userId, $"Playground: {email}")
{
DisplayName = name,
- Aliases = new HashSet(1) { email },
+ Aliases = [email],
AliasHashing = false,
- Attestation = attestation
+ Attestation = attestation,
+ Hints = hints.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)
});
return new JsonResult(token);
@@ -44,12 +39,7 @@ public async Task OnPostToken(string name, string email, string a
public async Task OnPost(string token)
{
- var res = await _passwordlessClient.VerifyAuthenticationTokenAsync(token);
+ var res = await passwordlessClient.VerifyAuthenticationTokenAsync(token);
return new JsonResult(res);
}
-
- [MaxLength(64)]
- public string Nickname { get; set; }
-
- public string Attestation { get; set; } = "none";
}
\ No newline at end of file
diff --git a/src/Service/Fido2Service.cs b/src/Service/Fido2Service.cs
index dbcf717df..6ea62733f 100644
--- a/src/Service/Fido2Service.cs
+++ b/src/Service/Fido2Service.cs
@@ -74,7 +74,7 @@ public async Task CreateRegisterTokenAsync(RegisterToken tokenProps)
if (string.IsNullOrEmpty(tokenProps.Attestation)) tokenProps.Attestation = "none";
TokenValidator.ValidateAttestation(tokenProps, features);
- // check if aliases is available
+ // Check if aliases is available
if (tokenProps.Aliases != null)
{
var hashedAliases = tokenProps.Aliases.Select(alias => HashAlias(alias, _tenantProvider.Tenant));
@@ -152,6 +152,8 @@ public async Task> RegisterBeginAsync(F
CredProps = true
});
+ options.Hints = token.Hints;
+
var session = await _tokenService.EncodeTokenAsync(
new RegisterSession
{
diff --git a/src/Service/Models/RegisterToken.cs b/src/Service/Models/RegisterToken.cs
index 7704561c9..582423042 100644
--- a/src/Service/Models/RegisterToken.cs
+++ b/src/Service/Models/RegisterToken.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using Fido2NetLib.Objects;
using MessagePack;
using Passwordless.Common.Validation;
@@ -20,17 +21,26 @@ public class RegisterToken : Token
[MessagePack.Key(13)]
public string Attestation { get; set; } = "None";
+
[MessagePack.Key(14)]
public string AuthenticatorType { get; set; }
+
[MessagePack.Key(15)]
public bool Discoverable { get; set; } = true;
+
[MessagePack.Key(16)]
public string UserVerification { get; set; } = "Preferred";
+
[MessagePack.Key(17)]
[MaxLength(10), MaxLengthCollection(250), RequiredCollection(AllowEmptyStrings = false)]
- public HashSet Aliases { get; set; }
+ public HashSet Aliases { get; set; } = [];
- [MessagePack.Key(18)] public bool AliasHashing { get; set; } = true;
+ [MessagePack.Key(18)]
+ public bool AliasHashing { get; set; } = true;
+
+ [MessagePack.Key(19)]
+ [MaxLength(3)]
+ public IReadOnlyList Hints { get; set; } = [];
}
[MessagePackObject]
diff --git a/src/Service/TokenService.cs b/src/Service/TokenService.cs
index 1d110662b..26302ac4e 100644
--- a/src/Service/TokenService.cs
+++ b/src/Service/TokenService.cs
@@ -149,31 +149,25 @@ private async Task> GetRandomKeyAsync()
public async Task EncodeTokenAsync(T token, string prefix, bool contractless = false)
{
- byte[] msgpack;
- if (contractless)
- {
- msgpack = MessagePackSerializer.Serialize(token, ContractlessStandardResolver.Options);
- }
- else
- {
- msgpack = MessagePackSerializer.Serialize(token);
- }
+ var msgpack = contractless
+ ? MessagePackSerializer.Serialize(token, ContractlessStandardResolver.Options)
+ : MessagePackSerializer.Serialize(token);
- (Key key, int keyId) = await GetRandomKeyAsync();
+ (Key key, var keyId) = await GetRandomKeyAsync();
_log.LogInformation("Encoding using keyId={keyId}", keyId);
var mac = CreateMac(key, msgpack);
var envelope = new MacEnvelope { Mac = mac, Token = msgpack, KeyId = keyId };
- var envelop_binary = MessagePackSerializer.Serialize(envelope);
- var envelop_binary_b64 = Base64Url.Encode(envelop_binary);
+ var envelopeBinary = MessagePackSerializer.Serialize(envelope);
+ var envelopeBinaryB64 = Base64Url.Encode(envelopeBinary);
if (!string.IsNullOrEmpty(prefix))
{
- return prefix + envelop_binary_b64;
+ return prefix + envelopeBinaryB64;
}
- return envelop_binary_b64;
+ return envelopeBinaryB64;
}
///
From 474cf418b5350adce762bea350645e01c408291d Mon Sep 17 00:00:00 2001
From: Oleksii Holub <1935960+Tyrrrz@users.noreply.github.com>
Date: Thu, 15 Aug 2024 23:52:58 +0300
Subject: [PATCH 2/3] asd
---
src/Service/Models/RegisterToken.cs | 2 +-
.../Implementations/Fido2ServiceTests.cs | 16 ++++++++++++++--
2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/src/Service/Models/RegisterToken.cs b/src/Service/Models/RegisterToken.cs
index 582423042..5db89aa67 100644
--- a/src/Service/Models/RegisterToken.cs
+++ b/src/Service/Models/RegisterToken.cs
@@ -33,7 +33,7 @@ public class RegisterToken : Token
[MessagePack.Key(17)]
[MaxLength(10), MaxLengthCollection(250), RequiredCollection(AllowEmptyStrings = false)]
- public HashSet Aliases { get; set; } = [];
+ public HashSet? Aliases { get; set; } = null;
[MessagePack.Key(18)]
public bool AliasHashing { get; set; } = true;
diff --git a/tests/Service.Tests/Implementations/Fido2ServiceTests.cs b/tests/Service.Tests/Implementations/Fido2ServiceTests.cs
index f0bc8faa2..51cf41955 100644
--- a/tests/Service.Tests/Implementations/Fido2ServiceTests.cs
+++ b/tests/Service.Tests/Implementations/Fido2ServiceTests.cs
@@ -74,7 +74,7 @@ public async Task CreateRegisterToken_Throws_ApiException_WhenMaxUsersExceededFo
.ReturnsAsync("test_token");
_mockFeatureContextProvider.Setup(x => x.UseContext()).ReturnsAsync(new FeaturesContext(false, 0, null, 10000, false, true, true));
_mockTenantStorage.Setup(x => x.GetUsersCount()).ReturnsAsync(10000);
- _mockTenantStorage.Setup(x => x.GetCredentialsByUserIdAsync(It.Is(p => p == "test"))).ReturnsAsync(new List(0));
+ _mockTenantStorage.Setup(x => x.GetCredentialsByUserIdAsync(It.Is(p => p == "test"))).ReturnsAsync([]);
// act
var actual = await Assert.ThrowsAsync(async () =>
@@ -104,7 +104,19 @@ public async Task CreateRegisterToken_Works_WhenMaxUsersExceededForExistingUser(
_mockFeatureContextProvider.Setup(x => x.UseContext()).ReturnsAsync(new FeaturesContext(false, 0, null, 10000, false, true, true));
_mockTenantStorage.Setup(x => x.GetUsersCount()).ReturnsAsync(10000);
_mockTenantStorage.Setup(x => x.GetCredentialsByUserIdAsync(It.Is(p => p == "test"))).ReturnsAsync(
- new List(1) { new() { UserHandle = "test"u8.ToArray(), Descriptor = null!, Origin = null!, AttestationFmt = null!, CreatedAt = DateTime.UtcNow, PublicKey = null!, SignatureCounter = 123, RPID = null! } });
+ [
+ new StoredCredential
+ {
+ UserHandle = "test"u8.ToArray(),
+ Descriptor = null!,
+ Origin = null!,
+ AttestationFmt = null!,
+ CreatedAt = DateTime.UtcNow,
+ PublicKey = null!,
+ SignatureCounter = 123,
+ RPID = null!
+ }
+ ]);
// act
var actual = await _sut.CreateRegisterTokenAsync(new RegisterToken
From e64329d2e30eafd65b3925b34242666c03f3b284 Mon Sep 17 00:00:00 2001
From: Oleksii Holub <1935960+Tyrrrz@users.noreply.github.com>
Date: Fri, 16 Aug 2024 17:54:09 +0300
Subject: [PATCH 3/3] Update src/Service/Models/RegisterToken.cs
---
src/Service/Models/RegisterToken.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Service/Models/RegisterToken.cs b/src/Service/Models/RegisterToken.cs
index 5db89aa67..a527b7487 100644
--- a/src/Service/Models/RegisterToken.cs
+++ b/src/Service/Models/RegisterToken.cs
@@ -33,7 +33,7 @@ public class RegisterToken : Token
[MessagePack.Key(17)]
[MaxLength(10), MaxLengthCollection(250), RequiredCollection(AllowEmptyStrings = false)]
- public HashSet? Aliases { get; set; } = null;
+ public HashSet? Aliases { get; set; }
[MessagePack.Key(18)]
public bool AliasHashing { get; set; } = true;