SEC-1058: Substantial refactoring of AbstractProcessingFilter to use AuthenticationFailureHandler strategy. Also changed attemptAuthentication method to take a response object and have the option of returning null, to allow OpenIDAuthenticationProcessingFilter to work without having to throw exceptions between the template methods (which made the logic very hard to follow). The OpenID filter now redirects to the OpenID provider service from this method, rather than treating it as a temporary failure and throwing OpenIDAuthenticationRequiredException.
This commit is contained in:
parent
839279161d
commit
2927b8464f
|
@ -78,7 +78,7 @@ public class CasProcessingFilter extends AbstractProcessingFilter {
|
|||
private ProxyGrantingTicketStorage proxyGrantingTicketStorage;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
public Authentication attemptAuthentication(final HttpServletRequest request)
|
||||
public Authentication attemptAuthentication(final HttpServletRequest request, HttpServletResponse response)
|
||||
throws AuthenticationException {
|
||||
final String username = CAS_STATEFUL_IDENTIFIER;
|
||||
String password = request.getParameter("ticket");
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.springframework.security.AuthenticationException;
|
|||
import org.springframework.security.MockAuthenticationManager;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -31,26 +32,8 @@ import org.springframework.mock.web.MockHttpServletRequest;
|
|||
* @version $Id$
|
||||
*/
|
||||
public class CasProcessingFilterTests extends TestCase {
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public CasProcessingFilterTests() {
|
||||
super();
|
||||
}
|
||||
|
||||
public CasProcessingFilterTests(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(CasProcessingFilterTests.class);
|
||||
}
|
||||
|
||||
public final void setUp() throws Exception {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
public void testGetters() {
|
||||
CasProcessingFilter filter = new CasProcessingFilter();
|
||||
assertEquals("/j_spring_cas_security_check", filter.getDefaultFilterProcessesUrl());
|
||||
|
@ -66,7 +49,7 @@ public class CasProcessingFilterTests extends TestCase {
|
|||
filter.setAuthenticationManager(authMgr);
|
||||
filter.init(null);
|
||||
|
||||
Authentication result = filter.attemptAuthentication(request);
|
||||
Authentication result = filter.attemptAuthentication(request, new MockHttpServletResponse());
|
||||
assertTrue(result != null);
|
||||
}
|
||||
|
||||
|
@ -81,7 +64,7 @@ public class CasProcessingFilterTests extends TestCase {
|
|||
filter.init(null);
|
||||
|
||||
try {
|
||||
filter.attemptAuthentication(request);
|
||||
filter.attemptAuthentication(request, new MockHttpServletResponse());
|
||||
fail("Should have thrown AuthenticationException");
|
||||
} catch (AuthenticationException expected) {
|
||||
assertTrue(true);
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.springframework.security.ui.logout.SecurityContextLogoutHandler;
|
|||
import org.springframework.security.util.UrlUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
|
@ -61,7 +62,8 @@ public class ConcurrentSessionFilter extends SpringSecurityFilter implements Ini
|
|||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(sessionRegistry, "SessionRegistry required");
|
||||
Assert.isTrue(UrlUtils.isValidRedirectUrl(expiredUrl), expiredUrl + " isn't a valid redirect URL");
|
||||
Assert.isTrue(expiredUrl == null || UrlUtils.isValidRedirectUrl(expiredUrl),
|
||||
expiredUrl + " isn't a valid redirect URL");
|
||||
}
|
||||
|
||||
public void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
||||
|
@ -120,7 +122,7 @@ public class ConcurrentSessionFilter extends SpringSecurityFilter implements Ini
|
|||
}
|
||||
|
||||
public void setLogoutHandlers(LogoutHandler[] handlers) {
|
||||
Assert.notNull(handlers);
|
||||
Assert.notNull(handlers);
|
||||
this.handlers = handlers;
|
||||
}
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@ abstract class ConfigUtils {
|
|||
* If not empty or starting with "$" (potential placeholder), "/" or "http" it will raise an error.
|
||||
*/
|
||||
static void validateHttpRedirect(String url, ParserContext pc, Object source) {
|
||||
if (UrlUtils.isValidRedirectUrl(url) || url.startsWith("$")) {
|
||||
if (!StringUtils.hasText(url) || UrlUtils.isValidRedirectUrl(url) || url.startsWith("$")) {
|
||||
return;
|
||||
}
|
||||
pc.getReaderContext().warning(url + " is not a valid redirect URL (must start with '/' or http(s))", source);
|
||||
|
|
|
@ -8,6 +8,7 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
|
|||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.ui.SavedRequestAwareAuthenticationSuccessHandler;
|
||||
import org.springframework.security.ui.SimpleUrlAuthenticationFailureHandler;
|
||||
import org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint;
|
||||
import org.springframework.security.ui.webapp.DefaultLoginPageGeneratingFilter;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
@ -37,6 +38,7 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser {
|
|||
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";
|
||||
|
||||
private String defaultLoginProcessingUrl;
|
||||
private String filterClassName;
|
||||
|
@ -56,6 +58,7 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser {
|
|||
String authenticationFailureUrl = null;
|
||||
String alwaysUseDefault = null;
|
||||
String successHandlerRef = null;
|
||||
String failureHandlerRef = null;
|
||||
|
||||
Object source = null;
|
||||
|
||||
|
@ -82,18 +85,18 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser {
|
|||
alwaysUseDefault = elt.getAttribute(ATT_ALWAYS_USE_DEFAULT_TARGET_URL);
|
||||
loginPage = elt.getAttribute(ATT_LOGIN_PAGE);
|
||||
successHandlerRef = elt.getAttribute(ATT_SUCCESS_HANDLER_REF);
|
||||
failureHandlerRef = elt.getAttribute(ATT_FAILURE_HANDLER_REF);
|
||||
|
||||
if (!StringUtils.hasText(loginPage)) {
|
||||
loginPage = null;
|
||||
}
|
||||
ConfigUtils.validateHttpRedirect(loginPage, pc, source);
|
||||
|
||||
}
|
||||
|
||||
ConfigUtils.registerProviderManagerIfNecessary(pc);
|
||||
|
||||
filterBean = createFilterBean(loginUrl, defaultTargetUrl, alwaysUseDefault, loginPage, authenticationFailureUrl,
|
||||
successHandlerRef);
|
||||
successHandlerRef, failureHandlerRef);
|
||||
filterBean.setSource(source);
|
||||
filterBean.getPropertyValues().addPropertyValue("authenticationManager",
|
||||
new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
||||
|
@ -123,7 +126,7 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser {
|
|||
}
|
||||
|
||||
private RootBeanDefinition createFilterBean(String loginUrl, String defaultTargetUrl, String alwaysUseDefault,
|
||||
String loginPage, String authenticationFailureUrl, String successHandlerRef) {
|
||||
String loginPage, String authenticationFailureUrl, String successHandlerRef, String failureHandlerRef) {
|
||||
|
||||
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(filterClassName);
|
||||
|
||||
|
@ -144,17 +147,22 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser {
|
|||
filterBuilder.addPropertyValue("successHandler", successHandler.getBeanDefinition());
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(authenticationFailureUrl)) {
|
||||
// Fallback to redisplaying the custom login page, if one was specified
|
||||
if (StringUtils.hasText(loginPage)) {
|
||||
authenticationFailureUrl = loginPage;
|
||||
} else {
|
||||
authenticationFailureUrl = DEF_FORM_LOGIN_AUTHENTICATION_FAILURE_URL;
|
||||
if (StringUtils.hasText(failureHandlerRef)) {
|
||||
filterBuilder.addPropertyReference("failureHandler", failureHandlerRef);
|
||||
} else {
|
||||
BeanDefinitionBuilder failureHandler = BeanDefinitionBuilder.rootBeanDefinition(SimpleUrlAuthenticationFailureHandler.class);
|
||||
if (!StringUtils.hasText(authenticationFailureUrl)) {
|
||||
// Fall back to redisplaying the custom login page, if one was specified.
|
||||
if (StringUtils.hasText(loginPage)) {
|
||||
authenticationFailureUrl = loginPage;
|
||||
} else {
|
||||
authenticationFailureUrl = DEF_FORM_LOGIN_AUTHENTICATION_FAILURE_URL;
|
||||
}
|
||||
}
|
||||
failureHandler.addPropertyValue("defaultFailureUrl", authenticationFailureUrl);
|
||||
filterBuilder.addPropertyValue("failureHandler", failureHandler.getBeanDefinition());
|
||||
}
|
||||
|
||||
filterBuilder.addPropertyValue("authenticationFailureUrl", authenticationFailureUrl);
|
||||
|
||||
return (RootBeanDefinition) filterBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ import org.springframework.security.SpringSecurityMessageSource;
|
|||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.AuthenticationException;
|
||||
import org.springframework.security.AuthenticationManager;
|
||||
import org.springframework.security.util.RedirectUtils;
|
||||
import org.springframework.security.util.SessionUtils;
|
||||
import org.springframework.security.util.UrlUtils;
|
||||
|
||||
|
@ -44,8 +43,6 @@ import org.springframework.util.Assert;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -128,45 +125,24 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
|||
//~ Instance fields ================================================================================================
|
||||
|
||||
protected ApplicationEventPublisher eventPublisher;
|
||||
|
||||
protected AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource();
|
||||
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||
|
||||
private Properties exceptionMappings = new Properties();
|
||||
|
||||
/**
|
||||
/*
|
||||
* Delay use of NullRememberMeServices until initialization so that namespace has a chance to inject
|
||||
* the RememberMeServices implementation into custom implementations.
|
||||
*/
|
||||
private RememberMeServices rememberMeServices = null;
|
||||
|
||||
/** Where to redirect the browser to if authentication fails */
|
||||
private String authenticationFailureUrl;
|
||||
|
||||
/**
|
||||
* The URL destination that this filter intercepts and processes (usually
|
||||
* something like <code>/j_spring_security_check</code>)
|
||||
*/
|
||||
private String filterProcessesUrl = getDefaultFilterProcessesUrl();
|
||||
|
||||
/**
|
||||
* Indicates if the filter chain should be continued prior to delegation to
|
||||
* {@link #successfulAuthentication(HttpServletRequest, HttpServletResponse,
|
||||
* Authentication)}, which may be useful in certain environment (eg
|
||||
* Tapestry). Defaults to <code>false</code>.
|
||||
*/
|
||||
private boolean continueChainBeforeSuccessfulAuthentication = false;
|
||||
|
||||
/**
|
||||
* If true, causes any redirection URLs to be calculated minus the protocol
|
||||
* and context path (defaults to false).
|
||||
*/
|
||||
protected boolean useRelativeContext = false;
|
||||
|
||||
|
||||
/**
|
||||
* Tells if we on successful authentication should invalidate the
|
||||
* current session. This is a common guard against session fixation attacks.
|
||||
|
@ -185,19 +161,16 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
|||
|
||||
private boolean allowSessionCreation = true;
|
||||
|
||||
private boolean serverSideRedirect = false;
|
||||
|
||||
private SessionRegistry sessionRegistry;
|
||||
|
||||
private AuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
|
||||
private AuthenticationFailureHandler failureHandler = null;
|
||||
private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.hasLength(filterProcessesUrl, "filterProcessesUrl must be specified");
|
||||
Assert.isTrue(UrlUtils.isValidRedirectUrl(filterProcessesUrl), filterProcessesUrl + " isn't a valid redirect URL");
|
||||
Assert.isTrue(UrlUtils.isValidRedirectUrl(authenticationFailureUrl), authenticationFailureUrl + " isn't a valid redirect URL");
|
||||
Assert.notNull(authenticationManager, "authenticationManager must be specified");
|
||||
|
||||
if (rememberMeServices == null) {
|
||||
|
@ -206,19 +179,26 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
|||
}
|
||||
|
||||
/**
|
||||
* Performs actual authentication.
|
||||
*
|
||||
* @param request from which to extract parameters and perform the
|
||||
* authentication
|
||||
*
|
||||
* @return the authenticated user
|
||||
*
|
||||
* @throws AuthenticationException if authentication fails
|
||||
* Invokes the {@link #requiresAuthentication(HttpServletRequest, HttpServletResponse) requiresAuthentication}
|
||||
* method to determine whether the request is for authentication and should be handled by this filter.
|
||||
* If it is an authentication request, the
|
||||
* {@link #attemptAuthentication(HttpServletRequest, HttpServletResponse) attemptAuthentication} will be invoked
|
||||
* to perform the authentication. There are then three possible outcomes:
|
||||
* <ol>
|
||||
* <li>An <tt>Authentication</tt> object is returned.
|
||||
* The {@link #successfulAuthentication(HttpServletRequest, HttpServletResponse, Authentication)
|
||||
* successfulAuthentication} method will be invoked</li>
|
||||
* <li>An <tt>AuthenticationException</tt> occurs during authentication.
|
||||
* The {@link #unSuccessfulAuthentication(HttpServletRequest, HttpServletResponse, Authentication)
|
||||
* unSuccessfulAuthentication} method will be invoked</li>
|
||||
* <li>Null is returned, indicating that the authentication process is incomplete.
|
||||
* The method will then return immediately, assuming that the subclass has done any necessary work (such as
|
||||
* redirects) to continue the authentication process. The assumption is that a later request will be received
|
||||
* by this method where the returned <tt>Authentication</tt> object is not null.
|
||||
* </ol>
|
||||
*/
|
||||
public abstract Authentication attemptAuthentication(HttpServletRequest request) throws AuthenticationException;
|
||||
|
||||
public void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException,
|
||||
ServletException {
|
||||
public void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
|
||||
if (!requiresAuthentication(request, response)) {
|
||||
chain.doFilter(request, response);
|
||||
|
@ -233,8 +213,11 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
|||
Authentication authResult;
|
||||
|
||||
try {
|
||||
onPreAuthentication(request, response);
|
||||
authResult = attemptAuthentication(request);
|
||||
authResult = attemptAuthentication(request, response);
|
||||
if (authResult == null) {
|
||||
// return immediately as subclass has indicated that it hasn't completed authentication
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (AuthenticationException failed) {
|
||||
// Authentication failed
|
||||
|
@ -251,35 +234,17 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
|||
successfulAuthentication(request, response, authResult);
|
||||
}
|
||||
|
||||
protected void onPreAuthentication(HttpServletRequest request, HttpServletResponse response)
|
||||
throws AuthenticationException, IOException {
|
||||
}
|
||||
|
||||
protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException failed) throws IOException {
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Indicates whether this filter should attempt to process a login request
|
||||
* for the current invocation.
|
||||
* </p>
|
||||
* Indicates whether this filter should attempt to process a login request for the current invocation.
|
||||
* <p>
|
||||
* It strips any parameters from the "path" section of the request URL (such
|
||||
* as the jsessionid parameter in
|
||||
* <em>http://host/myapp/index.html;jsessionid=blah</em>) before matching
|
||||
* against the <code>filterProcessesUrl</code> property.
|
||||
* </p>
|
||||
* <p>
|
||||
* Subclasses may override for special requirements, such as Tapestry
|
||||
* integration.
|
||||
* </p>
|
||||
* Subclasses may override for special requirements, such as Tapestry integration.
|
||||
*
|
||||
* @param request as received from the filter chain
|
||||
* @param response as received from the filter chain
|
||||
*
|
||||
* @return <code>true</code> if the filter should attempt authentication,
|
||||
* <code>false</code> otherwise
|
||||
* @return <code>true</code> if the filter should attempt authentication, <code>false</code> otherwise.
|
||||
*/
|
||||
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
|
||||
String uri = request.getRequestURI();
|
||||
|
@ -297,6 +262,41 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
|||
return uri.endsWith(request.getContextPath() + filterProcessesUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs actual authentication.
|
||||
* <p>
|
||||
* The implementation should do one of the following:
|
||||
* <ol>
|
||||
* <li>Return a populated authentication token for the authenticated user, indicating successful authentication</li>
|
||||
* <li>Return null, indicating that the authentication process is still in progress. Before returning, the
|
||||
* implementation should perform any additional work required to complete the process.</li>
|
||||
* <li>Throw an <tt>AuthenticationException</tt> if the authentication process fails</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param request from which to extract parameters and perform the authentication
|
||||
* @param response the response, which may be needed if the implementation has to do a redirect as part of a
|
||||
* multi-stage authentication process (such as OpenID).
|
||||
*
|
||||
* @return the authenticated user token, or null if authentication is incomplete.
|
||||
*
|
||||
* @throws AuthenticationException if authentication fails.
|
||||
*/
|
||||
public abstract Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
|
||||
throws AuthenticationException, IOException, ServletException;
|
||||
|
||||
/**
|
||||
* Default behaviour for successful authentication.
|
||||
* <ol>
|
||||
* <li>Sets the successful <tt>Authentication</tt> object on the {@link SecurityContextHolder}</li>
|
||||
* <li>Performs any configured session migration behaviour</li>
|
||||
* <li>Informs the configured <tt>RememberMeServices</tt> of the successul login</li>
|
||||
* <li>Fires an {@link InteractiveAuthenticationSuccessEvent} via the configured
|
||||
* <tt>ApplicationEventPublisher</tt></li>
|
||||
* <li>Delegates additional behaviour to the {@link AuthenticationSuccessHandler}.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param authResult the object returned from the <tt>attemptAuthentication</tt> method.
|
||||
*/
|
||||
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
|
||||
Authentication authResult) throws IOException, ServletException {
|
||||
|
||||
|
@ -310,28 +310,24 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
|||
SessionUtils.startNewSessionIfRequired(request, migrateInvalidatedSessionAttributes, sessionRegistry);
|
||||
}
|
||||
|
||||
successHandler.onAuthenticationSuccess(request, response, authResult);
|
||||
|
||||
rememberMeServices.loginSuccess(request, response, authResult);
|
||||
|
||||
// Fire event
|
||||
if (this.eventPublisher != null) {
|
||||
eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
|
||||
}
|
||||
|
||||
successHandler.onAuthenticationSuccess(request, response, authResult);
|
||||
}
|
||||
|
||||
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException failed) throws IOException, ServletException {
|
||||
SecurityContextHolder.getContext().setAuthentication(null);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Updated SecurityContextHolder to contain null Authentication");
|
||||
}
|
||||
|
||||
String failureUrl = determineFailureUrl(request, failed);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication request failed: " + failed.toString());
|
||||
logger.debug("Updated SecurityContextHolder to contain null Authentication");
|
||||
logger.debug("Delegating to authentication failure handler" + failureHandler);
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -344,29 +340,9 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
|||
catch (Exception ignored) {
|
||||
}
|
||||
|
||||
onUnsuccessfulAuthentication(request, response, failed);
|
||||
|
||||
rememberMeServices.loginFail(request, response);
|
||||
|
||||
if (failureUrl == null) {
|
||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication Failed:" + failed.getMessage());
|
||||
} else if (serverSideRedirect){
|
||||
request.getRequestDispatcher(failureUrl).forward(request, response);
|
||||
} else {
|
||||
RedirectUtils.sendRedirect(request, response, failureUrl, useRelativeContext);
|
||||
}
|
||||
}
|
||||
|
||||
protected String determineFailureUrl(HttpServletRequest request, AuthenticationException failed) {
|
||||
return exceptionMappings.getProperty(failed.getClass().getName(), authenticationFailureUrl);
|
||||
}
|
||||
|
||||
public String getAuthenticationFailureUrl() {
|
||||
return authenticationFailureUrl;
|
||||
}
|
||||
|
||||
public void setAuthenticationFailureUrl(String authenticationFailureUrl) {
|
||||
this.authenticationFailureUrl = authenticationFailureUrl;
|
||||
failureHandler.onAuthenticationFailure(request, response, failed);
|
||||
}
|
||||
|
||||
protected AuthenticationManager getAuthenticationManager() {
|
||||
|
@ -378,21 +354,12 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
|||
}
|
||||
|
||||
/**
|
||||
* Specifies the default <code>filterProcessesUrl</code> for the
|
||||
* implementation.
|
||||
* Specifies the default <code>filterProcessesUrl</code> for the implementation.
|
||||
*
|
||||
* @return the default <code>filterProcessesUrl</code>
|
||||
*/
|
||||
public abstract String getDefaultFilterProcessesUrl();
|
||||
|
||||
protected Properties getExceptionMappings() {
|
||||
return new Properties(exceptionMappings);
|
||||
}
|
||||
|
||||
public void setExceptionMappings(Properties exceptionMappings) {
|
||||
this.exceptionMappings = exceptionMappings;
|
||||
}
|
||||
|
||||
public String getFilterProcessesUrl() {
|
||||
return filterProcessesUrl;
|
||||
}
|
||||
|
@ -409,6 +376,12 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
|||
this.rememberMeServices = rememberMeServices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the filter chain should be continued prior to delegation to
|
||||
* {@link #successfulAuthentication(HttpServletRequest, HttpServletResponse,
|
||||
* Authentication)}, which may be useful in certain environment (such as
|
||||
* Tapestry applications). Defaults to <code>false</code>.
|
||||
*/
|
||||
public void setContinueChainBeforeSuccessfulAuthentication(boolean continueChainBeforeSuccessfulAuthentication) {
|
||||
this.continueChainBeforeSuccessfulAuthentication = continueChainBeforeSuccessfulAuthentication;
|
||||
}
|
||||
|
@ -439,10 +412,6 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
|||
return authenticationDetailsSource;
|
||||
}
|
||||
|
||||
public void setUseRelativeContext(boolean useRelativeContext) {
|
||||
this.useRelativeContext = useRelativeContext;
|
||||
}
|
||||
|
||||
protected boolean getAllowSessionCreation() {
|
||||
return allowSessionCreation;
|
||||
}
|
||||
|
@ -451,15 +420,6 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
|||
this.allowSessionCreation = allowSessionCreation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if we are to do a server side include of the error URL instead of a 302 redirect.
|
||||
*
|
||||
* @param serverSideRedirect
|
||||
*/
|
||||
public void setServerSideRedirect(boolean serverSideRedirect) {
|
||||
this.serverSideRedirect = serverSideRedirect;
|
||||
}
|
||||
|
||||
/**
|
||||
* The session registry needs to be set if session fixation attack protection is in use (and concurrent
|
||||
* session control is enabled).
|
||||
|
|
|
@ -4,11 +4,14 @@ import java.io.IOException;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.security.AuthenticationException;
|
||||
import org.springframework.security.util.RedirectUtils;
|
||||
import org.springframework.security.util.UrlUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Uses the internal map of exceptions types to URLs to determine the destination on authentication failure. The keys
|
||||
|
@ -26,7 +29,7 @@ public class ExceptionMappingAuthenticationFailureHandler extends SimpleUrlAuthe
|
|||
|
||||
@Override
|
||||
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException exception) throws IOException {
|
||||
AuthenticationException exception) throws IOException, ServletException {
|
||||
String url = failureUrlMap.get(exception.getClass().getName());
|
||||
|
||||
if (url != null) {
|
||||
|
@ -36,5 +39,23 @@ public class ExceptionMappingAuthenticationFailureHandler extends SimpleUrlAuthe
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the map of exception types (by name) to URLs.
|
||||
*
|
||||
* @param failureUrlMap the map keyed by the fully-qualified name of the exception class, with the corresponding
|
||||
* failure URL as the value.
|
||||
*
|
||||
* @throws IllegalArgumentException if the entries are not Strings or the URL is not valid.
|
||||
*/
|
||||
public void setExceptionMappings(Map<?,?> failureUrlMap) {
|
||||
this.failureUrlMap.clear();
|
||||
for (Map.Entry<?,?> entry : failureUrlMap.entrySet()) {
|
||||
Object exception = entry.getKey();
|
||||
Object url = entry.getValue();
|
||||
Assert.isInstanceOf(String.class, exception, "Exception key must be a String (the exception classname).");
|
||||
Assert.isInstanceOf(String.class, url, "URL must be a String");
|
||||
Assert.isTrue(UrlUtils.isValidRedirectUrl((String)url), "Not a valid redirect URL: " + url);
|
||||
this.failureUrlMap.put((String)exception, (String)url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.apache.commons.logging.LogFactory;
|
|||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.ui.savedrequest.SavedRequest;
|
||||
import org.springframework.security.util.RedirectUtils;
|
||||
import org.springframework.security.util.UrlUtils;
|
||||
import org.springframework.security.wrapper.SavedRequestAwareWrapper;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
@ -163,7 +164,7 @@ public class SavedRequestAwareAuthenticationSuccessHandler implements Authentica
|
|||
* @param defaultTargetUrl
|
||||
*/
|
||||
public void setDefaultTargetUrl(String defaultTargetUrl) {
|
||||
Assert.isTrue(defaultTargetUrl.startsWith("/") | defaultTargetUrl.startsWith("http"),
|
||||
Assert.isTrue(UrlUtils.isValidRedirectUrl(defaultTargetUrl),
|
||||
"defaultTarget must start with '/' or with 'http(s)'");
|
||||
this.defaultTargetUrl = defaultTargetUrl;
|
||||
}
|
||||
|
|
|
@ -2,11 +2,14 @@ package org.springframework.security.ui;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.security.AuthenticationException;
|
||||
import org.springframework.security.util.RedirectUtils;
|
||||
import org.springframework.security.util.UrlUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* <tt>AuthenticationFailureHandler</tt> which performs a redirect to the value of the {@link #setDefaultFailureUrl
|
||||
|
@ -31,11 +34,15 @@ public class SimpleUrlAuthenticationFailureHandler implements AuthenticationFail
|
|||
private boolean useRelativeContext = false;
|
||||
|
||||
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException exception) throws IOException {
|
||||
AuthenticationException exception) throws IOException, ServletException {
|
||||
if (defaultFailureUrl == null) {
|
||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication Failed:" + exception.getMessage());
|
||||
} else {
|
||||
RedirectUtils.sendRedirect(request, response, defaultFailureUrl, useRelativeContext);
|
||||
if (forwardToDestination) {
|
||||
request.getRequestDispatcher(defaultFailureUrl).forward(request, response);
|
||||
} else {
|
||||
RedirectUtils.sendRedirect(request, response, defaultFailureUrl, useRelativeContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,7 +51,8 @@ public class SimpleUrlAuthenticationFailureHandler implements AuthenticationFail
|
|||
*
|
||||
* @param defaultFailureUrl the failure URL, for example "/loginFailed.jsp".
|
||||
*/
|
||||
public void setDefaultTargetUrl(String defaultFailureUrl) {
|
||||
public void setDefaultFailureUrl(String defaultFailureUrl) {
|
||||
Assert.isTrue(UrlUtils.isValidRedirectUrl(defaultFailureUrl));
|
||||
this.defaultFailureUrl = defaultFailureUrl;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.springframework.security.util.TextUtils;
|
|||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
|
||||
|
@ -53,7 +54,7 @@ public class AuthenticationProcessingFilter extends AbstractProcessingFilter {
|
|||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public Authentication attemptAuthentication(HttpServletRequest request) throws AuthenticationException {
|
||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
|
||||
String username = obtainUsername(request);
|
||||
String password = obtainPassword(request);
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.springframework.security.util.PortMapperImpl;
|
|||
import org.springframework.security.util.PortResolver;
|
||||
import org.springframework.security.util.PortResolverImpl;
|
||||
import org.springframework.security.util.RedirectUrlBuilder;
|
||||
import org.springframework.security.util.UrlUtils;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
@ -31,6 +32,7 @@ import org.apache.commons.logging.LogFactory;
|
|||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
@ -79,7 +81,8 @@ public class AuthenticationProcessingFilterEntryPoint implements AuthenticationE
|
|||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.hasLength(loginFormUrl, "loginFormUrl must be specified");
|
||||
Assert.isTrue(StringUtils.hasText(loginFormUrl) && UrlUtils.isValidRedirectUrl(loginFormUrl),
|
||||
"loginFormUrl must be specified and must be a valid redirect URL");
|
||||
Assert.notNull(portMapper, "portMapper must be specified");
|
||||
Assert.notNull(portResolver, "portResolver must be specified");
|
||||
}
|
||||
|
@ -117,7 +120,7 @@ public class AuthenticationProcessingFilterEntryPoint implements AuthenticationE
|
|||
|
||||
if (redirectUrl == null) {
|
||||
String loginForm = determineUrlToUseForThisRequest(httpRequest, httpResponse, authException);
|
||||
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Server side forward to: " + loginForm);
|
||||
}
|
||||
|
@ -246,7 +249,7 @@ public class AuthenticationProcessingFilterEntryPoint implements AuthenticationE
|
|||
*/
|
||||
public void setServerSideRedirect(boolean serverSideRedirect) {
|
||||
this.serverSideRedirect = serverSideRedirect;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isServerSideRedirect() {
|
||||
return serverSideRedirect;
|
||||
|
|
|
@ -15,13 +15,11 @@
|
|||
|
||||
package org.springframework.security.util;
|
||||
|
||||
import org.springframework.security.intercept.web.FilterInvocation;
|
||||
|
||||
import org.springframework.security.ui.savedrequest.SavedRequest;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.security.intercept.web.FilterInvocation;
|
||||
import org.springframework.security.ui.savedrequest.SavedRequest;
|
||||
|
||||
|
||||
/**
|
||||
* Provides static methods for composing URLs.<p>Placed into a separate class for visibility, so that changes to
|
||||
|
@ -102,8 +100,11 @@ public final class UrlUtils {
|
|||
return buildRequestUrl(sr.getServletPath(), sr.getRequestURI(), sr.getContextPath(), sr.getPathInfo(),
|
||||
sr.getQueryString());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the supplied URL starts with a "/" or "http".
|
||||
*/
|
||||
public static boolean isValidRedirectUrl(String url) {
|
||||
return !StringUtils.hasText(url) || url.startsWith("/") || url.toLowerCase().startsWith("http");
|
||||
return url.startsWith("/") || url.toLowerCase().startsWith("http");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ import org.springframework.security.util.PortResolverImpl;
|
|||
*/
|
||||
public class AbstractProcessingFilterTests extends TestCase {
|
||||
SavedRequestAwareAuthenticationSuccessHandler successHandler;
|
||||
SimpleUrlAuthenticationFailureHandler failureHandler;
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
private MockHttpServletRequest createMockRequest() {
|
||||
|
@ -102,6 +103,8 @@ public class AbstractProcessingFilterTests extends TestCase {
|
|||
super.setUp();
|
||||
successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
|
||||
successHandler.setDefaultTargetUrl("/logged_in.jsp");
|
||||
failureHandler = new SimpleUrlAuthenticationFailureHandler();
|
||||
failureHandler.setDefaultFailureUrl("/failed.jsp");
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
|
@ -133,7 +136,7 @@ public class AbstractProcessingFilterTests extends TestCase {
|
|||
|
||||
// Setup our test object, to deny access
|
||||
MockAbstractProcessingFilter filter = new MockAbstractProcessingFilter(false);
|
||||
filter.setAuthenticationFailureUrl("/failed.jsp");
|
||||
filter.setFailureHandler(failureHandler);
|
||||
|
||||
// Test
|
||||
executeFilterInContainerSimulator(config, filter, request, response, chain);
|
||||
|
@ -143,11 +146,11 @@ public class AbstractProcessingFilterTests extends TestCase {
|
|||
|
||||
//Prepare again, this time using the exception mapping
|
||||
filter = new MockAbstractProcessingFilter(new AccountExpiredException("You're account is expired"));
|
||||
filter.setAuthenticationFailureUrl("/failed.jsp");
|
||||
|
||||
Properties exceptionMappings = filter.getExceptionMappings();
|
||||
ExceptionMappingAuthenticationFailureHandler failureHandler = new ExceptionMappingAuthenticationFailureHandler();
|
||||
filter.setFailureHandler(failureHandler);
|
||||
Properties exceptionMappings = new Properties();
|
||||
exceptionMappings.setProperty(AccountExpiredException.class.getName(), "/accountExpired.jsp");
|
||||
filter.setExceptionMappings(exceptionMappings);
|
||||
failureHandler.setExceptionMappings(exceptionMappings);
|
||||
response = new MockHttpServletResponse();
|
||||
|
||||
// Test
|
||||
|
@ -186,7 +189,6 @@ public class AbstractProcessingFilterTests extends TestCase {
|
|||
AbstractProcessingFilter filter = new MockAbstractProcessingFilter();
|
||||
filter.setAuthenticationManager(new MockAuthenticationManager());
|
||||
filter.setFilterProcessesUrl("/p");
|
||||
filter.setAuthenticationFailureUrl("/fail");
|
||||
filter.afterPropertiesSet();
|
||||
|
||||
assertNotNull(filter.getRememberMeServices());
|
||||
|
@ -194,7 +196,6 @@ public class AbstractProcessingFilterTests extends TestCase {
|
|||
assertEquals(TokenBasedRememberMeServices.class, filter.getRememberMeServices().getClass());
|
||||
assertTrue(filter.getAuthenticationManager() != null);
|
||||
assertEquals("/p", filter.getFilterProcessesUrl());
|
||||
assertEquals("/fail", filter.getAuthenticationFailureUrl());
|
||||
}
|
||||
|
||||
public void testIgnoresAnyServletPathOtherThanFilterProcessesUrl() throws Exception {
|
||||
|
@ -234,7 +235,7 @@ public class AbstractProcessingFilterTests extends TestCase {
|
|||
|
||||
filter.setFilterProcessesUrl("/j_mock_post");
|
||||
filter.setSuccessHandler(successHandler);
|
||||
filter.setAuthenticationFailureUrl("/failure.jsp");
|
||||
filter.setFailureHandler(failureHandler);
|
||||
filter.setAuthenticationManager(new MockAuthenticationManager(true));
|
||||
filter.afterPropertiesSet();
|
||||
|
||||
|
@ -249,7 +250,7 @@ public class AbstractProcessingFilterTests extends TestCase {
|
|||
|
||||
public void testStartupDetectsInvalidAuthenticationManager() throws Exception {
|
||||
AbstractProcessingFilter filter = new MockAbstractProcessingFilter();
|
||||
filter.setAuthenticationFailureUrl("/failed.jsp");
|
||||
filter.setFailureHandler(failureHandler);
|
||||
successHandler.setDefaultTargetUrl("/");
|
||||
filter.setSuccessHandler(successHandler);
|
||||
filter.setFilterProcessesUrl("/j_spring_security_check");
|
||||
|
@ -264,7 +265,7 @@ public class AbstractProcessingFilterTests extends TestCase {
|
|||
|
||||
public void testStartupDetectsInvalidFilterProcessesUrl() throws Exception {
|
||||
AbstractProcessingFilter filter = new MockAbstractProcessingFilter();
|
||||
filter.setAuthenticationFailureUrl("/failed.jsp");
|
||||
filter.setFailureHandler(failureHandler);
|
||||
filter.setAuthenticationManager(new MockAuthenticationManager());
|
||||
filter.setSuccessHandler(successHandler);
|
||||
filter.setFilterProcessesUrl(null);
|
||||
|
@ -308,7 +309,7 @@ public class AbstractProcessingFilterTests extends TestCase {
|
|||
// Setup our test object, to deny access
|
||||
filter = new MockAbstractProcessingFilter(false);
|
||||
filter.setFilterProcessesUrl("/j_mock_post");
|
||||
filter.setAuthenticationFailureUrl("/failed.jsp");
|
||||
filter.setFailureHandler(failureHandler);
|
||||
|
||||
// Test
|
||||
executeFilterInContainerSimulator(config, filter, request, response, chain);
|
||||
|
@ -468,7 +469,7 @@ public class AbstractProcessingFilterTests extends TestCase {
|
|||
// Reject authentication, so exception would normally be stored in session
|
||||
MockAbstractProcessingFilter filter = new MockAbstractProcessingFilter(false);
|
||||
filter.setAllowSessionCreation(false);
|
||||
filter.setAuthenticationFailureUrl("/");
|
||||
filter.setFailureHandler(failureHandler);
|
||||
successHandler.setDefaultTargetUrl("http://monkeymachine.co.uk/");
|
||||
filter.setSuccessHandler(successHandler);
|
||||
|
||||
|
@ -509,8 +510,9 @@ public class AbstractProcessingFilterTests extends TestCase {
|
|||
MockAbstractProcessingFilter filter = new MockAbstractProcessingFilter(false);
|
||||
successHandler.setDefaultTargetUrl("http://monkeymachine.co.uk/");
|
||||
filter.setSuccessHandler(successHandler);
|
||||
filter.setAuthenticationFailureUrl("/error");
|
||||
filter.setServerSideRedirect(true);
|
||||
filter.setFailureHandler(failureHandler);
|
||||
failureHandler.setForwardToDestination(true);
|
||||
failureHandler.setDefaultFailureUrl("/error");
|
||||
|
||||
executeFilterInContainerSimulator(config, filter, request, response, chain);
|
||||
|
||||
|
@ -532,7 +534,7 @@ public class AbstractProcessingFilterTests extends TestCase {
|
|||
filter.setSuccessHandler(successHandler);
|
||||
successHandler.setDefaultTargetUrl("http://monkeymachine.co.uk/");
|
||||
successHandler.setTargetUrlParameter("targetUrl");
|
||||
filter.setAuthenticationFailureUrl("/error");
|
||||
filter.setFailureHandler(failureHandler);
|
||||
|
||||
executeFilterInContainerSimulator(config, filter, request, response, chain);
|
||||
|
||||
|
@ -561,7 +563,7 @@ public class AbstractProcessingFilterTests extends TestCase {
|
|||
private MockAbstractProcessingFilter() {
|
||||
}
|
||||
|
||||
public Authentication attemptAuthentication(HttpServletRequest request) throws AuthenticationException {
|
||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
|
||||
if (grantAccess) {
|
||||
return new UsernamePasswordAuthenticationToken("test", "test", AuthorityUtils.createAuthorityList("TEST"));
|
||||
} else {
|
||||
|
|
|
@ -47,7 +47,6 @@ public class AuthenticationProcessingFilterEntryPointTests extends TestCase {
|
|||
ep.afterPropertiesSet();
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertEquals("loginFormUrl must be specified", expected.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,7 +59,6 @@ public class AuthenticationProcessingFilterEntryPointTests extends TestCase {
|
|||
ep.afterPropertiesSet();
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertEquals("portMapper must be specified", expected.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,7 +71,6 @@ public class AuthenticationProcessingFilterEntryPointTests extends TestCase {
|
|||
ep.afterPropertiesSet();
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertEquals("portResolver must be specified", expected.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,7 +123,7 @@ public class AuthenticationProcessingFilterEntryPointTests extends TestCase {
|
|||
assertEquals("https://www.example.com:8443/bigWebApp/hello", response.getRedirectedUrl());
|
||||
|
||||
PortMapperImpl portMapper = new PortMapperImpl();
|
||||
Map map = new HashMap();
|
||||
Map<String,String> map = new HashMap<String,String>();
|
||||
map.put("8888", "9999");
|
||||
portMapper.setPortMappings(map);
|
||||
response = new MockHttpServletResponse();
|
||||
|
|
|
@ -24,8 +24,10 @@ import org.springframework.security.AuthenticationException;
|
|||
import org.springframework.security.ui.WebAuthenticationDetails;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -60,7 +62,7 @@ public class AuthenticationProcessingFilterTests extends TestCase {
|
|||
filter.setAuthenticationManager(new MockAuthenticationManager(true));
|
||||
filter.init(null);
|
||||
|
||||
Authentication result = filter.attemptAuthentication(request);
|
||||
Authentication result = filter.attemptAuthentication(request, new MockHttpServletResponse());
|
||||
assertTrue(result != null);
|
||||
assertEquals("rod", request.getSession().getAttribute(
|
||||
AuthenticationProcessingFilter.SPRING_SECURITY_LAST_USERNAME_KEY));
|
||||
|
@ -74,7 +76,7 @@ public class AuthenticationProcessingFilterTests extends TestCase {
|
|||
AuthenticationProcessingFilter filter = new AuthenticationProcessingFilter();
|
||||
filter.setAuthenticationManager(new MockAuthenticationManager(true));
|
||||
|
||||
Authentication result = filter.attemptAuthentication(request);
|
||||
Authentication result = filter.attemptAuthentication(request, new MockHttpServletResponse());
|
||||
assertTrue(result != null);
|
||||
}
|
||||
|
||||
|
@ -85,7 +87,7 @@ public class AuthenticationProcessingFilterTests extends TestCase {
|
|||
AuthenticationProcessingFilter filter = new AuthenticationProcessingFilter();
|
||||
filter.setAuthenticationManager(new MockAuthenticationManager(true));
|
||||
|
||||
Authentication result = filter.attemptAuthentication(request);
|
||||
Authentication result = filter.attemptAuthentication(request, new MockHttpServletResponse());
|
||||
assertTrue(result != null);
|
||||
}
|
||||
|
||||
|
@ -99,7 +101,7 @@ public class AuthenticationProcessingFilterTests extends TestCase {
|
|||
request.addParameter("x", "rod");
|
||||
request.addParameter("y", "koala");
|
||||
|
||||
Authentication result = filter.attemptAuthentication(request);
|
||||
Authentication result = filter.attemptAuthentication(request, new MockHttpServletResponse());
|
||||
assertTrue(result != null);
|
||||
assertEquals("127.0.0.1", ((WebAuthenticationDetails) result.getDetails()).getRemoteAddress());
|
||||
}
|
||||
|
@ -112,7 +114,7 @@ public class AuthenticationProcessingFilterTests extends TestCase {
|
|||
AuthenticationProcessingFilter filter = new AuthenticationProcessingFilter();
|
||||
filter.setAuthenticationManager(new MockAuthenticationManager(true));
|
||||
|
||||
Authentication result = filter.attemptAuthentication(request);
|
||||
Authentication result = filter.attemptAuthentication(request, new MockHttpServletResponse());
|
||||
assertEquals("rod", result.getName());
|
||||
}
|
||||
|
||||
|
@ -123,7 +125,7 @@ public class AuthenticationProcessingFilterTests extends TestCase {
|
|||
filter.setAuthenticationManager(new MockAuthenticationManager(false));
|
||||
|
||||
try {
|
||||
filter.attemptAuthentication(request);
|
||||
filter.attemptAuthentication(request, new MockHttpServletResponse());
|
||||
fail("Expected AuthenticationException");
|
||||
} catch (AuthenticationException e) {
|
||||
}
|
||||
|
@ -143,7 +145,7 @@ public class AuthenticationProcessingFilterTests extends TestCase {
|
|||
filter.setAllowSessionCreation(false);
|
||||
filter.setAuthenticationManager(new MockAuthenticationManager(true));
|
||||
|
||||
filter.attemptAuthentication(request);
|
||||
filter.attemptAuthentication(request, new MockHttpServletResponse());
|
||||
|
||||
assertNull(request.getSession(false));
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.springframework.security.ui.webapp;
|
|||
import static org.junit.Assert.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
|
@ -38,7 +39,7 @@ public class DefaultLoginPageGeneratingFilterTests {
|
|||
private static class MockProcessingFilter extends AbstractProcessingFilter {
|
||||
|
||||
@Override
|
||||
public Authentication attemptAuthentication(HttpServletRequest request) throws AuthenticationException {
|
||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,6 @@ http://www.springframework.org/schema/security http://www.springframework.org/sc
|
|||
<bean id="sif" class="org.springframework.security.context.HttpSessionContextIntegrationFilter"/>
|
||||
|
||||
<bean id="apf" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
|
||||
<property name="authenticationFailureUrl" value="/whocares2"/>
|
||||
<property name="authenticationManager">
|
||||
<bean class="org.springframework.security.MockAuthenticationManager"/>
|
||||
</property>
|
||||
|
|
|
@ -15,18 +15,16 @@
|
|||
package org.springframework.security.providers.openid;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
|
||||
import org.springframework.security.providers.AbstractAuthenticationToken;
|
||||
|
||||
|
||||
/**
|
||||
* OpenID Authentication Token
|
||||
*
|
||||
* @author Robin Bramley, Opsera Ltd
|
||||
* @author Robin Bramley
|
||||
* @version $Id$
|
||||
*/
|
||||
public class OpenIDAuthenticationToken extends AbstractAuthenticationToken {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
@ -60,7 +58,8 @@ public class OpenIDAuthenticationToken extends AbstractAuthenticationToken {
|
|||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/* (non-Javadoc)
|
||||
/**
|
||||
* Returns 'null' always, as no credentials are processed by the OpenID provider.
|
||||
* @see org.springframework.security.Authentication#getCredentials()
|
||||
*/
|
||||
public Object getCredentials() {
|
||||
|
@ -75,7 +74,8 @@ public class OpenIDAuthenticationToken extends AbstractAuthenticationToken {
|
|||
return message;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
/**
|
||||
* Returns the <tt>identityUrl</tt> value.
|
||||
* @see org.springframework.security.Authentication#getPrincipal()
|
||||
*/
|
||||
public Object getPrincipal() {
|
||||
|
|
|
@ -15,47 +15,67 @@
|
|||
|
||||
package org.springframework.security.ui.openid;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.AuthenticationException;
|
||||
import org.springframework.security.AuthenticationServiceException;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.openid.OpenIDAuthenticationProvider;
|
||||
import org.springframework.security.providers.openid.OpenIDAuthenticationToken;
|
||||
import org.springframework.security.ui.AbstractProcessingFilter;
|
||||
import org.springframework.security.ui.FilterChainOrder;
|
||||
import org.springframework.security.ui.openid.consumers.OpenID4JavaConsumer;
|
||||
import org.springframework.security.ui.webapp.AuthenticationProcessingFilter;
|
||||
import org.springframework.security.util.RedirectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* @author Robin Bramley, Opsera Ltd
|
||||
* Filter which processes OpenID authentication requests.
|
||||
* <p>
|
||||
* The OpenID authentication involves two stages.
|
||||
*
|
||||
* <h2>Submission of OpenID identity</h2>
|
||||
*
|
||||
* The user's OpenID identity is submitted via a login form, just as it would be for a normal form login. At this stage
|
||||
* the filter will extract the identity from the submitted request (by default, the parameter is called
|
||||
* <tt>j_username</tt>, as it is for form login. It then passes the identity to the configured <tt>OpenIDConsumer</tt>,
|
||||
* which returns the URL to which the request should be redirected for authentication. A "return_to" URL is also supplied,
|
||||
* which matches the URL processed by this filter, to allow the filter to handle the request once the user has
|
||||
* been successfully authenticated. The OpenID server will then authenticate the user and redirect back to the
|
||||
* application.
|
||||
*
|
||||
* <h2>Processing the Redirect from the OpenID Server</h2>
|
||||
*
|
||||
* Once the user has been authenticated externally, the redirected request will be passed to the <tt>OpenIDConsumer</tt>
|
||||
* again for validation. The returned <tt>OpenIDAuthentication</tt> will be passed to the <tt>AuthenticationManager</tt>
|
||||
* where it should (normally) be processed by an <tt>OpenIDAuthenticationProvider</tt> in order to load the authorities
|
||||
* for the user.
|
||||
*
|
||||
* @author Robin Bramley
|
||||
* @author Ray Krueger
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 2.0
|
||||
* @see OpenIDAuthenticationProvider
|
||||
*/
|
||||
public class OpenIDAuthenticationProcessingFilter extends AbstractProcessingFilter {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
private static final Log log = LogFactory.getLog(OpenIDAuthenticationProcessingFilter.class);
|
||||
public static final String DEFAULT_CLAIMED_IDENTITY_FIELD = "j_username";
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private OpenIDConsumer consumer;
|
||||
private String claimedIdentityFieldName = DEFAULT_CLAIMED_IDENTITY_FIELD;
|
||||
private Map realmMapping = new HashMap();
|
||||
private Map<String,String> realmMapping = Collections.emptyMap();
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
|
@ -66,31 +86,65 @@ public class OpenIDAuthenticationProcessingFilter extends AbstractProcessingFilt
|
|||
}
|
||||
}
|
||||
|
||||
public Authentication attemptAuthentication(HttpServletRequest req) throws AuthenticationException {
|
||||
public String getDefaultFilterProcessesUrl() {
|
||||
return "/j_spring_openid_security_check";
|
||||
}
|
||||
|
||||
/**
|
||||
* Authentication has two phases.
|
||||
* <ol>
|
||||
* <li>The initial submission of the claimed OpenID. A redirect to the URL returned from the consumer
|
||||
* will be performed and null will be returned.</li>
|
||||
* <li>The redirection from the OpenID server to the return_to URL, once it has authenticated the user</li>
|
||||
* </ol>
|
||||
*/
|
||||
@Override
|
||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
|
||||
throws AuthenticationException, IOException {
|
||||
OpenIDAuthenticationToken token;
|
||||
|
||||
String identity = req.getParameter("openid.identity");
|
||||
String identity = request.getParameter("openid.identity");
|
||||
|
||||
if (!StringUtils.hasText(identity)) {
|
||||
String claimedIdentity = obtainUsername(request);
|
||||
// Make the username available to the view
|
||||
String username = obtainUsername(req);
|
||||
setLastUsername(username, req);
|
||||
throw new OpenIDAuthenticationRequiredException("External Authentication Required", username);
|
||||
setLastUsername(claimedIdentity, request);
|
||||
|
||||
try {
|
||||
String returnToUrl = buildReturnToUrl(request);
|
||||
String realm = lookupRealm(returnToUrl);
|
||||
String openIdUrl = consumer.beginConsumption(request, claimedIdentity, returnToUrl, realm);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("return_to is '" + returnToUrl + "', realm is '" + realm + "'");
|
||||
logger.debug("Redirecting to " + openIdUrl);
|
||||
}
|
||||
response.sendRedirect(openIdUrl);
|
||||
|
||||
// Indicate to parent class that authentication is continuing.
|
||||
return null;
|
||||
} catch (OpenIDConsumerException e) {
|
||||
logger.debug("Failed to consume claimedIdentity: " + claimedIdentity, e);
|
||||
throw new AuthenticationServiceException("Unable to process claimed identity '" + claimedIdentity + "'");
|
||||
}
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Supplied OpenID identity is " + identity);
|
||||
}
|
||||
|
||||
try {
|
||||
token = consumer.endConsumption(req);
|
||||
token = consumer.endConsumption(request);
|
||||
} catch (OpenIDConsumerException oice) {
|
||||
throw new AuthenticationServiceException("Consumer error", oice);
|
||||
}
|
||||
|
||||
token.setDetails(authenticationDetailsSource.buildDetails(req));
|
||||
token.setDetails(authenticationDetailsSource.buildDetails(request));
|
||||
|
||||
// delegate to the auth provider
|
||||
// delegate to the authentication provider
|
||||
Authentication authentication = this.getAuthenticationManager().authenticate(token);
|
||||
|
||||
if (authentication.isAuthenticated()) {
|
||||
setLastUsername(token.getIdentityUrl(), req);
|
||||
setLastUsername(token.getIdentityUrl(), request);
|
||||
}
|
||||
|
||||
return authentication;
|
||||
|
@ -104,28 +158,8 @@ public class OpenIDAuthenticationProcessingFilter extends AbstractProcessingFilt
|
|||
}
|
||||
}
|
||||
|
||||
protected String determineFailureUrl(HttpServletRequest request, AuthenticationException failed) {
|
||||
if (failed instanceof OpenIDAuthenticationRequiredException) {
|
||||
OpenIDAuthenticationRequiredException openIdRequiredException = (OpenIDAuthenticationRequiredException) failed;
|
||||
String claimedIdentity = openIdRequiredException.getClaimedIdentity();
|
||||
|
||||
if (StringUtils.hasText(claimedIdentity)) {
|
||||
try {
|
||||
String returnToUrl = buildReturnToUrl(request);
|
||||
String realm = lookupRealm(returnToUrl);
|
||||
return consumer.beginConsumption(request, claimedIdentity, returnToUrl, realm);
|
||||
} catch (OpenIDConsumerException e) {
|
||||
log.error("Unable to consume claimedIdentity [" + claimedIdentity + "]", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.determineFailureUrl(request, failed);
|
||||
}
|
||||
|
||||
protected String lookupRealm(String returnToUrl) {
|
||||
|
||||
String mapping = (String) realmMapping.get(returnToUrl);
|
||||
String mapping = realmMapping.get(returnToUrl);
|
||||
|
||||
if (mapping == null) {
|
||||
try {
|
||||
|
@ -140,61 +174,52 @@ public class OpenIDAuthenticationProcessingFilter extends AbstractProcessingFilt
|
|||
.append("/");
|
||||
mapping = realmBuffer.toString();
|
||||
} catch (MalformedURLException e) {
|
||||
log.warn("returnToUrl was not a valid URL: [" + returnToUrl + "]", e);
|
||||
logger.warn("returnToUrl was not a valid URL: [" + returnToUrl + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the <tt>return_to</tt> URL that will be sent to the OpenID service provider.
|
||||
* By default returns the URL of the current request.
|
||||
*
|
||||
* @param request the current request which is being processed by this filter
|
||||
* @return The <tt>return_to</tt> URL.
|
||||
*/
|
||||
protected String buildReturnToUrl(HttpServletRequest request) {
|
||||
return request.getRequestURL().toString();
|
||||
}
|
||||
|
||||
public String getClaimedIdentityFieldName() {
|
||||
return claimedIdentityFieldName;
|
||||
}
|
||||
|
||||
public OpenIDConsumer getConsumer() {
|
||||
return consumer;
|
||||
}
|
||||
|
||||
public String getDefaultFilterProcessesUrl() {
|
||||
return "/j_spring_openid_security_check";
|
||||
}
|
||||
|
||||
protected boolean isAuthenticated(HttpServletRequest request) {
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
return (auth != null) && auth.isAuthenticated();
|
||||
}
|
||||
|
||||
/**
|
||||
* The OpenIdAuthenticationProcessingFilter will ignore the request coming in if this method returns false.
|
||||
* The default functionality checks if the request scheme starts with http. <br/
|
||||
* > This method should be overridden in subclasses that wish to consider a different strategy
|
||||
*
|
||||
* @param request HttpServletRequest we're processing
|
||||
* @return true if this request is determined to be an OpenID request.
|
||||
* Reads the <tt>claimedIdentityFieldName</tt> from the submitted request.
|
||||
*/
|
||||
protected boolean isOpenIdRequest(HttpServletRequest request) {
|
||||
String username = obtainUsername(request);
|
||||
return (StringUtils.hasText(username)) && username.toLowerCase().startsWith("http");
|
||||
}
|
||||
|
||||
protected String obtainUsername(HttpServletRequest req) {
|
||||
return req.getParameter(claimedIdentityFieldName);
|
||||
}
|
||||
|
||||
protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException failed) throws IOException {
|
||||
if (failed instanceof OpenIDAuthenticationRequiredException) {
|
||||
OpenIDAuthenticationRequiredException openIdAuthenticationRequiredException = (OpenIDAuthenticationRequiredException) failed;
|
||||
request.setAttribute(OpenIDAuthenticationRequiredException.class.getName(),
|
||||
openIdAuthenticationRequiredException.getClaimedIdentity());
|
||||
}
|
||||
/**
|
||||
* Maps the <tt>return_to url</tt> to a realm, for example:
|
||||
* <pre>
|
||||
* http://www.example.com/j_spring_openid_security_check -> http://www.example.com/realm</tt>
|
||||
* </pre>
|
||||
* If no mapping is provided then the returnToUrl will be parsed to extract the protocol, hostname and port followed
|
||||
* by a trailing slash.
|
||||
* This means that <tt>http://www.example.com/j_spring_openid_security_check</tt> will automatically become
|
||||
* <tt>http://www.example.com:80/</tt>
|
||||
*
|
||||
* @param realmMapping containing returnToUrl -> realm mappings
|
||||
*/
|
||||
public void setRealmMapping(Map<String,String> realmMapping) {
|
||||
this.realmMapping = realmMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the request parameter containing the OpenID identity, as submitted from the initial login form.
|
||||
*
|
||||
* @param claimedIdentityFieldName defaults to "j_username"
|
||||
*/
|
||||
public void setClaimedIdentityFieldName(String claimedIdentityFieldName) {
|
||||
this.claimedIdentityFieldName = claimedIdentityFieldName;
|
||||
}
|
||||
|
@ -203,61 +228,7 @@ public class OpenIDAuthenticationProcessingFilter extends AbstractProcessingFilt
|
|||
this.consumer = consumer;
|
||||
}
|
||||
|
||||
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException failed) throws IOException {
|
||||
SecurityContextHolder.getContext().setAuthentication(null);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Updated SecurityContextHolder to contain null Authentication");
|
||||
}
|
||||
|
||||
String failureUrl = determineFailureUrl(request, failed);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication request failed: " + failed.toString());
|
||||
}
|
||||
|
||||
if (getAllowSessionCreation()) {
|
||||
try {
|
||||
request.getSession().setAttribute(SPRING_SECURITY_LAST_EXCEPTION_KEY, failed);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
super.getRememberMeServices().loginFail(request, response);
|
||||
|
||||
RedirectUtils.sendRedirect(request, response, failureUrl, useRelativeContext);
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return FilterChainOrder.OPENID_PROCESSING_FILTER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the return_to url to a realm.<br/>
|
||||
* For example http://www.example.com/j_spring_openid_security_check -> http://www.example.com/realm<br/>
|
||||
* If no mapping is provided then the returnToUrl will be parsed to extract the protocol, hostname and port followed
|
||||
* by a trailing slash.<br/>
|
||||
* This means that http://www.example.com/j_spring_openid_security_check will automatically
|
||||
* become http://www.example.com:80/
|
||||
*
|
||||
* @return Map containing returnToUrl -> realm mappings
|
||||
*/
|
||||
public Map getRealmMapping() {
|
||||
return realmMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the return_to url to a realm.<br/>
|
||||
* For example http://www.example.com/j_spring_openid_security_check -> http://www.example.com/realm<br/>
|
||||
* If no mapping is provided then the returnToUrl will be parsed to extract the protocol, hostname and port followed
|
||||
* by a trailing slash.<br/>
|
||||
* This means that http://www.example.com/j_spring_openid_security_check will automatically
|
||||
* become http://www.example.com:80/
|
||||
*
|
||||
* @param realmMapping containing returnToUrl -> realm mappings
|
||||
*/
|
||||
public void setRealmMapping(Map realmMapping) {
|
||||
this.realmMapping = realmMapping;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.ui.openid;
|
||||
|
||||
import org.springframework.security.AuthenticationException;
|
||||
|
||||
/**
|
||||
* @author Ray Krueger
|
||||
*/
|
||||
public class OpenIDAuthenticationRequiredException extends AuthenticationException {
|
||||
|
||||
private final String claimedIdentity;
|
||||
|
||||
public OpenIDAuthenticationRequiredException(String msg, String claimedIdentity) {
|
||||
super(msg);
|
||||
this.claimedIdentity = claimedIdentity;
|
||||
}
|
||||
|
||||
public String getClaimedIdentity() {
|
||||
return claimedIdentity;
|
||||
}
|
||||
}
|
|
@ -29,16 +29,6 @@ public class OpenIDAuthenticationProcessingFilterTests extends TestCase {
|
|||
filter.afterPropertiesSet();
|
||||
}
|
||||
|
||||
public void testNoIdentityCausesException() throws Exception {
|
||||
try {
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
filter.attemptAuthentication(req);
|
||||
fail("OpenIDAuthenticationRequiredException expected, no openid.identity parameter");
|
||||
} catch (OpenIDAuthenticationRequiredException e) {
|
||||
//cool
|
||||
}
|
||||
}
|
||||
|
||||
public void testFilterOperation() throws Exception {
|
||||
MockHttpServletRequest req = new MockHttpServletRequest("GET", REQUEST_PATH);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
|
|
@ -1,20 +1,12 @@
|
|||
# Global logging configuration
|
||||
log4j.rootLogger=INFO, stdout, fileout
|
||||
log4j.rootLogger=INFO, stdout
|
||||
|
||||
log4j.logger.org.springframework.security=DEBUG, stdout, fileout
|
||||
log4j.logger.org.springframework.security=DEBUG
|
||||
|
||||
# Console output...
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.conversionPattern=[%p,%c{1},%t] %m%n
|
||||
|
||||
# Rolling log file output...
|
||||
log4j.appender.fileout=org.apache.log4j.RollingFileAppender
|
||||
log4j.appender.fileout.File=spring-security-openid.log
|
||||
#log4j.appender.fileout.File=${webapp.root}/WEB-INF/log4j.log
|
||||
log4j.appender.fileout.MaxFileSize=1024KB
|
||||
log4j.appender.fileout.MaxBackupIndex=1
|
||||
log4j.appender.fileout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.fileout.layout.conversionPattern=%d{ABSOLUTE} %5p %c{1},%t:%L - %m%n
|
||||
log4j.appender.stdout.layout.conversionPattern=[%p,%c{1}] %m%n
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -12,20 +12,25 @@
|
|||
<display-name>Spring Security Preauthentication Demo Application</display-name>
|
||||
|
||||
<!--
|
||||
- Location of the XML file that defines the root application context
|
||||
- Applied by ContextLoaderListener.
|
||||
-->
|
||||
<context-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>
|
||||
/WEB-INF/applicationContext-security.xml
|
||||
</param-value>
|
||||
</context-param>
|
||||
- Location of the XML file that defines the root application context
|
||||
- Applied by ContextLoaderListener.
|
||||
-->
|
||||
<context-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>
|
||||
/WEB-INF/applicationContext-security.xml
|
||||
</param-value>
|
||||
</context-param>
|
||||
|
||||
<context-param>
|
||||
<param-name>log4jConfigLocation</param-name>
|
||||
<param-value>/WEB-INF/classes/log4j.properties</param-value>
|
||||
</context-param>
|
||||
</context-param>
|
||||
|
||||
<context-param>
|
||||
<param-name>webAppRootKey</param-name>
|
||||
<param-value>openid.root</param-value>
|
||||
</context-param>
|
||||
|
||||
<filter>
|
||||
<filter-name>springSecurityFilterChain</filter-name>
|
||||
|
@ -37,22 +42,22 @@
|
|||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
<!--
|
||||
- Loads the root application context of this web app at startup.
|
||||
- The application context is then available via
|
||||
- WebApplicationContextUtils.getWebApplicationContext(servletContext).
|
||||
<!--
|
||||
- Loads the root application context of this web app at startup.
|
||||
- The application context is then available via
|
||||
- WebApplicationContextUtils.getWebApplicationContext(servletContext).
|
||||
-->
|
||||
<listener>
|
||||
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
|
||||
</listener>
|
||||
<listener>
|
||||
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
|
||||
</listener>
|
||||
|
||||
<listener>
|
||||
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
|
||||
</listener>
|
||||
</listener>
|
||||
|
||||
<!--
|
||||
- Publishes events for session creation and destruction through the application
|
||||
- context. Optional unless concurrent session control is being used.
|
||||
- Publishes events for session creation and destruction through the application
|
||||
- context. Optional unless concurrent session control is being used.
|
||||
-->
|
||||
<listener>
|
||||
<listener-class>org.springframework.security.ui.session.HttpSessionEventPublisher</listener-class>
|
||||
|
|
|
@ -10,23 +10,28 @@
|
|||
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
|
||||
|
||||
<display-name>Spring Security Tutorial Application</display-name>
|
||||
|
||||
|
||||
<!--
|
||||
- Location of the XML file that defines the root application context
|
||||
- Applied by ContextLoaderListener.
|
||||
-->
|
||||
<context-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>
|
||||
classpath:applicationContext-business.xml
|
||||
/WEB-INF/applicationContext-security.xml
|
||||
</param-value>
|
||||
</context-param>
|
||||
|
||||
- Location of the XML file that defines the root application context
|
||||
- Applied by ContextLoaderListener.
|
||||
-->
|
||||
<context-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>
|
||||
classpath:applicationContext-business.xml
|
||||
/WEB-INF/applicationContext-security.xml
|
||||
</param-value>
|
||||
</context-param>
|
||||
|
||||
<context-param>
|
||||
<param-name>log4jConfigLocation</param-name>
|
||||
<param-value>/WEB-INF/classes/log4j.properties</param-value>
|
||||
</context-param>
|
||||
</context-param>
|
||||
|
||||
<context-param>
|
||||
<param-name>webAppRootKey</param-name>
|
||||
<param-value>tutorial.root</param-value>
|
||||
</context-param>
|
||||
|
||||
<filter>
|
||||
<filter-name>springSecurityFilterChain</filter-name>
|
||||
|
@ -38,43 +43,43 @@
|
|||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
<!--
|
||||
- Loads the root application context of this web app at startup.
|
||||
- The application context is then available via
|
||||
- WebApplicationContextUtils.getWebApplicationContext(servletContext).
|
||||
<!--
|
||||
- Loads the root application context of this web app at startup.
|
||||
- The application context is then available via
|
||||
- WebApplicationContextUtils.getWebApplicationContext(servletContext).
|
||||
-->
|
||||
<listener>
|
||||
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
|
||||
</listener>
|
||||
<listener>
|
||||
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
|
||||
</listener>
|
||||
|
||||
<!--
|
||||
- Publishes events for session creation and destruction through the application
|
||||
- context. Optional unless concurrent session control is being used.
|
||||
<!--
|
||||
- Publishes events for session creation and destruction through the application
|
||||
- context. Optional unless concurrent session control is being used.
|
||||
-->
|
||||
<listener>
|
||||
<listener-class>org.springframework.security.ui.session.HttpSessionEventPublisher</listener-class>
|
||||
</listener>
|
||||
|
||||
|
||||
<listener>
|
||||
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
|
||||
</listener>
|
||||
</listener>
|
||||
|
||||
<!--
|
||||
- Provides core MVC application controller. See contacts-servlet.xml.
|
||||
- Provides core MVC application controller. See contacts-servlet.xml.
|
||||
-->
|
||||
<servlet>
|
||||
<servlet-name>bank</servlet-name>
|
||||
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>bank</servlet-name>
|
||||
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>bank</servlet-name>
|
||||
<url-pattern>*.html</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>bank</servlet-name>
|
||||
<url-pattern>*.html</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<welcome-file-list>
|
||||
<welcome-file>index.jsp</welcome-file>
|
||||
</welcome-file-list>
|
||||
<welcome-file>index.jsp</welcome-file>
|
||||
</welcome-file-list>
|
||||
|
||||
</web-app>
|
||||
|
|
Loading…
Reference in New Issue