[java-idp-plugin-webauthn] branch main updated: Allow username to passthrough to WebAuthn flow from registration flow
Phil Smart
philip.smart at jisc.ac.uk
Fri Feb 23 17:27: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=b1c6c72b1a078b69fd8b89e6cb0f3661551e69a4
The following commit(s) were added to refs/heads/main by this push:
new b1c6c72 Allow username to passthrough to WebAuthn flow from registration flow
b1c6c72 is described below
commit b1c6c72b1a078b69fd8b89e6cb0f3661551e69a4
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Fri Feb 23 17:27:03 2024 +0000
Allow username to passthrough to WebAuthn flow from registration flow
- If exists, to avoid entering the username twice
---
... => UsernameLookupFromRegistrationContext.java} | 24 +++++++-------
.../navigate/UsernameLookupFromSubjectContext.java | 3 +-
...ava => YubicoWebAuthnAuthenticationClient.java} | 9 ++---
.../client/impl/YubicoWebauthnClientFactory.java | 16 ++++-----
.../storage/impl/InMemoryRegistrationStorage.java | 1 +
.../idp/flows/authn/WebAuthn/webauthn-beans.xml | 7 +++-
.../idp/flows/authn/WebAuthn/webauthn-flow.xml | 2 +-
.../webauthn/views/webauthn-authn-username.vm | 16 ++-------
.../plugin/authn/webauthn/views/webauthn-authn.vm | 38 +++++++++++-----------
.../webauthn/views/webauthn-register-username.vm | 38 +++++++---------------
.../authn/webauthn/views/webauthn-register.vm | 38 +++++++++++-----------
.../YubicoWebauthnAuthenticationClientTest.java | 6 ++--
.../impl/ValidatePublicKeyCredentialTest.java | 11 +++++--
13 files changed, 98 insertions(+), 111 deletions(-)
diff --git a/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/context/navigate/UsernameLookupFromSubjectContext.java b/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/context/navigate/UsernameLookupFromRegistrationContext.java
similarity index 59%
copy from webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/context/navigate/UsernameLookupFromSubjectContext.java
copy to webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/context/navigate/UsernameLookupFromRegistrationContext.java
index effb05b..d390b93 100644
--- a/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/context/navigate/UsernameLookupFromSubjectContext.java
+++ b/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/context/navigate/UsernameLookupFromRegistrationContext.java
@@ -22,17 +22,17 @@ import javax.annotation.Nullable;
import org.opensaml.profile.context.ProfileRequestContext;
import org.slf4j.Logger;
-import net.shibboleth.idp.authn.context.SubjectContext;
+import net.shibboleth.idp.plugin.authn.webauthn.context.WebAuthnRegistrationContext;
import net.shibboleth.shared.primitive.LoggerFactory;
/**
- * Pull out a username from a the {@link SubjectContext#getPrincipalName()} if it exists.
- * Useful when operating inside a WebAuthn registration flow.
+ * Pull out a username from a WebAuthn Registration Context if it exists. Useful when operating inside a WebAuthn
+ * registration flow.
*/
-public class UsernameLookupFromSubjectContext implements Function<ProfileRequestContext, String> {
+public class UsernameLookupFromRegistrationContext implements Function<ProfileRequestContext, String> {
/** Class logger. */
- @Nonnull private final Logger log = LoggerFactory.getLogger(UsernameLookupFromSubjectContext.class);
+ @Nonnull private final Logger log = LoggerFactory.getLogger(UsernameLookupFromRegistrationContext.class);
/** {@inheritDoc} */
@Override
@@ -41,13 +41,15 @@ public class UsernameLookupFromSubjectContext implements Function<ProfileRequest
log.trace("Profile context was null, can not find existing username");
return null;
}
- final SubjectContext subjectContext = input.getSubcontext(SubjectContext.class);
- if (subjectContext == null) {
- log.debug("Subject context was null, can not find existing username");
+ final WebAuthnRegistrationContext registrationContext =
+ input.getSubcontext(WebAuthnRegistrationContext.class);
+ if (registrationContext == null) {
+ log.trace("WebAuthn registration context was null, can not find existing username");
return null;
- }
- final String username = subjectContext.getPrincipalName();
- log.debug("Found existing username '{}' from subject", username);
+ }
+ final String username = registrationContext.getUsername();
+ log.debug("{}", username != null ? "Found existing username from registration context" :
+ "Did not find existing username from registration context");
return username;
}
diff --git a/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/context/navigate/UsernameLookupFromSubjectContext.java b/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/context/navigate/UsernameLookupFromSubjectContext.java
index effb05b..18393ab 100644
--- a/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/context/navigate/UsernameLookupFromSubjectContext.java
+++ b/webauthn-api/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/context/navigate/UsernameLookupFromSubjectContext.java
@@ -26,8 +26,7 @@ import net.shibboleth.idp.authn.context.SubjectContext;
import net.shibboleth.shared.primitive.LoggerFactory;
/**
- * Pull out a username from a the {@link SubjectContext#getPrincipalName()} if it exists.
- * Useful when operating inside a WebAuthn registration flow.
+ * Pull out a username from a the {@link SubjectContext#getPrincipalName()} if it exists.
*/
public class UsernameLookupFromSubjectContext implements Function<ProfileRequestContext, String> {
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
similarity index 97%
rename from webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebauthnAuthenticationClient.java
rename to webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/client/impl/YubicoWebAuthnAuthenticationClient.java
index d0ef7b0..ea934ed 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
@@ -59,10 +59,10 @@ import net.shibboleth.shared.primitive.LoggerFactory;
* <p>Thread-safe, only a single instance is required.</p>
*/
@ThreadSafe
-public class YubicoWebauthnAuthenticationClient implements WebAuthnAuthenticationClient {
+public class YubicoWebAuthnAuthenticationClient implements WebAuthnAuthenticationClient {
/** Class logger.*/
- @Nonnull private final Logger log = LoggerFactory.getLogger(YubicoWebauthnAuthenticationClient.class);
+ @Nonnull private final Logger log = LoggerFactory.getLogger(YubicoWebAuthnAuthenticationClient.class);
/** Information pertaining to the relying party.*/
@Nonnull private final RelyingParty rp;
@@ -71,14 +71,15 @@ public class YubicoWebauthnAuthenticationClient implements WebAuthnAuthenticatio
@Nonnull @NonnullElements @NotLive private final List<PublicKeyCredentialParameters> preferredPublickeyParams;
/**
+ * Package-private Constructor.
*
- * Constructor.
+ * <p>Should only be instantiated by the {@link YubicoWebauthnClientFactory}.</p>
*
* @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,
+ YubicoWebAuthnAuthenticationClient(@Nonnull final RelyingParty relyingParty,
@Nonnull @NonnullElements @NotLive final List<PublicKeyCredentialParameters> publickeyParams) {
rp = Constraint.isNotNull(relyingParty, "The reyling party configuration can not be null");
preferredPublickeyParams = Constraint.isNotNull(publickeyParams, "PreferredPublickeyParams can not be null");
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 fe5065a..5fa6d0c 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
@@ -45,7 +45,7 @@ import net.shibboleth.shared.logic.Constraint;
import net.shibboleth.shared.primitive.StringSupport;
/**
- * Spring factory beans for creating a {@link YubicoWebauthnAuthenticationClient}.
+ * Spring factory beans for creating a {@link YubicoWebAuthnAuthenticationClient}.
*/
@ThreadSafe
public class YubicoWebauthnClientFactory extends AbstractInitializableComponent
@@ -106,8 +106,8 @@ public class YubicoWebauthnClientFactory extends AbstractInitializableComponent
}
@Override
- public WebAuthnAuthenticationClient getObject() throws Exception {
-
+ public WebAuthnAuthenticationClient getObject() throws Exception {
+ checkComponentActive();
// FIXME: There is an issue in the builder here than prevents origins from being set as null
// once that is fixed, we only need one builder statement here.
final var builder = RelyingParty.builder().identity(
@@ -122,11 +122,11 @@ public class YubicoWebauthnClientFactory extends AbstractInitializableComponent
if (!getOrigins().isEmpty()) {
final RelyingParty rp = builder.origins(getOrigins()).build();
assert rp != null;
- return new YubicoWebauthnAuthenticationClient(rp, getPreferredPublickeyParams());
+ return new YubicoWebAuthnAuthenticationClient(rp, getPreferredPublickeyParams());
} else {
final RelyingParty rp = builder.build();
assert rp != null;
- return new YubicoWebauthnAuthenticationClient(rp, getPreferredPublickeyParams());
+ return new YubicoWebAuthnAuthenticationClient(rp, getPreferredPublickeyParams());
}
}
@@ -293,7 +293,7 @@ public class YubicoWebauthnClientFactory extends AbstractInitializableComponent
}
/**
- * Is origin port allowed?
+ * Is origin matching relaxed to allow any port number?
*
* @return allow origin port?
*/
@@ -313,7 +313,7 @@ public class YubicoWebauthnClientFactory extends AbstractInitializableComponent
}
/**
- * Are subdomains allowed?
+ * Is origin matching relaxed to allow any subdomain?
*
* @return allow subdomains?
*/
@@ -323,7 +323,7 @@ public class YubicoWebauthnClientFactory extends AbstractInitializableComponent
}
/**
- * Set if subdomains are allowed.
+ * Set if any subdomain is allowed.
*
* @param allow are subdomains allowed?
*/
diff --git a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/storage/impl/InMemoryRegistrationStorage.java b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/storage/impl/InMemoryRegistrationStorage.java
index 4f44e5e..5a82ec2 100644
--- a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/storage/impl/InMemoryRegistrationStorage.java
+++ b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/storage/impl/InMemoryRegistrationStorage.java
@@ -50,6 +50,7 @@ import net.shibboleth.idp.plugin.authn.webauthn.storage.StorageServiceCredential
/**
* Use {@link IdPStorageServiceCredentialRespository}
*/
+// move to test package
@Deprecated
public class InMemoryRegistrationStorage implements StorageServiceCredentialRepository {
diff --git a/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/WebAuthn/webauthn-beans.xml b/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/WebAuthn/webauthn-beans.xml
index 5a4e552..77c68b6 100644
--- a/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/WebAuthn/webauthn-beans.xml
+++ b/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/WebAuthn/webauthn-beans.xml
@@ -16,7 +16,12 @@
<bean id="PopulateWebAuthnAuthenticationContextPasswordless" scope="prototype"
- class="net.shibboleth.idp.plugin.authn.webauthn.impl.PopulateWebAuthnAuthenticationContext"/>
+ class="net.shibboleth.idp.plugin.authn.webauthn.impl.PopulateWebAuthnAuthenticationContext">
+ <property name="usernameLookupStrategy">
+ <bean id="usernameFromAuthnResult" scope="prototype"
+ class="net.shibboleth.idp.plugin.authn.webauthn.context.navigate.UsernameLookupFromRegistrationContext"/>
+ </property>
+ </bean>
<bean id="PopulateWebAuthnAuthenticationContextUsernameless" scope="prototype"
class="net.shibboleth.idp.plugin.authn.webauthn.impl.PopulateWebAuthnAuthenticationContext"/>
diff --git a/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/WebAuthn/webauthn-flow.xml b/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/WebAuthn/webauthn-flow.xml
index add3992..0fe80d0 100644
--- a/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/WebAuthn/webauthn-flow.xml
+++ b/webauthn-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/WebAuthn/webauthn-flow.xml
@@ -2,7 +2,7 @@
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow.xsd"
parent="authn.abstract, authn/conditions">
- <!-- Test if we are operating as a 2FA -->
+ <!-- Test if we are operating as 2FA -->
<decision-state id="DetermineSecondFactorLogin">
<if test="IsSecondFactor.test(opensamlProfileRequestContext)"
then="SecondFactorLogin"
diff --git a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-authn-username.vm b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-authn-username.vm
index a8f647b..47bd8d6 100644
--- a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-authn-username.vm
+++ b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-authn-username.vm
@@ -7,7 +7,7 @@
## flowExecutionKey - the SWF execution key (this is built into the flowExecutionUrl)
## profileRequestContext - root of context tree
## authenticationContext - context with authentication request information
-## passwordlessContext - context with Duo username and enrollment status
+## webauthnContext - context for WebAuthn authentication
## rpUIContext - the context with SP UI information from the metadata
## encoder - HTMLEncoder class
## cspDigester - Calculates base64-encoded SHA-2 hashes (call apply)
@@ -76,7 +76,7 @@ $response.addHeader("Content-Security-Policy", "script-src-elem 'nonce-$nonce'")
#parse("csrf/csrf.vm")
<label for="username">#springMessageText("idp.login.username", "Username")</label>
- <input id="j_username" name="j_username" type="text" autoComplete="username webauthn"
+ <input id="j_username" name="j_username" type="text" required
value="#if($username)$encoder.encodeForHTML($username)#end" />
<input type="checkbox" name="donotcache" value="1" id="donotcache" />
@@ -104,16 +104,6 @@ $response.addHeader("Content-Security-Policy", "script-src-elem 'nonce-$nonce'")
<div class="cc">
<p>#springMessageText("idp.footer", "Insert your footer text here.")</p>
</div>
- </footer>
-
- <script #if ($nonce)nonce="$nonce"#end>
- <!--
- const input = document.getElementById('j_username');
- const end = input.value.length;
- input.setSelectionRange(end, end);
- input.focus();
- // -->
- </script>
-
+ </footer>
</body>
</html>
\ No newline at end of file
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 5fef529..db58167 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
@@ -28,9 +28,9 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0">
<script type="text/javascript" src="$request.getContextPath()/js/webauthn/webauthn-support.js"></script>
- <link rel="stylesheet" type="text/css" href="$request.getContextPath()#springMessageText("
- idp.css", "/css/placeholder.css" )">
+ <link rel="stylesheet" type="text/css" href="$request.getContextPath()#springMessageText("idp.css", "/css/placeholder.css" )">
<link rel="stylesheet" type="text/css" href="$request.getContextPath()/css/webauthn.css">
+
<script type="module">
import {
get,
@@ -69,8 +69,7 @@
document.getElementById('supportedDiv').classList.add('hidden')
document.getElementById("supportedDiv").disabled = true;
document.getElementById("authenticate").disabled = true;
- document.getElementById("authenticatorAssertionForm").disabled = true;
- document.getElementById("authenticationSubmit").disabled = true;
+ document.getElementById("authenticator_assertion_form").disabled = true;
document.getElementById("unsupportedDiv").disabled = false;
document.getElementById('unsupportedDiv').classList.remove('hidden')
} else {
@@ -90,7 +89,7 @@
idp.logo", "/images/placeholder-logo.png" )" alt="#springMessageText(" idp.logo.alt-text", "logo" )" />
#set ($serviceName = $rpUIContext.serviceName)
#if ($serviceName && !$rpContext.getRelyingPartyId().contains($serviceName))
- <h1>#springMessageText("idp.login.loginTo", "Login to") $encoder.encodeForHTML($serviceName)</h1>
+ <h1>#springMessageText("idp.login.loginTo", "Login to") $encoder.encodeForHTML($serviceName)</h1>
#end
</header>
<section>
@@ -107,16 +106,16 @@
*#
#set ($logo = $rpUIContext.getLogo())
#if ($logo)
- <img class="service-logo" src="$encoder.encodeForHTMLAttribute($logo)"
- alt="$encoder.encodeForHTMLAttribute($serviceName)">
+ <img class="service-logo" src="$encoder.encodeForHTMLAttribute($logo)"
+ alt="$encoder.encodeForHTMLAttribute($serviceName)">
#end
#set ($desc = $rpUIContext.getServiceDescription())
#if ($desc)
- <p>$encoder.encodeForHTML($desc)</p>
+ <p>$encoder.encodeForHTML($desc)</p>
#end
<div id="supportedDiv">
<div class="content">
- <form id="authenticatorAssertionForm" action="$flowExecutionUrl" method="post">
+ <form id="authenticator_assertion_form" action="$flowExecutionUrl" method="post">
#parse("csrf/csrf.vm")
<input type="hidden" id="publicKeyAssertion" name="publicKeyAssertion" />
<button class="hidden" id="authenticationSubmit" type="submit"
@@ -128,18 +127,19 @@
class="form-element form-button">#springMessageText("idp.webauthn.authn.authenticate",
"Login with passkey or security key")</button>
</div>
+
#if($debug == "true")
- <hr />
- <button type="button" class="collapsible">#springMessageText("idp.webauthn.debug.title",
- "Debugging")</button>
- <div class="debug" id="debug-div">
- <label for="publicKeyCredentialCreation">#springMessageText("idp.webauthn.debug.request",
- "Request Options")</label>
- <textarea id="publicKeyCredentialRequestOptions" name="publicKeyCredentialRequestOptions"
- rows="20" cols="50">
- $webauthnContext.publicKeyCredentialRequestOptionsJSON</textarea>
- </div>
+ <hr />
+ <button type="button" class="collapsible">#springMessageText("idp.webauthn.debug.title","Debugging")</button>
+ <div class="debug" id="debug-div">
+ <label for="publicKeyCredentialCreation">#springMessageText("idp.webauthn.debug.request",
+ "Request Options")</label>
+ <textarea id="publicKeyCredentialRequestOptions" name="publicKeyCredentialRequestOptions"
+ rows="20" cols="50">
+ $webauthnContext.publicKeyCredentialRequestOptionsJSON</textarea>
+ </div>
#end
+
</div>
</div>
<div id="unsupportedDiv" class="hidden">
diff --git a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-register-username.vm b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-register-username.vm
index 089db99..1c3519a 100644
--- a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-register-username.vm
+++ b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-register-username.vm
@@ -1,12 +1,12 @@
##
-## Velocity Template for collection of username for Duo Passwordless use
+## Velocity Template for collection of username for WebAuthn registration use
##
## Velocity context will contain the following properties
## flowExecutionUrl - the form action location
## flowRequestContext - the Spring Web Flow RequestContext
## flowExecutionKey - the SWF execution key (this is built into the flowExecutionUrl)
## profileRequestContext - root of context tree
-## rpUIContext - the context with SP UI information from the metadata
+## webauthnRegContext - the WebAuthn registration context
## encoder - HTMLEncoder class
## cspDigester - Calculates base64-encoded SHA-2 hashes (call apply)
## cspNonce - Calculates secure nonces (call generateIdentifier)
@@ -15,17 +15,18 @@
## environment - Spring Environment object for property resolution
## custom - arbitrary object injected by deployer
##
-#set ($rpContext = $profileRequestContext.getSubcontext('net.shibboleth.profile.context.RelyingPartyContext'))
#set ($eventCtx = $profileRequestContext.getSubcontext('org.opensaml.profile.context.EventContext'))
#if ($eventCtx)
#set ($eventId = $eventCtx.getEvent())
#end
#set ($nonce = $cspNonce.generateIdentifier())
+
+### TODO ADD THIS BACK
$response.addHeader("Content-Security-Policy", "script-src-elem 'nonce-$nonce'")
#set ($onClick = "document.forms.password.j_username.value = document.forms.passwordless.j_username.value")
-### TODO ADD THIS BACK
###$response.addHeader("Content-Security-Policy", "script-src-attr 'unsafe-hashes' 'sha256-$cspDigester.apply($onClick)'")
-##
+
+
<!DOCTYPE html>
<html>
<head>
@@ -38,17 +39,11 @@ $response.addHeader("Content-Security-Policy", "script-src-elem 'nonce-$nonce'")
<body onLoad="$onLoad">
<main class="main">
<header>
- <img class="main-logo" src="$request.getContextPath()#springMessageText("idp.logo", "/images/placeholder-logo.png")" alt="#springMessageText("idp.logo.alt-text", "logo")" />
-
-
- </header>
-
- <section>
-
+ <img class="main-logo" src="$request.getContextPath()#springMessageText("idp.logo", "/images/placeholder-logo.png")" alt="#springMessageText("idp.logo.alt-text", "logo")" />
+ </header>
+ <section>
<blockquote>#springMessageText("idp.webauthn.register.username.explain", "Please enter your username below and press the corresponding button.")</blockquote>
-
-
#if ($eventId == "RequestUnsupported")
<p class="output-message output--error">$encoder.encodeForHTML("#springMessageText('idp.duo.passwordless.unsupported', 'You have not enrolled a qualifying device for Passwordless use.')")</p>
#end
@@ -57,13 +52,12 @@ $response.addHeader("Content-Security-Policy", "script-src-elem 'nonce-$nonce'")
#parse("csrf/csrf.vm")
<label for="username">#springMessageText("idp.login.username", "Username")</label>
- <input id="j_username" name="j_username" type="text" autoComplete="username webauthn"
+ <input id="j_username" name="j_username" type="text" required
value="#if($username)$encoder.encodeForHTML($username)#end" />
<input type="checkbox" name="donotcache" value="1" id="donotcache" />
<label for="donotcache">#springMessageText("idp.login.donotcache", "Don't Remember Login")</label>
-
<div class="grid">
<div class="grid-item">
<button type="submit" name="_eventId_proceed"
@@ -81,16 +75,6 @@ $response.addHeader("Content-Security-Policy", "script-src-elem 'nonce-$nonce'")
<div class="cc">
<p>#springMessageText("idp.footer", "Insert your footer text here.")</p>
</div>
- </footer>
-
- <script #if ($nonce)nonce="$nonce"#end>
- <!--
- const input = document.getElementById('j_username');
- const end = input.value.length;
- input.setSelectionRange(end, end);
- input.focus();
- // -->
- </script>
-
+ </footer>
</body>
</html>
\ No newline at end of file
diff --git a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-register.vm b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-register.vm
index 06b96e0..e4f9693 100644
--- a/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-register.vm
+++ b/webauthn-impl/src/main/resources/net/shibboleth/idp/plugin/authn/webauthn/views/webauthn-register.vm
@@ -60,24 +60,24 @@
}
window.addEventListener("load", () => {
- try {
- var isSupported = supported();
- if (!isSupported){
- document.getElementById('supportedDiv').classList.add('hidden')
- document.getElementById("supportedDiv").disabled = true;
- document.getElementById("authenticatorAttestationForm").disabled = true;
- document.getElementById("registrationSubmit").disabled = true;
-
- document.getElementById("unsupportedDiv").disabled = false;
- document.getElementById('unsupportedDiv').classList.remove('hidden')
- } else{
- initButton();
- }
-
- } catch (e) {
- console.error(e);
- }
- });
+ try {
+ var isSupported = supported();
+ if (!isSupported){
+ document.getElementById('supportedDiv').classList.add('hidden')
+ document.getElementById("supportedDiv").disabled = true;
+ document.getElementById("authenticatorAttestationForm").disabled = true;
+ document.getElementById("registrationSubmit").disabled = true;
+
+ document.getElementById("unsupportedDiv").disabled = false;
+ document.getElementById('unsupportedDiv').classList.remove('hidden')
+ } else{
+ initButton();
+ }
+
+ } catch (e) {
+ console.error(e);
+ }
+ });
</script>
</head>
<body>
@@ -110,7 +110,7 @@
<td>$encoder.encodeForHTML($webAuthnEncoder.formatDiscoverable($cred.isDiscoverable()))</td>
<td>$encoder.encodeForHTML($webAuthnEncoder.formatInstant($cred.registrationTime))</td>
<td>
- <form id="deleteKeyForm" action="$flowExecutionUrl" method="post">
+ <form id="delete_key_form" action="$flowExecutionUrl" method="post">
#parse("csrf/csrf.vm")
<input type="hidden" name="credentialId" value="$cred.credentialIdBase64Url"/>
<button class="webauthn-table-button" onclick="return confirm('#springMessageText("idp.webauthn.register.credential.remove.confirm", "Are you sure")');" id="removeButton" type="submit" name="_eventId_deleteKey">#springMessageText("idp.webauthn.register.credential.remove", "Remove")</button>
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 90ecdd2..e86adf0 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
@@ -51,14 +51,14 @@ import net.shibboleth.idp.plugin.authn.webauthn.storage.impl.InMemoryRegistratio
import net.shibboleth.shared.codec.Base64Support;
/**
- * Tests for {@link YubicoWebauthnAuthenticationClient}. To some extend this is testing the Yubico libraries work
+ * Tests for {@link YubicoWebAuthnAuthenticationClient}. To some extend this is testing the Yubico libraries work
* correctly. But it does ensure the client has been constructed to use those libraries correctly.
*/
public class YubicoWebauthnAuthenticationClientTest extends AbstractWebAuthnTest {
private final static String CHALLENGE_2_B64 = "8gneM8yvE20CqnSCUkyD";
- private YubicoWebauthnAuthenticationClient client;
+ private YubicoWebAuthnAuthenticationClient client;
private PublicKeyCredentialCreationOptions credentialCreationOptions;
@@ -85,7 +85,7 @@ public class YubicoWebauthnAuthenticationClientTest extends AbstractWebAuthnTest
.allowOriginPort(true)
.allowOriginSubdomain(true)
.build();
- client = new YubicoWebauthnAuthenticationClient(rp, preferredPublickeyParams);
+ 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/impl/ValidatePublicKeyCredentialTest.java b/webauthn-impl/src/test/java/net/shibboleth/idp/plugin/authn/webauthn/impl/ValidatePublicKeyCredentialTest.java
index 8561019..3770d93 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
@@ -27,7 +27,7 @@ import com.yubico.webauthn.data.UserIdentity;
import net.shibboleth.idp.plugin.authn.webauthn.admin.impl.ValidateAuthenticatorAttestationResponse;
import net.shibboleth.idp.plugin.authn.webauthn.client.WebAuthnAuthenticationClient;
-import net.shibboleth.idp.plugin.authn.webauthn.client.impl.YubicoWebauthnAuthenticationClient;
+import net.shibboleth.idp.plugin.authn.webauthn.client.impl.YubicoWebauthnClientFactory;
import net.shibboleth.idp.plugin.authn.webauthn.storage.impl.InMemoryRegistrationStorage;
import net.shibboleth.shared.codec.Base64Support;
@@ -73,8 +73,13 @@ public class ValidatePublicKeyCredentialTest extends AbstractWebAuthnTest{
.timeout(Optional.empty()).build();
webAuthnRegContext.setPublicKeyCredentialCreationOptions(credentialCreationOptions);
-
- final WebAuthnAuthenticationClient client = new YubicoWebauthnAuthenticationClient(rp, preferredPublickeyParams);
+ final YubicoWebauthnClientFactory factory = new YubicoWebauthnClientFactory();
+ factory.setPreferredPublickeyParams(preferredPublickeyParams.stream().map(alg -> alg.getAlg().name()).toList());
+ factory.setCredentialRepository(new InMemoryRegistrationStorage());
+ factory.setRelyingPartyId("idp.example.com");
+ factory.setRelyingPartyName("Demo IdP as a WebAuthn RP");
+ factory.initialize();
+ final WebAuthnAuthenticationClient client = factory.getObject();
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