[java-idp-plugin-webauthn] branch main updated: Add allowed origin override support
Phil Smart
philip.smart at jisc.ac.uk
Fri Feb 2 14:47:06 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=1c504c052fb4e3da6971805922e87804d89cf10e
The following commit(s) were added to refs/heads/main by this push:
new 1c504c0 Add allowed origin override support
1c504c0 is described below
commit 1c504c052fb4e3da6971805922e87804d89cf10e
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Fri Feb 2 14:47:04 2024 +0000
Add allowed origin override support
---
.../client/impl/YubicoWebauthnClientFactory.java | 88 +++++++++++++++++-----
.../META-INF/net.shibboleth.idp/postconfig.xml | 6 +-
.../authn/webauthn/conf/authn/webauthn.properties | 3 +
3 files changed, 77 insertions(+), 20 deletions(-)
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 e7e8859..7685d01 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.Set;
+import java.util.stream.Collectors;
+
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
@@ -22,15 +25,20 @@ 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.RelyingPartyIdentity;
import net.shibboleth.idp.plugin.authn.webauthn.client.WebAuthnAuthenticationClient;
import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
+import net.shibboleth.shared.annotation.constraint.NotLive;
+import net.shibboleth.shared.collection.CollectionSupport;
import net.shibboleth.shared.component.AbstractInitializableComponent;
import net.shibboleth.shared.component.ComponentInitializationException;
import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.StringSupport;
/**
* Spring factory beans for creating a {@link YubicoWebauthnAuthenticationClient}.
@@ -40,10 +48,10 @@ public class YubicoWebauthnClientFactory extends AbstractInitializableComponent
implements FactoryBean<WebAuthnAuthenticationClient> {
/** The relying party identifier.*/
- @GuardedBy("this") @Nullable private String relyingPartyId;
+ @GuardedBy("this") @NonnullAfterInit private String relyingPartyId;
/** The relying party name.*/
- @GuardedBy("this") @Nullable private String relyingPartyName;
+ @GuardedBy("this") @NonnullAfterInit private String relyingPartyName;
/** Allow unrestricted origin ports? Default is false.*/
@GuardedBy("this") private boolean allowOriginPort;
@@ -52,16 +60,19 @@ public class YubicoWebauthnClientFactory extends AbstractInitializableComponent
@GuardedBy("this") private boolean allowOriginSubdomain;
/** The JSON object mapper used to JSONify webauthn objects. */
- @GuardedBy("this") @Nullable private ObjectMapper om;
+ @GuardedBy("this") @NonnullAfterInit private ObjectMapper om;
/** The credential repository to store valid credentials in.*/
- // TODO replace with an adaptor to the storage service?
@GuardedBy("this") @NonnullAfterInit private CredentialRepository credentialRepository;
+ /** Allowable origins for this Relying Party. Overrides the origin derived from the relyingPartyId if used.*/
+ @GuardedBy("this") @Nonnull @NonnullElements private Set<String> origins;
+
/** Constructor.*/
public YubicoWebauthnClientFactory() {
allowOriginPort = false;
allowOriginSubdomain = false;
+ origins = CollectionSupport.emptySet();
}
@Override protected void doInitialize() throws ComponentInitializationException {
@@ -84,19 +95,36 @@ public class YubicoWebauthnClientFactory extends AbstractInitializableComponent
@Override
public WebAuthnAuthenticationClient getObject() throws Exception {
- final RelyingParty rp = RelyingParty.builder().identity(
- RelyingPartyIdentity
- .builder()
- .id(getRelyingPartyId())
- .name(getRelyingPartyName())
- //Use inmemory for now
- .build()).credentialRepository(getCredentialRepository())
- .allowOriginPort(isAllowOriginPort())
- .allowOriginSubdomain(isAllowOriginSubdomain())
- .build();
- assert rp != null;
- return new YubicoWebauthnAuthenticationClient(rp, getObjectMapper());
+ // FIXME: There is a bug in the builder here than prevents origins from being set as null
+ // once that is fixed, we only need one builder statement here.
+ if (!getOrigins().isEmpty()) {
+ final RelyingParty rp = RelyingParty.builder().identity(
+ RelyingPartyIdentity
+ .builder()
+ .id(getRelyingPartyId())
+ .name(getRelyingPartyName())
+ .build()).credentialRepository(getCredentialRepository())
+ .allowOriginPort(isAllowOriginPort())
+ .allowOriginSubdomain(isAllowOriginSubdomain())
+ .origins(getOrigins())
+ .build();
+ assert rp != null;
+ return new YubicoWebauthnAuthenticationClient(rp, getObjectMapper());
+ } else {
+ final RelyingParty rp = RelyingParty.builder().identity(
+ RelyingPartyIdentity
+ .builder()
+ .id(getRelyingPartyId())
+ .name(getRelyingPartyName())
+ .build()).credentialRepository(getCredentialRepository())
+ .allowOriginPort(isAllowOriginPort())
+ .allowOriginSubdomain(isAllowOriginSubdomain())
+ .build();
+ assert rp != null;
+ return new YubicoWebauthnAuthenticationClient(rp, getObjectMapper());
+ }
+
}
/**
@@ -110,6 +138,30 @@ public class YubicoWebauthnClientFactory extends AbstractInitializableComponent
return credentialRepository;
}
+ /**
+ * Get the allowable origins for this Relying Party. Overrides the origin derived from the relyingPartyId if used
+ *
+ * @return the origins.
+ */
+ @Nonnull @NonnullElements @NotLive public synchronized Set<String> getOrigins() {
+ return origins;
+ }
+
+ /**
+ * Set the allowable origins for this Relying Party. Overrides the origin derived from the relyingPartyId if used
+ *
+ * @param origins the origins to use
+ */
+ public synchronized void setOrigins(@Nullable final Set<String> allowedOrigins) {
+ checkSetterPreconditions();
+ if (allowedOrigins == null || allowedOrigins.isEmpty()) {
+ return;
+ }
+ origins = allowedOrigins.stream().
+ map(StringSupport::trimOrNull).
+ filter(Predicates.notNull()).
+ collect(CollectionSupport.nonnullCollector(Collectors.toSet())).get();
+ }
/**
* Set the credential repository used to store the valid webauthn credential.
@@ -170,7 +222,7 @@ public class YubicoWebauthnClientFactory extends AbstractInitializableComponent
*
* @return the relying party identifier.
*/
- @Nullable private synchronized String getRelyingPartyId() {
+ @NonnullAfterInit private synchronized String getRelyingPartyId() {
return relyingPartyId;
}
@@ -189,7 +241,7 @@ public class YubicoWebauthnClientFactory extends AbstractInitializableComponent
*
* @return the relying party name.
*/
- @Nullable private synchronized String getRelyingPartyName() {
+ @NonnullAfterInit private synchronized String getRelyingPartyName() {
checkComponentActive();
return relyingPartyName;
}
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 272895a..da2fe54 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
@@ -39,6 +39,7 @@
</property>
</bean>
+ <!-- WebAuthn authentication flow -->
<bean id="authn/WebAuthn" parent="shibboleth.AuthenticationFlow"
p:order="%{idp.authn.webauthn.order:1000}"
p:nonBrowserSupported="%{idp.authn.webauthn.nonBrowserSupported:false}"
@@ -89,8 +90,9 @@
class="net.shibboleth.idp.plugin.authn.webauthn.client.impl.YubicoWebauthnClientFactory"
p:relyingPartyId="%{idp.authn.webauthn.relyingPartyId}"
p:relyingPartyName="%{idp.authn.webauthn.relyingPartyName}"
- p:allowOriginPort ="%{idp.authn.webauthn.allowOriginPort:false}"
- p:allowOriginSubdomain ="%{idp.authn.webauthn.allowOriginSubdomain:false}"
+ 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:credentialRepository-ref="shibboleth.authn.webauthn.DefaultCredentialRepository"/>
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 0f5c994..ae6f003 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
@@ -5,7 +5,10 @@ idp.authn.webauthn.relyingPartyId = localhost
idp.authn.webauthn.relyingPartyName = Shibboleth
## Allow any port on that origin
idp.authn.webauthn.allowOriginPort = true
+## Allow any subdomain of that origin
idp.authn.webauthn.allowOriginSubdomain = false
+## An override of origins this RP is allowed to register and authenticate credentials for (must match that returned by the browser during registration or authentication)
+#idp.authn.webauthn.origins = https://localhost
## Which type of flow is supported? Usernameless or passwordless
# idp.authn.webauthn.usernameless.enabled = false
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list