[java-idp-plugin-webauthn] branch main updated: Improve credential registration builder
Phil Smart
philip.smart at jisc.ac.uk
Wed Aug 7 16:52:01 UTC 2024
This is an automated email from the git hooks/post-receive script.
philsmart pushed a commit to branch main
in repository java-idp-plugin-webauthn.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-plugin-webauthn.git;a=commit;h=056e50df02df014885f7366f854870bcea0f8314
The following commit(s) were added to refs/heads/main by this push:
new 056e50d Improve credential registration builder
056e50d is described below
commit 056e50df02df014885f7366f854870bcea0f8314
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Wed Aug 7 17:51:59 2024 +0100
Improve credential registration builder
---
.../authn/webauthn/admin/RegistrationResult.java | 2 +-
.../webauthn/storage/CredentialRegistration.java | 85 ++++++++++++++++++----
.../storage/CredentialRegistrationTest.java | 58 +++++++++++++++
3 files changed, 131 insertions(+), 14 deletions(-)
diff --git a/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/RegistrationResult.java b/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/RegistrationResult.java
index bb5d822..b4f5d88 100644
--- a/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/RegistrationResult.java
+++ b/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/RegistrationResult.java
@@ -266,7 +266,7 @@ public class RegistrationResult {
public IBuildStage withCredential(
@Nonnull final PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs>
cred) {
- this.credential = Constraint.isNotNull(cred, "Credential can not be null");
+ this.credential = Constraint.isNotNull(cred, "Credential cannot be null");
return this;
}
diff --git a/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/storage/CredentialRegistration.java b/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/storage/CredentialRegistration.java
index e65b8d7..546ee0b 100644
--- a/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/storage/CredentialRegistration.java
+++ b/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/storage/CredentialRegistration.java
@@ -43,6 +43,7 @@ import com.yubico.webauthn.data.UserIdentity;
import net.shibboleth.shared.annotation.constraint.NonnullElements;
import net.shibboleth.shared.annotation.constraint.Unmodifiable;
import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.logic.Constraint;
/**
* Registration record used to hold registered credentials.
@@ -87,7 +88,6 @@ public class CredentialRegistration {
*
* @param builder the builder
*/
- //TODO look at nullable here.
private CredentialRegistration(final Builder builder) {
this.userIdentity = builder.userIdentity;
this.transports = builder.transports;
@@ -147,7 +147,9 @@ public class CredentialRegistration {
*/
@JsonIgnore
@Nonnull public String getUsername() {
- return userIdentity.getName();
+ final String name = userIdentity.getName();
+ assert name != null;
+ return name;
}
/**
@@ -211,7 +213,7 @@ public class CredentialRegistration {
*/
@JsonIgnore
@Nullable public String getAuthenticatorDescription() {
- if (attestationMetadata != null && !attestationMetadata.isEmpty()) {
+ if (!attestationMetadata.isEmpty()) {
final Optional<Optional<String>> descriptionFound = attestationMetadata.stream()
.filter(mtd -> mtd.getMetadataStatement().isPresent())
.map(mtd -> mtd.getMetadataStatement().get().getDescription()).findFirst();
@@ -234,7 +236,7 @@ public class CredentialRegistration {
*/
@JsonIgnore
@Nullable public String getIcon() {
- if (attestationMetadata != null && !attestationMetadata.isEmpty()) {
+ if (!attestationMetadata.isEmpty()) {
final Optional<Optional<String>> iconFound = attestationMetadata.stream()
.filter(mtd -> mtd.getMetadataStatement().isPresent())
.map(mtd -> mtd.getMetadataStatement().get().getIcon()).findFirst();
@@ -313,35 +315,86 @@ public class CredentialRegistration {
/** Builder stage.*/
public interface IUserIdentityStage {
+ /**
+ * The users identity.
+ * @param userIdentity the users identity
+ * @return the next builder stage
+ */
@Nonnull public ITransportsStage withUserIdentity(@Nonnull final UserIdentity userIdentity);
}
/** Builder stage.*/
public interface ITransportsStage {
+ /**
+ * Set the {@link AuthenticatorTransport transports} the authenticator can
+ * use to communicate with the client.
+ *
+ * @param transports the transports
+ * @return the next builder stage
+ */
@Nonnull public IRegistrationTimeStage withTransports(@Nonnull SortedSet<AuthenticatorTransport> transports);
}
/** Builder stage.*/
public interface IRegistrationTimeStage {
+ /**
+ * Set the time the registration took place
+ *
+ * @param registrationTime the registration time
+ * @return the next builder stage
+ */
@Nonnull public ICredentialStage withRegistrationTime(@Nonnull final Instant registrationTime);
}
/** Builder stage.*/
public interface ICredentialStage {
+ /**
+ * Set the credential to register.
+ *
+ * @param credential the credential
+ * @return the next builder stage
+ */
@Nonnull public IBuildStage withCredential(@Nonnull final RegisteredCredential credential);
}
/** Builder stage.*/
public interface IBuildStage {
+ /**
+ * Set an optional nickname of the credential.
+ *
+ * @param credentialNickname the nickname
+ * @return the next builder stage
+ */
@Nonnull public IBuildStage withCredentialNickname(@Nullable final String credentialNickname);
+ /**
+ * Is the credential a discoverable type (passkey). Empty if not known.
+ *
+ * @param discoverable is the credential a discoverable type (passkey). Empty if not known
+ * @return the next builder stage
+ */
@Nonnull public IBuildStage withDiscoverable(@Nonnull final Optional<Boolean> discoverable);
+ /**
+ * Set the optional attestation metadata about the authenticator.
+ *
+ * @param attestationMetadata the metadata
+ * @return the next builder stage
+ */
@Nonnull public IBuildStage withAttestationMetadata(
@Nonnull final Set<MetadataBLOBPayloadEntry> attestationMetadata);
+ /**
+ * Was the user verified during registration?
+ *
+ * @param userVerified was the user verified during registration
+ * @return the next builder stage
+ */
@Nonnull public IBuildStage withUserVerified(boolean userVerified);
+ /**
+ * Build this credential registration
+ */
@Nonnull public CredentialRegistration build();
}
@@ -349,16 +402,17 @@ public class CredentialRegistration {
@JsonPOJOBuilder(buildMethodName = "build", withPrefix = "with")
public static final class Builder
implements IUserIdentityStage, ITransportsStage, IRegistrationTimeStage, ICredentialStage, IBuildStage {
- private UserIdentity userIdentity;
- private SortedSet<AuthenticatorTransport> transports;
- private Instant registrationTime;
- private RegisteredCredential credential;
+ @Nonnull private UserIdentity userIdentity;
+ @Nonnull private SortedSet<AuthenticatorTransport> transports;
+ @Nonnull private Instant registrationTime;
+ @Nonnull private RegisteredCredential credential;
@Nullable private String credentialNickname;
@Nonnull private Optional<Boolean> discoverable;
@Nonnull private Set<MetadataBLOBPayloadEntry> attestationMetadata;
private boolean userVerified;
/** Constructor.*/
+ @SuppressWarnings("null")
private Builder() {
// Create empty, corresponds to 'unknown'
discoverable = Optional.empty();
@@ -370,7 +424,7 @@ public class CredentialRegistration {
@Override
@JsonProperty("userIdentity")
@Nonnull public ITransportsStage withUserIdentity(@Nonnull final UserIdentity user) {
- userIdentity = user;
+ userIdentity = Constraint.isNotNull(user, "UserIdentity can not be null");
return this;
}
@@ -378,21 +432,25 @@ public class CredentialRegistration {
@JsonProperty("transports")
@Nonnull public IRegistrationTimeStage withTransports(@Nonnull
final SortedSet<AuthenticatorTransport> authenticatorTransports) {
- transports = authenticatorTransports;
+ if (authenticatorTransports == null) {
+ transports = Collections.emptySortedSet();
+ } else {
+ transports = authenticatorTransports;
+ }
return this;
}
@Override
@JsonProperty("registrationTime")
@Nonnull public ICredentialStage withRegistrationTime(@Nonnull final Instant time) {
- registrationTime = time;
+ registrationTime = Constraint.isNotNull(time, "Registration time can not be null");
return this;
}
@Override
@JsonProperty("credential")
@Nonnull public IBuildStage withCredential(@Nonnull final RegisteredCredential cred) {
- credential = cred;
+ credential = Constraint.isNotNull(cred, "Credential can not be null");
return this;
}
@@ -412,7 +470,8 @@ public class CredentialRegistration {
@Override
@JsonProperty("attestationMetadata")
- @Nonnull public IBuildStage withAttestationMetadata(@Nonnull final Set<MetadataBLOBPayloadEntry> attestationMtd) {
+ @Nonnull public IBuildStage withAttestationMetadata(
+ @Nonnull final Set<MetadataBLOBPayloadEntry> attestationMtd) {
attestationMetadata = attestationMtd;
return this;
}
diff --git a/webauthn-api/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/storage/CredentialRegistrationTest.java b/webauthn-api/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/storage/CredentialRegistrationTest.java
new file mode 100644
index 0000000..8b87609
--- /dev/null
+++ b/webauthn-api/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/storage/CredentialRegistrationTest.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.authn.webauthn.storage;
+
+import java.time.Instant;
+import java.util.TreeSet;
+
+import org.testng.annotations.Test;
+
+import com.yubico.webauthn.data.AuthenticatorTransport;
+import com.yubico.webauthn.data.ByteArray;
+import com.yubico.webauthn.data.UserIdentity;
+
+import net.shibboleth.shared.logic.ConstraintViolationException;
+
+/**
+ * Tests for {@link CredentialRegistration}
+ */
+public class CredentialRegistrationTest {
+
+ private CredentialRegistration credReg;
+
+ @SuppressWarnings("null")
+ @Test(expectedExceptions = ConstraintViolationException.class)
+ public void testCredentialRegistrationBuilder_NullIdentity() {
+ CredentialRegistration.builder()
+ .withUserIdentity(null)
+ .withTransports(new TreeSet<AuthenticatorTransport>())
+ .withRegistrationTime(Instant.now())
+ .withCredential(null).build();
+ }
+
+ @SuppressWarnings("null")
+ @Test(expectedExceptions = ConstraintViolationException.class)
+ public void testCredentialRegistrationBuilder_NullCredential() {
+ CredentialRegistration.builder()
+ .withUserIdentity(UserIdentity.builder().name("test")
+ .displayName("person")
+ .id(ByteArray.fromBase64("OjdT61K6rono3rZCXCRnSQ=="))
+ .build())
+ .withTransports(new TreeSet<AuthenticatorTransport>())
+ .withRegistrationTime(Instant.now())
+ .withCredential(null).build();
+ }
+
+}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list