[java-idp-plugin-webauthn] branch main updated: Add support to set PublicKeyCredentialParameters in properties file

Phil Smart philip.smart at jisc.ac.uk
Mon Feb 12 12:34:40 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=d0b4502b91827f9a08ebaca68db514c29953c8f1

The following commit(s) were added to refs/heads/main by this push:
     new d0b4502  Add support to set PublicKeyCredentialParameters in properties file
d0b4502 is described below

commit d0b4502b91827f9a08ebaca68db514c29953c8f1
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Mon Feb 12 12:34:37 2024 +0000

    Add support to set PublicKeyCredentialParameters in properties file
    
     - Remove redundant code
---
 webauthn-impl/pom.xml                              |   4 +-
 .../impl/YubicoWebauthnAuthenticationClient.java   |  29 ++----
 .../client/impl/YubicoWebauthnClientFactory.java   | 113 +++++++++++++++------
 .../IdPStorageServiceCredentialRespository.java    |   3 +-
 .../META-INF/net.shibboleth.idp/postconfig.xml     |  12 +--
 .../authn/webauthn/conf/authn/webauthn.properties  |   3 +
 .../plugin/authn/webauthn/views/webauthn-authn.vm  |   9 +-
 .../YubicoWebauthnAuthenticationClientTest.java    |   2 +-
 .../impl/YubicoWebauthnClientFactoryTest.java      |  93 +++++++++++++++++
 .../authn/webauthn/impl/AbstractWebAuthnTest.java  |  10 +-
 .../impl/ValidatePublicKeyCredentialTest.java      |   2 +-
 11 files changed, 203 insertions(+), 77 deletions(-)

diff --git a/webauthn-impl/pom.xml b/webauthn-impl/pom.xml
index 36ee0f8..0c18c8b 100644
--- a/webauthn-impl/pom.xml
+++ b/webauthn-impl/pom.xml
@@ -106,9 +106,7 @@
         <!-- Provided dependencies -->
         <dependency>
             <groupId>net.shibboleth</groupId>
-            <artifactId>shib-security</artifactId>
-            <!-- TODO, why does this need a version? -->
-           
+            <artifactId>shib-security</artifactId>          
             <scope>provided</scope>
         </dependency>
         <dependency>
diff --git a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnAuthenticationClient.java b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnAuthenticationClient.java
index 3277c78..b11419d 100644
--- a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnAuthenticationClient.java
+++ b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnAuthenticationClient.java
@@ -14,8 +14,6 @@
 
 package net.shibboleth.idp.plugin.authn.webauthn.client.impl;
 
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
 import java.util.Optional;
 
@@ -25,7 +23,6 @@ import javax.annotation.concurrent.ThreadSafe;
 
 import org.slf4j.Logger;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.yubico.webauthn.AssertionRequest;
 import com.yubico.webauthn.AssertionResult;
 import com.yubico.webauthn.FinishAssertionOptions;
@@ -51,6 +48,8 @@ import net.shibboleth.idp.plugin.authn.webauthn.client.WebAuthnAuthenticationCli
 import net.shibboleth.idp.plugin.authn.webauthn.exception.AssertionFailureException;
 import net.shibboleth.idp.plugin.authn.webauthn.exception.RegistrationFailureException;
 import net.shibboleth.idp.plugin.authn.webauthn.exception.WebAuthnAuthenticationClientException;
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
+import net.shibboleth.shared.annotation.constraint.NotLive;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
 
@@ -68,32 +67,22 @@ public class YubicoWebauthnAuthenticationClient implements WebAuthnAuthenticatio
     /** Information pertaining to the relying party.*/
     @Nonnull private final RelyingParty rp;
     
-    /** The JSON object mapper used to JSONify webauthn objects. */
-    @Nonnull private final ObjectMapper om;
-    
     /** List of acceptable public key algorithms.*/
-    private final List<PublicKeyCredentialParameters> preferredPublickeyParams =
-            Collections.unmodifiableList(
-                Arrays.asList(
-                    PublicKeyCredentialParameters.ES256,
-                    PublicKeyCredentialParameters.EdDSA,
-                    PublicKeyCredentialParameters.ES384,
-                    PublicKeyCredentialParameters.ES512,
-                    PublicKeyCredentialParameters.RS256,
-                    PublicKeyCredentialParameters.RS384,
-                    PublicKeyCredentialParameters.RS512));
+    private final List<PublicKeyCredentialParameters> preferredPublickeyParams;
     
     /**
      * 
      * Constructor.
      *
-     * @param relyingParty Information pertaining to the relying party.
-     * @param mapper the JSON object mapper.
+     * @param relyingParty information pertaining to the relying party.
+     * @param publickeyParams list of preferred public key credential parameters to send to the authenticator 
+     *                                  during registration.
      */
     public YubicoWebauthnAuthenticationClient(@Nonnull final RelyingParty relyingParty,
-            @Nonnull final ObjectMapper mapper) {
+            @Nonnull @NonnullElements @NotLive final List<PublicKeyCredentialParameters> publickeyParams) {
         rp = Constraint.isNotNull(relyingParty, "The reyling party configuration can not be null");
-        om = Constraint.isNotNull(mapper, "Object mapper can not be null");
+        preferredPublickeyParams = Constraint.isNotNull(publickeyParams, "PreferredPublickeyParams can not be null");
+
     }
 
     @Override
diff --git a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnClientFactory.java b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnClientFactory.java
index f57fe1e..0c7c4fa 100644
--- a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnClientFactory.java
+++ b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnClientFactory.java
@@ -14,6 +14,9 @@
 
 package net.shibboleth.idp.plugin.authn.webauthn.client.impl;
 
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -24,10 +27,11 @@ import javax.annotation.concurrent.ThreadSafe;
 
 import org.springframework.beans.factory.FactoryBean;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.base.Predicates;
 import com.yubico.webauthn.CredentialRepository;
 import com.yubico.webauthn.RelyingParty;
+import com.yubico.webauthn.data.COSEAlgorithmIdentifier;
+import com.yubico.webauthn.data.PublicKeyCredentialParameters;
 import com.yubico.webauthn.data.RelyingPartyIdentity;
 
 import net.shibboleth.idp.plugin.authn.webauthn.client.WebAuthnAuthenticationClient;
@@ -58,10 +62,7 @@ public class YubicoWebauthnClientFactory extends AbstractInitializableComponent
     
     /** Allow subdomains in origins? Default is false.*/
     @GuardedBy("this") private boolean allowOriginSubdomain;
-    
-    /** The JSON object mapper used to JSONify webauthn objects. */
-    @GuardedBy("this") @NonnullAfterInit private ObjectMapper om;    
-    
+
     /** The credential repository to store valid credentials in.*/
     @GuardedBy("this") @NonnullAfterInit private CredentialRepository credentialRepository;
     
@@ -71,11 +72,22 @@ public class YubicoWebauthnClientFactory extends AbstractInitializableComponent
      */
     @GuardedBy("this") @Nonnull @NonnullElements private Set<String> origins;
     
+    /** List of acceptable public key algorithms.*/
+    @GuardedBy("this") @Nonnull @NonnullElements private List<PublicKeyCredentialParameters> preferredPublickeyParams;
+    
     /** Constructor.*/
     public YubicoWebauthnClientFactory() {
         allowOriginPort = false;
         allowOriginSubdomain = false;
         origins = CollectionSupport.emptySet();
+        preferredPublickeyParams = CollectionSupport.listOf(
+                        PublicKeyCredentialParameters.ES256,
+                        PublicKeyCredentialParameters.EdDSA,
+                        PublicKeyCredentialParameters.ES384,
+                        PublicKeyCredentialParameters.ES512,
+                        PublicKeyCredentialParameters.RS256,
+                        PublicKeyCredentialParameters.RS384,
+                        PublicKeyCredentialParameters.RS512);
     }
     
     @Override protected void doInitialize() throws ComponentInitializationException {
@@ -87,9 +99,6 @@ public class YubicoWebauthnClientFactory extends AbstractInitializableComponent
         if (relyingPartyName ==  null) {
             throw new ComponentInitializationException("relyingPartyName cannot be null");
         }
-        if (om ==  null) {
-            throw new ComponentInitializationException("ObjectMapper cannot be null");
-        }
         if (credentialRepository == null) {
             throw new ComponentInitializationException("Credential repository cannot be null");
         }
@@ -113,15 +122,77 @@ public class YubicoWebauthnClientFactory extends AbstractInitializableComponent
         if (!getOrigins().isEmpty()) {            
             final RelyingParty rp = builder.origins(getOrigins()).build();
             assert rp != null;
-            return new YubicoWebauthnAuthenticationClient(rp, getObjectMapper());
+            return new YubicoWebauthnAuthenticationClient(rp, getPreferredPublickeyParams());
         } else {
             final RelyingParty rp = builder.build();
             assert rp != null;
-            return new YubicoWebauthnAuthenticationClient(rp, getObjectMapper());
+            return new YubicoWebauthnAuthenticationClient(rp, getPreferredPublickeyParams());
         }        
         
     }
     
+    /**
+     * Set the ordered list of preferred public key credential parameters to send to the authenticator during 
+     * registration.
+     * 
+     * @param publickeyParams the public key parameters to set.
+     */
+    public synchronized void setPreferredPublickeyParamsNative(
+            @Nonnull @NonnullElements final List<PublicKeyCredentialParameters> publickeyParams) {
+        checkSetterPreconditions();
+        preferredPublickeyParams = Constraint.isNotNull(publickeyParams.stream()
+                .filter(Objects::nonNull)
+                .collect(CollectionSupport.nonnullCollector(Collectors.toList())).get(),
+                "PreferredPublickeyParams can not be null");
+    }
+    
+    /**
+     * Set the ordered list of preferred public key credential parameters to send to the authenticator during 
+     * registration.
+     * 
+     * @param publickeyParams the COSE algorithm identifiers to set.
+     */
+    public synchronized void setPreferredPublickeyParams(
+            @Nonnull @NonnullElements final List<String> publickeyParams) {
+        checkSetterPreconditions();
+        final Collection<String> publicKeyParamsNormalized = StringSupport.normalizeStringCollection(publickeyParams);
+        preferredPublickeyParams = publicKeyParamsNormalized.stream()
+            .map(coseAlg -> {
+                switch (coseAlg) {
+                    case "EdDSA" : 
+                        return PublicKeyCredentialParameters.builder().alg(COSEAlgorithmIdentifier.EdDSA).build();
+                    case "ES256" :  
+                        return PublicKeyCredentialParameters.builder().alg(COSEAlgorithmIdentifier.ES256).build();
+                    case "ES384" :  
+                        return PublicKeyCredentialParameters.builder().alg(COSEAlgorithmIdentifier.ES384).build();
+                    case "ES512" :  
+                        return PublicKeyCredentialParameters.builder().alg(COSEAlgorithmIdentifier.ES512).build();
+                    case "RS1" :  
+                        return PublicKeyCredentialParameters.builder().alg(COSEAlgorithmIdentifier.RS1).build();
+                    case "RS256" :  
+                        return PublicKeyCredentialParameters.builder().alg(COSEAlgorithmIdentifier.RS256).build();
+                    case "RS384" :  
+                        return PublicKeyCredentialParameters.builder().alg(COSEAlgorithmIdentifier.RS384).build();
+                    case "RS512" :  
+                        return PublicKeyCredentialParameters.builder().alg(COSEAlgorithmIdentifier.RS512).build();
+                    default: return null;
+                }
+            })
+            .filter(Objects::nonNull)
+            .collect(CollectionSupport.nonnullCollector(Collectors.toList()))
+            .get();
+    }
+    
+    /**
+     * Get the ordered list of preferred public key credential parameters to send to the authenticator during 
+     * registration.
+     * 
+     * @return the public key parameters.
+     */
+    @Nonnull @NonnullElements public synchronized List<PublicKeyCredentialParameters> getPreferredPublickeyParams() {
+        return preferredPublickeyParams;
+    }
+    
     /**
      * Get the credential repository used to store the valid webauthn credential.
      * 
@@ -177,27 +248,7 @@ public class YubicoWebauthnClientFactory extends AbstractInitializableComponent
     public boolean isSingleton() {
         return true;
     }
-    
-    /**
-     * Set the object mapper.
-     * 
-     * @param objectMapper the object mapper.
-     */
-    public synchronized void setObjectMapper(@Nonnull final ObjectMapper objectMapper) {
-        checkSetterPreconditions(); 
-        om = Constraint.isNotNull(objectMapper, "Object mapper can not be null");
-    }
-    
-    /**
-     * Get the object mapper.
-     * 
-     * @return the objectMapper;
-     */
-    @Nonnull private synchronized ObjectMapper getObjectMapper() {
-        checkComponentActive();
-        assert om != null;
-        return om;
-    }
+
     /**
      * Set the relying party identifier.
      * 
diff --git a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/storage/impl/IdPStorageServiceCredentialRespository.java b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/storage/impl/IdPStorageServiceCredentialRespository.java
index 1996155..2689843 100644
--- a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/storage/impl/IdPStorageServiceCredentialRespository.java
+++ b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/storage/impl/IdPStorageServiceCredentialRespository.java
@@ -69,7 +69,7 @@ public class IdPStorageServiceCredentialRespository extends AbstractIdentifiable
     private static final Logger log = LoggerFactory.getLogger(IdPStorageServiceCredentialRespository.class);
     
     /** The context to use to partition the storage records.*/
-    private static final String STORAGE_CONTEXT = "webauthn";
+    private static final String STORAGE_CONTEXT = "net.shibboleth.idp.plugin.authn.webauthn";
     
     /** Storage record serializer. */
     @NonnullAfterInit private StorageSerializer<Set<CredentialRegistration>> serializer;
@@ -93,6 +93,7 @@ public class IdPStorageServiceCredentialRespository extends AbstractIdentifiable
         } else {
             throw new ConstraintViolationException("Credential repository requires an EnumeratableStorageService type");
         }
+        // Can not use client-side, as keys would not work across browsers. 
         final StorageCapabilities caps = storageService.getCapabilities();
         if (caps instanceof StorageCapabilities) {
             Constraint.isTrue(caps.isServerSide(), "StorageService cannot be client-side");
diff --git a/webauthn-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/webauthn-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
index da2fe54..1fadaf5 100644
--- a/webauthn-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
+++ b/webauthn-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
@@ -93,21 +93,17 @@
         p:allowOriginPort="%{idp.authn.webauthn.allowOriginPort:false}"
         p:allowOriginSubdomain="%{idp.authn.webauthn.allowOriginSubdomain:false}"
         p:origins="%{idp.authn.webauthn.origins:}"
-        p:objectMapper-ref="shibboleth.authn.WebAuthn.JSONObjectMapper" 
+        p:preferredPublickeyParams="%{idp.authn.webauthn.preferredPublicKeyParams:EdDSA,ES256,ES384,ES512,RS1,RS256,RS384,RS512}"
         p:credentialRepository-ref="shibboleth.authn.webauthn.DefaultCredentialRepository"/>
     
         
     <bean id="shibboleth.authn.webauthn.DefaultCredentialRepository" scope="singleton"
         class="net.shibboleth.idp.plugin.authn.webauthn.storage.impl.IdPStorageServiceCredentialRespository"
-        p:storageService-ref="shibboleth.authn.webauthn.DefaultCredentialRepositoryStorageService"
-        p:serializer-ref="shibboleth.authn.webauthn.DefaultCredentialRepositoryStorageSerializer"/>
-        
-     <bean id="shibboleth.authn.webauthn.DefaultCredentialRepositoryStorageService"
-        class="org.opensaml.storage.impl.MemoryStorageService"/>
+        p:storageService-ref="#{'%{idp.authn.webauthn.StorageService:shibboleth.StorageService}'.trim()}"
+        p:serializer-ref="shibboleth.authn.webauthn.DefaultCredentialRepositoryStorageSerializer"/>        
         
      <bean id="shibboleth.authn.webauthn.DefaultCredentialRepositoryStorageSerializer"
-        class="net.shibboleth.idp.plugin.authn.webauthn.storage.impl.CredentialRegistrationSerializer"/>
-    
+        class="net.shibboleth.idp.plugin.authn.webauthn.storage.impl.CredentialRegistrationSerializer"/>    
            
      <!-- 
      
diff --git a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/conf/authn/webauthn.properties b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/conf/authn/webauthn.properties
index 243f737..698d92c 100644
--- a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/conf/authn/webauthn.properties
+++ b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/conf/authn/webauthn.properties
@@ -24,6 +24,9 @@ idp.authn.webauthn.relyingPartyName = Shibboleth
 # Require a residentKey (passkey) to be created when registering a credential. One-of 'discouraged', 'preferred', 'required'
 #idp.authn.webauthn.registration.residentKey = preferred
 
+# Preferred set of COSE signature algorithms which a created credential will use. The sequence is ordered from the most preferred to the least. The client makes best effort to create the most preferred it can.
+#idp.authn.webauthn.preferredPublicKeyParams = EdDSA,ES256,ES384,ES512,RS1,RS256,RS384,RS512
+
 # The authenticator attachment (authenticator type) requirement. One-of 'any', 'cross-platform', or 'platform'. 
 #idp.authn.webauthn.registration.authenticatorAttachment = any
 
diff --git a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-authn.vm b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-authn.vm
index 4ae2d6a..05c002a 100644
--- a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-authn.vm
+++ b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-authn.vm
@@ -43,7 +43,7 @@
             async function authenticate() {
                 // Some UI changes
                 try {               
-                    document.getElementById('authenticate').textContent='#springMessageText("idp.webauthn.authn.authenticate",
+                    document.getElementById('authenticate').textContent='#springMessageText("idp.webauthn.authn.authenticate.inprogress",
                                         "Authenticating...")'
                 } catch (e) {
                     // No issue if this does not work
@@ -61,7 +61,7 @@
                     }).catch(function (err) { 
                         console.error(err);
                         document.getElementById('authenticate').textContent='#springMessageText("idp.webauthn.authn.authenticate.retry",
-                                        "Authentication failed, retry")'          
+                                        "Login failed, retry")'          
                     });    
             }    
             window.addEventListener("load", () => {
@@ -77,9 +77,6 @@
                         document.getElementById('unsupportedDiv').classList.remove('hidden')
                     } else {
                         document.getElementById("authenticate").onclick = authenticate;
-                        #if($debug == "false")
-                            authenticate();
-                        #end
                     }    
                 } catch (e) {
                     console.error(e);
@@ -134,7 +131,7 @@
                             <div class="centre">
                                     <button id="authenticate"
                                         class="form-element form-button">#springMessageText("idp.webauthn.authn.authenticate",
-                                        "Authenticate")</button>
+                                        "Login with passkey or security key")</button>
                             </div>                        
                             #if($debug == "true")
                                 <hr />
diff --git a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnAuthenticationClientTest.java b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnAuthenticationClientTest.java
index cd1f4c8..90ecdd2 100644
--- a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnAuthenticationClientTest.java
+++ b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnAuthenticationClientTest.java
@@ -85,7 +85,7 @@ public class YubicoWebauthnAuthenticationClientTest extends AbstractWebAuthnTest
             .allowOriginPort(true)
             .allowOriginSubdomain(true)
             .build();
-        client = new YubicoWebauthnAuthenticationClient(rp,jsonMapper);
+        client = new YubicoWebauthnAuthenticationClient(rp, preferredPublickeyParams);
         
         userIdentity = 
                 UserIdentity.builder().name(USERNAME).displayName("test user")
diff --git a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnClientFactoryTest.java b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnClientFactoryTest.java
new file mode 100644
index 0000000..21a2786
--- /dev/null
+++ b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnClientFactoryTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.client.impl;
+
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.yubico.webauthn.data.COSEAlgorithmIdentifier;
+
+import net.shibboleth.idp.plugin.authn.webauthn.impl.AbstractWebAuthnTest;
+import net.shibboleth.shared.collection.CollectionSupport;
+
+/**
+ * Tests for the {@link YubicoWebauthnClientFactory}.
+ */
+public class YubicoWebauthnClientFactoryTest extends AbstractWebAuthnTest {
+    
+    private YubicoWebauthnClientFactory factory;
+    
+    @Override
+    @BeforeMethod
+    public void setup() throws Exception {
+        super.setup();
+        factory = new YubicoWebauthnClientFactory();
+    }
+    
+    @Test
+    public void testPreferredPublickeyParams() {        
+        factory.setPreferredPublickeyParams(CollectionSupport.listOf("EdDSA"));
+        assertEquals(factory.getPreferredPublickeyParams().size(), 1);
+        assertEquals(factory.getPreferredPublickeyParams().get(0).getAlg(), COSEAlgorithmIdentifier.EdDSA);
+        
+        factory.setPreferredPublickeyParams(CollectionSupport.listOf("ES256"));
+        assertEquals(factory.getPreferredPublickeyParams().size(), 1);
+        assertEquals(factory.getPreferredPublickeyParams().get(0).getAlg(), COSEAlgorithmIdentifier.ES256);
+        
+        factory.setPreferredPublickeyParams(CollectionSupport.listOf("ES384"));
+        assertEquals(factory.getPreferredPublickeyParams().size(), 1);
+        assertEquals(factory.getPreferredPublickeyParams().get(0).getAlg(), COSEAlgorithmIdentifier.ES384);
+        
+        factory.setPreferredPublickeyParams(CollectionSupport.listOf("ES512"));
+        assertEquals(factory.getPreferredPublickeyParams().size(), 1);
+        assertEquals(factory.getPreferredPublickeyParams().get(0).getAlg(), COSEAlgorithmIdentifier.ES512);
+        
+        factory.setPreferredPublickeyParams(CollectionSupport.listOf("RS1"));
+        assertEquals(factory.getPreferredPublickeyParams().size(), 1);
+        assertEquals(factory.getPreferredPublickeyParams().get(0).getAlg(), COSEAlgorithmIdentifier.RS1);
+        
+        factory.setPreferredPublickeyParams(CollectionSupport.listOf("RS256"));
+        assertEquals(factory.getPreferredPublickeyParams().size(), 1);
+        assertEquals(factory.getPreferredPublickeyParams().get(0).getAlg(), COSEAlgorithmIdentifier.RS256);
+        
+        factory.setPreferredPublickeyParams(CollectionSupport.listOf("RS384"));
+        assertEquals(factory.getPreferredPublickeyParams().size(), 1);
+        assertEquals(factory.getPreferredPublickeyParams().get(0).getAlg(), COSEAlgorithmIdentifier.RS384);
+        
+        factory.setPreferredPublickeyParams(CollectionSupport.listOf("RS512"));
+        assertEquals(factory.getPreferredPublickeyParams().size(), 1);
+        assertEquals(factory.getPreferredPublickeyParams().get(0).getAlg(), COSEAlgorithmIdentifier.RS512);
+        
+        // Also tests ordering is preserved
+        factory.setPreferredPublickeyParams(
+                CollectionSupport.listOf("EdDSA","ES256","ES384","ES512","RS1","RS256","RS384","RS512"));
+        assertEquals(factory.getPreferredPublickeyParams().size(), 8);
+        assertEquals(factory.getPreferredPublickeyParams().get(0).getAlg(), COSEAlgorithmIdentifier.EdDSA);
+        assertEquals(factory.getPreferredPublickeyParams().get(1).getAlg(), COSEAlgorithmIdentifier.ES256);
+        assertEquals(factory.getPreferredPublickeyParams().get(2).getAlg(), COSEAlgorithmIdentifier.ES384);
+        assertEquals(factory.getPreferredPublickeyParams().get(3).getAlg(), COSEAlgorithmIdentifier.ES512);
+        assertEquals(factory.getPreferredPublickeyParams().get(4).getAlg(), COSEAlgorithmIdentifier.RS1);
+        assertEquals(factory.getPreferredPublickeyParams().get(5).getAlg(), COSEAlgorithmIdentifier.RS256);
+        assertEquals(factory.getPreferredPublickeyParams().get(6).getAlg(), COSEAlgorithmIdentifier.RS384);
+        assertEquals(factory.getPreferredPublickeyParams().get(7).getAlg(), COSEAlgorithmIdentifier.RS512);
+        
+        factory.setPreferredPublickeyParams(CollectionSupport.listOf("unknown"));
+        assertEquals(factory.getPreferredPublickeyParams().size(), 0);
+        
+    }
+
+}
diff --git a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/impl/AbstractWebAuthnTest.java b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/impl/AbstractWebAuthnTest.java
index 4ffd63f..53186ee 100644
--- a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/impl/AbstractWebAuthnTest.java
+++ b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/impl/AbstractWebAuthnTest.java
@@ -14,8 +14,6 @@
 
 package net.shibboleth.idp.plugin.authn.webauthn.impl;
 
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -40,6 +38,7 @@ import net.shibboleth.idp.plugin.authn.webauthn.context.WebAuthnRegistrationCont
 import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
 import net.shibboleth.idp.profile.testing.RequestContextBuilder;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.collection.CollectionSupport;
 
 /** Abstract class for tests that require context setup.*/
 public abstract class AbstractWebAuthnTest {
@@ -76,16 +75,15 @@ public abstract class AbstractWebAuthnTest {
     protected ObjectMapper jsonMapper;
     
     /** List of acceptable public key algorithms.*/
-    protected final List<PublicKeyCredentialParameters> preferredPublickeyParams =
-            Collections.unmodifiableList(
-                Arrays.asList(
+    @Nonnull protected final List<PublicKeyCredentialParameters> preferredPublickeyParams =
+            CollectionSupport.listOf(
                     PublicKeyCredentialParameters.ES256,
                     PublicKeyCredentialParameters.EdDSA,
                     PublicKeyCredentialParameters.ES384,
                     PublicKeyCredentialParameters.ES512,
                     PublicKeyCredentialParameters.RS256,
                     PublicKeyCredentialParameters.RS384,
-                    PublicKeyCredentialParameters.RS512));
+                    PublicKeyCredentialParameters.RS512);
     
     
     /** 
diff --git a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/impl/ValidatePublicKeyCredentialTest.java b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/impl/ValidatePublicKeyCredentialTest.java
index ac07f23..8561019 100644
--- a/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/impl/ValidatePublicKeyCredentialTest.java
+++ b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/impl/ValidatePublicKeyCredentialTest.java
@@ -74,7 +74,7 @@ public class ValidatePublicKeyCredentialTest extends AbstractWebAuthnTest{
 
         webAuthnRegContext.setPublicKeyCredentialCreationOptions(credentialCreationOptions);
                 
-        final WebAuthnAuthenticationClient client = new YubicoWebauthnAuthenticationClient(rp, jsonMapper);
+        final WebAuthnAuthenticationClient client = new YubicoWebauthnAuthenticationClient(rp, preferredPublickeyParams);
         validator.setWebAuthnClient(client);
         validator.setCredentialRepository(new InMemoryRegistrationStorage());
         validator.initialize();

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list