Skip to content

Commit 15263ca

Browse files
authored
Breakout development services & improve naming (#427)
* 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
1 parent 6655af9 commit 15263ca

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+320
-348
lines changed

BlazorWasmDemo/Client/BlazorWasmDemo.Client.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<TargetFramework>net6.0</TargetFramework>
55
<Nullable>enable</Nullable>
66
<ImplicitUsings>enable</ImplicitUsings>
7+
<LangVersion>11</LangVersion>
78
</PropertyGroup>
89

910
<ItemGroup>
@@ -13,6 +14,7 @@
1314

1415
<ItemGroup>
1516
<ProjectReference Include="..\..\Src\Fido2.BlazorWebAssembly\Fido2.BlazorWebAssembly.csproj" />
17+
<ProjectReference Include="..\..\Src\Fido2.Development\Fido2.Development.csproj" />
1618
<ProjectReference Include="..\..\Src\Fido2.Models\Fido2.Models.csproj" />
1719
</ItemGroup>
1820

BlazorWasmDemo/Client/Program.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
using BlazorWasmDemo.Client;
22
using BlazorWasmDemo.Client.Shared;
33
using BlazorWasmDemo.Client.Shared.Toasts;
4+
45
using Fido2.BlazorWebAssembly;
6+
57
using Microsoft.AspNetCore.Components.Web;
68
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
79

BlazorWasmDemo/Client/Shared/UserService.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
using System.Net.Http.Json;
44
using System.Text;
55
using System.Text.Json;
6+
67
using Fido2.BlazorWebAssembly;
8+
79
using Fido2NetLib;
810
using Fido2NetLib.Objects;
911

@@ -126,14 +128,15 @@ public async Task<string> LoginAsync(string? username)
126128
{
127129
// Get options from server
128130
var options = await _httpClient.GetFromJsonAsync<AssertionOptions>(route, _jsonOptions);
129-
if (options == null)
131+
132+
if (options is null)
130133
{
131134
return "No options received";
132135
}
133136

134137
if (options.Status != "ok")
135138
{
136-
return options.ErrorMessage;
139+
return options.ErrorMessage ?? string.Empty;
137140
}
138141

139142
// 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)

BlazorWasmDemo/Server/BlazorWasmDemo.Server.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<UserSecretsId>d4e312c9-f55a-43e0-b3ea-699aa6421a5c</UserSecretsId>
88
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
99
<DockerfileContext>..\..</DockerfileContext>
10+
<LangVersion>11</LangVersion>
1011
</PropertyGroup>
1112

1213
<ItemGroup>

BlazorWasmDemo/Server/Controllers/UserController.cs

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
using System.Security.Claims;
66
using System.Text;
77
using System.Text.Json;
8+
89
using Fido2NetLib;
910
using Fido2NetLib.Development;
1011
using Fido2NetLib.Objects;
12+
1113
using Microsoft.AspNetCore.Mvc;
1214
using Microsoft.IdentityModel.Tokens;
1315

@@ -16,19 +18,16 @@
1618
public class UserController : ControllerBase
1719
{
1820
private static readonly SigningCredentials _signingCredentials = new(
19-
new SymmetricSecurityKey(
20-
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.")),
21-
SecurityAlgorithms.HmacSha256);
21+
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()),
22+
SecurityAlgorithms.HmacSha256
23+
);
2224

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

28-
private string FormatException(Exception e)
29-
{
30-
return $"{e.Message}{e.InnerException?.Message ?? string.Empty}";
31-
}
30+
private static string FormatException(Exception e) => $"{e.Message}{e.InnerException?.Message ?? string.Empty}";
3231

3332
public UserController(IFido2 fido2)
3433
{
@@ -47,8 +46,9 @@ public UserController(IFido2 fido2)
4746
/// <returns>A new <see cref="CredentialCreateOptions"/>. Contains an error message if .Status is "error".</returns>
4847
[HttpGet("{username}/credential-options")]
4948
[HttpGet("credential-options")]
50-
public CredentialCreateOptions GetCredentialOptions([FromRoute] string? username,
51-
[FromQuery] string? displayName,
49+
public CredentialCreateOptions GetCredentialOptions(
50+
[FromRoute] string? username,
51+
[FromQuery] string? displayName,
5252
[FromQuery] AttestationConveyancePreference? attestationType,
5353
[FromQuery] AuthenticatorAttachment? authenticator,
5454
[FromQuery] UserVerificationRequirement? userVerification,
@@ -108,12 +108,12 @@ public CredentialCreateOptions GetCredentialOptions([FromRoute] string? username
108108
existingKeys,
109109
authenticatorSelection,
110110
attestationType ?? AttestationConveyancePreference.None,
111-
new AuthenticationExtensionsClientInputs()
111+
new AuthenticationExtensionsClientInputs
112112
{
113113
Extensions = true,
114114
UserVerificationMethod = true,
115115
CredProps = true,
116-
DevicePubKey = new AuthenticationExtensionsDevicePublicKeyInputs()
116+
DevicePubKey = new AuthenticationExtensionsDevicePublicKeyInputs
117117
{
118118
Attestation = attestationType?.ToString() ?? AttestationConveyancePreference.None.ToString()
119119
},
@@ -152,29 +152,28 @@ public async Task<string> CreateCredentialAsync([FromRoute] string username, [Fr
152152
// 3. Verify and make the credentials
153153
var result = await _fido2.MakeNewCredentialAsync(attestationResponse, options, CredentialIdUniqueToUserAsync, cancellationToken: cancellationToken);
154154

155-
if (result.Status == "error" || result.Result == null)
155+
if (result.Status is "error" || result.Result is null)
156156
{
157-
return result.ErrorMessage;
157+
return result.ErrorMessage ?? string.Empty;
158158
}
159159

160160
// 4. Store the credentials in db
161161
_demoStorage.AddCredentialToUser(options.User, new StoredCredential
162162
{
163-
Type = result.Result.Type,
164-
CredType = result.Result.CredType,
163+
AttestationFormat = result.Result.AttestationFormat,
165164
Id = result.Result.Id,
166165
Descriptor = new PublicKeyCredentialDescriptor(result.Result.Id),
167166
PublicKey = result.Result.PublicKey,
168167
UserHandle = result.Result.User.Id,
169-
SignCount = result.Result.Counter,
168+
SignCount = result.Result.SignCount,
170169
RegDate = DateTime.Now,
171170
AaGuid = result.Result.AaGuid,
172171
DevicePublicKeys = new List<byte[]> { result.Result.DevicePublicKey },
173172
Transports = result.Result.Transports,
174-
BE = result.Result.BE,
175-
BS = result.Result.BS,
173+
IsBackupEligible = result.Result.IsBackupEligible,
174+
IsBackedUp = result.Result.IsBackedUp,
176175
AttestationObject = result.Result.AttestationObject,
177-
AttestationClientDataJSON = result.Result.AttestationClientDataJSON,
176+
AttestationClientDataJSON = result.Result.AttestationClientDataJson,
178177
});
179178

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

214-
var exts = new AuthenticationExtensionsClientInputs()
213+
var exts = new AuthenticationExtensionsClientInputs
215214
{
216215
UserVerificationMethod = true,
217216
Extensions = true,
@@ -256,7 +255,7 @@ public async Task<string> MakeAssertionAsync([FromBody] AuthenticatorAssertionRa
256255
{
257256
// 1. Get the assertion options we sent the client remove them from memory so they can't be used again
258257
var response = JsonSerializer.Deserialize<AuthenticatorResponse>(clientResponse.Response.ClientDataJson);
259-
if (response == null)
258+
if (response is null)
260259
{
261260
return "Error: Could not deserialize client data";
262261
}
@@ -277,14 +276,14 @@ public async Task<string> MakeAssertionAsync([FromBody] AuthenticatorAssertionRa
277276
options,
278277
creds.PublicKey,
279278
creds.DevicePublicKeys,
280-
creds.SignatureCounter,
279+
creds.SignCount,
281280
UserHandleOwnerOfCredentialIdAsync,
282281
cancellationToken: cancellationToken);
283282

284283
// 4. Store the updated counter
285-
if (res.Status == "ok")
284+
if (res.Status is "ok")
286285
{
287-
_demoStorage.UpdateCounter(res.CredentialId, res.Counter);
286+
_demoStorage.UpdateCounter(res.CredentialId, res.SignCount);
288287
if (res.DevicePublicKey is not null)
289288
{
290289
creds.DevicePublicKeys.Add(res.DevicePublicKey);
@@ -306,6 +305,7 @@ public async Task<string> MakeAssertionAsync([FromBody] AuthenticatorAssertionRa
306305
DateTime.Now,
307306
_signingCredentials,
308307
null);
308+
309309
if (token is null)
310310
{
311311
return "Error: Token couldn't be created";

BlazorWasmDemo/Server/Pages/Error.cshtml.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
namespace BlazorWasmDemo.Server.Pages;
22
using System.Diagnostics;
3+
34
using Microsoft.AspNetCore.Mvc;
45
using Microsoft.AspNetCore.Mvc.RazorPages;
56

Demo/Controller.cs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public class MyController : Controller
2121
{
2222
private IFido2 _fido2;
2323
public static IMetadataService _mds;
24-
public static readonly DevelopmentInMemoryStore DemoStorage = new DevelopmentInMemoryStore();
24+
public static readonly DevelopmentInMemoryStore DemoStorage = new();
2525

2626
public MyController(IFido2 fido2)
2727
{
@@ -119,20 +119,19 @@ public async Task<JsonResult> MakeCredential([FromBody] AuthenticatorAttestation
119119
// 3. Store the credentials in db
120120
DemoStorage.AddCredentialToUser(options.User, new StoredCredential
121121
{
122-
Type = success.Result.Type,
123122
Id = success.Result.Id,
124123
Descriptor = new PublicKeyCredentialDescriptor(success.Result.Id),
125124
PublicKey = success.Result.PublicKey,
126125
UserHandle = success.Result.User.Id,
127-
SignCount = success.Result.Counter,
128-
CredType = success.Result.CredType,
126+
SignCount = success.Result.SignCount,
127+
AttestationFormat = success.Result.AttestationFormat,
129128
RegDate = DateTime.Now,
130129
AaGuid = success.Result.AaGuid,
131130
Transports = success.Result.Transports,
132-
BE = success.Result.BE,
133-
BS = success.Result.BS,
131+
IsBackupEligible = success.Result.IsBackupEligible,
132+
IsBackedUp = success.Result.IsBackedUp,
134133
AttestationObject = success.Result.AttestationObject,
135-
AttestationClientDataJSON = success.Result.AttestationClientDataJSON,
134+
AttestationClientDataJSON = success.Result.AttestationClientDataJson,
136135
DevicePublicKeys = new List<byte[]>() { success.Result.DevicePublicKey }
137136
});
138137

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

206205
// 3. Get credential counter from database
207-
var storedCounter = creds.SignatureCounter;
206+
var storedCounter = creds.SignCount;
208207

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

219218
// 6. Store the updated counter
220-
DemoStorage.UpdateCounter(res.CredentialId, res.Counter);
219+
DemoStorage.UpdateCounter(res.CredentialId, res.SignCount);
221220

222221
if (res.DevicePublicKey is not null)
223222
creds.DevicePublicKeys.Add(res.DevicePublicKey);
@@ -227,7 +226,7 @@ public async Task<JsonResult> MakeAssertion([FromBody] AuthenticatorAssertionRaw
227226
}
228227
catch (Exception e)
229228
{
230-
return Json(new AssertionVerificationResult { Status = "error", ErrorMessage = FormatException(e) });
229+
return Json(new VerifyAssertionResult { Status = "error", ErrorMessage = FormatException(e) });
231230
}
232231
}
233232
}

Demo/Demo.csproj

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,10 @@
66
</PropertyGroup>
77
<ItemGroup>
88
<ProjectReference Include="..\Src\Fido2.AspNet\Fido2.AspNet.csproj" />
9+
<ProjectReference Include="..\Src\Fido2.Development\Fido2.Development.csproj" />
910
<ProjectReference Include="..\Src\Fido2.Models\Fido2.Models.csproj" />
1011
<ProjectReference Include="..\Src\Fido2\Fido2.csproj" />
1112
</ItemGroup>
12-
<ItemGroup Condition=" '$(TargetFramework)' == 'net5.0' ">
13-
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="5.0.2" />
14-
</ItemGroup>
1513
<ItemGroup Condition=" '$(TargetFramework)' == 'net6.0' ">
1614
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.0" />
1715
</ItemGroup>

Demo/Pages/_options.cshtml.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
using System.Threading.Tasks;
5-
using Microsoft.AspNetCore.Mvc;
6-
using Microsoft.AspNetCore.Mvc.RazorPages;
1+
using Microsoft.AspNetCore.Mvc.RazorPages;
72

83
namespace Fido2Demo.Pages
94
{

Demo/Pages/custom.cshtml.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
using System.Threading.Tasks;
5-
using Microsoft.AspNetCore.Mvc;
6-
using Microsoft.AspNetCore.Mvc.RazorPages;
1+
using Microsoft.AspNetCore.Mvc.RazorPages;
72

83
namespace Fido2Demo
94
{

0 commit comments

Comments
 (0)