Skip to content

Commit

Permalink
Remove base-class, Status and ErrorMessage (#529)
Browse files Browse the repository at this point in the history
* Remove base-class

* Removed usage of Status/ErrorMessage in tests

* Rename MakeNewCredentialResult.Result to .Credential

* format

* Removed MakeNewCredentialResult

* fixed after rebase

* Passes conformance tests

* undo local changes

* small fix

* small fix
  • Loading branch information
abergs authored Jul 16, 2024
1 parent 184f70f commit cb71a15
Show file tree
Hide file tree
Showing 23 changed files with 182 additions and 305 deletions.
5 changes: 0 additions & 5 deletions BlazorWasmDemo/Client/Shared/UserService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,6 @@ public async Task<string> LoginAsync(string? username)
return "No options received";
}

if (options.Status != "ok")
{
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)
var assertion = await _webAuthn.VerifyAsync(options);

Expand Down
54 changes: 22 additions & 32 deletions BlazorWasmDemo/Server/Controllers/UserController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,9 @@ public CredentialCreateOptions GetCredentialOptions(
// 6. return options to client
return options;
}
catch (Exception e)
catch (Exception)
{
return new CredentialCreateOptions { Status = "error", ErrorMessage = FormatException(e) };
throw;
}
}

Expand All @@ -150,29 +150,25 @@ public async Task<string> CreateCredentialAsync([FromRoute] string username, [Fr
// 2. Create callback so that lib can verify credential id is unique to this user

// 3. Verify and make the credentials
var result = await _fido2.MakeNewCredentialAsync(attestationResponse, options, CredentialIdUniqueToUserAsync, cancellationToken: cancellationToken);

if (result.Status is "error" || result.Result is null)
{
return result.ErrorMessage ?? string.Empty;
}
var credential = await _fido2.MakeNewCredentialAsync(attestationResponse, options, CredentialIdUniqueToUserAsync, cancellationToken: cancellationToken);

// 4. Store the credentials in db
_demoStorage.AddCredentialToUser(options.User, new StoredCredential
{
AttestationFormat = result.Result.AttestationFormat,
Id = result.Result.Id,
PublicKey = result.Result.PublicKey,
UserHandle = result.Result.User.Id,
SignCount = result.Result.SignCount,

AttestationFormat = credential.AttestationFormat,
Id = credential.Id,
PublicKey = credential.PublicKey,
UserHandle = credential.User.Id,
SignCount = credential.SignCount,
RegDate = DateTimeOffset.UtcNow,
AaGuid = result.Result.AaGuid,
DevicePublicKeys = [result.Result.DevicePublicKey],
Transports = result.Result.Transports,
IsBackupEligible = result.Result.IsBackupEligible,
IsBackedUp = result.Result.IsBackedUp,
AttestationObject = result.Result.AttestationObject,
AttestationClientDataJson = result.Result.AttestationClientDataJson,
AaGuid = credential.AaGuid,
DevicePublicKeys = [credential.DevicePublicKey],
Transports = credential.Transports,
IsBackupEligible = credential.IsBackupEligible,
IsBackedUp = credential.IsBackedUp,
AttestationObject = credential.AttestationObject,
AttestationClientDataJson = credential.AttestationClientDataJson,
});

// 5. Now we need to remove the options from the pending dictionary
Expand Down Expand Up @@ -228,9 +224,9 @@ public AssertionOptions MakeAssertionOptions([FromRoute] string? username, [From
// 5. return options to client
return options;
}
catch (Exception e)
catch (Exception)
{
return new AssertionOptions { Status = "error", ErrorMessage = FormatException(e) };
throw;
}
}

Expand Down Expand Up @@ -280,19 +276,13 @@ public async Task<string> MakeAssertionAsync([FromBody] AuthenticatorAssertionRa
cancellationToken: cancellationToken);

// 4. Store the updated counter
if (res.Status is "ok")
_demoStorage.UpdateCounter(res.CredentialId, res.SignCount);
if (res.DevicePublicKey is not null)
{
_demoStorage.UpdateCounter(res.CredentialId, res.SignCount);
if (res.DevicePublicKey is not null)
{
creds.DevicePublicKeys.Add(res.DevicePublicKey);
}
}
else
{
return $"Error: {res.ErrorMessage}";
creds.DevicePublicKeys.Add(res.DevicePublicKey);
}


// 5. return result to client
var handler = new JwtSecurityTokenHandler();
var token = handler.CreateEncodedJwt(
Expand Down
36 changes: 18 additions & 18 deletions Demo/Controller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public JsonResult MakeCredentialOptions([FromForm] string username,
}
catch (Exception e)
{
return Json(new CredentialCreateOptions { Status = "error", ErrorMessage = FormatException(e) });
return Json(new { Status = "error", ErrorMessage = FormatException(e) });
}
}

Expand All @@ -106,32 +106,32 @@ public async Task<JsonResult> MakeCredential([FromBody] AuthenticatorAttestation
};

// 2. Verify and make the credentials
var success = await _fido2.MakeNewCredentialAsync(attestationResponse, options, callback, cancellationToken: cancellationToken);
var credential = await _fido2.MakeNewCredentialAsync(attestationResponse, options, callback, cancellationToken: cancellationToken);

// 3. Store the credentials in db
DemoStorage.AddCredentialToUser(options.User, new StoredCredential
{
Id = success.Result.Id,
PublicKey = success.Result.PublicKey,
UserHandle = success.Result.User.Id,
SignCount = success.Result.SignCount,
AttestationFormat = success.Result.AttestationFormat,
Id = credential.Id,
PublicKey = credential.PublicKey,
UserHandle = credential.User.Id,
SignCount = credential.SignCount,
AttestationFormat = credential.AttestationFormat,
RegDate = DateTimeOffset.UtcNow,
AaGuid = success.Result.AaGuid,
Transports = success.Result.Transports,
IsBackupEligible = success.Result.IsBackupEligible,
IsBackedUp = success.Result.IsBackedUp,
AttestationObject = success.Result.AttestationObject,
AttestationClientDataJson = success.Result.AttestationClientDataJson,
DevicePublicKeys = [success.Result.DevicePublicKey]
AaGuid = credential.AaGuid,
Transports = credential.Transports,
IsBackupEligible = credential.IsBackupEligible,
IsBackedUp = credential.IsBackedUp,
AttestationObject = credential.AttestationObject,
AttestationClientDataJson = credential.AttestationClientDataJson,
DevicePublicKeys = [credential.DevicePublicKey]
});

// 4. return "ok" to the client
return Json(success);
return Json(credential);
}
catch (Exception e)
{
return Json(new MakeNewCredentialResult(status: "error", errorMessage: FormatException(e), result: null));
return Json(new { status = "error", errorMessage = FormatException(e) });
}
}

Expand Down Expand Up @@ -176,7 +176,7 @@ public ActionResult AssertionOptionsPost([FromForm] string username, [FromForm]

catch (Exception e)
{
return Json(new AssertionOptions { Status = "error", ErrorMessage = FormatException(e) });
return Json(new { Status = "error", ErrorMessage = FormatException(e) });
}
}

Expand Down Expand Up @@ -217,7 +217,7 @@ public async Task<JsonResult> MakeAssertion([FromBody] AuthenticatorAssertionRaw
}
catch (Exception e)
{
return Json(new VerifyAssertionResult { Status = "error", ErrorMessage = FormatException(e) });
return Json(new { Status = "error", ErrorMessage = FormatException(e) });
}
}
}
33 changes: 22 additions & 11 deletions Demo/TestController.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Text;

using System.Text.Json;
using System.Text.Json.Serialization;
using Fido2NetLib;
using Fido2NetLib.Development;
using Fido2NetLib.Objects;
Expand Down Expand Up @@ -34,7 +35,7 @@ public TestController(IOptions<Fido2Configuration> fido2Configuration)

[HttpPost]
[Route("/attestation/options")]
public JsonResult MakeCredentialOptionsTest([FromBody] TEST_MakeCredentialParams opts)
public OkObjectResult MakeCredentialOptionsTest([FromBody] TEST_MakeCredentialParams opts)
{
var attType = opts.Attestation;

Expand Down Expand Up @@ -72,12 +73,16 @@ public JsonResult MakeCredentialOptionsTest([FromBody] TEST_MakeCredentialParams
HttpContext.Session.SetString("fido2.attestationOptions", options.ToJson());

// 5. return options to client
return Json(options);

var jsonResponse = JsonSerializer.SerializeToNode(options);
jsonResponse["status"] = "ok";
jsonResponse["errorMessage"] = "";
return new OkObjectResult(jsonResponse);
}

[HttpPost]
[Route("/attestation/result")]
public async Task<JsonResult> MakeCredentialResultTestAsync([FromBody] AuthenticatorAttestationRawResponse attestationResponse, CancellationToken cancellationToken)
public async Task<OkObjectResult> MakeCredentialResultTestAsync([FromBody] AuthenticatorAttestationRawResponse attestationResponse, CancellationToken cancellationToken)
{
// 1. get the options we sent the client
var jsonOptions = HttpContext.Session.GetString("fido2.attestationOptions");
Expand All @@ -91,19 +96,22 @@ public async Task<JsonResult> MakeCredentialResultTestAsync([FromBody] Authentic
};

// 2. Verify and make the credentials
var success = await _fido2.MakeNewCredentialAsync(attestationResponse, options, callback, cancellationToken: cancellationToken);
var credential = await _fido2.MakeNewCredentialAsync(attestationResponse, options, callback, cancellationToken: cancellationToken);

// 3. Store the credentials in db
_demoStorage.AddCredentialToUser(options.User, new StoredCredential
{
Id = success.Result.Id,
PublicKey = success.Result.PublicKey,
UserHandle = success.Result.User.Id,
SignCount = success.Result.SignCount
Id = credential.Id,
PublicKey = credential.PublicKey,
UserHandle = credential.User.Id,
SignCount = credential.SignCount
});

// 4. return "ok" to the client
return Json(success);
var jsonResponse = JsonSerializer.SerializeToNode(credential);
jsonResponse["status"] = "ok";
jsonResponse["errorMessage"] = "";
return new OkObjectResult(jsonResponse);
}

[HttpPost]
Expand Down Expand Up @@ -142,7 +150,10 @@ public IActionResult AssertionOptionsTest([FromBody] TEST_AssertionClientParams
HttpContext.Session.SetString("fido2.assertionOptions", options.ToJson());

// 5. Return options to client
return Json(options);
var jsonResponse = JsonSerializer.SerializeToNode(options);
jsonResponse["status"] = "ok";
jsonResponse["errorMessage"] = "";
return new OkObjectResult(jsonResponse);
}

[HttpPost]
Expand Down
4 changes: 1 addition & 3 deletions Src/Fido2.Models/AssertionOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Fido2NetLib;
/// <summary>
/// Sent to the browser when we want to Assert credentials and authenticate a user
/// </summary>
public class AssertionOptions : Fido2ResponseBase
public class AssertionOptions
{
/// <summary>
/// This member represents a challenge that the selected authenticator signs, along with other data, when producing an authentication assertion.
Expand Down Expand Up @@ -71,8 +71,6 @@ public static AssertionOptions Create(
{
return new AssertionOptions()
{
Status = "ok",
ErrorMessage = string.Empty,
Challenge = challenge,
Timeout = config.Timeout,
RpId = config.ServerDomain,
Expand Down
4 changes: 1 addition & 3 deletions Src/Fido2.Models/CredentialCreateOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace Fido2NetLib;

public sealed class CredentialCreateOptions : Fido2ResponseBase
public sealed class CredentialCreateOptions
{
/// <summary>
///
Expand Down Expand Up @@ -117,8 +117,6 @@ public static CredentialCreateOptions Create(
{
return new CredentialCreateOptions
{
Status = "ok",
ErrorMessage = string.Empty,
Challenge = challenge,
Rp = new PublicKeyCredentialRpEntity(config.ServerDomain, config.ServerName, config.ServerIcon),
Timeout = config.Timeout,
Expand Down
14 changes: 0 additions & 14 deletions Src/Fido2.Models/Fido2ResponseBase.cs

This file was deleted.

20 changes: 0 additions & 20 deletions Src/Fido2.Models/Objects/MakeNewCredentialResult.cs

This file was deleted.

2 changes: 1 addition & 1 deletion Src/Fido2.Models/Objects/RegisteredPublicKeyCredential.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Fido2NetLib.Objects;
/// <summary>
/// Holds parsed credential data
/// </summary>
public class RegisteredPublicKeyCredential : Fido2ResponseBase
public class RegisteredPublicKeyCredential
{
/// <summary>
/// The type of the public key credential source.
Expand Down
2 changes: 1 addition & 1 deletion Src/Fido2.Models/Objects/VerifyAssertionResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/// <summary>
/// Result of the MakeAssertion verification
/// </summary>
public class VerifyAssertionResult : Fido2ResponseBase
public class VerifyAssertionResult
{
public byte[] CredentialId { get; init; }

Expand Down
1 change: 0 additions & 1 deletion Src/Fido2/AuthenticatorAssertionResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,6 @@ public async Task<VerifyAssertionResult> VerifyAsync(

return new VerifyAssertionResult
{
Status = "ok",
CredentialId = Raw.Id,
SignCount = authData.SignCount,
IsBackedUp = authData.IsBackedUp,
Expand Down
13 changes: 4 additions & 9 deletions Src/Fido2/Fido2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,21 +67,16 @@ public CredentialCreateOptions RequestNewCredential(
/// <param name="isCredentialIdUniqueToUser">The delegate used to validate that the CredentialID is unique to this user.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns></returns>
public async Task<MakeNewCredentialResult> MakeNewCredentialAsync(
public async Task<RegisteredPublicKeyCredential> MakeNewCredentialAsync(
AuthenticatorAttestationRawResponse attestationResponse,
CredentialCreateOptions originalOptions,
IsCredentialIdUniqueToUserAsyncDelegate isCredentialIdUniqueToUser,
CancellationToken cancellationToken = default)
{
var parsedResponse = AuthenticatorAttestationResponse.Parse(attestationResponse);
var success = await parsedResponse.VerifyAsync(originalOptions, _config, isCredentialIdUniqueToUser, _metadataService, cancellationToken);

// todo: Set Errormessage etc.
return new MakeNewCredentialResult(
status: "ok",
errorMessage: string.Empty,
result: success
);
var credential = await parsedResponse.VerifyAsync(originalOptions, _config, isCredentialIdUniqueToUser, _metadataService, cancellationToken);

return credential;
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion Src/Fido2/IFido2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Task<VerifyAssertionResult> MakeAssertionAsync(
IsUserHandleOwnerOfCredentialIdAsync isUserHandleOwnerOfCredentialIdCallback,
CancellationToken cancellationToken = default);

Task<MakeNewCredentialResult> MakeNewCredentialAsync(
Task<RegisteredPublicKeyCredential> MakeNewCredentialAsync(
AuthenticatorAttestationRawResponse attestationResponse,
CredentialCreateOptions originalOptions,
IsCredentialIdUniqueToUserAsyncDelegate isCredentialIdUniqueToUser,
Expand Down
Loading

0 comments on commit cb71a15

Please sign in to comment.