diff --git a/integration-tests/jakarta-ee/src/main/webapp/WEB-INF/web.xml b/integration-tests/jakarta-ee/src/main/webapp/WEB-INF/web.xml
index cead2eaece..3008d063e4 100644
--- a/integration-tests/jakarta-ee/src/main/webapp/WEB-INF/web.xml
+++ b/integration-tests/jakarta-ee/src/main/webapp/WEB-INF/web.xml
@@ -70,6 +70,10 @@
org.apache.shiro.form-resubmit.secure-cookies
false
+
+ org.apache.shiro.form-resubmit.whitelist.disabled
+ true
+
diff --git a/support/jakarta-ee/src/main/java/org/apache/shiro/ee/filters/AuthenticationFilterDelegate.java b/support/jakarta-ee/src/main/java/org/apache/shiro/ee/filters/AuthenticationFilterDelegate.java
index 7cb31df49f..fcc63912a5 100644
--- a/support/jakarta-ee/src/main/java/org/apache/shiro/ee/filters/AuthenticationFilterDelegate.java
+++ b/support/jakarta-ee/src/main/java/org/apache/shiro/ee/filters/AuthenticationFilterDelegate.java
@@ -33,12 +33,15 @@
import static org.apache.shiro.ee.filters.FormAuthenticationFilter.LOGIN_URL_ATTR_NAME;
import static org.apache.shiro.ee.filters.FormAuthenticationFilter.LOGIN_WAITTIME_ATTR_NAME;
import static org.apache.shiro.ee.filters.FormAuthenticationFilter.NO_PREDICATE;
+import static org.apache.shiro.ee.filters.FormAuthenticationFilter.getPathWithinApplication;
+import static org.apache.shiro.ee.filters.FormResubmitSupport.isPostRequest;
import static org.apache.shiro.ee.filters.FormResubmitSupport.savePostDataForResubmit;
import static org.apache.shiro.ee.filters.FormResubmitSupport.saveRequestReferer;
import static org.apache.shiro.ee.filters.LogoutFilter.LOGOUT_PREDICATE_ATTR_NAME;
import static org.apache.shiro.ee.filters.LogoutFilter.YES_PREDICATE;
import static org.apache.shiro.ee.listeners.EnvironmentLoaderListener.isFormResubmitDisabled;
import static org.apache.shiro.ee.listeners.EnvironmentLoaderListener.isServletNoPrincipal;
+import static org.apache.shiro.web.filter.authc.NoAccessFilter.FORM_RESUBMIT_CHECK_SERVLET_PATH;
import static org.apache.shiro.web.jaxrs.SubjectPrincipalRequestFilter.SHIRO_WEB_JAXRS_DISABLE_PRINCIPAL_PARAM;
/**
@@ -101,7 +104,10 @@ public boolean preHandle(ServletRequest request, ServletResponse response) throw
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
Subject subject = methods.getSubject(request, response);
boolean isAuthenticated = subject.isAuthenticated() && subject.getPrincipal() != null;
- return isAuthenticated || (useRemembered && subject.isRemembered());
+ return isAuthenticated || (useRemembered && subject.isRemembered())
+ || (isPostRequest(request)
+ && FORM_RESUBMIT_CHECK_SERVLET_PATH.equals(getPathWithinApplication(request,
+ () -> WebUtils.getPathWithinApplication(WebUtils.toHttp(request)))));
}
/**
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 44f1cf56d7..20e8b6108f 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
@@ -37,10 +37,12 @@
import java.net.URISyntaxException;
import java.time.Duration;
import java.util.Collections;
+import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.crypto.CryptoException;
import org.apache.shiro.ee.filters.Forms.FallbackPredicate;
import static org.apache.shiro.ee.filters.FormResubmitSupportCookies.initializeCookies;
import static org.apache.shiro.ee.filters.FormResubmitSupportCookies.transformCookieHeader;
+import static org.apache.shiro.ee.listeners.EnvironmentLoaderListener.isFormResubmitBlacklistEnabled;
import static org.apache.shiro.ee.listeners.EnvironmentLoaderListener.isFormResubmitDisabled;
import java.io.IOException;
import java.net.CookieManager;
@@ -57,6 +59,7 @@
import java.util.Set;
import java.util.UUID;
import static java.util.function.Predicate.not;
+import static org.apache.shiro.ee.listeners.EnvironmentLoaderListener.isFormResubmitWhitelistEnabled;
import static org.apache.shiro.ee.listeners.IniEnvironment.hasFacesContext;
import static org.apache.shiro.web.filter.authc.NoAccessFilter.FORM_RESUBMIT_CHECK_SERVLET_PATH;
import static org.apache.shiro.web.filter.authz.PortFilter.DEFAULT_HTTP_PORT;
@@ -646,13 +649,18 @@ private static boolean checkWhitelist(ServletContext servletContext, URI savedRe
} else if (isBlacklisted(blacklist, authority)) {
log.debug("Form resubmit blacklist cache hit for {}", savedRequestURI);
return false;
- } else if (checkWhitelistClient(savedRequestURI, servletContext.getContextPath(), client, savedFormDataKey)) {
- putWhitelistEntry(whitelist, authority);
+ } else if (checkWhitelistClient(savedRequestURI, servletContext.getContextPath(), client,
+ savedFormDataKey, dsm.getCacheManager())) {
+ if (isFormResubmitWhitelistEnabled(servletContext)) {
+ putWhitelistEntry(whitelist, authority);
+ }
blacklist.remove(authority);
return true;
}
- putBlacklistEntry(blacklist, authority);
+ if (isFormResubmitBlacklistEnabled(servletContext)) {
+ putBlacklistEntry(blacklist, authority);
+ }
return false;
}
@@ -710,7 +718,10 @@ static boolean isBlacklisted(Cache blacklist, String authority,
}
private static boolean checkWhitelistClient(URI savedRequestURI, String contextPath, HttpClient client,
- String savedFormDataKey) {
+ String savedFormDataKey, @NonNull CacheManager cacheManager) {
+ Cache cache = null;
+ UUID savedFormDataUUID = null;
+
try {
var rememberMeManager = getRememberMeManager();
if (rememberMeManager == null || rememberMeManager.getCipherService() == null
@@ -719,6 +730,13 @@ private static boolean checkWhitelistClient(URI savedRequestURI, String contextP
return false;
}
+ if (savedFormDataKey == null) {
+ savedFormDataUUID = UUID.randomUUID();
+ savedFormDataKey = savedFormDataUUID.toString();
+ cache = cacheManager.getCache(FORM_DATA_CACHE);
+ cache.put(savedFormDataUUID, "__DUMMY_FOR_CLIENT_WHITELIST_CHECK__");
+ }
+
var request = HttpRequest.newBuilder()
.uri(URI.create("%s://%s%s%s".formatted(savedRequestURI.getScheme(), savedRequestURI.getAuthority(),
contextPath, FORM_RESUBMIT_CHECK_SERVLET_PATH)))
@@ -738,6 +756,10 @@ private static boolean checkWhitelistClient(URI savedRequestURI, String contextP
} catch (IOException | InterruptedException e) {
log.debug("Form resubmit whitelist check failed for {} with exception: {}",
savedRequestURI, e);
+ } finally {
+ if (cache != null) {
+ cache.remove(savedFormDataUUID);
+ }
}
return false;
}
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 fa4b0a08f0..5d49862ec5 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
@@ -46,6 +46,8 @@ public class EnvironmentLoaderListener extends EnvironmentLoader implements Serv
private static final String SHIRO_EE_CHAR_ENCODING_PARAM = "org.apache.shiro.ee.character-encoding";
private static final String FORM_RESUBMIT_DISABLED_PARAM = "org.apache.shiro.form-resubmit.disabled";
private static final String FORM_RESUBMIT_SECURE_COOKIES = "org.apache.shiro.form-resubmit.secure-cookies";
+ private static final String FORM_RESUBMIT_WHITE_LIST_DISABLED = "org.apache.shiro.form-resubmit.whitelist.disabled";
+ private static final String FORM_RESUBMIT_BLACK_LIST_DISABLED = "org.apache.shiro.form-resubmit.blacklist.disabled";
private static final String SHIRO_WEB_DISABLE_PRINCIPAL_PARAM = "org.apache.shiro.web.disable-principal";
public static boolean isShiroEEDisabled(ServletContext ctx) {
@@ -64,6 +66,14 @@ public static boolean isFormResubmitSecureCookies(ServletContext ctx) {
return Boolean.TRUE.equals(ctx.getAttribute(FORM_RESUBMIT_SECURE_COOKIES));
}
+ public static boolean isFormResubmitWhitelistEnabled(ServletContext ctx) {
+ return !Boolean.TRUE.equals(ctx.getAttribute(FORM_RESUBMIT_WHITE_LIST_DISABLED));
+ }
+
+ public static boolean isFormResubmitBlacklistEnabled(ServletContext ctx) {
+ return !Boolean.TRUE.equals(ctx.getAttribute(FORM_RESUBMIT_BLACK_LIST_DISABLED));
+ }
+
public static boolean isServletNoPrincipal(ServletContext ctx) {
return Boolean.TRUE.equals(ctx.getAttribute(SHIRO_WEB_DISABLE_PRINCIPAL_PARAM));
}
@@ -96,6 +106,12 @@ public void contextInitialized(ServletContextEvent sce) {
} else {
sce.getServletContext().setAttribute(FORM_RESUBMIT_SECURE_COOKIES, Boolean.FALSE);
}
+ if (Boolean.parseBoolean(sce.getServletContext().getInitParameter(FORM_RESUBMIT_WHITE_LIST_DISABLED))) {
+ sce.getServletContext().setAttribute(FORM_RESUBMIT_WHITE_LIST_DISABLED, Boolean.TRUE);
+ }
+ if (Boolean.parseBoolean(sce.getServletContext().getInitParameter(FORM_RESUBMIT_BLACK_LIST_DISABLED))) {
+ sce.getServletContext().setAttribute(FORM_RESUBMIT_BLACK_LIST_DISABLED, Boolean.TRUE);
+ }
if (Boolean.parseBoolean(sce.getServletContext().getInitParameter(SHIRO_WEB_DISABLE_PRINCIPAL_PARAM))) {
sce.getServletContext().setAttribute(SHIRO_WEB_DISABLE_PRINCIPAL_PARAM, Boolean.TRUE);
}