diff --git a/NEWS b/NEWS index d2384d656..83ccbaa98 100644 --- a/NEWS +++ b/NEWS @@ -1,9 +1,17 @@ == Version 2.1.0 (unreleased) == +Deprecations: + +* Deprecated method `AssertionResult.getCredentialId(): ByteArray`. Use + `.getCredential().getCredentialId()` instead. +* Deprecated method `AssertionResult.getUserHandle(): ByteArray`. Use + `.getCredential().getUserHandle()` instead. + New features: * Added method `FidoMetadataDownloader.refreshBlob()`. * Added function `COSEAlgorithmIdentifier.fromPublicKey(ByteArray)`. +* Added method `AssertionResult.getCredential(): RegisteredCredential`. == Version 2.0.0 == diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/AssertionResult.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/AssertionResult.java index 2b8c3c0f1..1fb1d9909 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/AssertionResult.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/AssertionResult.java @@ -26,6 +26,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; +import com.yubico.internal.util.ExceptionUtil; import com.yubico.webauthn.data.AuthenticatorAssertionExtensionOutputs; import com.yubico.webauthn.data.AuthenticatorData; import com.yubico.webauthn.data.ByteArray; @@ -46,24 +47,16 @@ public class AssertionResult { private final boolean success; /** - * The credential - * ID of the credential used for the assertion. - * - * @see Credential - * ID - * @see PublicKeyCredentialRequestOptions#getAllowCredentials() - */ - @NonNull private final ByteArray credentialId; - - /** - * The user handle - * of the authenticated user. + * The {@link RegisteredCredential} that was returned by {@link + * CredentialRepository#lookup(ByteArray, ByteArray)} and whose public key was used to + * successfully verify the assertion signature. * - * @see User Handle - * @see UserIdentity#getId() - * @see #getUsername() + *

NOTE: The {@link RegisteredCredential#getSignatureCount() signature count} in this object + * will reflect the signature counter state before the assertion operation, not the new + * counter value. When updating your database state, use the signature counter from {@link + * #getSignatureCount()} instead. */ - @NonNull private final ByteArray userHandle; + private final RegisteredCredential credential; /** * The username of the authenticated user. @@ -107,12 +100,33 @@ public class AssertionResult { private final AuthenticatorAssertionExtensionOutputs authenticatorExtensionOutputs; + private AssertionResult( + boolean success, + @NonNull @JsonProperty("credential") RegisteredCredential credential, + @NonNull String username, + long signatureCount, + boolean signatureCounterValid, + ClientAssertionExtensionOutputs clientExtensionOutputs, + AuthenticatorAssertionExtensionOutputs authenticatorExtensionOutputs) { + this( + success, + credential, + username, + null, + null, + signatureCount, + signatureCounterValid, + clientExtensionOutputs, + authenticatorExtensionOutputs); + } + @JsonCreator private AssertionResult( @JsonProperty("success") boolean success, - @NonNull @JsonProperty("credentialId") ByteArray credentialId, - @NonNull @JsonProperty("userHandle") ByteArray userHandle, + @NonNull @JsonProperty("credential") RegisteredCredential credential, @NonNull @JsonProperty("username") String username, + @JsonProperty("credentialId") ByteArray credentialId, // TODO: Delete in next major release + @JsonProperty("userHandle") ByteArray userHandle, // TODO: Delete in next major release @JsonProperty("signatureCount") long signatureCount, @JsonProperty("signatureCounterValid") boolean signatureCounterValid, @JsonProperty("clientExtensionOutputs") @@ -120,9 +134,20 @@ private AssertionResult( @JsonProperty("authenticatorExtensionOutputs") AuthenticatorAssertionExtensionOutputs authenticatorExtensionOutputs) { this.success = success; - this.credentialId = credentialId; - this.userHandle = userHandle; + this.credential = credential; this.username = username; + + if (credentialId != null) { + ExceptionUtil.assure( + credential.getCredentialId().equals(credentialId), + "Legacy credentialId is present and does not equal credential.credentialId"); + } + if (userHandle != null) { + ExceptionUtil.assure( + credential.getUserHandle().equals(userHandle), + "Legacy userHandle is present and does not equal credential.userHandle"); + } + this.signatureCount = signatureCount; this.signatureCounterValid = signatureCounterValid; this.clientExtensionOutputs = @@ -132,6 +157,36 @@ private AssertionResult( this.authenticatorExtensionOutputs = authenticatorExtensionOutputs; } + /** + * The credential + * ID of the credential used for the assertion. + * + * @see Credential + * ID + * @see PublicKeyCredentialRequestOptions#getAllowCredentials() + * @deprecated Use {@link #getCredential()}.{@link RegisteredCredential#getCredentialId() + * getCredentialId()} instead. + */ + @Deprecated + public ByteArray getCredentialId() { + return credential.getCredentialId(); + } + + /** + * The user handle + * of the authenticated user. + * + * @see User Handle + * @see UserIdentity#getId() + * @see #getUsername() + * @deprecated Use {@link #getCredential()}.{@link RegisteredCredential#getUserHandle()} () + * getUserHandle()} instead. + */ + @Deprecated + public ByteArray getUserHandle() { + return credential.getUserHandle(); + } + /** * The client @@ -180,49 +235,42 @@ public Step2 success(boolean success) { } public class Step2 { - public Step3 credentialId(ByteArray credentialId) { - builder.credentialId(credentialId); + public Step3 credential(RegisteredCredential credential) { + builder.credential(credential); return new Step3(); } } public class Step3 { - public Step4 userHandle(ByteArray userHandle) { - builder.userHandle(userHandle); + public Step4 username(String username) { + builder.username(username); return new Step4(); } } public class Step4 { - public Step5 username(String username) { - builder.username(username); + public Step5 signatureCount(long signatureCount) { + builder.signatureCount(signatureCount); return new Step5(); } } public class Step5 { - public Step6 signatureCount(long signatureCount) { - builder.signatureCount(signatureCount); + public Step6 signatureCounterValid(boolean signatureCounterValid) { + builder.signatureCounterValid(signatureCounterValid); return new Step6(); } } public class Step6 { - public Step7 signatureCounterValid(boolean signatureCounterValid) { - builder.signatureCounterValid(signatureCounterValid); - return new Step7(); - } - } - - public class Step7 { - public Step8 clientExtensionOutputs( + public Step7 clientExtensionOutputs( ClientAssertionExtensionOutputs clientExtensionOutputs) { builder.clientExtensionOutputs(clientExtensionOutputs); - return new Step8(); + return new Step7(); } } - public class Step8 { + public class Step7 { public AssertionResultBuilder assertionExtensionOutputs( AuthenticatorAssertionExtensionOutputs authenticatorExtensionOutputs) { return builder.authenticatorExtensionOutputs(authenticatorExtensionOutputs); diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/FinishAssertionSteps.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/FinishAssertionSteps.java index 543cd2d96..b0194b501 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/FinishAssertionSteps.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/FinishAssertionSteps.java @@ -203,7 +203,7 @@ class Step7 implements Step { @Override public Step8 nextStep() { - return new Step8(username, userHandle, credential.get()); + return new Step8(username, credential.get()); } @Override @@ -220,7 +220,6 @@ public void validate() { class Step8 implements Step { private final String username; - private final ByteArray userHandle; private final RegisteredCredential credential; @Override @@ -232,7 +231,7 @@ public void validate() { @Override public Step10 nextStep() { - return new Step10(username, userHandle, credential); + return new Step10(username, credential); } public ByteArray authenticatorData() { @@ -253,7 +252,6 @@ public ByteArray signature() { @Value class Step10 implements Step { private final String username; - private final ByteArray userHandle; private final RegisteredCredential credential; @Override @@ -263,7 +261,7 @@ public void validate() { @Override public Step11 nextStep() { - return new Step11(username, userHandle, credential, clientData()); + return new Step11(username, credential, clientData()); } public CollectedClientData clientData() { @@ -274,7 +272,6 @@ public CollectedClientData clientData() { @Value class Step11 implements Step { private final String username; - private final ByteArray userHandle; private final RegisteredCredential credential; private final CollectedClientData clientData; @@ -289,14 +286,13 @@ public void validate() { @Override public Step12 nextStep() { - return new Step12(username, userHandle, credential); + return new Step12(username, credential); } } @Value class Step12 implements Step { private final String username; - private final ByteArray userHandle; private final RegisteredCredential credential; @Override @@ -311,14 +307,13 @@ public void validate() { @Override public Step13 nextStep() { - return new Step13(username, userHandle, credential); + return new Step13(username, credential); } } @Value class Step13 implements Step { private final String username; - private final ByteArray userHandle; private final RegisteredCredential credential; @Override @@ -331,14 +326,13 @@ public void validate() { @Override public Step14 nextStep() { - return new Step14(username, userHandle, credential); + return new Step14(username, credential); } } @Value class Step14 implements Step { private final String username; - private final ByteArray userHandle; private final RegisteredCredential credential; @Override @@ -349,14 +343,13 @@ public void validate() { @Override public Step15 nextStep() { - return new Step15(username, userHandle, credential); + return new Step15(username, credential); } } @Value class Step15 implements Step { private final String username; - private final ByteArray userHandle; private final RegisteredCredential credential; @Override @@ -382,14 +375,13 @@ public void validate() { @Override public Step16 nextStep() { - return new Step16(username, userHandle, credential); + return new Step16(username, credential); } } @Value class Step16 implements Step { private final String username; - private final ByteArray userHandle; private final RegisteredCredential credential; @Override @@ -401,14 +393,13 @@ public void validate() { @Override public Step17 nextStep() { - return new Step17(username, userHandle, credential); + return new Step17(username, credential); } } @Value class Step17 implements Step { private final String username; - private final ByteArray userHandle; private final RegisteredCredential credential; @Override @@ -425,14 +416,13 @@ public void validate() { @Override public Step18 nextStep() { - return new Step18(username, userHandle, credential); + return new Step18(username, credential); } } @Value class Step18 implements Step { private final String username; - private final ByteArray userHandle; private final RegisteredCredential credential; @Override @@ -440,14 +430,13 @@ public void validate() {} @Override public Step19 nextStep() { - return new Step19(username, userHandle, credential); + return new Step19(username, credential); } } @Value class Step19 implements Step { private final String username; - private final ByteArray userHandle; private final RegisteredCredential credential; @Override @@ -457,7 +446,7 @@ public void validate() { @Override public Step20 nextStep() { - return new Step20(username, userHandle, credential, clientDataJsonHash()); + return new Step20(username, credential, clientDataJsonHash()); } public ByteArray clientDataJsonHash() { @@ -468,7 +457,6 @@ public ByteArray clientDataJsonHash() { @Value class Step20 implements Step { private final String username; - private final ByteArray userHandle; private final RegisteredCredential credential; private final ByteArray clientDataJsonHash; @@ -503,7 +491,7 @@ public void validate() { @Override public Step21 nextStep() { - return new Step21(username, userHandle, credential); + return new Step21(username, credential); } public ByteArray signedBytes() { @@ -514,13 +502,11 @@ public ByteArray signedBytes() { @Value class Step21 implements Step { private final String username; - private final ByteArray userHandle; private final RegisteredCredential credential; private final long storedSignatureCountBefore; - public Step21(String username, ByteArray userHandle, RegisteredCredential credential) { + public Step21(String username, RegisteredCredential credential) { this.username = username; - this.userHandle = userHandle; this.credential = credential; this.storedSignatureCountBefore = credential.getSignatureCount(); } @@ -540,7 +526,7 @@ private boolean signatureCounterValid() { @Override public Finished nextStep() { - return new Finished(username, userHandle, assertionSignatureCount(), signatureCounterValid()); + return new Finished(credential, username, assertionSignatureCount(), signatureCounterValid()); } private long assertionSignatureCount() { @@ -550,8 +536,8 @@ private long assertionSignatureCount() { @Value class Finished implements Step { + private final RegisteredCredential credential; private final String username; - private final ByteArray userHandle; private final long assertionSignatureCount; private final boolean signatureCounterValid; @@ -570,8 +556,7 @@ public Optional result() { return Optional.of( AssertionResult.builder() .success(true) - .credentialId(response.getId()) - .userHandle(userHandle) + .credential(credential) .username(username) .signatureCount(assertionSignatureCount) .signatureCounterValid(signatureCounterValid) diff --git a/webauthn-server-core/src/test/scala/com/yubico/webauthn/Generators.scala b/webauthn-server-core/src/test/scala/com/yubico/webauthn/Generators.scala index cdf29f722..15d346337 100644 --- a/webauthn-server-core/src/test/scala/com/yubico/webauthn/Generators.scala +++ b/webauthn-server-core/src/test/scala/com/yubico/webauthn/Generators.scala @@ -25,17 +25,15 @@ object Generators { authenticatorExtensionOutputs <- arbitrary[Option[AuthenticatorAssertionExtensionOutputs]] clientExtensionOutputs <- arbitrary[ClientAssertionExtensionOutputs] - credentialId <- arbitrary[ByteArray] + credential <- arbitrary[RegisteredCredential] signatureCount <- arbitrary[Long] signatureCounterValid <- arbitrary[Boolean] success <- arbitrary[Boolean] - userHandle <- arbitrary[ByteArray] username <- arbitrary[String] } yield AssertionResult .builder() .success(success) - .credentialId(credentialId) - .userHandle(userHandle) + .credential(credential) .username(username) .signatureCount(signatureCount) .signatureCounterValid(signatureCounterValid) diff --git a/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyAssertionSpec.scala b/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyAssertionSpec.scala index da17187b5..fc546d5ef 100644 --- a/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyAssertionSpec.scala +++ b/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyAssertionSpec.scala @@ -1829,6 +1829,13 @@ class RelyingPartyAssertionSpec step.result.get.isSuccess should be(true) step.result.get.getCredentialId should equal(Defaults.credentialId) step.result.get.getUserHandle should equal(Defaults.userHandle) + step.result.get.getCredential.getCredentialId should equal( + step.result.get.getCredentialId + ) + step.result.get.getCredential.getUserHandle should equal( + step.result.get.getUserHandle + ) + step.result.get.getCredential.getPublicKeyCose should not be null } } }