mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-06-29 15:22:15 +00:00
SEC-516: TargetUrlResolver path to avoid redirecting to POST requests.
This commit is contained in:
parent
9f45f95fab
commit
feadb3582a
@ -153,6 +153,8 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
|||||||
|
|
||||||
private RememberMeServices rememberMeServices = new NullRememberMeServices();
|
private RememberMeServices rememberMeServices = new NullRememberMeServices();
|
||||||
|
|
||||||
|
private TargetUrlResolver targetUrlResolver = new TargetUrlResolverImpl();
|
||||||
|
|
||||||
/** Where to redirect the browser to if authentication fails */
|
/** Where to redirect the browser to if authentication fails */
|
||||||
private String authenticationFailureUrl;
|
private String authenticationFailureUrl;
|
||||||
|
|
||||||
@ -216,7 +218,8 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
|||||||
Assert.hasLength(defaultTargetUrl, "defaultTargetUrl must be specified");
|
Assert.hasLength(defaultTargetUrl, "defaultTargetUrl must be specified");
|
||||||
Assert.hasLength(authenticationFailureUrl, "authenticationFailureUrl must be specified");
|
Assert.hasLength(authenticationFailureUrl, "authenticationFailureUrl must be specified");
|
||||||
Assert.notNull(authenticationManager, "authenticationManager 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) {
|
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);
|
HttpSession session = request.getSession(false);
|
||||||
|
|
||||||
if (session == null) {
|
if (session == null) {
|
||||||
@ -274,8 +283,8 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
|||||||
|
|
||||||
SavedRequest savedRequest = (SavedRequest) session.getAttribute(SPRING_SECURITY_SAVED_REQUEST_KEY);
|
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)
|
protected void onPreAuthentication(HttpServletRequest request, HttpServletResponse response)
|
||||||
throws AuthenticationException, IOException {
|
throws AuthenticationException, IOException {
|
||||||
@ -416,9 +425,9 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected String determineTargetUrl(HttpServletRequest request) {
|
protected String determineTargetUrl(HttpServletRequest request) {
|
||||||
// Don't attempt to obtain the url from the saved request if
|
// Don't attempt to obtain the url from the saved request if alwaysUsedefaultTargetUrl is set
|
||||||
// alwaysUsedefaultTargetUrl is set
|
String targetUrl = alwaysUseDefaultTargetUrl ? null :
|
||||||
String targetUrl = alwaysUseDefaultTargetUrl ? null : obtainFullSavedRequestUrl(request);
|
targetUrlResolver.determineTargetUrl(getSavedRequest(request), request, SecurityContextHolder.getContext().getAuthentication());
|
||||||
|
|
||||||
if (targetUrl == null) {
|
if (targetUrl == null) {
|
||||||
targetUrl = getDefaultTargetUrl();
|
targetUrl = getDefaultTargetUrl();
|
||||||
@ -578,4 +587,18 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
|
|||||||
public void setAllowSessionCreation(boolean allowSessionCreation) {
|
public void setAllowSessionCreation(boolean allowSessionCreation) {
|
||||||
this.allowSessionCreation = 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -31,7 +31,6 @@ import org.springframework.security.util.PortResolverImpl;
|
|||||||
import org.springframework.mock.web.MockFilterConfig;
|
import org.springframework.mock.web.MockFilterConfig;
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.mock.web.MockHttpServletResponse;
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
import org.springframework.mock.web.MockHttpSession;
|
|
||||||
|
|
||||||
import javax.servlet.Filter;
|
import javax.servlet.Filter;
|
||||||
import javax.servlet.FilterChain;
|
import javax.servlet.FilterChain;
|
||||||
@ -94,6 +93,17 @@ public class AbstractProcessingFilterTests extends TestCase {
|
|||||||
return new SavedRequest(request, new PortResolverImpl());
|
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 {
|
protected void setUp() throws Exception {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
SecurityContextHolder.clearContext();
|
SecurityContextHolder.clearContext();
|
||||||
@ -426,6 +436,36 @@ public class AbstractProcessingFilterTests extends TestCase {
|
|||||||
assertNotNull(SecurityContextHolder.getContext().getAuthentication());
|
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.
|
* SEC-297 fix.
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user