You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shiro.apache.org by lp...@apache.org on 2026/04/30 15:48:43 UTC
(shiro) 01/02: enh: rememberMe cookie options
This is an automated email from the ASF dual-hosted git repository.
lprimak pushed a commit to branch 3.x
in repository https://gitbox.apache.org/repos/asf/shiro.git
commit 4cf109fc916dcc765ee8ed1f95931726e174fd4c
Author: lprimak <le...@flowlogix.com>
AuthorDate: Thu Apr 30 09:30:17 2026 -0500
enh: rememberMe cookie options
---
.../shiro/ee/filters/FormResubmitSupport.java | 9 +-----
.../org/apache/shiro/ee/filters/SslFilter.java | 2 +-
.../ee/listeners/EnvironmentLoaderListener.java | 15 ++++++++--
.../apache/shiro/ee/listeners/IniEnvironment.java | 9 ++++++
.../web/config/AbstractShiroWebConfiguration.java | 4 +--
.../shiro/web/mgt/CookieRememberMeManager.java | 32 ++++++++++++++++++++++
6 files changed, 58 insertions(+), 13 deletions(-)
diff --git a/support/jakarta-ee/src/main/java/org/apache/shiro/ee/filters/FormResubmitSupport.java b/support/jakarta-ee/src/main/java/org/apache/shiro/ee/filters/FormResubmitSupport.java
index 049f84d12..f4ef06964 100644
--- a/support/jakarta-ee/src/main/java/org/apache/shiro/ee/filters/FormResubmitSupport.java
+++ b/support/jakarta-ee/src/main/java/org/apache/shiro/ee/filters/FormResubmitSupport.java
@@ -52,6 +52,7 @@ import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.UUID;
import static java.util.function.Predicate.not;
+import static org.apache.shiro.ee.listeners.IniEnvironment.hasFacesContext;
import static org.apache.shiro.web.mgt.CookieRememberMeManager.DEFAULT_REMEMBER_ME_COOKIE_NAME;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -353,14 +354,6 @@ public class FormResubmitSupport {
}
}
- static boolean hasFacesContext() {
- try {
- return Faces.hasContext();
- } catch (Throwable e) {
- return false;
- }
- }
-
static boolean isLoginUrl(HttpServletRequest request) {
String loginUrl = (String) request.getAttribute(LOGIN_URL_ATTR_NAME);
return loginUrl != null && request.getRequestURI().equals(request.getContextPath() + loginUrl);
diff --git a/support/jakarta-ee/src/main/java/org/apache/shiro/ee/filters/SslFilter.java b/support/jakarta-ee/src/main/java/org/apache/shiro/ee/filters/SslFilter.java
index ac8abe002..b10321056 100644
--- a/support/jakarta-ee/src/main/java/org/apache/shiro/ee/filters/SslFilter.java
+++ b/support/jakarta-ee/src/main/java/org/apache/shiro/ee/filters/SslFilter.java
@@ -13,7 +13,7 @@
*/
package org.apache.shiro.ee.filters;
-import static org.apache.shiro.ee.filters.FormResubmitSupport.hasFacesContext;
+import static org.apache.shiro.ee.listeners.IniEnvironment.hasFacesContext;
import java.io.IOException;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
diff --git a/support/jakarta-ee/src/main/java/org/apache/shiro/ee/listeners/EnvironmentLoaderListener.java b/support/jakarta-ee/src/main/java/org/apache/shiro/ee/listeners/EnvironmentLoaderListener.java
index 764971d5e..d16169245 100644
--- a/support/jakarta-ee/src/main/java/org/apache/shiro/ee/listeners/EnvironmentLoaderListener.java
+++ b/support/jakarta-ee/src/main/java/org/apache/shiro/ee/listeners/EnvironmentLoaderListener.java
@@ -24,8 +24,13 @@ import jakarta.servlet.ServletContextListener;
import jakarta.servlet.SessionTrackingMode;
import jakarta.servlet.annotation.WebListener;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.web.env.EnvironmentLoader;
import org.apache.shiro.web.env.WebEnvironment;
+import org.apache.shiro.web.mgt.CookieRememberMeManager;
+import org.omnifaces.util.Faces;
+import static org.apache.shiro.ee.listeners.IniEnvironment.hasFacesContext;
/**
* Automatic, adds ability to disable via system property
@@ -74,7 +79,7 @@ public class EnvironmentLoaderListener extends EnvironmentLoader implements Serv
}
@Override
- @SuppressWarnings("checkstyle:NPathComplexity")
+ @SuppressWarnings({"checkstyle:NPathComplexity", "checkstyle:CyclomaticComplexity"})
public void contextInitialized(ServletContextEvent sce) {
if (Boolean.parseBoolean(sce.getServletContext().getInitParameter(SHIRO_EE_DISABLED_PARAM))) {
sce.getServletContext().setAttribute(SHIRO_EE_DISABLED_PARAM, Boolean.TRUE);
@@ -108,7 +113,13 @@ public class EnvironmentLoaderListener extends EnvironmentLoader implements Serv
modifySessionTrackingConfiguration(sce);
}
- initEnvironment(sce.getServletContext());
+ WebEnvironment environment = initEnvironment(sce.getServletContext());
+ if (hasFacesContext() && Faces.isDevelopment()
+ && SecurityUtils.unwrapSecurityManager(environment.getWebSecurityManager(), DefaultSecurityManager.class)
+ .getRememberMeManager() instanceof CookieRememberMeManager rememberMeManager
+ && !rememberMeManager.isSecureInDevMode()) {
+ rememberMeManager.getCookie().setSecure(false);
+ }
}
}
diff --git a/support/jakarta-ee/src/main/java/org/apache/shiro/ee/listeners/IniEnvironment.java b/support/jakarta-ee/src/main/java/org/apache/shiro/ee/listeners/IniEnvironment.java
index 04461e9c8..4d9154900 100644
--- a/support/jakarta-ee/src/main/java/org/apache/shiro/ee/listeners/IniEnvironment.java
+++ b/support/jakarta-ee/src/main/java/org/apache/shiro/ee/listeners/IniEnvironment.java
@@ -35,6 +35,7 @@ import org.apache.shiro.web.env.IniWebEnvironment;
import org.apache.shiro.web.filter.mgt.DefaultFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.omnifaces.util.Beans;
+import org.omnifaces.util.Faces;
import org.omnifaces.util.Lazy;
import static org.omnifaces.util.Utils.isBlank;
@@ -104,6 +105,14 @@ public class IniEnvironment extends IniWebEnvironment {
}
}
+ public static boolean hasFacesContext() {
+ try {
+ return Faces.hasContext();
+ } catch (Throwable e) {
+ return false;
+ }
+ }
+
@Override
protected Ini getFrameworkIni() {
if (otherConfigLocation != null) {
diff --git a/support/spring/src/main/java/org/apache/shiro/spring/web/config/AbstractShiroWebConfiguration.java b/support/spring/src/main/java/org/apache/shiro/spring/web/config/AbstractShiroWebConfiguration.java
index 8e29dea6e..fb28fa2f0 100644
--- a/support/spring/src/main/java/org/apache/shiro/spring/web/config/AbstractShiroWebConfiguration.java
+++ b/support/spring/src/main/java/org/apache/shiro/spring/web/config/AbstractShiroWebConfiguration.java
@@ -83,10 +83,10 @@ public class AbstractShiroWebConfiguration extends AbstractShiroConfiguration {
@Value("#{ @environment['shiro.rememberMeManager.cookie.domain'] ?: null }")
protected String rememberMeCookieDomain;
- @Value("#{ @environment['shiro.rememberMeManager.cookie.path'] ?: null }")
+ @Value("#{ @environment['shiro.rememberMeManager.cookie.path'] ?: T(org.apache.shiro.web.servlet.Cookie).ROOT_PATH } }")
protected String rememberMeCookiePath;
- @Value("#{ @environment['shiro.rememberMeManager.cookie.secure'] ?: false }")
+ @Value("#{ @environment['shiro.rememberMeManager.cookie.secure'] ?: true }")
protected boolean rememberMeCookieSecure;
@Value("#{ @environment['shiro.rememberMeManager.cookie.sameSite'] ?:"
diff --git a/web/src/main/java/org/apache/shiro/web/mgt/CookieRememberMeManager.java b/web/src/main/java/org/apache/shiro/web/mgt/CookieRememberMeManager.java
index 6695c89d5..732cbb9aa 100644
--- a/web/src/main/java/org/apache/shiro/web/mgt/CookieRememberMeManager.java
+++ b/web/src/main/java/org/apache/shiro/web/mgt/CookieRememberMeManager.java
@@ -76,10 +76,12 @@ public class CookieRememberMeManager extends AbstractRememberMeManager {
* The default name of the underlying rememberMe cookie which is {@code rememberMe}.
*/
public static final String DEFAULT_REMEMBER_ME_COOKIE_NAME = "rememberMe";
+ public static final String REMEMBER_ME_SECURE_COOKIE_DISABLED = "org.apache.shiro.rememberMe.secure.disabled";
private static final Logger LOGGER = LoggerFactory.getLogger(CookieRememberMeManager.class);
private Cookie cookie;
+ private boolean secureInDevMode = true;
/**
* Constructs a new {@code CookieRememberMeManager} with a default {@code rememberMe} cookie template.
@@ -128,6 +130,33 @@ public class CookieRememberMeManager extends AbstractRememberMeManager {
this.cookie = cookie;
}
+ /**
+ * Returns {@code true} if the rememberMe cookie should be marked as secure when the application is running in
+ * development mode. This is a convenience method that allows users to set the rememberMe cookie as secure in
+ * production environments but not in development environments where SSL is often not used.
+ * The default value is {@code true}.
+ * @return {@code true} if the rememberMe cookie should be marked as secure when the application is running in
+ * development mode, {@code false} otherwise (the default value is {@code true}).
+ * @since 2.1.1
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public boolean isSecureInDevMode() {
+ return secureInDevMode;
+ }
+
+ /**
+ * Sets whether the rememberMe cookie should be marked as secure when the application is running in development mode.
+ * This is a convenience method that allows users to set the rememberMe cookie as secure in production environments but not
+ * in development environments where SSL is often not used. The default value is {@code true}.
+ * @param secureInDevMode set to {@code true} if the rememberMe cookie should be marked as secure when the
+ * application is running in development mode, {@code false} otherwise (the default value is {@code true}).
+ * @since 2.1.1
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public void setSecureInDevMode(boolean secureInDevMode) {
+ this.secureInDevMode = secureInDevMode;
+ }
+
/**
* Base64-encodes the specified serialized byte array and sets that base64-encoded String as the cookie value.
* <p/>
@@ -313,6 +342,9 @@ public class CookieRememberMeManager extends AbstractRememberMeManager {
private Cookie createDefaultCookie() {
Cookie cookie = new SimpleCookie(DEFAULT_REMEMBER_ME_COOKIE_NAME);
cookie.setHttpOnly(true);
+ if (!Boolean.getBoolean(REMEMBER_ME_SECURE_COOKIE_DISABLED)) {
+ cookie.setSecure(true);
+ }
//One year should be long enough - most sites won't object to requiring a user to log in if they haven't visited
//in a year:
cookie.setMaxAge(Cookie.ONE_YEAR);