This is an automated email from the ASF dual-hosted git repository.

lprimak pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/shiro.git


The following commit(s) were added to refs/heads/main by this push:
     new be31c133e enh(jakarta-ee): encrypt SAVED_REQUEST_KEY cookie
be31c133e is described below

commit be31c133e61843f14fddd209da4d9c3609bcc9ef
Author: lprimak <[email protected]>
AuthorDate: Wed May 6 17:14:29 2026 -0500

    enh(jakarta-ee): encrypt SAVED_REQUEST_KEY cookie
---
 .../shiro/mgt/AbstractRememberMeManager.java       |  1 -
 .../shiro/ee/filters/FormResubmitSupport.java      | 52 +++++++++++++++++-----
 .../ee/filters/FormResubmitSupportCookies.java     |  3 +-
 3 files changed, 44 insertions(+), 12 deletions(-)

diff --git 
a/core/src/main/java/org/apache/shiro/mgt/AbstractRememberMeManager.java 
b/core/src/main/java/org/apache/shiro/mgt/AbstractRememberMeManager.java
index 9107cd679..cfe210713 100644
--- a/core/src/main/java/org/apache/shiro/mgt/AbstractRememberMeManager.java
+++ b/core/src/main/java/org/apache/shiro/mgt/AbstractRememberMeManager.java
@@ -81,7 +81,6 @@ public abstract class AbstractRememberMeManager implements 
RememberMeManager {
      * Cipher to use for encrypting/decrypting serialized byte arrays for 
added security
      */
     private CipherService cipherService = new AesCipherService();
-    ;
 
     /**
      * Cipher encryption key to use with the Cipher when encrypting data
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 6b463c0af..0e4732eff 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
@@ -34,6 +34,7 @@ import static 
org.apache.shiro.ee.filters.FormResubmitSupportCookies.getCookieAg
 import static 
org.apache.shiro.ee.filters.FormResubmitSupportCookies.getSessionCookieName;
 import java.net.URISyntaxException;
 import java.util.Collections;
+import org.apache.shiro.crypto.CryptoException;
 import org.apache.shiro.ee.filters.Forms.FallbackPredicate;
 import static 
org.apache.shiro.ee.filters.FormResubmitSupportCookies.transformCookieHeader;
 import static 
org.apache.shiro.ee.listeners.EnvironmentLoaderListener.isFormResubmitDisabled;
@@ -47,6 +48,7 @@ import java.net.http.HttpHeaders;
 import java.net.http.HttpRequest;
 import java.net.http.HttpResponse;
 import java.nio.charset.StandardCharsets;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.UUID;
 import static java.util.function.Predicate.not;
@@ -71,6 +73,7 @@ import lombok.ToString;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.shiro.SecurityUtils;
 import static org.apache.shiro.ee.util.JakartaTransformer.jakartify;
+import org.apache.shiro.lang.codec.Base64;
 import org.apache.shiro.mgt.AbstractRememberMeManager;
 import org.apache.shiro.mgt.DefaultSecurityManager;
 import org.apache.shiro.mgt.SecurityManager;
@@ -152,7 +155,7 @@ public class FormResubmitSupport {
             DefaultSecurityManager dsm = 
getSecurityManager(DefaultSecurityManager.class);
             if (dsm.getCacheManager() != null) {
                 var cache = dsm.getCacheManager().getCache(FORM_DATA_CACHE);
-                var rememberMeManager = (AbstractRememberMeManager) 
dsm.getRememberMeManager();
+                var rememberMeManager = getRememberMeManager();
                 if (rememberMeManager != null && 
rememberMeManager.getCipherService() != null) {
                     cache.put(cacheKey, rememberMeManager.getCipherService()
                             .encrypt(postData.getBytes(StandardCharsets.UTF_8),
@@ -162,7 +165,7 @@ public class FormResubmitSupport {
                     cache.put(cacheKey, postData);
                 }
                 addCookie(response, request.getServletContext(), 
SHIRO_FORM_DATA_KEY,
-                        cacheKey.toString(), getCookieAge(request, dsm));
+                        cacheKey.toString(), getCookieAge(request, dsm), true);
             } else {
                 log.warn("Shiro Cache manager is not configured, cannot store 
form data");
             }
@@ -192,7 +195,7 @@ public class FormResubmitSupport {
             if (dsm.getCacheManager() != null) {
                 var cache = dsm.getCacheManager().getCache(FORM_DATA_CACHE);
                 var cacheKey = UUID.fromString(savedFormDataKey);
-                var rememberMeManager = (AbstractRememberMeManager) 
dsm.getRememberMeManager();
+                var rememberMeManager = getRememberMeManager();
                 if (rememberMeManager != null && 
rememberMeManager.getCipherService() != null) {
                     var cachedData = Optional.ofNullable((byte[]) 
cache.get(cacheKey));
                     savedFormData = cachedData.map(encryptedData ->
@@ -207,17 +210,38 @@ public class FormResubmitSupport {
     }
 
     static String decrypt(byte[] encrypted, AbstractRememberMeManager 
rememberMeManager) {
-        return new String(rememberMeManager.getCipherService()
-                .decrypt(encrypted, 
rememberMeManager.getDecryptionCipherKey()).getClonedBytes(),
-                StandardCharsets.UTF_8);
+        try {
+            Objects.requireNonNull(rememberMeManager, "rememberMeManager 
cannot be null.");
+            return new String(rememberMeManager.getCipherService()
+                    .decrypt(encrypted, 
rememberMeManager.getDecryptionCipherKey()).getClonedBytes(),
+                    StandardCharsets.UTF_8);
+        } catch (CryptoException e) {
+            log.debug("Failed to decrypt", e);
+            return null;
+        }
+    }
+
+    static String decrypt(String encrypted, AbstractRememberMeManager 
rememberMeManager) {
+        if (encrypted == null) {
+            return null;
+        }
+        try {
+            return decrypt(Base64.decode(encrypted), rememberMeManager);
+        } catch (IllegalArgumentException e) {
+            log.debug("Failed to decode", e);
+            return null;
+        }
     }
 
     static void saveRequest(HttpServletRequest request, HttpServletResponse 
response, boolean useReferer) {
         String path = useReferer ? getReferer(request)
                 : Servlets.getRequestURLWithQueryString(request);
-        if (path != null) {
+        var rememberMeManager = getRememberMeManager();
+        if (path != null && rememberMeManager != null) {
             Servlets.addResponseCookie(request, response, 
WebUtils.SAVED_REQUEST_KEY,
-                    path, null, request.getContextPath(),
+                    
rememberMeManager.getCipherService().encrypt(path.getBytes(StandardCharsets.UTF_8),
+                            
rememberMeManager.getEncryptionCipherKey()).toBase64(),
+                    null, request.getContextPath(),
                     // cookie age = session timeout
                     getCookieAge(request, getSecurityManager()));
         }
@@ -256,7 +280,7 @@ public class FormResubmitSupport {
     @SneakyThrows({IOException.class, InterruptedException.class})
     static void redirectToSaved(HttpServletRequest request, 
HttpServletResponse response,
             FallbackPredicate useFallbackPath, String fallbackPath, boolean 
resubmit) {
-        String savedRequest = Servlets.getRequestCookie(request, 
WebUtils.SAVED_REQUEST_KEY);
+        String savedRequest = decrypt(Servlets.getRequestCookie(request, 
WebUtils.SAVED_REQUEST_KEY), getRememberMeManager());
         if (savedRequest != null) {
             doRedirectToSaved(request, response, savedRequest, resubmit);
         } else {
@@ -479,7 +503,7 @@ public class FormResubmitSupport {
                         .entrySet().stream().filter(not(entry -> entry.getKey()
                                 
.startsWith(getSessionCookieName(servletContext, getSecurityManager()))))
                         .forEach(entry -> addCookie(originalResponse, 
servletContext,
-                                entry.getKey(), entry.getValue(), -1));
+                                entry.getKey(), entry.getValue(), -1, false));
                 if ((response.statusCode() == FOUND || redirect) && 
isPartialAjaxRequest) {
                     originalResponse.setHeader(CONTENT_TYPE, TEXT_XML);
                     
originalResponse.setCharacterEncoding(StandardCharsets.UTF_8.name());
@@ -544,6 +568,14 @@ public class FormResubmitSupport {
         return rv;
     }
 
+    private static AbstractRememberMeManager getRememberMeManager() {
+        if (isSecurityManagerTypeOf(getSecurityManager(), 
DefaultSecurityManager.class)) {
+            var dsm = getSecurityManager(DefaultSecurityManager.class);
+            return (AbstractRememberMeManager) dsm.getRememberMeManager();
+        }
+        return null;
+    }
+
     private static String getJSFNewViewState(URI savedRequest, HttpClient 
client, String savedFormData)
             throws IOException, InterruptedException {
         var getRequest = 
HttpRequest.newBuilder().uri(savedRequest).GET().build();
diff --git 
a/support/jakarta-ee/src/main/java/org/apache/shiro/ee/filters/FormResubmitSupportCookies.java
 
b/support/jakarta-ee/src/main/java/org/apache/shiro/ee/filters/FormResubmitSupportCookies.java
index ac3fa41ec..2bc9aeca5 100644
--- 
a/support/jakarta-ee/src/main/java/org/apache/shiro/ee/filters/FormResubmitSupportCookies.java
+++ 
b/support/jakarta-ee/src/main/java/org/apache/shiro/ee/filters/FormResubmitSupportCookies.java
@@ -42,10 +42,11 @@ public class FormResubmitSupportCookies {
     static final String DONT_ADD_ANY_MORE_COOKIES = 
"org.apache.shiro.no-more-cookies";
 
     static void addCookie(@NonNull HttpServletResponse response, 
ServletContext servletContext,
-            @NonNull String cookieName, @NonNull String cookieValue, int 
maxAge) {
+            @NonNull String cookieName, @NonNull String cookieValue, int 
maxAge, boolean httpOnly) {
         var cookie = new Cookie(cookieName, cookieValue);
         cookie.setPath(servletContext.getContextPath());
         cookie.setMaxAge(maxAge);
+        cookie.setHttpOnly(httpOnly);
         if 
(EnvironmentLoaderListener.isFormResubmitSecureCookies(servletContext)) {
             cookie.setSecure(true);
         }

Reply via email to