[java-identity-provider] branch main updated: IDP-2286 - Add equivalent of PasswordlessCookieManager from Duo plugin
Scott Cantor
cantor.2 at osu.edu
Tue Mar 25 18:47:09 UTC 2025
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch main
in repository java-identity-provider.
View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=fb4aebcad09fefeda68d2680418188fb4aa9ed84
The following commit(s) were added to refs/heads/main by this push:
new fb4aebcad IDP-2286 - Add equivalent of PasswordlessCookieManager from Duo plugin
fb4aebcad is described below
commit fb4aebcad09fefeda68d2680418188fb4aa9ed84
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue Mar 25 14:47:06 2025 -0400
IDP-2286 - Add equivalent of PasswordlessCookieManager from Duo plugin
https://shibboleth.atlassian.net/browse/IDP-2286
Added utility bean for managing cached username.
Converted original Password code to use new utility bean.
---
.../idp/authn/impl/PrePopulateUsername.java | 57 ++----------------
.../idp/authn/impl/ValidateCredentials.java | 70 ++++------------------
.../net/shibboleth/idp/conf/global-system.xml | 10 ++++
.../idp/flows/authn/password-authn-beans.xml | 8 +--
.../idp/module/conf/authn/authn.properties | 2 +-
.../idp/module/conf/authn/authn.properties | 5 ++
6 files changed, 33 insertions(+), 119 deletions(-)
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/PrePopulateUsername.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/PrePopulateUsername.java
index 7e735cf38..da7d260f7 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/PrePopulateUsername.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/PrePopulateUsername.java
@@ -36,12 +36,9 @@ import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
import net.shibboleth.shared.annotation.constraint.NotEmpty;
import net.shibboleth.shared.collection.CollectionSupport;
import net.shibboleth.shared.logic.Constraint;
-import net.shibboleth.shared.net.CookieManager;
-import net.shibboleth.shared.net.URISupport;
import net.shibboleth.shared.primitive.LoggerFactory;
import net.shibboleth.shared.primitive.StringSupport;
-import net.shibboleth.shared.security.DataSealer;
-import net.shibboleth.shared.security.DataSealerException;
+import net.shibboleth.shared.security.EncryptedCookieManager;
/**
* An action to populate a username into a cleared {@link UsernamePasswordContext}, either from a form
@@ -65,15 +62,9 @@ public class PrePopulateUsername extends AbstractExtractionAction {
/** Form parameter name to carry username. */
@Nonnull @NotEmpty private String usernameFieldName;
-
- /** Username cookie name. */
- @Nullable @NotEmpty private String cookieName;
/** Optional cookie manager to use. */
- @Nullable private CookieManager cookieManager;
-
- /** Optional data sealer to use. */
- @Nullable private DataSealer dataSealer;
+ @Nullable private EncryptedCookieManager cookieManager;
/** Order to pull username from. */
@Nonnull private List<String> precedence;
@@ -117,37 +108,15 @@ public class PrePopulateUsername extends AbstractExtractionAction {
}
/**
- * Set cookie name to use for cached username.
- *
- * @param name cookie name
- */
- public void setCookieName(@Nullable final String name) {
- checkSetterPreconditions();
-
- cookieName = StringSupport.trimOrNull(name);
- }
-
- /**
- * Sets optional {@link CookieManager} to use.
+ * Sets optional {@link EncryptedCookieManager} to use.
*
* @param manager cookie manager
*/
- public void setCookieManager(@Nullable final CookieManager manager) {
+ public void setEncryptedCookieManager(@Nullable final EncryptedCookieManager manager) {
checkSetterPreconditions();
cookieManager = manager;
}
-
- /**
- * Sets optional {@link DataSealer} to use.
- *
- * @param sealer data sealer
- */
- public void setDataSealer(@Nullable final DataSealer sealer) {
- checkSetterPreconditions();
-
- dataSealer = sealer;
- }
/**
* Sets the precedence rules to use in populating the username.
@@ -258,23 +227,7 @@ public class PrePopulateUsername extends AbstractExtractionAction {
* @return username from existing sealed cookie, or null
*/
@Nullable private String getUsernameFromCookie(@Nonnull final ProfileRequestContext profileRequestContext) {
-
- if (cookieManager != null && dataSealer != null && cookieName != null) {
- final String cookie = URISupport.doURLDecode(cookieManager.getCookieValue(cookieName, null));
- if (cookie != null) {
- try {
- assert dataSealer != null;
- return dataSealer.unwrap(cookie);
- } catch (final DataSealerException e) {
- log.warn("{} Unable to unwrap sealed username cookie", getLogPrefix(), e);
- assert cookieName != null;
- assert cookieManager != null;
- cookieManager.unsetCookie(cookieName);
- }
- }
- }
-
- return null;
+ return cookieManager != null ? cookieManager.readCookie() : null;
}
/**
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateCredentials.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateCredentials.java
index 9bd6d9866..9fb222720 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateCredentials.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateCredentials.java
@@ -29,8 +29,6 @@ import org.opensaml.profile.action.EventIds;
import org.opensaml.profile.context.ProfileRequestContext;
import org.slf4j.Logger;
-import com.google.common.net.UrlEscapers;
-
import net.shibboleth.idp.authn.AccountLockoutManager;
import net.shibboleth.idp.authn.AuthenticationResult;
import net.shibboleth.idp.authn.AuthnAuditFields;
@@ -44,11 +42,8 @@ import net.shibboleth.shared.annotation.constraint.NotEmpty;
import net.shibboleth.shared.annotation.constraint.NotLive;
import net.shibboleth.shared.annotation.constraint.Unmodifiable;
import net.shibboleth.shared.collection.CollectionSupport;
-import net.shibboleth.shared.net.CookieManager;
import net.shibboleth.shared.primitive.LoggerFactory;
-import net.shibboleth.shared.primitive.StringSupport;
-import net.shibboleth.shared.security.DataSealer;
-import net.shibboleth.shared.security.DataSealerException;
+import net.shibboleth.shared.security.EncryptedCookieManager;
/**
* An action that processes a list of {@link CredentialValidator} objects to produce an {@link AuthenticationResult}.
@@ -289,53 +284,21 @@ public class ValidateCredentials extends AbstractAuditingValidationAction implem
* @since 4.1.0
*/
public static class UsernamePasswordCleanupHook implements Consumer<ProfileRequestContext> {
-
- /** Class logger. */
- @Nonnull private final Logger log = LoggerFactory.getLogger(UsernamePasswordCleanupHook.class);
- /** Username cookie name. */
- @Nullable @NotEmpty private String cookieName;
-
/** Optional cookie manager to use. */
- @Nullable private CookieManager cookieManager;
-
- /** Optional data sealer to use. */
- @Nullable private DataSealer dataSealer;
-
- /**
- * Set cookie name to use for cached username.
- *
- * @param name cookie name
- *
- * @since 5.1.0
- */
- public void setCookieName(@Nullable final String name) {
- cookieName = StringSupport.trimOrNull(name);
- }
+ @Nullable private EncryptedCookieManager cookieManager;
/**
- * Sets optional {@link CookieManager} to use.
+ * Sets optional {@link EncryptedCookieManager} to use.
*
* @param manager cookie manager
*
- * @since 5.1.0
+ * @since 5.2.0
*/
- public void setCookieManager(@Nullable final CookieManager manager) {
+ public void setEncryptedCookieManager(@Nullable final EncryptedCookieManager manager) {
cookieManager = manager;
}
-
- /**
- * Sets optional {@link DataSealer} to use.
- *
- * @param sealer data sealer
- *
- * @since 5.1.0
- */
- public void setDataSealer(@Nullable final DataSealer sealer) {
- dataSealer = sealer;
- }
-// Checkstyle: CyclomaticComplexity OFF
/** {@inheritDoc} */
public void accept(@Nullable final ProfileRequestContext input) {
@@ -350,31 +313,18 @@ public class ValidateCredentials extends AbstractAuditingValidationAction implem
return;
}
- final String localCookieName = cookieName;
if (authnCtx.isResultCacheable()) {
- if (cookieManager != null && dataSealer != null && localCookieName != null) {
- String wrapped = upCtx.getUsername();
- if (wrapped != null) {
- try {
- assert dataSealer != null;
- wrapped = dataSealer.wrap(wrapped);
- assert cookieManager != null;
- cookieManager.addCookie(localCookieName,
- UrlEscapers.urlFormParameterEscaper().escape(wrapped));
- } catch (final DataSealerException e) {
- wrapped = null;
- log.warn("Error sealing username cookie", e);
- }
- }
+ final String username = upCtx.getUsername();
+ if (cookieManager != null && username != null) {
+ cookieManager.writeCookie(username);
}
- } else if (cookieManager != null && localCookieName != null) {
- cookieManager.unsetCookie(localCookieName);
+ } else if (cookieManager != null) {
+ cookieManager.clearCookie();
}
upCtx.setPassword(null);
authnCtx.removeSubcontext(upCtx);
}
}
-// Checkstyle: CyclomaticComplexity ON
}
\ No newline at end of file
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/global-system.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/global-system.xml
index 90dc1c19b..bcf526d91 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/global-system.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/global-system.xml
@@ -363,6 +363,16 @@
p:cookiePath="%{idp.cookie.path:/}"
p:maxAge="%{idp.cookie.maxAge:31536000}" />
+ <!--
+ Helper for caching username in cookie in authn flows. This is global for optional use by deployers in custom logic.
+ -->
+ <bean id="shibboleth.authn.UsernameCookieManager" lazy-init="true"
+ class="net.shibboleth.shared.security.EncryptedCookieManager"
+ p:dataSealer="#{'%{idp.authn.usernameCookieName:}'.trim().isEmpty() ? null : getObject('shibboleth.DataSealer')}"
+ p:cookieManager-ref="shibboleth.PersistentCookieManager"
+ p:cookieName="%{idp.authn.usernameCookieName:}" />
+
+
<bean id="shibboleth.StorageService" lazy-init="true"
class="%{idp.storage.StorageService:org.opensaml.storage.impl.MemoryStorageService}"
p:cleanupInterval="%{idp.storage.cleanupInterval:PT10M}" />
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/password-authn-beans.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/password-authn-beans.xml
index eb489d61f..e95d683c4 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/password-authn-beans.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/password-authn-beans.xml
@@ -52,9 +52,7 @@
<bean id="PrePopulateUsername"
class="net.shibboleth.idp.authn.impl.PrePopulateUsername" scope="prototype"
p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier"
- p:dataSealer="#{'%{idp.authn.usernameCookieName:}'.trim().isEmpty() ? null : getObject('shibboleth.DataSealer')}"
- p:cookieManager="#{'%{idp.authn.usernameCookieName:}'.trim().isEmpty() ? null : getObject('shibboleth.PersistentCookieManager')}"
- p:cookieName="%{idp.authn.usernameCookieName:}"
+ p:encryptedCookieManager="#{'%{idp.authn.usernameCookieName:}'.trim().isEmpty() ? null : getObject('shibboleth.authn.UsernameCookieManager')}"
p:usernameFieldName="#{getObject('shibboleth.authn.Password.UsernameFieldName') ?: '%{idp.authn.Password.usernameFieldName:j_username}'.trim()}">
<property name="precedence">
<bean parent="shibboleth.CommaDelimStringArray"
@@ -78,9 +76,7 @@
p:usableFlows-ref="UsableC14NFlows" />
<bean id="DefaultCleanupHook" class="net.shibboleth.idp.authn.impl.ValidateCredentials.UsernamePasswordCleanupHook"
- p:dataSealer="#{'%{idp.authn.usernameCookieName:}'.trim().isEmpty() ? null : getObject('shibboleth.DataSealer')}"
- p:cookieManager="#{'%{idp.authn.usernameCookieName:}'.trim().isEmpty() ? null : getObject('shibboleth.PersistentCookieManager')}"
- p:cookieName="%{idp.authn.usernameCookieName:}" />
+ p:encryptedCookieManager="#{'%{idp.authn.usernameCookieName:}'.trim().isEmpty() ? null : getObject('shibboleth.authn.UsernameCookieManager')}" />
<!-- New action bean that uses CredentialValidator chains. -->
<bean id="ValidateCredentials"
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/authn/authn.properties b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/authn/authn.properties
index 3d412208c..018ed29f6 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/authn/authn.properties
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/authn/authn.properties
@@ -27,7 +27,7 @@
# Login flow audit logging (defaults false for log compatibility)
#idp.authn.audit.enabled = false
-# Uncomment to cache username in cookie (e.g. __Host-shib_idp_username)
+# Set this to cache username in cookie (e.g. __Host-shib_idp_username)
#idp.authn.usernameCookieName =
# Precedence for pulling existing username into authentication forms
#idp.authn.usernamePrecedence = form,session,cookie
diff --git a/idp-conf-impl/src/test/resources/net/shibboleth/idp/module/conf/authn/authn.properties b/idp-conf-impl/src/test/resources/net/shibboleth/idp/module/conf/authn/authn.properties
index 54b659f84..ee5511223 100644
--- a/idp-conf-impl/src/test/resources/net/shibboleth/idp/module/conf/authn/authn.properties
+++ b/idp-conf-impl/src/test/resources/net/shibboleth/idp/module/conf/authn/authn.properties
@@ -27,6 +27,11 @@
# Login flow audit logging (defaults false for log compatibility)
idp.authn.audit.enabled = true
+# Set this to cache username in cookie (e.g. __Host-shib_idp_username)
+idp.authn.usernameCookieName = __Host-shib_idp_username
+# Precedence for pulling existing username into authentication forms
+#idp.authn.usernamePrecedence = form,session,cookie
+
# Revocation (administrative logout)
#idp.authn.revocation = false
#idp.authn.revocation.lifetime = %{idp.authn.defaultAuthnLifetime:PT12H}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list