From 998b781948c817427501aa769a76935877560092 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Mon, 4 Mar 2019 16:16:59 +0100 Subject: [PATCH 01/19] Add overload AssertionRequestBuilder.username(String) --- .../com/yubico/webauthn/AssertionRequest.java | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/AssertionRequest.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/AssertionRequest.java index 28dcf304b..ff753e3bd 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/AssertionRequest.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/AssertionRequest.java @@ -59,8 +59,7 @@ public class AssertionRequest { *

*/ @NonNull - @Builder.Default - private final Optional username = Optional.empty(); + private final Optional username; @JsonCreator private AssertionRequest( @@ -75,6 +74,8 @@ public static AssertionRequestBuilder.MandatoryStages builder() { } public static class AssertionRequestBuilder { + private Optional username = Optional.empty(); + public static class MandatoryStages { private final AssertionRequestBuilder builder = new AssertionRequestBuilder(); @@ -86,6 +87,31 @@ public AssertionRequestBuilder publicKeyCredentialRequestOptions(PublicKeyCreden return builder.publicKeyCredentialRequestOptions(publicKeyCredentialRequestOptions); } } + + /** + * The username of the user to authenticate, if the user has already been identified. + *

+ * If this is absent, this indicates that this is a request for an assertion by a client-side-resident + * credential, and identification of the user has been deferred until the response is received. + *

+ */ + public AssertionRequestBuilder username(@NonNull Optional username) { + this.username = username; + return this; + } + + /** + * The username of the user to authenticate, if the user has already been identified. + *

+ * If this is absent, this indicates that this is a request for an assertion by a client-side-resident + * credential, and identification of the user has been deferred until the response is received. + *

+ */ + public AssertionRequestBuilder username(@NonNull String username) { + return this.username(Optional.of(username)); + } } } From eb79a00cb0b3cddde2e3d08eb572170a3c6b81fe Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Mon, 4 Mar 2019 17:15:00 +0100 Subject: [PATCH 02/19] Add overload AuthenticatorAssertionResponse.userHandle(ByteArray) --- .../data/AuthenticatorAssertionResponse.java | 19 +++++++++++++++++++ .../webauthn/RelyingPartyAssertionSpec.scala | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/AuthenticatorAssertionResponse.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/AuthenticatorAssertionResponse.java index 27dcd29b2..471d4faa4 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/AuthenticatorAssertionResponse.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/AuthenticatorAssertionResponse.java @@ -133,6 +133,25 @@ public AuthenticatorAssertionResponseBuilder signature(ByteArray signature) { } } } + + /** + * The user handle returned from the authenticator, or empty if the authenticator did not return a user handle. See + * §6.3.3 The authenticatorGetAssertion + * Operation. + */ + public AuthenticatorAssertionResponseBuilder userHandle(@NonNull Optional userHandle) { + this.userHandle = userHandle; + return this; + } + + /** + * The user handle returned from the authenticator, or empty if the authenticator did not return a user handle. See + * §6.3.3 The authenticatorGetAssertion + * Operation. + */ + public AuthenticatorAssertionResponseBuilder userHandle(@NonNull ByteArray userHandle) { + return this.userHandle(Optional.of(userHandle)); + } } } 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 27d559b2e..f14d4e1de 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 @@ -163,7 +163,7 @@ class RelyingPartyAssertionSpec extends FunSpec with Matchers with GeneratorDriv .authenticatorData(if (authenticatorData == null) null else authenticatorData) .clientDataJSON(if (clientDataJsonBytes == null) null else clientDataJsonBytes) .signature(if (signature == null) null else signature) - .userHandle(Optional.of(userHandleForResponse)) + .userHandle(userHandleForResponse) .build() ) .clientExtensionResults(clientExtensionResults) From 147c599c750ccdb3f69dfac4d26cf775797ce837 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Mon, 4 Mar 2019 17:21:45 +0100 Subject: [PATCH 03/19] Add overload FinishAssertionOptions.callerTokenBindingId(ByteArray) --- .../webauthn/FinishAssertionOptions.java | 26 +++++++++++++++++-- .../webauthn/FinishAssertionOptionsTest.java | 26 +++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 webauthn-server-core/src/test/java/com/yubico/webauthn/FinishAssertionOptionsTest.java diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/FinishAssertionOptions.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/FinishAssertionOptions.java index 59a7b7253..4e0064081 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/FinishAssertionOptions.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/FinishAssertionOptions.java @@ -61,14 +61,15 @@ public class FinishAssertionOptions { * @see The Token Binding Protocol Version 1.0 */ @NonNull - @Builder.Default - private final Optional callerTokenBindingId = Optional.empty(); + private final Optional callerTokenBindingId; public static FinishAssertionOptionsBuilder.MandatoryStages builder() { return new FinishAssertionOptionsBuilder.MandatoryStages(); } public static class FinishAssertionOptionsBuilder { + private Optional callerTokenBindingId = Optional.empty(); + public static class MandatoryStages { private final FinishAssertionOptionsBuilder builder = new FinishAssertionOptionsBuilder(); @@ -83,6 +84,27 @@ public FinishAssertionOptionsBuilder response(PublicKeyCredentialtoken binding ID of the connection to the + * client, if any. + * + * @see The Token Binding Protocol Version 1.0 + */ + public FinishAssertionOptionsBuilder callerTokenBindingId(@NonNull Optional callerTokenBindingId) { + this.callerTokenBindingId = callerTokenBindingId; + return this; + } + + /** + * The token binding ID of the connection to the + * client, if any. + * + * @see The Token Binding Protocol Version 1.0 + */ + public FinishAssertionOptionsBuilder callerTokenBindingId(@NonNull ByteArray callerTokenBindingId) { + return this.callerTokenBindingId(Optional.of(callerTokenBindingId)); + } } } diff --git a/webauthn-server-core/src/test/java/com/yubico/webauthn/FinishAssertionOptionsTest.java b/webauthn-server-core/src/test/java/com/yubico/webauthn/FinishAssertionOptionsTest.java new file mode 100644 index 000000000..85a3fe6ba --- /dev/null +++ b/webauthn-server-core/src/test/java/com/yubico/webauthn/FinishAssertionOptionsTest.java @@ -0,0 +1,26 @@ +package com.yubico.webauthn; + +import com.yubico.webauthn.data.ByteArray; +import com.yubico.webauthn.data.exception.HexException; +import java.util.Optional; +import org.junit.Test; + +public class FinishAssertionOptionsTest { + + @Test(expected = NullPointerException.class) + public void itHasANonOptionalCallerTokenBindingIdMethod() throws HexException { + FinishAssertionOptions.builder() + .request(null) + .response(null) + .callerTokenBindingId(ByteArray.fromHex("aa")); + } + + @Test(expected = NullPointerException.class) + public void itHasAnOptionalCallerTokenBindingIdMethod() throws HexException { + FinishAssertionOptions.builder() + .request(null) + .response(null) + .callerTokenBindingId(Optional.of(ByteArray.fromHex("aa"))); + } + +} From f6d168c22635119af062582626f7d4022c782086 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Mon, 4 Mar 2019 17:23:54 +0100 Subject: [PATCH 04/19] Add overload FinishRegistrationOptions.callerTokenBindingId(ByteArray) --- .../webauthn/FinishRegistrationOptions.java | 26 +++++++++++++++++-- .../FinishRegistrationOptionsTest.java | 26 +++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 webauthn-server-core/src/test/java/com/yubico/webauthn/FinishRegistrationOptionsTest.java diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/FinishRegistrationOptions.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/FinishRegistrationOptions.java index d2c369c28..1cc475d44 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/FinishRegistrationOptions.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/FinishRegistrationOptions.java @@ -62,14 +62,15 @@ public class FinishRegistrationOptions { * @see The Token Binding Protocol Version 1.0 */ @NonNull - @Builder.Default - private final Optional callerTokenBindingId = Optional.empty(); + private final Optional callerTokenBindingId; public static FinishRegistrationOptionsBuilder.MandatoryStages builder() { return new FinishRegistrationOptionsBuilder.MandatoryStages(); } public static class FinishRegistrationOptionsBuilder { + private Optional callerTokenBindingId = Optional.empty(); + public static class MandatoryStages { private final FinishRegistrationOptionsBuilder builder = new FinishRegistrationOptionsBuilder(); @@ -84,5 +85,26 @@ public FinishRegistrationOptionsBuilder response(PublicKeyCredentialtoken binding ID of the connection to the + * client, if any. + * + * @see The Token Binding Protocol Version 1.0 + */ + public FinishRegistrationOptionsBuilder callerTokenBindingId(@NonNull Optional callerTokenBindingId) { + this.callerTokenBindingId = callerTokenBindingId; + return this; + } + + /** + * The token binding ID of the connection to the + * client, if any. + * + * @see The Token Binding Protocol Version 1.0 + */ + public FinishRegistrationOptionsBuilder callerTokenBindingId(@NonNull ByteArray callerTokenBindingId) { + return this.callerTokenBindingId(Optional.of(callerTokenBindingId)); + } } } diff --git a/webauthn-server-core/src/test/java/com/yubico/webauthn/FinishRegistrationOptionsTest.java b/webauthn-server-core/src/test/java/com/yubico/webauthn/FinishRegistrationOptionsTest.java new file mode 100644 index 000000000..c6fe88494 --- /dev/null +++ b/webauthn-server-core/src/test/java/com/yubico/webauthn/FinishRegistrationOptionsTest.java @@ -0,0 +1,26 @@ +package com.yubico.webauthn; + +import com.yubico.webauthn.data.ByteArray; +import com.yubico.webauthn.data.exception.HexException; +import java.util.Optional; +import org.junit.Test; + +public class FinishRegistrationOptionsTest { + + @Test(expected = NullPointerException.class) + public void itHasANonOptionalCallerTokenBindingIdMethod() throws HexException { + FinishRegistrationOptions.builder() + .request(null) + .response(null) + .callerTokenBindingId(ByteArray.fromHex("aa")); + } + + @Test(expected = NullPointerException.class) + public void itHasAnOptionalCallerTokenBindingIdMethod() throws HexException { + FinishAssertionOptions.builder() + .request(null) + .response(null) + .callerTokenBindingId(Optional.of(ByteArray.fromHex("aa"))); + } + +} From 86105221c1ca3472fbee6a782da766f81178f03a Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Mon, 4 Mar 2019 17:40:00 +0100 Subject: [PATCH 05/19] Add Optional-less overloads to PublicKeyCredentialCreationOptions builder --- .../com/yubico/webauthn/RelyingParty.java | 2 +- .../PublicKeyCredentialCreationOptions.java | 66 +++++++++++++++++-- ...ublicKeyCredentialCreationOptionsTest.java | 27 ++++++++ 3 files changed, 88 insertions(+), 7 deletions(-) create mode 100644 webauthn-server-core/src/test/java/com/yubico/webauthn/data/PublicKeyCredentialCreationOptionsTest.java diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/RelyingParty.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/RelyingParty.java index bbe7dc034..5d2fef5c8 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/RelyingParty.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/RelyingParty.java @@ -291,7 +291,7 @@ public PublicKeyCredentialCreationOptions startRegistration(StartRegistrationOpt .challenge(generateChallenge()) .pubKeyCredParams(preferredPubkeyParams) .excludeCredentials( - Optional.of(credentialRepository.getCredentialIdsForUsername(startRegistrationOptions.getUser().getName())) + credentialRepository.getCredentialIdsForUsername(startRegistrationOptions.getUser().getName()) ) .authenticatorSelection(startRegistrationOptions.getAuthenticatorSelection()) .extensions(startRegistrationOptions.getExtensions()) diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/PublicKeyCredentialCreationOptions.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/PublicKeyCredentialCreationOptions.java index ce3e45715..8abadc09b 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/PublicKeyCredentialCreationOptions.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/PublicKeyCredentialCreationOptions.java @@ -87,8 +87,7 @@ public class PublicKeyCredentialCreationOptions { * and MAY be overridden by the client. */ @NonNull - @Builder.Default - private final Optional timeout = Optional.empty(); + private final Optional timeout; /** * Intended for use by Relying Parties that wish to limit the creation of multiple credentials for the same account @@ -96,16 +95,14 @@ public class PublicKeyCredentialCreationOptions { * an authenticator that also contains one of the credentials enumerated in this parameter. */ @NonNull - @Builder.Default - private final Optional> excludeCredentials = Optional.empty(); + private final Optional> excludeCredentials; /** * Intended for use by Relying Parties that wish to select the appropriate authenticators to participate in the * create() operation. */ @NonNull - @Builder.Default - private final Optional authenticatorSelection = Optional.empty(); + private final Optional authenticatorSelection; /** * Intended for use by Relying Parties that wish to express their preference for attestation conveyance. The default @@ -182,6 +179,10 @@ public static PublicKeyCredentialCreationOptionsBuilder.MandatoryStages builder( } public static class PublicKeyCredentialCreationOptionsBuilder { + private @NonNull Optional timeout = Optional.empty(); + private @NonNull Optional> excludeCredentials = Optional.empty(); + private @NonNull Optional authenticatorSelection = Optional.empty(); + public static class MandatoryStages { private PublicKeyCredentialCreationOptionsBuilder builder = new PublicKeyCredentialCreationOptionsBuilder(); @@ -222,6 +223,59 @@ public PublicKeyCredentialCreationOptionsBuilder pubKeyCredParams(List timeout) { + this.timeout = timeout; + return this; + } + + /** + * A time, in milliseconds, that the caller is willing to wait for the call to complete. This is treated as a hint, + * and MAY be overridden by the client. + */ + public PublicKeyCredentialCreationOptionsBuilder timeout(long timeout) { + return this.timeout(Optional.of(timeout)); + } + + /** + * Intended for use by Relying Parties that wish to limit the creation of multiple credentials for the same account + * on a single authenticator. The client is requested to return an error if the new credential would be created on + * an authenticator that also contains one of the credentials enumerated in this parameter. + */ + public PublicKeyCredentialCreationOptionsBuilder excludeCredentials(@NonNull Optional> excludeCredentials) { + this.excludeCredentials = excludeCredentials; + return this; + } + + /** + * Intended for use by Relying Parties that wish to limit the creation of multiple credentials for the same account + * on a single authenticator. The client is requested to return an error if the new credential would be created on + * an authenticator that also contains one of the credentials enumerated in this parameter. + */ + public PublicKeyCredentialCreationOptionsBuilder excludeCredentials(@NonNull Set excludeCredentials) { + return this.excludeCredentials(Optional.of(excludeCredentials)); + } + + /** + * Intended for use by Relying Parties that wish to select the appropriate authenticators to participate in the + * create() operation. + */ + public PublicKeyCredentialCreationOptionsBuilder authenticatorSelection(@NonNull Optional authenticatorSelection) { + this.authenticatorSelection = authenticatorSelection; + return this; + } + + /** + * Intended for use by Relying Parties that wish to select the appropriate authenticators to participate in the + * create() operation. + */ + public PublicKeyCredentialCreationOptionsBuilder authenticatorSelection(@NonNull AuthenticatorSelectionCriteria authenticatorSelection) { + return this.authenticatorSelection(Optional.of(authenticatorSelection)); + } } } diff --git a/webauthn-server-core/src/test/java/com/yubico/webauthn/data/PublicKeyCredentialCreationOptionsTest.java b/webauthn-server-core/src/test/java/com/yubico/webauthn/data/PublicKeyCredentialCreationOptionsTest.java new file mode 100644 index 000000000..848c1c5f1 --- /dev/null +++ b/webauthn-server-core/src/test/java/com/yubico/webauthn/data/PublicKeyCredentialCreationOptionsTest.java @@ -0,0 +1,27 @@ +package com.yubico.webauthn.data; + +import java.util.Collections; +import java.util.Optional; +import org.junit.Test; + +public class PublicKeyCredentialCreationOptionsTest { + + @Test(expected = NullPointerException.class) + public void itHasTheseBuilderMethods() { + PublicKeyCredentialCreationOptions.builder() + .rp(null) + .user(null) + .challenge(null) + .pubKeyCredParams(null) + .attestation(null) + .authenticatorSelection(AuthenticatorSelectionCriteria.builder().build()) + .authenticatorSelection(Optional.of(AuthenticatorSelectionCriteria.builder().build())) + .excludeCredentials(Collections.emptySet()) + .excludeCredentials(Optional.of(Collections.emptySet())) + .extensions(RegistrationExtensionInputs.builder().build()) + .timeout(0) + .timeout(Optional.of(0L)) + ; + } + +} From 2d24176a5e610104d4a59beb5511124bb222bf4e Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Mon, 4 Mar 2019 17:48:04 +0100 Subject: [PATCH 06/19] Add overload PublicKeyCredentialDescriptorBuilder.transports(Set) --- .../data/PublicKeyCredentialDescriptor.java | 22 +++++++++++++++++-- .../PublicKeyCredentialDescriptorTest.java | 18 +++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 webauthn-server-core/src/test/java/com/yubico/webauthn/data/PublicKeyCredentialDescriptorTest.java diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/PublicKeyCredentialDescriptor.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/PublicKeyCredentialDescriptor.java index 14038fb67..834be2bde 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/PublicKeyCredentialDescriptor.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/PublicKeyCredentialDescriptor.java @@ -66,8 +66,7 @@ public class PublicKeyCredentialDescriptor implements Comparable> transports = Optional.empty(); + private final Optional> transports; private PublicKeyCredentialDescriptor( @NonNull PublicKeyCredentialType type, @@ -118,6 +117,8 @@ public static PublicKeyCredentialDescriptorBuilder.MandatoryStages builder() { } public static class PublicKeyCredentialDescriptorBuilder { + private Optional> transports = Optional.empty(); + public static class MandatoryStages { private PublicKeyCredentialDescriptorBuilder builder = new PublicKeyCredentialDescriptorBuilder(); @@ -125,5 +126,22 @@ public PublicKeyCredentialDescriptorBuilder id(ByteArray id) { return builder.id(id); } } + + /** + * An OPTIONAL hint as to how the client might communicate with the managing authenticator of the public key + * credential the caller is referring to. + */ + public PublicKeyCredentialDescriptorBuilder transports(@NonNull Optional> transports) { + this.transports = transports; + return this; + } + + /** + * An OPTIONAL hint as to how the client might communicate with the managing authenticator of the public key + * credential the caller is referring to. + */ + public PublicKeyCredentialDescriptorBuilder transports(@NonNull Set transports) { + return this.transports(Optional.of(transports)); + } } } diff --git a/webauthn-server-core/src/test/java/com/yubico/webauthn/data/PublicKeyCredentialDescriptorTest.java b/webauthn-server-core/src/test/java/com/yubico/webauthn/data/PublicKeyCredentialDescriptorTest.java new file mode 100644 index 000000000..f9fce0c3e --- /dev/null +++ b/webauthn-server-core/src/test/java/com/yubico/webauthn/data/PublicKeyCredentialDescriptorTest.java @@ -0,0 +1,18 @@ +package com.yubico.webauthn.data; + +import java.util.Collections; +import java.util.Optional; +import org.junit.Test; + +public class PublicKeyCredentialDescriptorTest { + + @Test(expected = NullPointerException.class) + public void itHasTheseBuilderMethods() { + PublicKeyCredentialDescriptor.builder() + .id(null) + .transports(Collections.emptySet()) + .transports(Optional.of(Collections.emptySet())) + ; + } + +} From 98a7082424313c213981511891f0f4583c1bb8f1 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Mon, 4 Mar 2019 18:05:38 +0100 Subject: [PATCH 07/19] Add Optional-less overloads to PublicKeyCredentialRequestOptions builder --- .../com/yubico/webauthn/RelyingParty.java | 2 +- .../PublicKeyCredentialRequestOptions.java | 74 +++++++++++++++++-- ...PublicKeyCredentialRequestOptionsTest.java | 23 ++++++ .../webauthn/RelyingPartyAssertionSpec.scala | 2 +- .../demo/webauthn/WebAuthnServerSpec.scala | 2 +- 5 files changed, 94 insertions(+), 9 deletions(-) create mode 100644 webauthn-server-core/src/test/java/com/yubico/webauthn/data/PublicKeyCredentialRequestOptionsTest.java diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/RelyingParty.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/RelyingParty.java index 5d2fef5c8..7c88766e5 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/RelyingParty.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/RelyingParty.java @@ -336,7 +336,7 @@ FinishRegistrationSteps _finishRegistration( public AssertionRequest startAssertion(StartAssertionOptions startAssertionOptions) { PublicKeyCredentialRequestOptionsBuilder pkcro = PublicKeyCredentialRequestOptions.builder() .challenge(generateChallenge()) - .rpId(Optional.of(identity.getId())) + .rpId(identity.getId()) .allowCredentials( startAssertionOptions.getUsername().map(un -> new ArrayList<>(credentialRepository.getCredentialIdsForUsername(un))) diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/PublicKeyCredentialRequestOptions.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/PublicKeyCredentialRequestOptions.java index 763a208d7..61f3fe1f7 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/PublicKeyCredentialRequestOptions.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/PublicKeyCredentialRequestOptions.java @@ -63,8 +63,7 @@ public class PublicKeyCredentialRequestOptions { *

*/ @NonNull - @Builder.Default - private final Optional timeout = Optional.empty(); + private final Optional timeout; /** * Specifies the relying party identifier claimed by the caller. @@ -73,8 +72,7 @@ public class PublicKeyCredentialRequestOptions { *

*/ @NonNull - @Builder.Default - private final Optional rpId = Optional.empty(); + private final Optional rpId; /** * A list of {@link PublicKeyCredentialDescriptor} objects representing public key credentials acceptable to the @@ -82,8 +80,7 @@ public class PublicKeyCredentialRequestOptions { * credential, and so on down the list). */ @NonNull - @Builder.Default - private final Optional> allowCredentials = Optional.empty(); + private final Optional> allowCredentials; /** * Describes the Relying Party's requirements regarding user @@ -147,6 +144,10 @@ public static PublicKeyCredentialRequestOptionsBuilder.MandatoryStages builder() } public static class PublicKeyCredentialRequestOptionsBuilder { + private @NonNull Optional timeout = Optional.empty(); + private @NonNull Optional rpId = Optional.empty(); + private @NonNull Optional> allowCredentials = Optional.empty(); + public static class MandatoryStages { private PublicKeyCredentialRequestOptionsBuilder builder = new PublicKeyCredentialRequestOptionsBuilder(); @@ -154,5 +155,66 @@ public PublicKeyCredentialRequestOptionsBuilder challenge(ByteArray challenge) { return builder.challenge(challenge); } } + + /** + * Specifies a time, in milliseconds, that the caller is willing to wait for the call to complete. + *

+ * This is treated as a hint, and MAY be overridden by the client. + *

+ */ + public PublicKeyCredentialRequestOptionsBuilder timeout(@NonNull Optional timeout) { + this.timeout = timeout; + return this; + } + + /** + * Specifies a time, in milliseconds, that the caller is willing to wait for the call to complete. + *

+ * This is treated as a hint, and MAY be overridden by the client. + *

+ */ + public PublicKeyCredentialRequestOptionsBuilder timeout(long timeout) { + return this.timeout(Optional.of(timeout)); + } + + /** + * Specifies the relying party identifier claimed by the caller. + *

+ * If omitted, its value will be set by the client. + *

+ */ + public PublicKeyCredentialRequestOptionsBuilder rpId(@NonNull Optional rpId) { + this.rpId = rpId; + return this; + } + + /** + * Specifies the relying party identifier claimed by the caller. + *

+ * If omitted, its value will be set by the client. + *

+ */ + public PublicKeyCredentialRequestOptionsBuilder rpId(@NonNull String rpId) { + return this.rpId(Optional.of(rpId)); + } + + /** + * A list of {@link PublicKeyCredentialDescriptor} objects representing public key credentials acceptable to the + * caller, in descending order of the caller’s preference (the first item in the list is the most preferred + * credential, and so on down the list). + */ + public PublicKeyCredentialRequestOptionsBuilder allowCredentials(@NonNull Optional> allowCredentials) { + this.allowCredentials = allowCredentials; + return this; + } + + /** + * A list of {@link PublicKeyCredentialDescriptor} objects representing public key credentials acceptable to the + * caller, in descending order of the caller’s preference (the first item in the list is the most preferred + * credential, and so on down the list). + */ + public PublicKeyCredentialRequestOptionsBuilder allowCredentials(@NonNull List allowCredentials) { + return this.allowCredentials(Optional.of(allowCredentials)); + } } } diff --git a/webauthn-server-core/src/test/java/com/yubico/webauthn/data/PublicKeyCredentialRequestOptionsTest.java b/webauthn-server-core/src/test/java/com/yubico/webauthn/data/PublicKeyCredentialRequestOptionsTest.java new file mode 100644 index 000000000..8fc2c8d20 --- /dev/null +++ b/webauthn-server-core/src/test/java/com/yubico/webauthn/data/PublicKeyCredentialRequestOptionsTest.java @@ -0,0 +1,23 @@ +package com.yubico.webauthn.data; + +import java.util.Collections; +import java.util.Optional; +import org.junit.Test; + +public class PublicKeyCredentialRequestOptionsTest { + + @Test(expected = NullPointerException.class) + public void itHasTheseBuilderMethods() { + PublicKeyCredentialRequestOptions.builder() + .challenge(null) + .timeout(0) + .timeout(Optional.of(0L)) + .rpId("") + .rpId(Optional.of("")) + .allowCredentials(Collections.emptyList()) + .allowCredentials(Optional.of(Collections.emptyList())) + .userVerification(UserVerificationRequirement.PREFERRED) + .extensions(AssertionExtensionInputs.builder().build()) + ; + } +} 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 f14d4e1de..6fea04aa9 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 @@ -147,7 +147,7 @@ class RelyingPartyAssertionSpec extends FunSpec with Matchers with GeneratorDriv .publicKeyCredentialRequestOptions( PublicKeyCredentialRequestOptions.builder() .challenge(challenge) - .rpId(Some(rpId.getId).asJava) + .rpId(rpId.getId) .allowCredentials(allowCredentials.asJava) .userVerification(userVerificationRequirement) .extensions(requestedExtensions) diff --git a/webauthn-server-demo/src/test/scala/demo/webauthn/WebAuthnServerSpec.scala b/webauthn-server-demo/src/test/scala/demo/webauthn/WebAuthnServerSpec.scala index 073f18a30..d403aaddc 100644 --- a/webauthn-server-demo/src/test/scala/demo/webauthn/WebAuthnServerSpec.scala +++ b/webauthn-server-demo/src/test/scala/demo/webauthn/WebAuthnServerSpec.scala @@ -154,7 +154,7 @@ class WebAuthnServerSpec extends FunSpec with Matchers { .publicKeyCredentialRequestOptions( PublicKeyCredentialRequestOptions.builder() .challenge(challenge) - .rpId(Some(rpId.getId).asJava) + .rpId(rpId.getId) .build() ) .username(Some(testData.userId.getName).asJava) From 45cc6402607f0c85f53236c44da7b00ef69c5a70 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Mon, 4 Mar 2019 18:22:36 +0100 Subject: [PATCH 08/19] Add Optional-less overloads to RelyingParty builder --- .../com/yubico/webauthn/RelyingParty.java | 128 +++++++++++++++++- .../com/yubico/webauthn/RelyingPartyTest.java | 41 ++++++ 2 files changed, 163 insertions(+), 6 deletions(-) create mode 100644 webauthn-server-core/src/test/java/com/yubico/webauthn/RelyingPartyTest.java diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/RelyingParty.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/RelyingParty.java index 7c88766e5..f5b2c7e8c 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/RelyingParty.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/RelyingParty.java @@ -145,9 +145,8 @@ public class RelyingParty { * @see
§10.1. FIDO AppID Extension * (appid) */ - @Builder.Default @NonNull - private final Optional appId = Optional.empty(); + private final Optional appId; /** * The argument for the {@link PublicKeyCredentialCreationOptions#getAttestation() attestation} parameter in @@ -165,9 +164,8 @@ public class RelyingParty { * @see PublicKeyCredentialCreationOptions#getAttestation() * @see §6.4. Attestation */ - @Builder.Default @NonNull - private final Optional attestationConveyancePreference = Optional.empty(); + private final Optional attestationConveyancePreference; /** * A {@link MetadataService} instance to use for looking up device attestation metadata. This matters only if {@link @@ -180,9 +178,8 @@ public class RelyingParty { * @see PublicKeyCredentialCreationOptions#getAttestation() * @see §6.4. Attestation */ - @Builder.Default @NonNull - private final Optional metadataService = Optional.empty(); + private final Optional metadataService; /** * The argument for the {@link PublicKeyCredentialCreationOptions#getPubKeyCredParams() pubKeyCredParams} parameter @@ -404,6 +401,10 @@ public static RelyingPartyBuilder.MandatoryStages builder() { } public static class RelyingPartyBuilder { + private @NonNull Optional appId = Optional.empty(); + private @NonNull Optional attestationConveyancePreference = Optional.empty(); + private @NonNull Optional metadataService = Optional.empty(); + public static class MandatoryStages { private final RelyingPartyBuilder builder = new RelyingPartyBuilder(); @@ -429,5 +430,120 @@ public RelyingPartyBuilder credentialRepository(CredentialRepository credentialR } } } + + /** + * The extension input to set for the appid extension when initiating authentication operations. + * + *

+ * If this member is set, {@link #startAssertion(StartAssertionOptions) startAssertion} will automatically set the + * appid extension input, and {@link #finishAssertion(FinishAssertionOptions) finishAssertion} will + * adjust its verification logic to also accept this AppID as an alternative to the RP ID. + *

+ * + *

+ * By default, this is not set. + *

+ * + * @see AssertionExtensionInputs#getAppid() + * @see §10.1. FIDO AppID Extension + * (appid) + */ + public RelyingPartyBuilder appId(@NonNull Optional appId) { + this.appId = appId; + return this; + } + + /** + * The extension input to set for the appid extension when initiating authentication operations. + * + *

+ * If this member is set, {@link #startAssertion(StartAssertionOptions) startAssertion} will automatically set the + * appid extension input, and {@link #finishAssertion(FinishAssertionOptions) finishAssertion} will + * adjust its verification logic to also accept this AppID as an alternative to the RP ID. + *

+ * + *

+ * By default, this is not set. + *

+ * + * @see AssertionExtensionInputs#getAppid() + * @see §10.1. FIDO AppID Extension + * (appid) + */ + public RelyingPartyBuilder appId(@NonNull AppId appId) { + return this.appId(Optional.of(appId)); + } + + /** + * The argument for the {@link PublicKeyCredentialCreationOptions#getAttestation() attestation} parameter in + * registration operations. + * + *

+ * Unless your application has a concrete policy for authenticator attestation, it is recommended to leave this + * parameter undefined. + *

+ * + *

+ * By default, this is not set. + *

+ * + * @see PublicKeyCredentialCreationOptions#getAttestation() + * @see §6.4. Attestation + */ + public RelyingPartyBuilder attestationConveyancePreference(@NonNull Optional attestationConveyancePreference) { + this.attestationConveyancePreference = attestationConveyancePreference; + return this; + } + + /** + * The argument for the {@link PublicKeyCredentialCreationOptions#getAttestation() attestation} parameter in + * registration operations. + * + *

+ * Unless your application has a concrete policy for authenticator attestation, it is recommended to leave this + * parameter undefined. + *

+ * + *

+ * By default, this is not set. + *

+ * + * @see PublicKeyCredentialCreationOptions#getAttestation() + * @see §6.4. Attestation + */ + public RelyingPartyBuilder attestationConveyancePreference(@NonNull AttestationConveyancePreference attestationConveyancePreference) { + return this.attestationConveyancePreference(Optional.of(attestationConveyancePreference)); + } + + /** + * A {@link MetadataService} instance to use for looking up device attestation metadata. This matters only if {@link + * #getAttestationConveyancePreference()} is non-empty and not set to {@link AttestationConveyancePreference#NONE}. + * + *

+ * By default, this is not set. + *

+ * + * @see PublicKeyCredentialCreationOptions#getAttestation() + * @see §6.4. Attestation + */ + public RelyingPartyBuilder metadataService(@NonNull Optional metadataService) { + this.metadataService = metadataService; + return this; + } + + /** + * A {@link MetadataService} instance to use for looking up device attestation metadata. This matters only if {@link + * #getAttestationConveyancePreference()} is non-empty and not set to {@link AttestationConveyancePreference#NONE}. + * + *

+ * By default, this is not set. + *

+ * + * @see PublicKeyCredentialCreationOptions#getAttestation() + * @see §6.4. Attestation + */ + public RelyingPartyBuilder metadataService(@NonNull MetadataService metadataService) { + return this.metadataService(Optional.of(metadataService)); + } } } diff --git a/webauthn-server-core/src/test/java/com/yubico/webauthn/RelyingPartyTest.java b/webauthn-server-core/src/test/java/com/yubico/webauthn/RelyingPartyTest.java new file mode 100644 index 000000000..b4382b4ac --- /dev/null +++ b/webauthn-server-core/src/test/java/com/yubico/webauthn/RelyingPartyTest.java @@ -0,0 +1,41 @@ +package com.yubico.webauthn; + +import com.yubico.webauthn.attestation.Attestation; +import com.yubico.webauthn.attestation.MetadataService; +import com.yubico.webauthn.data.AttestationConveyancePreference; +import com.yubico.webauthn.extension.appid.AppId; +import com.yubico.webauthn.extension.appid.InvalidAppIdException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import org.junit.Test; + +public class RelyingPartyTest { + + @Test(expected = NullPointerException.class) + public void itHasTheseBuilderMethods() throws InvalidAppIdException { + + final MetadataService metadataService = new MetadataService() { + @Override public Attestation getAttestation(List attestationCertificateChain) throws CertificateEncodingException { return null; } + }; + + RelyingParty.builder() + .identity(null) + .credentialRepository(null) + .origins(Collections.emptySet()) + .appId(new AppId("https://example.com")) + .appId(Optional.of(new AppId("https://example.com"))) + .attestationConveyancePreference(AttestationConveyancePreference.DIRECT) + .attestationConveyancePreference(Optional.of(AttestationConveyancePreference.DIRECT)) + .metadataService(metadataService) + .metadataService(Optional.of(metadataService)) + .preferredPubkeyParams(Collections.emptyList()) + .allowUnrequestedExtensions(true) + .allowUntrustedAttestation(true) + .validateSignatureCounter(true) + ; + } + +} From 4022231bdff65e3804335aef2995f98048fe4c57 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Mon, 4 Mar 2019 18:26:40 +0100 Subject: [PATCH 09/19] Add javadoc to RelyingPartyIdentity.icon and UserIdentity.icon --- .../com/yubico/webauthn/data/RelyingPartyIdentity.java | 10 ++++++++++ .../java/com/yubico/webauthn/data/UserIdentity.java | 9 +++++++++ 2 files changed, 19 insertions(+) diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/RelyingPartyIdentity.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/RelyingPartyIdentity.java index 318340622..cfd95c500 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/RelyingPartyIdentity.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/RelyingPartyIdentity.java @@ -68,6 +68,16 @@ public class RelyingPartyIdentity implements PublicKeyCredentialEntity { @NonNull private final String id; + /** + * A URL which resolves to an image associated with the entity. For example, this could be the Relying Party's + * logo. + * + *

This URL MUST be an a priori authenticated URL. Authenticators MUST accept and store a + * 128-byte minimum length for an icon member’s value. Authenticators MAY ignore an icon member’s value if its + * length is greater than 128 bytes. The URL’s scheme MAY be "data" to avoid fetches of the URL, at the cost of + * needing more storage. + *

+ */ @NonNull @Builder.Default @Getter(onMethod = @__({ @Override })) diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/UserIdentity.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/UserIdentity.java index 7cf55949f..bc1a5c87a 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/UserIdentity.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/UserIdentity.java @@ -113,6 +113,15 @@ public class UserIdentity implements PublicKeyCredentialEntity { @NonNull private final ByteArray id; + /** + * A URL which resolves to an image associated with the entity. For example, this could be the user’s avatar. + * + *

This URL MUST be an a priori authenticated URL. Authenticators MUST accept and store a + * 128-byte minimum length for an icon member’s value. Authenticators MAY ignore an icon member’s value if its + * length is greater than 128 bytes. The URL’s scheme MAY be "data" to avoid fetches of the URL, at the cost of + * needing more storage. + *

+ */ @NonNull @Builder.Default @Getter(onMethod = @__({ @Override })) From d9c62fb54f1c2132d13f7fee7133652809789a1f Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Mon, 4 Mar 2019 18:29:48 +0100 Subject: [PATCH 10/19] Add overload RelyingPartyIdentityBuilder.icon(URL) --- .../webauthn/data/RelyingPartyIdentity.java | 34 +++++++++++++++++-- .../data/RelyingPartyIdentityTest.java | 20 +++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 webauthn-server-core/src/test/java/com/yubico/webauthn/data/RelyingPartyIdentityTest.java diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/RelyingPartyIdentity.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/RelyingPartyIdentity.java index cfd95c500..effb9a6a1 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/RelyingPartyIdentity.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/RelyingPartyIdentity.java @@ -79,9 +79,8 @@ public class RelyingPartyIdentity implements PublicKeyCredentialEntity { *

*/ @NonNull - @Builder.Default @Getter(onMethod = @__({ @Override })) - private final Optional icon = Optional.empty(); + private final Optional icon; @JsonCreator private RelyingPartyIdentity( @@ -97,6 +96,8 @@ public static RelyingPartyIdentityBuilder.MandatoryStages builder() { } public static class RelyingPartyIdentityBuilder { + private @NonNull Optional icon = Optional.empty(); + public static class MandatoryStages { private RelyingPartyIdentityBuilder builder = new RelyingPartyIdentityBuilder(); @@ -111,6 +112,35 @@ public RelyingPartyIdentityBuilder name(String name) { } } } + + /** + * A URL which resolves to an image associated with the entity. For example, this could be the Relying Party's + * logo. + * + *

This URL MUST be an a priori authenticated URL. Authenticators MUST accept and store a + * 128-byte minimum length for an icon member’s value. Authenticators MAY ignore an icon member’s value if its + * length is greater than 128 bytes. The URL’s scheme MAY be "data" to avoid fetches of the URL, at the cost of + * needing more storage. + *

+ */ + public RelyingPartyIdentityBuilder icon(@NonNull Optional icon) { + this.icon = icon; + return this; + } + + /** + * A URL which resolves to an image associated with the entity. For example, this could be the Relying Party's + * logo. + * + *

This URL MUST be an a priori authenticated URL. Authenticators MUST accept and store a + * 128-byte minimum length for an icon member’s value. Authenticators MAY ignore an icon member’s value if its + * length is greater than 128 bytes. The URL’s scheme MAY be "data" to avoid fetches of the URL, at the cost of + * needing more storage. + *

+ */ + public RelyingPartyIdentityBuilder icon(@NonNull URL icon) { + return this.icon(Optional.of(icon)); + } } } diff --git a/webauthn-server-core/src/test/java/com/yubico/webauthn/data/RelyingPartyIdentityTest.java b/webauthn-server-core/src/test/java/com/yubico/webauthn/data/RelyingPartyIdentityTest.java new file mode 100644 index 000000000..d950c5e8c --- /dev/null +++ b/webauthn-server-core/src/test/java/com/yubico/webauthn/data/RelyingPartyIdentityTest.java @@ -0,0 +1,20 @@ +package com.yubico.webauthn.data; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Optional; +import org.junit.Test; + +public class RelyingPartyIdentityTest { + + @Test + public void itHasTheseBuilderMethods() throws MalformedURLException { + RelyingPartyIdentity.builder() + .id("") + .name("") + .icon(new URL("https://example.com")) + .icon(Optional.of(new URL("https://example.com"))) + ; + } + +} From 2aaa8b8a07c37011c4450729d2086c1ecd2a8eb5 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Tue, 5 Mar 2019 12:57:40 +0100 Subject: [PATCH 11/19] Add overload UserIdentityBuilder.icon(URL) --- .../yubico/webauthn/data/UserIdentity.java | 32 +++++++++++++++++-- .../webauthn/data/UserIdentityTest.java | 21 ++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 webauthn-server-core/src/test/java/com/yubico/webauthn/data/UserIdentityTest.java diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/UserIdentity.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/UserIdentity.java index bc1a5c87a..2eea7716c 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/UserIdentity.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/UserIdentity.java @@ -123,9 +123,8 @@ public class UserIdentity implements PublicKeyCredentialEntity { *

*/ @NonNull - @Builder.Default @Getter(onMethod = @__({ @Override })) - private final Optional icon = Optional.empty(); + private final Optional icon; @JsonCreator private UserIdentity( @@ -142,6 +141,8 @@ public static UserIdentityBuilder.MandatoryStages builder() { } public static class UserIdentityBuilder { + private @NonNull Optional icon = Optional.empty(); + public static class MandatoryStages { private UserIdentityBuilder builder = new UserIdentityBuilder(); @@ -164,6 +165,33 @@ public UserIdentityBuilder id(ByteArray id) { } } + + /** + * A URL which resolves to an image associated with the entity. For example, this could be the user’s avatar. + * + *

This URL MUST be an a priori authenticated URL. Authenticators MUST accept and store a + * 128-byte minimum length for an icon member’s value. Authenticators MAY ignore an icon member’s value if its + * length is greater than 128 bytes. The URL’s scheme MAY be "data" to avoid fetches of the URL, at the cost of + * needing more storage. + *

+ */ + public UserIdentityBuilder icon(@NonNull Optional icon) { + this.icon = icon; + return this; + } + + /** + * A URL which resolves to an image associated with the entity. For example, this could be the user’s avatar. + * + *

This URL MUST be an a priori authenticated URL. Authenticators MUST accept and store a + * 128-byte minimum length for an icon member’s value. Authenticators MAY ignore an icon member’s value if its + * length is greater than 128 bytes. The URL’s scheme MAY be "data" to avoid fetches of the URL, at the cost of + * needing more storage. + *

+ */ + public UserIdentityBuilder icon(@NonNull URL icon) { + return this.icon(Optional.of(icon)); + } } } diff --git a/webauthn-server-core/src/test/java/com/yubico/webauthn/data/UserIdentityTest.java b/webauthn-server-core/src/test/java/com/yubico/webauthn/data/UserIdentityTest.java new file mode 100644 index 000000000..2bb16fc83 --- /dev/null +++ b/webauthn-server-core/src/test/java/com/yubico/webauthn/data/UserIdentityTest.java @@ -0,0 +1,21 @@ +package com.yubico.webauthn.data; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Optional; +import org.junit.Test; + +public class UserIdentityTest { + + @Test + public void itHasTheseBuilderMethods() throws MalformedURLException { + UserIdentity.builder() + .name("") + .displayName("") + .id(new ByteArray(new byte[]{})) + .icon(new URL("https://example.com")) + .icon(Optional.of(new URL("https://example.com"))) + ; + } + +} From 34414040d9cadfa5b0deaddbab904aee11fa8284 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Tue, 5 Mar 2019 13:08:45 +0100 Subject: [PATCH 12/19] Add overload StartRegistrationOptionsBuilder.authenticatorSelection(AuthenticatorSelectionCriteria) --- .../webauthn/StartRegistrationOptions.java | 20 +++++++++++++++++-- .../StartRegistrationOptionsTest.java | 20 +++++++++++++++++++ .../java/demo/webauthn/WebAuthnServer.java | 8 ++++---- 3 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 webauthn-server-core/src/test/java/com/yubico/webauthn/StartRegistrationOptionsTest.java diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/StartRegistrationOptions.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/StartRegistrationOptions.java index 086d16420..3660c86c9 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/StartRegistrationOptions.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/StartRegistrationOptions.java @@ -49,8 +49,7 @@ public class StartRegistrationOptions { * Constraints on what kind of authenticator the user is allowed to use to create the credential. */ @NonNull - @Builder.Default - private final Optional authenticatorSelection = Optional.empty(); + private final Optional authenticatorSelection; /** * Extension inputs for this registration operation. @@ -64,6 +63,8 @@ public static StartRegistrationOptionsBuilder.MandatoryStages builder() { } public static class StartRegistrationOptionsBuilder { + private @NonNull Optional authenticatorSelection = Optional.empty(); + public static class MandatoryStages { private final StartRegistrationOptionsBuilder builder = new StartRegistrationOptionsBuilder(); @@ -71,6 +72,21 @@ public StartRegistrationOptionsBuilder user(UserIdentity user) { return builder.user(user); } } + + /** + * Constraints on what kind of authenticator the user is allowed to use to create the credential. + */ + public StartRegistrationOptionsBuilder authenticatorSelection(@NonNull Optional authenticatorSelection) { + this.authenticatorSelection = authenticatorSelection; + return this; + } + + /** + * Constraints on what kind of authenticator the user is allowed to use to create the credential. + */ + public StartRegistrationOptionsBuilder authenticatorSelection(@NonNull AuthenticatorSelectionCriteria authenticatorSelection) { + return this.authenticatorSelection(Optional.of(authenticatorSelection)); + } } } diff --git a/webauthn-server-core/src/test/java/com/yubico/webauthn/StartRegistrationOptionsTest.java b/webauthn-server-core/src/test/java/com/yubico/webauthn/StartRegistrationOptionsTest.java new file mode 100644 index 000000000..fa324a702 --- /dev/null +++ b/webauthn-server-core/src/test/java/com/yubico/webauthn/StartRegistrationOptionsTest.java @@ -0,0 +1,20 @@ +package com.yubico.webauthn; + +import com.yubico.webauthn.data.AuthenticatorSelectionCriteria; +import com.yubico.webauthn.data.RegistrationExtensionInputs; +import java.util.Optional; +import org.junit.Test; + +public class StartRegistrationOptionsTest { + + @Test(expected = NullPointerException.class) + public void itHasTheseBuilderMethods() { + StartRegistrationOptions.builder() + .user(null) + .authenticatorSelection(AuthenticatorSelectionCriteria.builder().build()) + .authenticatorSelection(Optional.of(AuthenticatorSelectionCriteria.builder().build())) + .extensions(RegistrationExtensionInputs.builder().build()) + .build(); + } + +} diff --git a/webauthn-server-demo/src/main/java/demo/webauthn/WebAuthnServer.java b/webauthn-server-demo/src/main/java/demo/webauthn/WebAuthnServer.java index e4c2fd70b..c1c157032 100644 --- a/webauthn-server-demo/src/main/java/demo/webauthn/WebAuthnServer.java +++ b/webauthn-server-demo/src/main/java/demo/webauthn/WebAuthnServer.java @@ -209,10 +209,10 @@ public Either startRegistration( .id(generateRandom(32)) .build() ) - .authenticatorSelection(Optional.of(AuthenticatorSelectionCriteria.builder() + .authenticatorSelection(AuthenticatorSelectionCriteria.builder() .requireResidentKey(requireResidentKey) .build() - )) + ) .build() ) ); @@ -250,10 +250,10 @@ public Either, AssertionRequest> startAddCredential( rp.startRegistration( StartRegistrationOptions.builder() .user(existingUser) - .authenticatorSelection(Optional.of(AuthenticatorSelectionCriteria.builder() + .authenticatorSelection(AuthenticatorSelectionCriteria.builder() .requireResidentKey(requireResidentKey) .build() - )) + ) .build() ) ); From 493e1fc2ad8b237d73edbde2c56addbb0d52e8fd Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Tue, 5 Mar 2019 13:20:47 +0100 Subject: [PATCH 13/19] Add overload ClientAssertionExtensionInputs.appid(boolean) --- .../data/ClientAssertionExtensionOutputs.java | 34 +++++++++++++++++++ .../ClientAssertionExtensionOutputsTest.java | 16 +++++++++ .../webauthn/RelyingPartyAssertionSpec.scala | 2 +- 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 webauthn-server-core/src/test/java/com/yubico/webauthn/data/ClientAssertionExtensionOutputsTest.java diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/ClientAssertionExtensionOutputs.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/ClientAssertionExtensionOutputs.java index 6cb467fc9..2076eccab 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/ClientAssertionExtensionOutputs.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/ClientAssertionExtensionOutputs.java @@ -83,4 +83,38 @@ public Set getExtensionIds() { return ids; } + public static class ClientAssertionExtensionOutputsBuilder { + private Optional appid; + + /** + * The output from the FIDO AppID Extension (appid). + * + *

+ * This value should be ignored because its behaviour is underspecified, see: https://github.com/w3c/webauthn/issues/1034. + *

+ * + * @see §10.1. FIDO AppID Extension + * (appid) + */ + public ClientAssertionExtensionOutputsBuilder appid(Optional appid) { + this.appid = appid; + return this; + } + + /** + * The output from the FIDO AppID Extension (appid). + * + *

+ * This value should be ignored because its behaviour is underspecified, see: https://github.com/w3c/webauthn/issues/1034. + *

+ * + * @see §10.1. FIDO AppID Extension + * (appid) + */ + public ClientAssertionExtensionOutputsBuilder appid(boolean appid) { + return this.appid(Optional.of(appid)); + } + } } diff --git a/webauthn-server-core/src/test/java/com/yubico/webauthn/data/ClientAssertionExtensionOutputsTest.java b/webauthn-server-core/src/test/java/com/yubico/webauthn/data/ClientAssertionExtensionOutputsTest.java new file mode 100644 index 000000000..84f3b9d1e --- /dev/null +++ b/webauthn-server-core/src/test/java/com/yubico/webauthn/data/ClientAssertionExtensionOutputsTest.java @@ -0,0 +1,16 @@ +package com.yubico.webauthn.data; + +import java.util.Optional; +import org.junit.Test; + +public class ClientAssertionExtensionOutputsTest { + + @Test + public void itHasTheseBuilderMethods() { + ClientAssertionExtensionOutputs.builder() + .appid(false) + .appid(Optional.of(false)) + .build(); + } + +} 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 6fea04aa9..d20074b18 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 @@ -780,7 +780,7 @@ class RelyingPartyAssertionSpec extends FunSpec with Matchers with GeneratorDriv describe("client extension outputs in clientExtensionResults are as expected, considering the client extension input values that were given as the extensions option in the get() call. In particular, any extension identifier values in the clientExtensionResults MUST be also be present as extension identifier values in the extensions member of options, i.e., no extensions are present that were not requested. In the general case, the meaning of \"are as expected\" is specific to the Relying Party and which extensions are in use.") { it("Fails if clientExtensionResults is not a subset of the extensions requested by the Relying Party.") { val extensionInputs = AssertionExtensionInputs.builder().build() - val clientExtensionOutputs = ClientAssertionExtensionOutputs.builder().appid(Optional.of(true)).build() + val clientExtensionOutputs = ClientAssertionExtensionOutputs.builder().appid(true).build() // forAll(unrequestedAssertionExtensions, minSuccessful(1)) { case (extensionInputs, clientExtensionOutputs) => val steps = finishAssertion( From 68b801caf6b4f77122f68d78e7575f716948ad4d Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Tue, 5 Mar 2019 13:21:29 +0100 Subject: [PATCH 14/19] Make ClientAssertionExtensionOutputs.appid @NonNull --- .../webauthn/data/ClientAssertionExtensionOutputs.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/ClientAssertionExtensionOutputs.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/ClientAssertionExtensionOutputs.java index 2076eccab..a7b4af055 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/ClientAssertionExtensionOutputs.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/ClientAssertionExtensionOutputs.java @@ -64,8 +64,8 @@ public class ClientAssertionExtensionOutputs implements ClientExtensionOutputs { * @see §10.1. FIDO AppID Extension * (appid) */ - @Builder.Default - private final Optional appid = Optional.empty(); + @NonNull + private final Optional appid; @JsonCreator private ClientAssertionExtensionOutputs( @@ -84,7 +84,7 @@ public Set getExtensionIds() { } public static class ClientAssertionExtensionOutputsBuilder { - private Optional appid; + private Optional appid = Optional.empty(); /** * The output from the FIDO AppID Extension (appid). @@ -97,7 +97,7 @@ public static class ClientAssertionExtensionOutputsBuilder { * @see §10.1. FIDO AppID Extension * (appid) */ - public ClientAssertionExtensionOutputsBuilder appid(Optional appid) { + public ClientAssertionExtensionOutputsBuilder appid(@NonNull Optional appid) { this.appid = appid; return this; } From 6f0bd24591f74bf0a836061c04dac3f6054aab8b Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Tue, 5 Mar 2019 13:33:39 +0100 Subject: [PATCH 15/19] Add overload AuthenticatorSelectionCriteria.authenticatorAttachment(AuthenticatorAttachment) --- .../data/AuthenticatorSelectionCriteria.java | 25 +++++++++++++++++-- .../AuthenticatorSelectionCriteriaTest.java | 18 +++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 webauthn-server-core/src/test/java/com/yubico/webauthn/data/AuthenticatorSelectionCriteriaTest.java diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/AuthenticatorSelectionCriteria.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/AuthenticatorSelectionCriteria.java index 957695d8c..ff874299d 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/AuthenticatorSelectionCriteria.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/AuthenticatorSelectionCriteria.java @@ -52,8 +52,7 @@ public class AuthenticatorSelectionCriteria { * (enum AuthenticatorAttachment). */ @NonNull - @Builder.Default - private final Optional authenticatorAttachment = Optional.empty(); + private final Optional authenticatorAttachment; /** * Describes the Relying Party's requirements regarding resident credentials. If set to true, the @@ -82,4 +81,26 @@ private AuthenticatorSelectionCriteria( this(Optional.ofNullable(authenticatorAttachment), requireResidentKey, userVerification); } + public static class AuthenticatorSelectionCriteriaBuilder { + private @NonNull Optional authenticatorAttachment = Optional.empty(); + + /** + * If present, eligible authenticators are filtered to only authenticators attached with the specified §5.4.5 Authenticator Attachment Enumeration + * (enum AuthenticatorAttachment). + */ + public AuthenticatorSelectionCriteriaBuilder authenticatorAttachment(@NonNull Optional authenticatorAttachment) { + this.authenticatorAttachment = authenticatorAttachment; + return this; + } + + /** + * If present, eligible authenticators are filtered to only authenticators attached with the specified §5.4.5 Authenticator Attachment Enumeration + * (enum AuthenticatorAttachment). + */ + public AuthenticatorSelectionCriteriaBuilder authenticatorAttachment(@NonNull AuthenticatorAttachment authenticatorAttachment) { + return this.authenticatorAttachment(Optional.of(authenticatorAttachment)); + } + } } diff --git a/webauthn-server-core/src/test/java/com/yubico/webauthn/data/AuthenticatorSelectionCriteriaTest.java b/webauthn-server-core/src/test/java/com/yubico/webauthn/data/AuthenticatorSelectionCriteriaTest.java new file mode 100644 index 000000000..006dbcd2e --- /dev/null +++ b/webauthn-server-core/src/test/java/com/yubico/webauthn/data/AuthenticatorSelectionCriteriaTest.java @@ -0,0 +1,18 @@ +package com.yubico.webauthn.data; + +import java.util.Optional; +import org.junit.Test; + +public class AuthenticatorSelectionCriteriaTest { + + @Test + public void itHasTheseBuilderMethods() { + AuthenticatorSelectionCriteria.builder() + .authenticatorAttachment(AuthenticatorAttachment.CROSS_PLATFORM) + .authenticatorAttachment(Optional.of(AuthenticatorAttachment.CROSS_PLATFORM)) + .requireResidentKey(false) + .userVerification(UserVerificationRequirement.PREFERRED) + .build(); + } + +} From 1700eb9f76c72127115660cac3e6efa8dffccb28 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Tue, 5 Mar 2019 13:57:14 +0100 Subject: [PATCH 16/19] Add overload AssertionExtensionInputsBuilder.appid(AppId) --- .../data/AssertionExtensionInputs.java | 63 ++++++++++++++++++- .../data/AssertionExtensionInputsTest.java | 18 ++++++ 2 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 webauthn-server-core/src/test/java/com/yubico/webauthn/data/AssertionExtensionInputsTest.java diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/AssertionExtensionInputs.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/AssertionExtensionInputs.java index f73cdbb40..b629899af 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/AssertionExtensionInputs.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/AssertionExtensionInputs.java @@ -75,8 +75,7 @@ public class AssertionExtensionInputs implements ExtensionInputs { * @see §10.1. FIDO AppID Extension * (appid) */ - @Builder.Default - private final Optional appid = Optional.empty(); + private final Optional appid; @JsonCreator private AssertionExtensionInputs( @@ -94,4 +93,64 @@ public Set getExtensionIds() { return ids; } + public static class AssertionExtensionInputsBuilder { + private Optional appid = Optional.empty(); + + /** + * The input to the FIDO AppID Extension (appid). + * + *

+ * This extension allows WebAuthn Relying Parties that have previously registered a credential using the legacy FIDO + * JavaScript APIs to request an assertion. The FIDO APIs use an alternative identifier for Relying Parties called + * an AppID, + * and any credentials created using those APIs will be scoped to that identifier. Without this extension, they + * would need to be re-registered in order to be scoped to an RP ID. + *

+ *

+ * This extension does not allow FIDO-compatible credentials to be created. Thus, credentials created with WebAuthn + * are not backwards compatible with the FIDO JavaScript APIs. + *

+ * + *

+ * {@link RelyingParty#startAssertion(StartAssertionOptions)} sets this extension input automatically if the {@link + * RelyingParty.RelyingPartyBuilder#appId(Optional)} parameter is given when constructing the {@link RelyingParty} + * instance. + *

+ * + * @see §10.1. FIDO AppID Extension + * (appid) + */ + public AssertionExtensionInputsBuilder appid(Optional appid) { + this.appid = appid; + return this; + } + + /** + * The input to the FIDO AppID Extension (appid). + * + *

+ * This extension allows WebAuthn Relying Parties that have previously registered a credential using the legacy FIDO + * JavaScript APIs to request an assertion. The FIDO APIs use an alternative identifier for Relying Parties called + * an AppID, + * and any credentials created using those APIs will be scoped to that identifier. Without this extension, they + * would need to be re-registered in order to be scoped to an RP ID. + *

+ *

+ * This extension does not allow FIDO-compatible credentials to be created. Thus, credentials created with WebAuthn + * are not backwards compatible with the FIDO JavaScript APIs. + *

+ * + *

+ * {@link RelyingParty#startAssertion(StartAssertionOptions)} sets this extension input automatically if the {@link + * RelyingParty.RelyingPartyBuilder#appId(Optional)} parameter is given when constructing the {@link RelyingParty} + * instance. + *

+ * + * @see §10.1. FIDO AppID Extension + * (appid) + */ + public AssertionExtensionInputsBuilder appid(AppId appid) { + return this.appid(Optional.of(appid)); + } + } } diff --git a/webauthn-server-core/src/test/java/com/yubico/webauthn/data/AssertionExtensionInputsTest.java b/webauthn-server-core/src/test/java/com/yubico/webauthn/data/AssertionExtensionInputsTest.java new file mode 100644 index 000000000..cfa211ce7 --- /dev/null +++ b/webauthn-server-core/src/test/java/com/yubico/webauthn/data/AssertionExtensionInputsTest.java @@ -0,0 +1,18 @@ +package com.yubico.webauthn.data; + +import com.yubico.webauthn.extension.appid.AppId; +import com.yubico.webauthn.extension.appid.InvalidAppIdException; +import java.util.Optional; +import org.junit.Test; + +public class AssertionExtensionInputsTest { + + @Test + public void itHasTheseBuilderMethods() throws InvalidAppIdException { + AssertionExtensionInputs.builder() + .appid(new AppId("https://example.com")) + .appid(Optional.of(new AppId("https://example.com"))) + .build(); + } + +} From a7d413fca1f4e0e2cca140b5e450ababb3c70c4a Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Tue, 5 Mar 2019 14:17:36 +0100 Subject: [PATCH 17/19] Make AssertionExtensionInputs.appid @NonNull --- .../webauthn/StartAssertionOptions.java | 68 +++++++++++++++++-- .../data/AssertionExtensionInputs.java | 5 +- .../webauthn/StartAssertionOptionsTest.java | 22 ++++++ .../webauthn/RelyingPartyAssertionSpec.scala | 4 +- .../RelyingPartyStartOperationSpec.scala | 4 +- .../RelyingPartyUserIdentificationSpec.scala | 2 +- 6 files changed, 94 insertions(+), 11 deletions(-) create mode 100644 webauthn-server-core/src/test/java/com/yubico/webauthn/StartAssertionOptionsTest.java diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/StartAssertionOptions.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/StartAssertionOptions.java index 5aac5060b..5d958f020 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/StartAssertionOptions.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/StartAssertionOptions.java @@ -54,8 +54,7 @@ public class StartAssertionOptions { * credential */ @NonNull - @Builder.Default - private final Optional username = Optional.empty(); + private final Optional username; /** * Extension inputs for this authentication operation. @@ -79,7 +78,68 @@ public class StartAssertionOptions { *

*/ @NonNull - @Builder.Default - private final Optional userVerification = Optional.empty(); + private final Optional userVerification; + + public static class StartAssertionOptionsBuilder { + private @NonNull Optional username = Optional.empty(); + private @NonNull Optional userVerification = Optional.empty(); + + /** + * The username of the user to authenticate, if the user has already been identified. + *

+ * If this is absent, that implies a first-factor authentication operation - meaning identification of the user is + * deferred until after receiving the response from the client. + *

+ * + *

+ * The default is empty (absent). + *

+ * + * @see Client-side-resident + * credential + */ + public StartAssertionOptionsBuilder username(@NonNull Optional username) { + this.username = username; + return this; + } + + /** + * The username of the user to authenticate, if the user has already been identified. + *

+ * If this is absent, that implies a first-factor authentication operation - meaning identification of the user is + * deferred until after receiving the response from the client. + *

+ * + *

+ * The default is empty (absent). + *

+ * + * @see Client-side-resident + * credential + */ + public StartAssertionOptionsBuilder username(@NonNull String username) { + return this.username(Optional.of(username)); + } + + /** + * The value for {@link PublicKeyCredentialRequestOptions#getUserVerification()} for this authentication operation. + *

+ * The default is {@link UserVerificationRequirement#PREFERRED}. + *

+ */ + public StartAssertionOptionsBuilder userVerification(@NonNull Optional userVerification) { + this.userVerification = userVerification; + return this; + } + /** + * The value for {@link PublicKeyCredentialRequestOptions#getUserVerification()} for this authentication operation. + *

+ * The default is {@link UserVerificationRequirement#PREFERRED}. + *

+ */ + public StartAssertionOptionsBuilder userVerification(@NonNull UserVerificationRequirement userVerification) { + return this.userVerification(Optional.of(userVerification)); + } + } } diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/AssertionExtensionInputs.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/AssertionExtensionInputs.java index b629899af..3176a9301 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/AssertionExtensionInputs.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/AssertionExtensionInputs.java @@ -75,6 +75,7 @@ public class AssertionExtensionInputs implements ExtensionInputs { * @see §10.1. FIDO AppID Extension * (appid) */ + @NonNull private final Optional appid; @JsonCreator @@ -120,7 +121,7 @@ public static class AssertionExtensionInputsBuilder { * @see §10.1. FIDO AppID Extension * (appid) */ - public AssertionExtensionInputsBuilder appid(Optional appid) { + public AssertionExtensionInputsBuilder appid(@NonNull Optional appid) { this.appid = appid; return this; } @@ -149,7 +150,7 @@ public AssertionExtensionInputsBuilder appid(Optional appid) { * @see §10.1. FIDO AppID Extension * (appid) */ - public AssertionExtensionInputsBuilder appid(AppId appid) { + public AssertionExtensionInputsBuilder appid(@NonNull AppId appid) { return this.appid(Optional.of(appid)); } } diff --git a/webauthn-server-core/src/test/java/com/yubico/webauthn/StartAssertionOptionsTest.java b/webauthn-server-core/src/test/java/com/yubico/webauthn/StartAssertionOptionsTest.java new file mode 100644 index 000000000..7cec0b344 --- /dev/null +++ b/webauthn-server-core/src/test/java/com/yubico/webauthn/StartAssertionOptionsTest.java @@ -0,0 +1,22 @@ +package com.yubico.webauthn; + +import com.yubico.webauthn.data.AuthenticatorSelectionCriteria; +import com.yubico.webauthn.data.ByteArray; +import com.yubico.webauthn.data.RegistrationExtensionInputs; +import com.yubico.webauthn.data.UserIdentity; +import java.util.Optional; +import org.junit.Test; + +public class StartAssertionOptionsTest { + + @Test + public void itHasTheseBuilderMethods() { + StartRegistrationOptions.builder() + .user(UserIdentity.builder().name("").displayName("").id(new ByteArray(new byte[]{})).build()) + .authenticatorSelection(AuthenticatorSelectionCriteria.builder().build()) + .authenticatorSelection(Optional.of(AuthenticatorSelectionCriteria.builder().build())) + .extensions(RegistrationExtensionInputs.builder().build()) + .build(); + } + +} 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 d20074b18..b332a2326 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 @@ -211,7 +211,7 @@ class RelyingPartyAssertionSpec extends FunSpec with Matchers with GeneratorDriv .credentialRepository(emptyCredentialRepository) .build() val request1 = rp.startAssertion(StartAssertionOptions.builder().build()) - val request2 = rp.startAssertion(StartAssertionOptions.builder().userVerification(None.asJava).build()) + val request2 = rp.startAssertion(StartAssertionOptions.builder().userVerification(Optional.empty[UserVerificationRequirement]).build()) request1.getPublicKeyCredentialRequestOptions.getUserVerification should equal (default) request2.getPublicKeyCredentialRequestOptions.getUserVerification should equal (default) @@ -224,7 +224,7 @@ class RelyingPartyAssertionSpec extends FunSpec with Matchers with GeneratorDriv .build() forAll { uv: UserVerificationRequirement => - val request = rp.startAssertion(StartAssertionOptions.builder().userVerification(Some(uv).asJava).build()) + val request = rp.startAssertion(StartAssertionOptions.builder().userVerification(uv).build()) request.getPublicKeyCredentialRequestOptions.getUserVerification should equal (uv) } diff --git a/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyStartOperationSpec.scala b/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyStartOperationSpec.scala index a00a2468e..df7339445 100644 --- a/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyStartOperationSpec.scala +++ b/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyStartOperationSpec.scala @@ -121,7 +121,7 @@ class RelyingPartyStartOperationSpec extends FunSpec with Matchers with Generato forAll { credentials: Set[PublicKeyCredentialDescriptor] => val rp = relyingParty(credentials = credentials) val result = rp.startAssertion(StartAssertionOptions.builder() - .username(Some(userId.getName).asJava) + .username(userId.getName) .build() ) @@ -144,7 +144,7 @@ class RelyingPartyStartOperationSpec extends FunSpec with Matchers with Generato forAll { appId: Optional[AppId] => val rp = relyingParty(appId = appId) val result = rp.startAssertion(StartAssertionOptions.builder() - .username(Some(userId.getName).asJava) + .username(userId.getName) .build() ) diff --git a/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyUserIdentificationSpec.scala b/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyUserIdentificationSpec.scala index 49d47cc99..0cd5714df 100644 --- a/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyUserIdentificationSpec.scala +++ b/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyUserIdentificationSpec.scala @@ -162,7 +162,7 @@ class RelyingPartyUserIdentificationSpec extends FunSpec with Matchers { it("succeeds for the default test case if a username was given.") { val request = rp.startAssertion(StartAssertionOptions.builder() - .username(Optional.of(Defaults.username)) + .username(Defaults.username) .build()) val deterministicRequest = request.toBuilder.publicKeyCredentialRequestOptions( From 04d1edf58e880c8b3b7bc158b980e8c43bfb339f Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Tue, 5 Mar 2019 15:43:19 +0100 Subject: [PATCH 18/19] Update NEWS --- NEWS | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/NEWS b/NEWS index bce20dc26..e61afdbe3 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,19 @@ +== Version 1.1.0 (unreleased) == + +Changed behaviours: + +* `AssertionExtensionInputsBuilder.appid(Optional)` now fails fast if the + argument is `null` +* `ClientAssertionExtensionOutputsBuilder.appid(Optional)` now fails + fast if the argument is `null` + + +New features: + +* Public API methods that take `Optional` parameters now come with + `Optional`-less aliases. + + == Version 1.0.1 == Bugfixes: From 8ab358bf477e983063bed9cd89cd96b54ec74410 Mon Sep 17 00:00:00 2001 From: asaph Date: Sat, 16 Mar 2019 15:20:13 -0700 Subject: [PATCH 19/19] Update README to reflect that v1.0.1 is the current release --- README | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README b/README index b30d6f92d..cee81801e 100644 --- a/README +++ b/README @@ -27,7 +27,7 @@ Maven: com.yubico webauthn-server-core - 1.0.0 + 1.0.1 compile ---------- @@ -35,7 +35,7 @@ Maven: Gradle: ---------- -compile 'com.yubico:webauthn-server-core:1.0.0' +compile 'com.yubico:webauthn-server-core:1.0.1' ----------