diff --git a/core/src/main/java/org/springframework/security/context/HttpSessionSecurityContextRepository.java b/core/src/main/java/org/springframework/security/context/HttpSessionSecurityContextRepository.java index 2551f7fe69..b9569a975f 100644 --- a/core/src/main/java/org/springframework/security/context/HttpSessionSecurityContextRepository.java +++ b/core/src/main/java/org/springframework/security/context/HttpSessionSecurityContextRepository.java @@ -61,6 +61,7 @@ public class HttpSessionSecurityContextRepository implements SecurityContextRepo private Object contextObject = new SecurityContextImpl(); private boolean cloneFromHttpSession = false; private boolean allowSessionCreation = true; + private boolean disableUrlRewriting = false; private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl(); @@ -234,6 +235,16 @@ public class HttpSessionSecurityContextRepository implements SecurityContextRepo this.allowSessionCreation = allowSessionCreation; } + /** + * Allows the use of session identifiers in URLs to be disabled. Off by default. + * + * @param disableUrlRewriting set to true to disable URL encoding methods in the response wrapper + * and prevent the use of jsessionid parameters. + */ + public void setDisableUrlRewriting(boolean disableUrlRewriting) { + this.disableUrlRewriting = disableUrlRewriting; + } + //~ Inner Classes ================================================================================================== /** @@ -265,7 +276,7 @@ public class HttpSessionSecurityContextRepository implements SecurityContextRepo SaveToSessionResponseWrapper(HttpServletResponse response, HttpServletRequest request, boolean httpSessionExistedAtStartOfRequest, int contextHashBeforeChainExecution) { - super(response); + super(response, disableUrlRewriting); this.request = request; this.httpSessionExistedAtStartOfRequest = httpSessionExistedAtStartOfRequest; this.contextHashBeforeChainExecution = contextHashBeforeChainExecution; diff --git a/core/src/main/java/org/springframework/security/context/SaveContextOnUpdateOrErrorResponseWrapper.java b/core/src/main/java/org/springframework/security/context/SaveContextOnUpdateOrErrorResponseWrapper.java index 1250ca281b..5d260bc9a8 100644 --- a/core/src/main/java/org/springframework/security/context/SaveContextOnUpdateOrErrorResponseWrapper.java +++ b/core/src/main/java/org/springframework/security/context/SaveContextOnUpdateOrErrorResponseWrapper.java @@ -8,21 +8,31 @@ import javax.servlet.http.HttpServletResponseWrapper; /** * Base class for response wrappers which encapsulate the logic for storing a security context and which * store the with the SecurityContext when a sendError() or sendRedirect - * happens. See SEC-398. + * happens. See issue SEC-398. *

* Sub-classes should implement the {@link #saveContext(SecurityContext context)} method. + *

+ * Support is also provided for disabling URL rewriting * * @author Luke Taylor * @author Marten Algesten * @version $Id$ * @since 2.5 */ -abstract class SaveContextOnUpdateOrErrorResponseWrapper extends HttpServletResponseWrapper { +public abstract class SaveContextOnUpdateOrErrorResponseWrapper extends HttpServletResponseWrapper { - boolean contextSaved = false; + private boolean contextSaved = false; + /* See SEC-1052 */ + private boolean disableUrlRewriting; - SaveContextOnUpdateOrErrorResponseWrapper(HttpServletResponse response) { + /** + * @param response the response to be wrapped + * @param disableUrlRewriting turns the URL encoding methods into null operations, preventing the use + * of URL rewriting to add the session identifier as a URL parameter. + */ + public SaveContextOnUpdateOrErrorResponseWrapper(HttpServletResponse response, boolean disableUrlRewriting) { super(response); + this.disableUrlRewriting = disableUrlRewriting; } /** @@ -36,7 +46,8 @@ abstract class SaveContextOnUpdateOrErrorResponseWrapper extends HttpServletResp * Makes sure the session is updated before calling the * superclass sendError() */ - public void sendError(int sc) throws IOException { + @Override + public final void sendError(int sc) throws IOException { doSaveContext(); super.sendError(sc); } @@ -45,7 +56,8 @@ abstract class SaveContextOnUpdateOrErrorResponseWrapper extends HttpServletResp * Makes sure the session is updated before calling the * superclass sendError() */ - public void sendError(int sc, String msg) throws IOException { + @Override + public final void sendError(int sc, String msg) throws IOException { doSaveContext(); super.sendError(sc, msg); } @@ -54,7 +66,8 @@ abstract class SaveContextOnUpdateOrErrorResponseWrapper extends HttpServletResp * Makes sure the context is stored before calling the * superclass sendRedirect() */ - public void sendRedirect(String location) throws IOException { + @Override + public final void sendRedirect(String location) throws IOException { doSaveContext(); super.sendRedirect(location); } @@ -67,10 +80,42 @@ abstract class SaveContextOnUpdateOrErrorResponseWrapper extends HttpServletResp contextSaved = true; } + @Override + public final String encodeRedirectUrl(String url) { + if (disableUrlRewriting) { + return url; + } + return super.encodeRedirectUrl(url); + } + + @Override + public final String encodeRedirectURL(String url) { + if (disableUrlRewriting) { + return url; + } + return super.encodeRedirectURL(url); + } + + @Override + public final String encodeUrl(String url) { + if (disableUrlRewriting) { + return url; + } + return super.encodeUrl(url); + } + + @Override + public final String encodeURL(String url) { + if (disableUrlRewriting) { + return url; + } + return super.encodeURL(url); + } + /** * Tells if the response wrapper has called saveContext() because of an error or redirect. */ - public boolean isContextSaved() { + public final boolean isContextSaved() { return contextSaved; } diff --git a/core/src/main/java/org/springframework/security/context/package.html b/core/src/main/java/org/springframework/security/context/package.html index 3954b286d4..6684b8943b 100644 --- a/core/src/main/java/org/springframework/security/context/package.html +++ b/core/src/main/java/org/springframework/security/context/package.html @@ -1,10 +1,11 @@ -Provides a "request context". +Classes related to the establishment of a security context for the duration of a request (such as +an HTTP or RMI invocation) and for the maintenance of the context between requests (by storing it in an HTTP sessio, for +example).

-A request context is associated with the current execution thread. It holds -objects that would otherwise need to be included in many method signatures, -such as for authentication.

+A security context is associated with the current execution thread for the duration of the request, making the +authentication information it contains available throughout all the layers of an application. diff --git a/core/src/test/java/org/springframework/security/context/HttpSessionSecurityContextRepositoryTests.java b/core/src/test/java/org/springframework/security/context/HttpSessionSecurityContextRepositoryTests.java index ee5769d3ab..22e40acadd 100644 --- a/core/src/test/java/org/springframework/security/context/HttpSessionSecurityContextRepositoryTests.java +++ b/core/src/test/java/org/springframework/security/context/HttpSessionSecurityContextRepositoryTests.java @@ -161,6 +161,49 @@ public class HttpSessionSecurityContextRepositoryTests { assertTrue(repo.generateNewContext() instanceof MockContext); } + @Test + @SuppressWarnings("deprecation") + public void sessionDisableUrlRewritingPreventsSessionIdBeingWrittenToUrl() throws Exception { + HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository(); + MockHttpServletRequest request = new MockHttpServletRequest(); + final String sessionId = ";jsessionid=id"; + MockHttpServletResponse response = new MockHttpServletResponse() { + @Override + public String encodeRedirectUrl(String url) { + return url + sessionId; + } + + @Override + public String encodeRedirectURL(String url) { + return url + sessionId; + } + + @Override + public String encodeUrl(String url) { + return url + sessionId; + } + + @Override + public String encodeURL(String url) { + return url + sessionId; + } + }; + HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request, response); + repo.loadContext(holder); + String url = "/aUrl"; + assertEquals(url + sessionId, holder.getResponse().encodeRedirectUrl(url)); + assertEquals(url + sessionId, holder.getResponse().encodeRedirectURL(url)); + assertEquals(url + sessionId, holder.getResponse().encodeUrl(url)); + assertEquals(url + sessionId, holder.getResponse().encodeURL(url)); + repo.setDisableUrlRewriting(true); + holder = new HttpRequestResponseHolder(request, response); + repo.loadContext(holder); + assertEquals(url, holder.getResponse().encodeRedirectUrl(url)); + assertEquals(url, holder.getResponse().encodeRedirectURL(url)); + assertEquals(url, holder.getResponse().encodeUrl(url)); + assertEquals(url, holder.getResponse().encodeURL(url)); + } + static class MockContext implements Cloneable, SecurityContext { Authentication a;