[java-idp-plugin-webauthn] branch main updated: JWEBAUTHN-69 - Add donotcache directive to WebAuthn view

Phil Smart philip.smart at jisc.ac.uk
Wed Oct 29 16:47:40 UTC 2025


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:
https://git.shibboleth.net/view/?p=java-idp-plugin-webauthn.git;a=commit;h=ff3fd9d931606ed7986692b83f847f63e5fa210f

The following commit(s) were added to refs/heads/main by this push:
     new ff3fd9d  JWEBAUTHN-69 - Add donotcache directive to WebAuthn view
ff3fd9d is described below

commit ff3fd9d931606ed7986692b83f847f63e5fa210f
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Wed Oct 29 16:47:38 2025 +0000

    JWEBAUTHN-69 - Add donotcache directive to WebAuthn view
    
     - Add 'Don't Remember Login' input to the webauthn view
     - Add logic to extract the donotcache instruction from the 'Don't
    Remember Login' input
     - Add a velocity directive to preselect the 'Don't Remember Login'
    checkbox to the default view template
     - Add property options to control the names of the input fields
    
    https://shibboleth.atlassian.net/browse/JWEBAUTHN-69
---
 ...ublicKeyCredentialAssertionFromFormRequest.java | 43 +++++++++++++++++++++-
 .../idp/flows/authn/WebAuthn/webauthn-beans.xml    |  6 ++-
 .../authn/webauthn/conf/authn/webauthn.properties  |  5 +++
 .../plugin/authn/webauthn/views/webauthn-authn.vm  |  4 ++
 4 files changed, 55 insertions(+), 3 deletions(-)

diff --git a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/impl/ExtractPublicKeyCredentialAssertionFromFormRequest.java b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/impl/ExtractPublicKeyCredentialAssertionFromFormRequest.java
index cf71e64..4b01ce1 100644
--- a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/impl/ExtractPublicKeyCredentialAssertionFromFormRequest.java
+++ b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/impl/ExtractPublicKeyCredentialAssertionFromFormRequest.java
@@ -17,6 +17,7 @@ package net.shibboleth.idp.plugin.authn.webauthn.impl;
 import java.io.IOException;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import org.opensaml.messaging.context.navigate.ChildContextLookup;
 import org.opensaml.profile.action.ActionSupport;
@@ -42,7 +43,7 @@ import net.shibboleth.shared.primitive.StringSupport;
 
 /**
  * An action that extracts the PublicKeyCredential containing the authenticator assertion response from the 
- * incoming HTTP request.
+ * incoming HTTP request. Also processes the do-not-cache instruction for SSO bypass.
  * 
  * @event {@link AuthnEventIds#NO_CREDENTIALS}
  * @pre <pre>ProfileRequestContext.getSubcontext(WebAuthnAuthenticationContext.class) != null</pre>
@@ -60,6 +61,9 @@ public class ExtractPublicKeyCredentialAssertionFromFormRequest
     
     /** Name of public key credential with the assertion response parameter. */
     @NonnullAfterInit @NotEmpty private String publicKeyCredentialAssertionParameterName;
+    
+    /** Parameter name for SSO bypass. */
+    @Nonnull @NotEmpty private String ssoBypassFieldName;
 
     /** JSON object mapper. */
     @NonnullAfterInit private ObjectMapper objectMapper;
@@ -68,6 +72,7 @@ public class ExtractPublicKeyCredentialAssertionFromFormRequest
     public ExtractPublicKeyCredentialAssertionFromFormRequest() {
         super(new ChildContextLookup<>(WebAuthnAuthenticationContext.class).
                 compose(new ChildContextLookup<>(AuthenticationContext.class)));
+        ssoBypassFieldName = "donotcache";
         publicKeyCredentialAssertionParameterName = DEFAULT_PARAMETER_NAME;
     }
     
@@ -90,6 +95,18 @@ public class ExtractPublicKeyCredentialAssertionFromFormRequest
         objectMapper = Constraint.isNotNull(mapper, "Object mapper cannot be null");
     }
     
+    /**
+     * Set the SSO bypass parameter name.
+     * 
+     * @param fieldName the SSO bypass parameter name
+     */
+    public void setSSOBypassFieldName(@Nonnull @NotEmpty final String fieldName) {
+        checkSetterPreconditions();
+        
+        ssoBypassFieldName = Constraint.isNotNull(
+                StringSupport.trimOrNull(fieldName), "SSO Bypass field name cannot be null or empty.");
+    }
+    
     /**
      * Set the name of the public key credential assertion parameter to extract.
      * 
@@ -111,7 +128,9 @@ public class ExtractPublicKeyCredentialAssertionFromFormRequest
             log.debug("{} Profile action does not contain an HttpServletRequest", getLogPrefix());
             ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.NO_CREDENTIALS);
             return;
-        }
+        }        
+        
+        processDoNotCacheInstruction(profileRequestContext, request);
 
         final String pkCredAssertionJson = request.getParameter(publicKeyCredentialAssertionParameterName);       
         if (pkCredAssertionJson == null) {
@@ -134,4 +153,24 @@ public class ExtractPublicKeyCredentialAssertionFromFormRequest
 
     }
     
+    /**
+     * Process the do-not-cache instruction.
+     * 
+     * @param authenticationContext authentication context
+     * @param request current HTTP servlet request
+     */
+    private void processDoNotCacheInstruction(@Nonnull final ProfileRequestContext profileRequestContext,
+            @Nullable final HttpServletRequest request) {
+        final AuthenticationContext authnContext = profileRequestContext.ensureSubcontext(AuthenticationContext.class);
+        if (request != null) {
+            final String donotcache = request.getParameter(ssoBypassFieldName);
+            if (donotcache != null && "1".equals(donotcache)) {
+                log.debug("{} Recording do-not-cache instruction in authentication context", getLogPrefix());
+                authnContext.setResultCacheable(false);
+            } else {
+                authnContext.setResultCacheable(true);
+            }                      
+        }        
+    }
+    
 }
\ No newline at end of file
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 562d9f7..bcbfdc1 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
@@ -89,6 +89,8 @@
         class="net.shibboleth.idp.plugin.authn.webauthn.impl.ExtractUsernameFromForm"
         p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier"
         p:webAuthnContextLookupStrategy-ref="shibboleth.ChildLookup.WebAuthnAuthenticationContextFromAuthenticationContext"
+        p:usernameFieldName="#{getObject('shibboleth.authn.WebAuthn.UsernameFieldName') ?: '%{idp.authn.webauthn.usernameFieldName:j_username}'.trim()}"
+        p:SSOBypassFieldName="#{getObject('shibboleth.authn.WebAuthn.SSOBypassFieldName') ?: '%{idp.authn.webauthn.ssoBypassFieldName:donotcache}'.trim()}"
         p:uppercase="%{idp.authn.webauthn.passwordless.username.uppercase:false}"
         p:lowercase="%{idp.authn.webauthn.passwordless.username.lowercase:false}"
         p:trim="%{idp.authn.webauthn.passwordless.username.trim:false}"
@@ -157,7 +159,9 @@
     <bean id="ExtractPublicKeyCredentialAssertionFromFormRequest" scope="prototype" parent="AbstractWebAuthnAuthenticationAction"
         class="net.shibboleth.idp.plugin.authn.webauthn.impl.ExtractPublicKeyCredentialAssertionFromFormRequest"
         p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier"
-        p:objectMapper-ref="shibboleth.authn.WebAuthn.JSONObjectMapper" />
+        p:objectMapper-ref="shibboleth.authn.WebAuthn.JSONObjectMapper"
+        p:publicKeyCredentialAssertionParameterName="#{getObject('shibboleth.authn.WebAuthn.PublicKeyCredentialAssertionFieldName') ?: '%{idp.authn.webauthn.publicKeyCredentialAssertionFieldName:publicKeyCredential}'.trim()}"
+        p:SSOBypassFieldName="#{getObject('shibboleth.authn.WebAuthn.SSOBypassFieldName') ?: '%{idp.authn.webauthn.ssoBypassFieldName:donotcache}'.trim()}" />
         
     <bean id="LookupRegisteredCredentialsFromUserHandle" scope="prototype" parent="AbstractWebAuthnAuthenticationAction"
         class="net.shibboleth.idp.plugin.authn.webauthn.impl.LookupRegisteredCredentialsFromUserHandle"
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 c2787ca..2448f8f 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
@@ -77,6 +77,11 @@ idp.authn.webauthn.supportedPrincipals = \
 #idp.authn.webauthn.passwordless.username.lowercase = false
 #idp.authn.webauthn.passwordless.username.trim = false
 
+# Field name settings for various input views
+#idp.authn.webauthn.ssoBypassFieldName = donotcache
+#idp.authn.webauthn.usernameFieldName = j_username
+#idp.authn.webauthn.publicKeyCredentialAssertionFieldName = publicKeyCredential
+
 # The ID of the bean that supplies the c14n flows that are applied to the username entered during the passwordless flow
 #idp.authn.webauthn.passwordless.c14n.postUsernameFlows = shibboleth.PostLoginSubjectCanonicalizationFlows
 
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 5daff80..15ea732 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
@@ -133,6 +133,10 @@ $response.addHeader("Content-Security-Policy", "default-src 'none'; style-src 's
                             <button class="hidden" id="authenticationSubmit" type="submit"
                                 name="_eventId_proceed">#springMessageText("idp.webauthn.authn.submit", "Submit
                             authentication")</button>
+                            
+                            <input type="checkbox" name="donotcache" value="1" id="donotcache" #if($!authenticationContext.isResultCacheable()==false)checked#end/>
+                            <label for="donotcache">#springMessageText("idp.login.donotcache", "Don't Remember Login")</label>
+                            
                             <input id="_shib_idp_revokeConsent" type="checkbox" name="_shib_idp_revokeConsent" value="true" #if($revokeConsent)checked#end/>
                             <label for="_shib_idp_revokeConsent">#springMessageText("idp.attribute-release.revoke", "Clear prior granting of permission for release of your information to this service.")</label>
                         </form>

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


More information about the commits mailing list