SEC-1226: Introduce RedirectStrategy to replace RedirectUtils. Implemented strategy and applied throughout relevant classes.

This commit is contained in:
Luke Taylor 2009-08-27 10:42:11 +00:00
parent 092d7b5c2b
commit ab0d66071a
10 changed files with 139 additions and 113 deletions

View File

@ -167,15 +167,17 @@ public class OpenIDAuthenticationProcessingFilter extends AbstractAuthentication
if (mapping == null) {
try {
URL url = new URL(returnToUrl);
int port = (url.getPort() == -1) ? 80 : url.getPort();
StringBuffer realmBuffer = new StringBuffer(returnToUrl.length())
int port = url.getPort();
StringBuilder realmBuffer = new StringBuilder(returnToUrl.length())
.append(url.getProtocol())
.append("://")
.append(url.getHost())
.append(":").append(port)
.append("/");
.append(url.getHost());
if (port > 0) {
realmBuffer.append(":").append(port);
}
realmBuffer.append("/");
mapping = realmBuffer.toString();
} catch (MalformedURLException e) {
logger.warn("returnToUrl was not a valid URL: [" + returnToUrl + "]", e);

View File

@ -0,0 +1,58 @@
package org.springframework.security.web;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Simple implementation of <tt>RedirectStrategy</tt> which is the default used throughout the framework.
*
* @author Luke Taylor
* @version $Id$
* @since 3.0
*/
public class DefaultRedirectStrategy implements RedirectStrategy {
private boolean useRelativeContext;
/**
* Redirects the response to the supplied URL.
* <p>
* If <tt>useRelativeContext</tt> is set, the redirect value will be the value after the request context path.
*/
public void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url) throws IOException {
String finalUrl;
if (!url.startsWith("http://") && !url.startsWith("https://")) {
if (useRelativeContext) {
finalUrl = url;
}
else {
finalUrl = request.getContextPath() + url;
}
}
else if (useRelativeContext) {
// Calculate the relative URL from the fully qualifed URL, minus the protocol and base context.
int len = request.getContextPath().length();
int index = url.indexOf(request.getContextPath()) + len;
finalUrl = url.substring(index);
if (finalUrl.length() > 1 && finalUrl.charAt(0) == '/') {
finalUrl = finalUrl.substring(1);
}
}
else {
finalUrl = url;
}
response.sendRedirect(response.encodeRedirectURL(finalUrl));
}
/**
* If <tt>true</tt>, causes any redirection URLs to be calculated minus the protocol
* and context path (defaults to <tt>false</tt>).
*/
public void setUseRelativeContext(boolean useRelativeContext) {
this.useRelativeContext = useRelativeContext;
}
}

View File

@ -0,0 +1,24 @@
package org.springframework.security.web;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Encapsulates the redirection logic for all classes in the framework which perform redirects.
*
* @author Luke Taylor
* @version $Id$
* @since 3.0
*/
public interface RedirectStrategy {
/**
* Performs a redirect to the supplied URL
* @param request the current request
* @param response the response to redirect
* @param url the target URL to redirect to, for example "/login"
*/
void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url) throws IOException;
}

View File

@ -11,7 +11,8 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.util.RedirectUtils;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@ -50,8 +51,8 @@ public abstract class AbstractAuthenticationTargetUrlRequestHandler {
private String targetUrlParameter = DEFAULT_TARGET_PARAMETER;
private String defaultTargetUrl = "/";
private boolean alwaysUseDefaultTargetUrl = false;
private boolean useRelativeContext = false;
private boolean useReferer = false;
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
protected AbstractAuthenticationTargetUrlRequestHandler() {
}
@ -60,7 +61,7 @@ public abstract class AbstractAuthenticationTargetUrlRequestHandler {
throws IOException, ServletException {
String targetUrl = determineTargetUrl(request, response);
RedirectUtils.sendRedirect(request, response, targetUrl, useRelativeContext);
redirectStrategy.sendRedirect(request, response, targetUrl);
}
private String determineTargetUrl(HttpServletRequest request, HttpServletResponse response) {
@ -149,15 +150,14 @@ public abstract class AbstractAuthenticationTargetUrlRequestHandler {
}
/**
* If <tt>true</tt>, causes any redirection URLs to be calculated minus the protocol
* and context path (defaults to <tt>false</tt>).
* Allows overriding of the behaviour when redirecting to a target URL.
*/
public void setUseRelativeContext(boolean useRelativeContext) {
this.useRelativeContext = useRelativeContext;
public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
this.redirectStrategy = redirectStrategy;
}
protected boolean isUseRelativeContext() {
return useRelativeContext;
protected RedirectStrategy getRedirectStrategy() {
return redirectStrategy;
}
/**

View File

@ -9,7 +9,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.util.RedirectUtils;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert;
@ -35,7 +34,7 @@ public class ExceptionMappingAuthenticationFailureHandler extends SimpleUrlAuthe
String url = failureUrlMap.get(exception.getClass().getName());
if (url != null) {
RedirectUtils.sendRedirect(request, response, url, isUseRelativeContext());
getRedirectStrategy().sendRedirect(request, response, url);
} else {
super.onAuthenticationFailure(request, response, exception);
}

View File

@ -17,24 +17,6 @@ package org.springframework.security.web.authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.PortMapper;
import org.springframework.security.web.PortMapperImpl;
import org.springframework.security.web.PortResolver;
import org.springframework.security.web.PortResolverImpl;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.util.RedirectUrlBuilder;
import org.springframework.security.web.util.UrlUtils;
import org.apache.commons.logging.Log;
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;
import javax.servlet.RequestDispatcher;
@ -42,6 +24,23 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.PortMapper;
import org.springframework.security.web.PortMapperImpl;
import org.springframework.security.web.PortResolver;
import org.springframework.security.web.PortResolverImpl;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.util.RedirectUrlBuilder;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Used by the {@link ExceptionTranslationFilter} to commence a form login
* authentication via the {@link UsernamePasswordAuthenticationProcessingFilter}. This object
@ -80,6 +79,8 @@ public class LoginUrlAuthenticationEntryPoint implements AuthenticationEntryPoin
private boolean useForward = false;
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
@ -117,6 +118,8 @@ public class LoginUrlAuthenticationEntryPoint implements AuthenticationEntryPoin
if (useForward) {
if (forceHttps && "http".equals(request.getScheme())) {
// First redirect the current request to HTTPS.
// When that request is received, the forward to the login page will be used.
redirectUrl = buildHttpsRedirectUrlForRequest(httpRequest);
}
@ -140,7 +143,7 @@ public class LoginUrlAuthenticationEntryPoint implements AuthenticationEntryPoin
}
httpResponse.sendRedirect(httpResponse.encodeRedirectURL(redirectUrl));
redirectStrategy.sendRedirect(httpRequest, httpResponse, redirectUrl);
}
protected String buildRedirectUrlToLoginPage(HttpServletRequest request, HttpServletResponse response,
@ -174,7 +177,8 @@ public class LoginUrlAuthenticationEntryPoint implements AuthenticationEntryPoin
}
/**
* Builds a URL to redirect the supplied request to HTTPS.
* Builds a URL to redirect the supplied request to HTTPS. Used to redirect the current request
* to HTTPS, before doing a forward to the login page.
*/
protected String buildHttpsRedirectUrlForRequest(HttpServletRequest request)
throws IOException, ServletException {

View File

@ -13,7 +13,6 @@ import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.security.web.util.RedirectUtils;
import org.springframework.util.StringUtils;
/**
@ -76,7 +75,7 @@ public class SavedRequestAwareAuthenticationSuccessHandler extends SimpleUrlAuth
// Use the SavedRequest URL
String targetUrl = savedRequest.getFullRequestUrl();
logger.debug("Redirecting to SavedRequest Url: " + targetUrl);
RedirectUtils.sendRedirect(request, response, targetUrl, isUseRelativeContext());
getRedirectStrategy().sendRedirect(request, response, targetUrl);
}
public void setRequestCache(RequestCache requestCache) {

View File

@ -7,7 +7,8 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.util.RedirectUtils;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert;
@ -27,7 +28,7 @@ import org.springframework.util.Assert;
public class SimpleUrlAuthenticationFailureHandler implements AuthenticationFailureHandler {
private String defaultFailureUrl;
private boolean forwardToDestination = false;
private boolean useRelativeContext = false;
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
public SimpleUrlAuthenticationFailureHandler() {
}
@ -44,7 +45,7 @@ public class SimpleUrlAuthenticationFailureHandler implements AuthenticationFail
if (forwardToDestination) {
request.getRequestDispatcher(defaultFailureUrl).forward(request, response);
} else {
RedirectUtils.sendRedirect(request, response, defaultFailureUrl, useRelativeContext);
redirectStrategy.sendRedirect(request, response, defaultFailureUrl);
}
}
}
@ -71,16 +72,14 @@ public class SimpleUrlAuthenticationFailureHandler implements AuthenticationFail
this.forwardToDestination = forwardToDestination;
}
protected boolean isUseRelativeContext() {
return useRelativeContext;
}
/**
* If true, causes any redirection URLs to be calculated minus the protocol
* and context path (defaults to false).
* Allows overriding of the behaviour when redirecting to a target URL.
*/
public void setUseRelativeContext(boolean useRelativeContext) {
this.useRelativeContext = useRelativeContext;
public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
this.redirectStrategy = redirectStrategy;
}
protected RedirectStrategy getRedirectStrategy() {
return redirectStrategy;
}
}

View File

@ -1,62 +0,0 @@
package org.springframework.security.web.util;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author Luke Taylor
* @version $Id$
*/
public abstract class RedirectUtils {
//~ Constructors ===================================================================================================
private RedirectUtils() {
}
//~ Methods ========================================================================================================
/**
* Encapsulates the redirect logic used in classes like {@link AbstractAuthenticationProcessingFilter} and {@link LogoutFilter}.
*
* @param request the incoming request
* @param response the response to redirect
* @param url the target url to redirect to
* @param useRelativeContext if true, causes any redirection URLs to be calculated minus the protocol
* and context path.
*
* @see AbstractAuthenticationProcessingFilter#setUseRelativeContext(boolean)
*/
public static final void sendRedirect(HttpServletRequest request,
HttpServletResponse response,
String url,
boolean useRelativeContext) throws IOException {
String finalUrl;
if (!url.startsWith("http://") && !url.startsWith("https://")) {
if (useRelativeContext) {
finalUrl = url;
}
else {
finalUrl = request.getContextPath() + url;
}
}
else if (useRelativeContext) {
// Calculate the relative URL from the fully qualifed URL, minus the protocol and base context.
int len = request.getContextPath().length();
int index = url.indexOf(request.getContextPath()) + len;
finalUrl = url.substring(index);
if (finalUrl.length() > 1 && finalUrl.charAt(0) == '/') {
finalUrl = finalUrl.substring(1);
}
}
else {
finalUrl = url;
}
response.sendRedirect(response.encodeRedirectURL(finalUrl));
}
}

View File

@ -43,6 +43,7 @@ import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.util.FieldUtils;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.switchuser.SwitchUserAuthorityChanger;
import org.springframework.security.web.authentication.switchuser.SwitchUserGrantedAuthority;
@ -306,7 +307,9 @@ public class SwitchUserProcessingFilterTests {
filter.setSwitchUserUrl("/j_spring_security_switch_user");
SimpleUrlAuthenticationSuccessHandler switchSuccessHandler =
new SimpleUrlAuthenticationSuccessHandler("/someOtherUrl");
switchSuccessHandler.setUseRelativeContext(true);
DefaultRedirectStrategy contextRelativeRedirector = new DefaultRedirectStrategy();
contextRelativeRedirector.setUseRelativeContext(true);
switchSuccessHandler.setRedirectStrategy(contextRelativeRedirector);
filter.setSuccessHandler(switchSuccessHandler);
filter.setUserDetailsService(new MockUserDetailsService());