diff --git a/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java b/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java
index 866d47aed2..b5604e785d 100644
--- a/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java
+++ b/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java
@@ -155,7 +155,7 @@ final class AuthenticationConfigBuilder {
if (formLoginElt != null || autoConfig) {
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
- AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy);
+ AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy, allowSessionCreation);
parser.parse(formLoginElt, pc);
formFilter = parser.getFilterBean();
@@ -163,7 +163,7 @@ final class AuthenticationConfigBuilder {
}
if (formFilter != null) {
- formFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
+ formFilter.getPropertyValues().addPropertyValue("allowSessionCreation", allowSessionCreation);
formFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
@@ -179,7 +179,7 @@ final class AuthenticationConfigBuilder {
if (openIDLoginElt != null) {
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
- OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy);
+ OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy, allowSessionCreation);
parser.parse(openIDLoginElt, pc);
openIDFilter = parser.getFilterBean();
@@ -214,7 +214,7 @@ final class AuthenticationConfigBuilder {
}
if (openIDFilter != null) {
- openIDFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
+ openIDFilter.getPropertyValues().addPropertyValue("allowSessionCreation", allowSessionCreation);
openIDFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
// Required by login page filter
openIDFilterId = pc.getReaderContext().generateBeanName(openIDFilter);
@@ -540,7 +540,8 @@ final class AuthenticationConfigBuilder {
}
void createUserServiceInjector() {
- BeanDefinitionBuilder userServiceInjector = BeanDefinitionBuilder.rootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class);
+ BeanDefinitionBuilder userServiceInjector =
+ BeanDefinitionBuilder.rootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class);
userServiceInjector.addConstructorArgValue(x509ProviderId);
userServiceInjector.addConstructorArgValue(rememberMeServicesId);
userServiceInjector.addConstructorArgValue(openIDProviderId);
diff --git a/config/src/main/java/org/springframework/security/config/http/FormLoginBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/http/FormLoginBeanDefinitionParser.java
index ecc44c79b2..380e5c772a 100644
--- a/config/src/main/java/org/springframework/security/config/http/FormLoginBeanDefinitionParser.java
+++ b/config/src/main/java/org/springframework/security/config/http/FormLoginBeanDefinitionParser.java
@@ -31,7 +31,8 @@ public class FormLoginBeanDefinitionParser {
private static final String DEF_FORM_LOGIN_TARGET_URL = "/";
private static final String ATT_FORM_LOGIN_AUTHENTICATION_FAILURE_URL = "authentication-failure-url";
- private static final String DEF_FORM_LOGIN_AUTHENTICATION_FAILURE_URL = DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL + "?" + DefaultLoginPageGeneratingFilter.ERROR_PARAMETER_NAME;
+ private static final String DEF_FORM_LOGIN_AUTHENTICATION_FAILURE_URL =
+ DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL + "?" + DefaultLoginPageGeneratingFilter.ERROR_PARAMETER_NAME;
private static final String ATT_SUCCESS_HANDLER_REF = "authentication-success-handler-ref";
private static final String ATT_FAILURE_HANDLER_REF = "authentication-failure-handler-ref";
@@ -40,17 +41,19 @@ public class FormLoginBeanDefinitionParser {
private final String filterClassName;
private final BeanReference requestCache;
private final BeanReference sessionStrategy;
+ private final boolean allowSessionCreation;
private RootBeanDefinition filterBean;
private RootBeanDefinition entryPointBean;
private String loginPage;
FormLoginBeanDefinitionParser(String defaultLoginProcessingUrl, String filterClassName,
- BeanReference requestCache, BeanReference sessionStrategy) {
+ BeanReference requestCache, BeanReference sessionStrategy, boolean allowSessionCreation) {
this.defaultLoginProcessingUrl = defaultLoginProcessingUrl;
this.filterClassName = filterClassName;
this.requestCache = requestCache;
this.sessionStrategy = sessionStrategy;
+ this.allowSessionCreation = allowSessionCreation;
}
public BeanDefinition parse(Element elt, ParserContext pc) {
@@ -135,6 +138,7 @@ public class FormLoginBeanDefinitionParser {
}
}
failureHandler.addPropertyValue("defaultFailureUrl", authenticationFailureUrl);
+ failureHandler.addPropertyValue("allowSessionCreation", allowSessionCreation);
filterBuilder.addPropertyValue("authenticationFailureHandler", failureHandler.getBeanDefinition());
}
diff --git a/core/src/test/java/org/springframework/security/core/userdetails/memory/UserMapTests.java b/core/src/test/java/org/springframework/security/core/userdetails/memory/UserMapTests.java
index 581c1db957..94924f1b79 100644
--- a/core/src/test/java/org/springframework/security/core/userdetails/memory/UserMapTests.java
+++ b/core/src/test/java/org/springframework/security/core/userdetails/memory/UserMapTests.java
@@ -16,14 +16,12 @@
package org.springframework.security.core.userdetails.memory;
import static org.junit.Assert.*;
-import junit.framework.TestCase;
import org.junit.Test;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.security.core.userdetails.memory.UserMap;
/**
diff --git a/web/src/main/java/org/springframework/security/web/WebAttributes.java b/web/src/main/java/org/springframework/security/web/WebAttributes.java
new file mode 100644
index 0000000000..3072e7ba57
--- /dev/null
+++ b/web/src/main/java/org/springframework/security/web/WebAttributes.java
@@ -0,0 +1,14 @@
+package org.springframework.security.web;
+
+/**
+ * Well-known keys which are used to store Spring Security information in request or session scope.
+ *
+ * @author Luke Taylor
+ * @since 3.0.3
+ */
+public final class WebAttributes {
+ public static final String ACCESS_DENIED_403 = "SPRING_SECURITY_403_EXCEPTION";
+ public static final String AUTHENTICATION_EXCEPTION = "SPRING_SECURITY_LAST_EXCEPTION";
+ public static final String LAST_USERNAME = "SPRING_SECURITY_LAST_USERNAME";
+ public static final String SAVED_REQUEST = "SPRING_SECURITY_SAVED_REQUEST_KEY";
+}
diff --git a/web/src/main/java/org/springframework/security/web/access/AccessDeniedHandlerImpl.java b/web/src/main/java/org/springframework/security/web/access/AccessDeniedHandlerImpl.java
index 5bdf4547f1..43cd1c08c2 100644
--- a/web/src/main/java/org/springframework/security/web/access/AccessDeniedHandlerImpl.java
+++ b/web/src/main/java/org/springframework/security/web/access/AccessDeniedHandlerImpl.java
@@ -25,6 +25,7 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.web.WebAttributes;
/**
@@ -35,14 +36,17 @@ import org.springframework.security.access.AccessDeniedException;
* Being a "forward", the SecurityContextHolder
will remain
* populated. This is of benefit if the view (or a tag library or macro) wishes to access the
* SecurityContextHolder
. The request scope will also be populated with the exception itself, available
- * from the key {@link #SPRING_SECURITY_ACCESS_DENIED_EXCEPTION_KEY}.
+ * from the key {@link WebAttributes.ACCESS_DENIED_403}.
*
* @author Ben Alex
*/
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
//~ Static fields/initializers =====================================================================================
-
- public static final String SPRING_SECURITY_ACCESS_DENIED_EXCEPTION_KEY = "SPRING_SECURITY_403_EXCEPTION";
+ /**
+ * @deprecated Use the value in {@link WebAttributes} directly.
+ */
+ @Deprecated
+ public static final String SPRING_SECURITY_ACCESS_DENIED_EXCEPTION_KEY = WebAttributes.ACCESS_DENIED_403;
protected static final Log logger = LogFactory.getLog(AccessDeniedHandlerImpl.class);
//~ Instance fields ================================================================================================
@@ -56,7 +60,7 @@ public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
if (!response.isCommitted()) {
if (errorPage != null) {
// Put exception into request scope (perhaps of use to a view)
- request.setAttribute(SPRING_SECURITY_ACCESS_DENIED_EXCEPTION_KEY, accessDeniedException);
+ request.setAttribute(WebAttributes.ACCESS_DENIED_403, accessDeniedException);
// Set the 403 status code.
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
diff --git a/web/src/main/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.java b/web/src/main/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.java
index 67db2d257d..2ec631dcc7 100644
--- a/web/src/main/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.java
+++ b/web/src/main/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.java
@@ -23,7 +23,6 @@ import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
@@ -37,6 +36,7 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.util.UrlUtils;
@@ -76,20 +76,16 @@ import org.springframework.web.filter.GenericFilterBean;
*
*
* The filter has an optional attribute invalidateSessionOnSuccessfulAuthentication that will invalidate * the current session on successful authentication. This is to protect against session fixation attacks (see @@ -106,7 +102,11 @@ public abstract class AbstractAuthenticationProcessingFilter extends GenericFilt ApplicationEventPublisherAware, MessageSourceAware { //~ Static fields/initializers ===================================================================================== - public static final String SPRING_SECURITY_LAST_EXCEPTION_KEY = "SPRING_SECURITY_LAST_EXCEPTION"; + /** + * @deprecated Use the value in {@link WebAttributes} directly. + */ + @Deprecated + public static final String SPRING_SECURITY_LAST_EXCEPTION_KEY = WebAttributes.AUTHENTICATION_EXCEPTION; //~ Instance fields ================================================================================================ @@ -321,12 +321,6 @@ public abstract class AbstractAuthenticationProcessingFilter extends GenericFilt logger.debug("Delegating to authentication failure handler" + failureHandler); } - HttpSession session = request.getSession(false); - - if (session != null || allowSessionCreation) { - request.getSession().setAttribute(SPRING_SECURITY_LAST_EXCEPTION_KEY, failed); - } - rememberMeServices.loginFail(request, response); failureHandler.onAuthenticationFailure(request, response, failed); diff --git a/web/src/main/java/org/springframework/security/web/authentication/SimpleUrlAuthenticationFailureHandler.java b/web/src/main/java/org/springframework/security/web/authentication/SimpleUrlAuthenticationFailureHandler.java index 573137add2..4ad1a2b046 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/SimpleUrlAuthenticationFailureHandler.java +++ b/web/src/main/java/org/springframework/security/web/authentication/SimpleUrlAuthenticationFailureHandler.java @@ -5,10 +5,12 @@ import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.WebAttributes; import org.springframework.security.web.DefaultRedirectStrategy; import org.springframework.security.web.RedirectStrategy; import org.springframework.security.web.util.UrlUtils; @@ -31,6 +33,7 @@ public class SimpleUrlAuthenticationFailureHandler implements AuthenticationFail private String defaultFailureUrl; private boolean forwardToDestination = false; + private boolean allowSessionCreation = true; private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); public SimpleUrlAuthenticationFailureHandler() { @@ -40,6 +43,12 @@ public class SimpleUrlAuthenticationFailureHandler implements AuthenticationFail setDefaultFailureUrl(defaultFailureUrl); } + /** + * Performs the redirect or forward to the {@code defaultFailureUrl} if set, otherwise returns a 401 error code. + *
+ * If redirecting or forwarding, {@code saveException} will be called to cache the exception for use in + * the target view. + */ public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { @@ -48,6 +57,8 @@ public class SimpleUrlAuthenticationFailureHandler implements AuthenticationFail response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication Failed: " + exception.getMessage()); } else { + saveException(request, exception); + if (forwardToDestination) { logger.debug("Forwarding to " + defaultFailureUrl); @@ -59,6 +70,25 @@ public class SimpleUrlAuthenticationFailureHandler implements AuthenticationFail } } + /** + * Caches the {@code AuthenticationException} for use in view rendering. + *
+ * If {@code forwardToDestination} is set to true, request scope will be used, otherwise it will attempt to store
+ * the exception in the session. If there is no session and {@code allowSessionCreation} is {@code true} a session
+ * will be created. Otherwise the exception will not be stored.
+ */
+ protected final void saveException(HttpServletRequest request, AuthenticationException exception) {
+ if (forwardToDestination) {
+ request.setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception);
+ } else {
+ HttpSession session = request.getSession(false);
+
+ if (session != null || allowSessionCreation) {
+ request.getSession().setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception);
+ }
+ }
+ }
+
/**
* The URL which will be used as the failure destination.
*
@@ -92,4 +122,12 @@ public class SimpleUrlAuthenticationFailureHandler implements AuthenticationFail
protected RedirectStrategy getRedirectStrategy() {
return redirectStrategy;
}
+
+ protected boolean isAllowSessionCreation() {
+ return allowSessionCreation;
+ }
+
+ public void setAllowSessionCreation(boolean allowSessionCreation) {
+ this.allowSessionCreation = allowSessionCreation;
+ }
}
diff --git a/web/src/main/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilter.java b/web/src/main/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilter.java
index 96117b6dd9..8ab40a2190 100755
--- a/web/src/main/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilter.java
+++ b/web/src/main/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilter.java
@@ -19,7 +19,7 @@ import org.springframework.security.authentication.event.InteractiveAuthenticati
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
+import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.util.Assert;
import org.springframework.web.filter.GenericFilterBean;
@@ -176,7 +176,7 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
if (logger.isDebugEnabled()) {
logger.debug("Cleared security context due to exception", failed);
}
- request.getSession().setAttribute(AbstractAuthenticationProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY, failed);
+ request.getSession().setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, failed);
}
/**
diff --git a/web/src/main/java/org/springframework/security/web/authentication/session/SessionFixationProtectionStrategy.java b/web/src/main/java/org/springframework/security/web/authentication/session/SessionFixationProtectionStrategy.java
index 5f31e3fa54..29406d261e 100644
--- a/web/src/main/java/org/springframework/security/web/authentication/session/SessionFixationProtectionStrategy.java
+++ b/web/src/main/java/org/springframework/security/web/authentication/session/SessionFixationProtectionStrategy.java
@@ -13,7 +13,7 @@ import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.core.Authentication;
-import org.springframework.security.web.savedrequest.DefaultSavedRequest;
+import org.springframework.security.web.WebAttributes;
/**
* The default implementation of {@link SessionAuthenticationStrategy}.
@@ -44,7 +44,7 @@ public class SessionFixationProtectionStrategy implements SessionAuthenticationS
* In the case where the attributes will not be migrated, this field allows a list of named attributes
* which should not be discarded.
*/
- private List