SEC-516: TargetUrlResolver path to avoid redirecting to POST requests.

This commit is contained in:
Luke Taylor 2008-01-31 16:05:25 +00:00
parent 9f45f95fab
commit feadb3582a
4 changed files with 189 additions and 8 deletions

View File

@ -153,6 +153,8 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
private RememberMeServices rememberMeServices = new NullRememberMeServices();
private TargetUrlResolver targetUrlResolver = new TargetUrlResolverImpl();
/** Where to redirect the browser to if authentication fails */
private String authenticationFailureUrl;
@ -216,7 +218,8 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
Assert.hasLength(defaultTargetUrl, "defaultTargetUrl must be specified");
Assert.hasLength(authenticationFailureUrl, "authenticationFailureUrl must be specified");
Assert.notNull(authenticationManager, "authenticationManager must be specified");
Assert.notNull(this.rememberMeServices);
Assert.notNull(rememberMeServices, "rememberMeServices cannot be null");
Assert.notNull(targetUrlResolver, "targetUrlResolver cannot be null");
}
/**
@ -266,6 +269,12 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
}
public static String obtainFullSavedRequestUrl(HttpServletRequest request) {
SavedRequest savedRequest = getSavedRequest(request);
return savedRequest == null ? null : savedRequest.getFullRequestUrl();
}
private static SavedRequest getSavedRequest(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session == null) {
@ -274,9 +283,9 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
SavedRequest savedRequest = (SavedRequest) session.getAttribute(SPRING_SECURITY_SAVED_REQUEST_KEY);
return savedRequest == null ? null : savedRequest.getFullRequestUrl();
}
return savedRequest;
}
protected void onPreAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException {
}
@ -416,9 +425,9 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
}
protected String determineTargetUrl(HttpServletRequest request) {
// Don't attempt to obtain the url from the saved request if
// alwaysUsedefaultTargetUrl is set
String targetUrl = alwaysUseDefaultTargetUrl ? null : obtainFullSavedRequestUrl(request);
// Don't attempt to obtain the url from the saved request if alwaysUsedefaultTargetUrl is set
String targetUrl = alwaysUseDefaultTargetUrl ? null :
targetUrlResolver.determineTargetUrl(getSavedRequest(request), request, SecurityContextHolder.getContext().getAuthentication());
if (targetUrl == null) {
targetUrl = getDefaultTargetUrl();
@ -578,4 +587,18 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
public void setAllowSessionCreation(boolean allowSessionCreation) {
this.allowSessionCreation = allowSessionCreation;
}
/**
* @return the targetUrlResolver
*/
protected TargetUrlResolver getTargetUrlResolver() {
return targetUrlResolver;
}
/**
* @param targetUrlResolver the targetUrlResolver to set
*/
public void setTargetUrlResolver(TargetUrlResolver targetUrlResolver) {
this.targetUrlResolver = targetUrlResolver;
}
}

View File

@ -0,0 +1,42 @@
/* 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;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.Authentication;
import org.springframework.security.ui.savedrequest.SavedRequest;
/**
* Used by {@link AbstractProcessingFilter} to determine target URL in case of
* successfull authentication.
*
* @author Martino Piccinato
* @version $Id$
* @since 2.0
*
*/
public interface TargetUrlResolver {
/**
* @param savedRequest The request that initiated the authentication process
* @param currentRequest the current request
* @param auth The authentication token generated after successfull authentication
* @return The URL to be used
*/
public String determineTargetUrl(SavedRequest savedRequest, HttpServletRequest currentRequest, Authentication auth);
}

View File

@ -0,0 +1,76 @@
/* 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;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.Authentication;
import org.springframework.security.ui.savedrequest.SavedRequest;
/**
* Default implementation for {@link TargetUrlResolver}
*
* @author Martino Piccinato
* @version $Id$
* @since 2.0
*
*/
public class TargetUrlResolverImpl implements TargetUrlResolver {
/**
* If <code>true</code>, will only use <code>SavedRequest</code> to determine the target url on successful
* authentication if the request that caused the authentication request was a GET.
* It will return null on POST/PUT request.
* In most cases it's meaningless to redirect to a Url generated by a POST/PUT request.
* Defaults to true.
*/
private boolean justUseSavedRequestOnGet = true;
/* (non-Javadoc)
* @see org.acegisecurity.ui.TargetUrlResolver#determineTargetUrl(org.acegisecurity.ui.savedrequest.SavedRequest, javax.servlet.http.HttpServletRequest, org.acegisecurity.Authentication)
*/
public String determineTargetUrl(SavedRequest savedRequest, HttpServletRequest currentRequest,
Authentication auth) {
String targetUrl = null;
if (savedRequest != null) {
if (!justUseSavedRequestOnGet || savedRequest.getMethod().equals("GET")) {
targetUrl = savedRequest.getFullRequestUrl();
}
}
return targetUrl;
}
/**
* @return <code>true</code> if just GET request will be used
* to determine target URLs, <code>false</code> otherwise.
*/
protected boolean isJustUseSavedRequestOnGet() {
return justUseSavedRequestOnGet;
}
/**
* @param justUseSavedRequestOnGet set to <code>true</code> if
* just GET request will be used to determine target URLs,
* <code>false</code> otherwise.
*/
public void setJustUseSavedRequestOnGet(boolean justUseSavedRequestOnGet) {
this.justUseSavedRequestOnGet = justUseSavedRequestOnGet;
}
}

View File

@ -31,7 +31,6 @@ import org.springframework.security.util.PortResolverImpl;
import org.springframework.mock.web.MockFilterConfig;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockHttpSession;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
@ -93,7 +92,18 @@ public class AbstractProcessingFilterTests extends TestCase {
return new SavedRequest(request, new PortResolverImpl());
}
private SavedRequest makePostSavedRequestForUrl() {
MockHttpServletRequest request = createMockRequest();
request.setServletPath("/some_protected_file.html");
request.setScheme("http");
request.setServerName("www.example.com");
request.setRequestURI("/mycontext/post/some_protected_file.html");
request.setMethod("POST");
return new SavedRequest(request, new PortResolverImpl());
}
protected void setUp() throws Exception {
super.setUp();
SecurityContextHolder.clearContext();
@ -425,6 +435,36 @@ public class AbstractProcessingFilterTests extends TestCase {
assertEquals(makeSavedRequestForUrl().getFullRequestUrl(), response.getRedirectedUrl());
assertNotNull(SecurityContextHolder.getContext().getAuthentication());
}
public void testSuccessfulAuthenticationCausesRedirectToDefaultTargetUrlOnPOSTSavedRequest() throws Exception {
// Setup our HTTP request with a POST method request
MockHttpServletRequest request = createMockRequest();
request.getSession().setAttribute(AbstractProcessingFilter.SPRING_SECURITY_SAVED_REQUEST_KEY, makePostSavedRequestForUrl());
// Setup our filter configuration
MockFilterConfig config = new MockFilterConfig(null, null);
// Setup our expectation that the filter chain will be invoked, as we want to go to the location requested in the session
MockFilterChain chain = new MockFilterChain(true);
MockHttpServletResponse response = new MockHttpServletResponse();
// Setup our test object, to grant access
MockAbstractProcessingFilter filter = new MockAbstractProcessingFilter(true);
filter.setFilterProcessesUrl("/j_mock_post");
filter.setDefaultTargetUrl("/foobar");
// Configure target resolver default implementation not to use POST SavedRequest
TargetUrlResolverImpl targetUrlResolver = new TargetUrlResolverImpl();
targetUrlResolver.setJustUseSavedRequestOnGet(true);
filter.setTargetUrlResolver(targetUrlResolver);
// Test
executeFilterInContainerSimulator(config, filter, request, response, chain);
assertEquals("/mycontext/foobar", response.getRedirectedUrl());
assertNotNull(SecurityContextHolder.getContext().getAuthentication());
}
/**
* SEC-297 fix.