SEC-1255: Modified UrlUtils. Full request URL for redirects uses the requestURI (which is encoded). The URL for path comparsions is built using the servletpath, as before.
This commit is contained in:
parent
df9e2eac9e
commit
073198886d
|
@ -1056,14 +1056,5 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||||
return ((RememberMeProcessingFilter)getFilter(RememberMeProcessingFilter.class)).getRememberMeServices();
|
return ((RememberMeProcessingFilter)getFilter(RememberMeProcessingFilter.class)).getRememberMeServices();
|
||||||
}
|
}
|
||||||
|
|
||||||
// @SuppressWarnings("unchecked")
|
|
||||||
// private ConcurrentSessionController getConcurrentSessionController() {
|
|
||||||
// Map beans = appContext.getBeansOfType(ConcurrentSessionController.class);
|
|
||||||
//
|
|
||||||
// if (beans.size() == 0) {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// return (ConcurrentSessionController) new ArrayList(beans.values()).get(0);
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
|
||||||
xmlns:sec="http://www.springframework.org/schema/security"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
|
||||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.2.xsd">
|
|
||||||
|
|
||||||
<!-- A second APF in addition to the standard namespace one -->
|
|
||||||
<bean name="formLoginFilter2" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationProcessingFilter">
|
|
||||||
<sec:custom-filter after="AUTHENTICATION_PROCESSING_FILTER"/>
|
|
||||||
<property name="filterProcessesUrl" value="/j_spring_security_check_2"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
|
|
||||||
<bean name="switchUserFilter" class="org.springframework.security.web.authentication.switchuser.SwitchUserProcessingFilter">
|
|
||||||
<sec:custom-filter position="SWITCH_USER_FILTER"/>
|
|
||||||
</bean>
|
|
||||||
</beans>
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE html
|
||||||
|
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
|
<head>
|
||||||
|
<title>Special Chars File</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>I'm file?with?special?chars.html</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,6 +1,6 @@
|
||||||
package org.springframework.security.integration;
|
package org.springframework.security.integration;
|
||||||
|
|
||||||
import org.testng.annotations.*;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
|
@ -39,4 +39,12 @@ public class InMemoryProviderWebAppTests extends AbstractWebServerIntegrationTes
|
||||||
assertTextPresent("xcount=2");
|
assertTextPresent("xcount=2");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SEC-1255
|
||||||
|
@Test
|
||||||
|
public void redirectToUrlWithSpecialCharsInFilenameWorksOk() throws Exception {
|
||||||
|
beginAt("secure/file%3Fwith%3Fspecial%3Fchars.html?someArg=1");
|
||||||
|
login("jimi", "jimispassword");
|
||||||
|
assertTextPresent("I'm file?with?special?chars.html");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -234,8 +234,7 @@ public class DefaultSavedRequest implements SavedRequest {
|
||||||
* @return the full URL of this request
|
* @return the full URL of this request
|
||||||
*/
|
*/
|
||||||
public String getRedirectUrl() {
|
public String getRedirectUrl() {
|
||||||
return UrlUtils.buildFullRequestUrl(scheme, serverName, serverPort, contextPath, servletPath, requestURI,
|
return UrlUtils.buildFullRequestUrl(scheme, serverName, serverPort, requestURI, queryString);
|
||||||
pathInfo, queryString);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<String> getHeaderNames() {
|
public Collection<String> getHeaderNames() {
|
||||||
|
|
|
@ -29,8 +29,8 @@ public final class UrlUtils {
|
||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
public static String buildFullRequestUrl(HttpServletRequest r) {
|
public static String buildFullRequestUrl(HttpServletRequest r) {
|
||||||
return buildFullRequestUrl(r.getScheme(), r.getServerName(), r.getServerPort(), r.getContextPath(),
|
return buildFullRequestUrl(r.getScheme(), r.getServerName(), r.getServerPort(), r.getRequestURI(),
|
||||||
r.getServletPath(), r.getRequestURI(), r.getPathInfo(), r.getQueryString());
|
r.getQueryString());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,29 +39,53 @@ public final class UrlUtils {
|
||||||
* Note that the server port will not be shown if it is the default server port for HTTP or HTTPS
|
* Note that the server port will not be shown if it is the default server port for HTTP or HTTPS
|
||||||
* (80 and 443 respectively).
|
* (80 and 443 respectively).
|
||||||
*
|
*
|
||||||
* @return the full URL
|
* @return the full URL, suitable for redirects (not decoded).
|
||||||
*/
|
*/
|
||||||
public static String buildFullRequestUrl(String scheme, String serverName, int serverPort, String contextPath,
|
public static String buildFullRequestUrl(String scheme, String serverName, int serverPort, String requestURI,
|
||||||
String servletPath, String requestURI, String pathInfo, String queryString) {
|
String queryString) {
|
||||||
|
|
||||||
boolean includePort = true;
|
scheme = scheme.toLowerCase();
|
||||||
|
|
||||||
if ("http".equals(scheme.toLowerCase()) && (serverPort == 80)) {
|
StringBuilder url = new StringBuilder();
|
||||||
includePort = false;
|
url.append(scheme).append("://").append(serverName);
|
||||||
|
|
||||||
|
// Only add port if not default
|
||||||
|
if ("http".equals(scheme)) {
|
||||||
|
if (serverPort != 80) {
|
||||||
|
url.append(":").append(serverPort);
|
||||||
|
}
|
||||||
|
} else if ("https".equals(scheme)) {
|
||||||
|
if (serverPort != 443) {
|
||||||
|
url.append(":").append(serverPort);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("https".equals(scheme.toLowerCase()) && (serverPort == 443)) {
|
// Use the requestURI as it is encoded (RFC 3986) and hence suitable for redirects.
|
||||||
includePort = false;
|
url.append(requestURI);
|
||||||
|
|
||||||
|
if (queryString != null) {
|
||||||
|
url.append("?").append(queryString);
|
||||||
}
|
}
|
||||||
|
|
||||||
return scheme + "://" + serverName + ((includePort) ? (":" + serverPort) : "") + contextPath
|
return url.toString();
|
||||||
+ buildRequestUrl(servletPath, requestURI, contextPath, pathInfo, queryString);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains the web application-specific fragment of the request URL.
|
* Obtains the web application-specific fragment of the request URL.
|
||||||
|
* <p>
|
||||||
|
* Under normal spec conditions,
|
||||||
|
* <pre>
|
||||||
|
* requestURI = contextPath + servletPath + pathInfo
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* But the requestURI is not decoded, whereas the servletPath and pathInfo are (SEC-1255).
|
||||||
|
* This method is typically used to return a URL for matching against secured paths, hence the decoded form is
|
||||||
|
* used in preference to the requestURI for building the returned value. But this method may also be called using
|
||||||
|
* dummy request objects which just have the requestURI and contextPatth set, for example, so it will fall back to
|
||||||
|
* using those.
|
||||||
|
*
|
||||||
|
* @return the decoded URL, excluding any server name, context path or servlet path
|
||||||
*
|
*
|
||||||
* @return the URL, excluding any server name, context path or servlet path
|
|
||||||
*/
|
*/
|
||||||
public static String buildRequestUrl(HttpServletRequest r) {
|
public static String buildRequestUrl(HttpServletRequest r) {
|
||||||
return buildRequestUrl(r.getServletPath(), r.getRequestURI(), r.getContextPath(), r.getPathInfo(),
|
return buildRequestUrl(r.getServletPath(), r.getRequestURI(), r.getContextPath(), r.getPathInfo(),
|
||||||
|
@ -70,18 +94,9 @@ public final class UrlUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains the web application-specific fragment of the URL.
|
* Obtains the web application-specific fragment of the URL.
|
||||||
* <p>
|
|
||||||
* Under normal spec conditions,
|
|
||||||
* <pre>
|
|
||||||
* requestURI = contextPath + servletPath + pathInfo
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* But this method may also be called using dummy request objects which just have the requestURI and contextPath
|
|
||||||
* set, for example.
|
|
||||||
*
|
|
||||||
* @return the URL, excluding any server name, context path or servlet path
|
|
||||||
*/
|
*/
|
||||||
public static String buildRequestUrl(String servletPath, String requestURI, String contextPath, String pathInfo,
|
private static String buildRequestUrl(String servletPath, String requestURI, String contextPath, String pathInfo,
|
||||||
String queryString) {
|
String queryString) {
|
||||||
|
|
||||||
StringBuilder url = new StringBuilder();
|
StringBuilder url = new StringBuilder();
|
||||||
|
|
Loading…
Reference in New Issue