Skip to content

Commit

Permalink
Breakout development services & improve naming (#427)
Browse files Browse the repository at this point in the history
* Breakout development services into their own project and remove duplicate/redundant properties

* Rename CredType to AttestationFormat

* Rename CredentialID -> CredentialId

* React to CredType -> AttestationFormat rename

* Remove unused CrytoUtils.PemToBytes method

* Remove overlapping properties from AttestationVerificationSuccess and make immutable

* Rename AssertionVerificationResult -> VerifyAssertionResult and set SignCount

* Make errorMessage optional

* React to Counter -> SignCount rename

* Remove unused namespaces

* Remove unused .NET5.0 logic

* Try to make dotnet format happy

* Try to make dotnet format happy (take 2)

* Rename AttestationVerificationSuccess -> RegisteredPublicKeyCredential
  • Loading branch information
iamcarbon authored Oct 3, 2023
1 parent 6655af9 commit 15263ca
Show file tree
Hide file tree
Showing 48 changed files with 320 additions and 348 deletions.
2 changes: 2 additions & 0 deletions BlazorWasmDemo/Client/BlazorWasmDemo.Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>11</LangVersion>
</PropertyGroup>

<ItemGroup>
Expand All @@ -13,6 +14,7 @@

<ItemGroup>
<ProjectReference Include="..\..\Src\Fido2.BlazorWebAssembly\Fido2.BlazorWebAssembly.csproj" />
<ProjectReference Include="..\..\Src\Fido2.Development\Fido2.Development.csproj" />
<ProjectReference Include="..\..\Src\Fido2.Models\Fido2.Models.csproj" />
</ItemGroup>

Expand Down
2 changes: 2 additions & 0 deletions BlazorWasmDemo/Client/Program.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using BlazorWasmDemo.Client;
using BlazorWasmDemo.Client.Shared;
using BlazorWasmDemo.Client.Shared.Toasts;

using Fido2.BlazorWebAssembly;

using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;

Expand Down
7 changes: 5 additions & 2 deletions BlazorWasmDemo/Client/Shared/UserService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;

using Fido2.BlazorWebAssembly;

using Fido2NetLib;
using Fido2NetLib.Objects;

Expand Down Expand Up @@ -126,14 +128,15 @@ public async Task<string> LoginAsync(string? username)
{
// Get options from server
var options = await _httpClient.GetFromJsonAsync<AssertionOptions>(route, _jsonOptions);
if (options == null)

if (options is null)
{
return "No options received";
}

if (options.Status != "ok")
{
return options.ErrorMessage;
return options.ErrorMessage ?? string.Empty;
}

// Present options to user and get response (usernameless users will be asked by their authenticator, which credential they want to use to sign the challenge)
Expand Down
1 change: 1 addition & 0 deletions BlazorWasmDemo/Server/BlazorWasmDemo.Server.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<UserSecretsId>d4e312c9-f55a-43e0-b3ea-699aa6421a5c</UserSecretsId>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileContext>..\..</DockerfileContext>
<LangVersion>11</LangVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
48 changes: 24 additions & 24 deletions BlazorWasmDemo/Server/Controllers/UserController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
using System.Security.Claims;
using System.Text;
using System.Text.Json;

using Fido2NetLib;
using Fido2NetLib.Development;
using Fido2NetLib.Objects;

using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;

Expand All @@ -16,19 +18,16 @@
public class UserController : ControllerBase
{
private static readonly SigningCredentials _signingCredentials = new(
new SymmetricSecurityKey(
Encoding.UTF8.GetBytes("This is my very long and totally secret key for signing tokens, which clients may never learn or I'd have to replace it.")),
SecurityAlgorithms.HmacSha256);
new SymmetricSecurityKey("This is my very long and totally secret key for signing tokens, which clients may never learn or I'd have to replace it."u8.ToArray()),
SecurityAlgorithms.HmacSha256
);

private static readonly DevelopmentInMemoryStore _demoStorage = new();
private static readonly Dictionary<string, CredentialCreateOptions> _pendingCredentials = new();
private static readonly Dictionary<string, AssertionOptions> _pendingAssertions = new();
private readonly IFido2 _fido2;

private string FormatException(Exception e)
{
return $"{e.Message}{e.InnerException?.Message ?? string.Empty}";
}
private static string FormatException(Exception e) => $"{e.Message}{e.InnerException?.Message ?? string.Empty}";

public UserController(IFido2 fido2)
{
Expand All @@ -47,8 +46,9 @@ public UserController(IFido2 fido2)
/// <returns>A new <see cref="CredentialCreateOptions"/>. Contains an error message if .Status is "error".</returns>
[HttpGet("{username}/credential-options")]
[HttpGet("credential-options")]
public CredentialCreateOptions GetCredentialOptions([FromRoute] string? username,
[FromQuery] string? displayName,
public CredentialCreateOptions GetCredentialOptions(
[FromRoute] string? username,
[FromQuery] string? displayName,
[FromQuery] AttestationConveyancePreference? attestationType,
[FromQuery] AuthenticatorAttachment? authenticator,
[FromQuery] UserVerificationRequirement? userVerification,
Expand Down Expand Up @@ -108,12 +108,12 @@ public CredentialCreateOptions GetCredentialOptions([FromRoute] string? username
existingKeys,
authenticatorSelection,
attestationType ?? AttestationConveyancePreference.None,
new AuthenticationExtensionsClientInputs()
new AuthenticationExtensionsClientInputs
{
Extensions = true,
UserVerificationMethod = true,
CredProps = true,
DevicePubKey = new AuthenticationExtensionsDevicePublicKeyInputs()
DevicePubKey = new AuthenticationExtensionsDevicePublicKeyInputs
{
Attestation = attestationType?.ToString() ?? AttestationConveyancePreference.None.ToString()
},
Expand Down Expand Up @@ -152,29 +152,28 @@ public async Task<string> CreateCredentialAsync([FromRoute] string username, [Fr
// 3. Verify and make the credentials
var result = await _fido2.MakeNewCredentialAsync(attestationResponse, options, CredentialIdUniqueToUserAsync, cancellationToken: cancellationToken);

if (result.Status == "error" || result.Result == null)
if (result.Status is "error" || result.Result is null)
{
return result.ErrorMessage;
return result.ErrorMessage ?? string.Empty;
}

// 4. Store the credentials in db
_demoStorage.AddCredentialToUser(options.User, new StoredCredential
{
Type = result.Result.Type,
CredType = result.Result.CredType,
AttestationFormat = result.Result.AttestationFormat,
Id = result.Result.Id,
Descriptor = new PublicKeyCredentialDescriptor(result.Result.Id),
PublicKey = result.Result.PublicKey,
UserHandle = result.Result.User.Id,
SignCount = result.Result.Counter,
SignCount = result.Result.SignCount,
RegDate = DateTime.Now,
AaGuid = result.Result.AaGuid,
DevicePublicKeys = new List<byte[]> { result.Result.DevicePublicKey },
Transports = result.Result.Transports,
BE = result.Result.BE,
BS = result.Result.BS,
IsBackupEligible = result.Result.IsBackupEligible,
IsBackedUp = result.Result.IsBackedUp,
AttestationObject = result.Result.AttestationObject,
AttestationClientDataJSON = result.Result.AttestationClientDataJSON,
AttestationClientDataJSON = result.Result.AttestationClientDataJson,
});

// 5. Now we need to remove the options from the pending dictionary
Expand Down Expand Up @@ -211,7 +210,7 @@ public AssertionOptions MakeAssertionOptions([FromRoute] string? username, [From
existingKeys = _demoStorage.GetCredentialsByUser(user).Select(c => c.Descriptor).ToList();
}

var exts = new AuthenticationExtensionsClientInputs()
var exts = new AuthenticationExtensionsClientInputs
{
UserVerificationMethod = true,
Extensions = true,
Expand Down Expand Up @@ -256,7 +255,7 @@ public async Task<string> MakeAssertionAsync([FromBody] AuthenticatorAssertionRa
{
// 1. Get the assertion options we sent the client remove them from memory so they can't be used again
var response = JsonSerializer.Deserialize<AuthenticatorResponse>(clientResponse.Response.ClientDataJson);
if (response == null)
if (response is null)
{
return "Error: Could not deserialize client data";
}
Expand All @@ -277,14 +276,14 @@ public async Task<string> MakeAssertionAsync([FromBody] AuthenticatorAssertionRa
options,
creds.PublicKey,
creds.DevicePublicKeys,
creds.SignatureCounter,
creds.SignCount,
UserHandleOwnerOfCredentialIdAsync,
cancellationToken: cancellationToken);

// 4. Store the updated counter
if (res.Status == "ok")
if (res.Status is "ok")
{
_demoStorage.UpdateCounter(res.CredentialId, res.Counter);
_demoStorage.UpdateCounter(res.CredentialId, res.SignCount);
if (res.DevicePublicKey is not null)
{
creds.DevicePublicKeys.Add(res.DevicePublicKey);
Expand All @@ -306,6 +305,7 @@ public async Task<string> MakeAssertionAsync([FromBody] AuthenticatorAssertionRa
DateTime.Now,
_signingCredentials,
null);

if (token is null)
{
return "Error: Token couldn't be created";
Expand Down
1 change: 1 addition & 0 deletions BlazorWasmDemo/Server/Pages/Error.cshtml.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace BlazorWasmDemo.Server.Pages;
using System.Diagnostics;

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

Expand Down
21 changes: 10 additions & 11 deletions Demo/Controller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class MyController : Controller
{
private IFido2 _fido2;
public static IMetadataService _mds;
public static readonly DevelopmentInMemoryStore DemoStorage = new DevelopmentInMemoryStore();
public static readonly DevelopmentInMemoryStore DemoStorage = new();

public MyController(IFido2 fido2)
{
Expand Down Expand Up @@ -119,20 +119,19 @@ public async Task<JsonResult> MakeCredential([FromBody] AuthenticatorAttestation
// 3. Store the credentials in db
DemoStorage.AddCredentialToUser(options.User, new StoredCredential
{
Type = success.Result.Type,
Id = success.Result.Id,
Descriptor = new PublicKeyCredentialDescriptor(success.Result.Id),
PublicKey = success.Result.PublicKey,
UserHandle = success.Result.User.Id,
SignCount = success.Result.Counter,
CredType = success.Result.CredType,
SignCount = success.Result.SignCount,
AttestationFormat = success.Result.AttestationFormat,
RegDate = DateTime.Now,
AaGuid = success.Result.AaGuid,
Transports = success.Result.Transports,
BE = success.Result.BE,
BS = success.Result.BS,
IsBackupEligible = success.Result.IsBackupEligible,
IsBackedUp = success.Result.IsBackedUp,
AttestationObject = success.Result.AttestationObject,
AttestationClientDataJSON = success.Result.AttestationClientDataJSON,
AttestationClientDataJSON = success.Result.AttestationClientDataJson,
DevicePublicKeys = new List<byte[]>() { success.Result.DevicePublicKey }
});

Expand Down Expand Up @@ -204,9 +203,9 @@ public async Task<JsonResult> MakeAssertion([FromBody] AuthenticatorAssertionRaw
var creds = DemoStorage.GetCredentialById(clientResponse.Id) ?? throw new Exception("Unknown credentials");

// 3. Get credential counter from database
var storedCounter = creds.SignatureCounter;
var storedCounter = creds.SignCount;

// 4. Create callback to check if userhandle owns the credentialId
// 4. Create callback to check if the user handle owns the credentialId
IsUserHandleOwnerOfCredentialIdAsync callback = static async (args, cancellationToken) =>
{
var storedCreds = await DemoStorage.GetCredentialsByUserHandleAsync(args.UserHandle, cancellationToken);
Expand All @@ -217,7 +216,7 @@ public async Task<JsonResult> MakeAssertion([FromBody] AuthenticatorAssertionRaw
var res = await _fido2.MakeAssertionAsync(clientResponse, options, creds.PublicKey, creds.DevicePublicKeys, storedCounter, callback, cancellationToken: cancellationToken);

// 6. Store the updated counter
DemoStorage.UpdateCounter(res.CredentialId, res.Counter);
DemoStorage.UpdateCounter(res.CredentialId, res.SignCount);

if (res.DevicePublicKey is not null)
creds.DevicePublicKeys.Add(res.DevicePublicKey);
Expand All @@ -227,7 +226,7 @@ public async Task<JsonResult> MakeAssertion([FromBody] AuthenticatorAssertionRaw
}
catch (Exception e)
{
return Json(new AssertionVerificationResult { Status = "error", ErrorMessage = FormatException(e) });
return Json(new VerifyAssertionResult { Status = "error", ErrorMessage = FormatException(e) });
}
}
}
4 changes: 1 addition & 3 deletions Demo/Demo.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Src\Fido2.AspNet\Fido2.AspNet.csproj" />
<ProjectReference Include="..\Src\Fido2.Development\Fido2.Development.csproj" />
<ProjectReference Include="..\Src\Fido2.Models\Fido2.Models.csproj" />
<ProjectReference Include="..\Src\Fido2\Fido2.csproj" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net5.0' ">
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="5.0.2" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net6.0' ">
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.0" />
</ItemGroup>
Expand Down
7 changes: 1 addition & 6 deletions Demo/Pages/_options.cshtml.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace Fido2Demo.Pages
{
Expand Down
7 changes: 1 addition & 6 deletions Demo/Pages/custom.cshtml.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace Fido2Demo
{
Expand Down
4 changes: 2 additions & 2 deletions Demo/Pages/dashboard.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@
<tr>
<td>@item.RegDate</td>
<td><img src="@icon" /> @desc</td>
<td>@item.SignatureCounter</td>
<td>@item.SignCount</td>
<td>@item.AaGuid</td>
<td>@userHandle</td>
<td>@userId</td>
<td>@item.CredType</td>
<td>@item.AttestationFormat</td>
<td>
<details>
<summary>@publicKey.Substring(0, 10).Substring(0, 10)...</summary>
Expand Down
7 changes: 1 addition & 6 deletions Demo/Pages/dashboard.cshtml.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace Fido2Demo.Pages
{
Expand Down
7 changes: 1 addition & 6 deletions Demo/Pages/mfa.cshtml.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace Fido2Demo
{
Expand Down
7 changes: 1 addition & 6 deletions Demo/Pages/overview.cshtml.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace Fido2Demo
{
Expand Down
7 changes: 1 addition & 6 deletions Demo/Pages/passwordless.cshtml.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace Fido2Demo
{
Expand Down
7 changes: 1 addition & 6 deletions Demo/Pages/usernameless.cshtml.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace Fido2Demo
{
Expand Down
2 changes: 2 additions & 0 deletions Demo/Startup.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;

using Fido2NetLib;

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
Expand Down
Loading

0 comments on commit 15263ca

Please sign in to comment.