HttpSessionContextIntegrationFilter elegantly handles IOExceptions and ServletExceptions within filter chain (see http://opensource.atlassian.com/projects/spring/browse/SEC-20).
This commit is contained in:
parent
a3d26edea3
commit
ef8281f534
|
@ -212,65 +212,74 @@ public class HttpSessionContextIntegrationFilter implements InitializingBean,
|
||||||
httpSession = null;
|
httpSession = null;
|
||||||
|
|
||||||
// Proceed with chain
|
// Proceed with chain
|
||||||
chain.doFilter(request, response);
|
|
||||||
|
|
||||||
// Store context back to HttpSession
|
|
||||||
try {
|
try {
|
||||||
httpSession = ((HttpServletRequest) request).getSession(false);
|
chain.doFilter(request, response);
|
||||||
} catch (IllegalStateException ignored) {}
|
} catch (IOException ioe) {
|
||||||
|
throw ioe;
|
||||||
|
} catch (ServletException se) {
|
||||||
|
throw se;
|
||||||
|
} finally {
|
||||||
|
// do clean up, even if there was an exception
|
||||||
|
// Store context back to HttpSession
|
||||||
|
try {
|
||||||
|
httpSession = ((HttpServletRequest) request).getSession(false);
|
||||||
|
} catch (IllegalStateException ignored) {}
|
||||||
|
|
||||||
|
if ((httpSession == null) && httpSessionExistedAtStartOfRequest) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(
|
||||||
|
"HttpSession is now null, but was not null at start of request; session was invalidated, so do not create a new session");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a HttpSession only if we need to
|
||||||
|
if ((httpSession == null)
|
||||||
|
&& !httpSessionExistedAtStartOfRequest) {
|
||||||
|
if (!allowSessionCreation) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(
|
||||||
|
"The HttpSession is currently null, and the HttpSessionContextIntegrationFilter is prohibited from creating a HttpSession (because the allowSessionCreation property is false) - SecurityContext thus not stored for next request");
|
||||||
|
}
|
||||||
|
} else if (!contextObject.equals(
|
||||||
|
SecurityContextHolder.getContext())) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(
|
||||||
|
"HttpSession being created as SecurityContextHolder contents are non-default");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
httpSession = ((HttpServletRequest) request)
|
||||||
|
.getSession(true);
|
||||||
|
} catch (IllegalStateException ignored) {}
|
||||||
|
} else {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(
|
||||||
|
"HttpSession is null, but SecurityContextHolder has not changed from default: ' "
|
||||||
|
+ SecurityContextHolder.getContext()
|
||||||
|
+ "'; not creating HttpSession or storing SecurityContextHolder contents");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If HttpSession exists, store current SecurityContextHolder contents
|
||||||
|
if (httpSession != null) {
|
||||||
|
httpSession.setAttribute(ACEGI_SECURITY_CONTEXT_KEY,
|
||||||
|
SecurityContextHolder.getContext());
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("SecurityContext stored to HttpSession: '"
|
||||||
|
+ SecurityContextHolder.getContext() + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove SecurityContextHolder contents
|
||||||
|
SecurityContextHolder.setContext(generateNewContext());
|
||||||
|
|
||||||
if ((httpSession == null) && httpSessionExistedAtStartOfRequest) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"HttpSession is now null, but was not null at start of request; session was invalidated, so do not create a new session");
|
"SecurityContextHolder set to new context, as request processing completed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a HttpSession only if we need to
|
|
||||||
if ((httpSession == null) && !httpSessionExistedAtStartOfRequest) {
|
|
||||||
if (!allowSessionCreation) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug(
|
|
||||||
"The HttpSession is currently null, and the HttpSessionContextIntegrationFilter is prohibited from creating a HttpSession (because the allowSessionCreation property is false) - SecurityContext thus not stored for next request");
|
|
||||||
}
|
|
||||||
} else if (!contextObject.equals(
|
|
||||||
SecurityContextHolder.getContext())) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug(
|
|
||||||
"HttpSession being created as SecurityContextHolder contents are non-default");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
httpSession = ((HttpServletRequest) request).getSession(true);
|
|
||||||
} catch (IllegalStateException ignored) {}
|
|
||||||
} else {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug(
|
|
||||||
"HttpSession is null, but SecurityContextHolder has not changed from default: ' "
|
|
||||||
+ SecurityContextHolder.getContext()
|
|
||||||
+ "'; not creating HttpSession or storing SecurityContextHolder contents");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If HttpSession exists, store current SecurityContextHolder contents
|
|
||||||
if (httpSession != null) {
|
|
||||||
httpSession.setAttribute(ACEGI_SECURITY_CONTEXT_KEY,
|
|
||||||
SecurityContextHolder.getContext());
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("SecurityContext stored to HttpSession: '"
|
|
||||||
+ SecurityContextHolder.getContext() + "'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove SecurityContextHolder contents
|
|
||||||
SecurityContextHolder.setContext(generateNewContext());
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug(
|
|
||||||
"SecurityContextHolder set to new context, as request processing completed");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,46 @@ public class HttpSessionContextIntegrationFilterTests extends TestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testExceptionWithinFilterChainStillClearsSecurityContextHolder()
|
||||||
|
throws Exception {
|
||||||
|
// Build an Authentication object we simulate came from HttpSession
|
||||||
|
PrincipalAcegiUserToken sessionPrincipal = new PrincipalAcegiUserToken("key",
|
||||||
|
"someone", "password",
|
||||||
|
new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_ROLE")});
|
||||||
|
|
||||||
|
// Build a Context to store in HttpSession (simulating prior request)
|
||||||
|
SecurityContext sc = new SecurityContextImpl();
|
||||||
|
sc.setAuthentication(sessionPrincipal);
|
||||||
|
|
||||||
|
// Build a mock request
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
request.getSession().setAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY,
|
||||||
|
sc);
|
||||||
|
|
||||||
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
FilterChain chain = new MockFilterChain(sessionPrincipal, null,
|
||||||
|
new IOException());
|
||||||
|
|
||||||
|
// Prepare filter
|
||||||
|
HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
|
||||||
|
filter.setContext(SecurityContextImpl.class);
|
||||||
|
filter.afterPropertiesSet();
|
||||||
|
|
||||||
|
// Execute filter
|
||||||
|
try {
|
||||||
|
executeFilterInContainerSimulator(new MockFilterConfig(), filter,
|
||||||
|
request, response, chain);
|
||||||
|
fail(
|
||||||
|
"We should have received the IOException thrown inside the filter chain here");
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
assertTrue(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the SecurityContextHolder is null, even though an exception was thrown during chain
|
||||||
|
assertEquals(new SecurityContextImpl(),
|
||||||
|
SecurityContextHolder.getContext());
|
||||||
|
}
|
||||||
|
|
||||||
public void testExistingContextContentsCopiedIntoContextHolderFromSessionAndChangesToContextCopiedBackToSession()
|
public void testExistingContextContentsCopiedIntoContextHolderFromSessionAndChangesToContextCopiedBackToSession()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
// Build an Authentication object we simulate came from HttpSession
|
// Build an Authentication object we simulate came from HttpSession
|
||||||
|
@ -106,7 +146,7 @@ public class HttpSessionContextIntegrationFilterTests extends TestCase {
|
||||||
|
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
FilterChain chain = new MockFilterChain(sessionPrincipal,
|
FilterChain chain = new MockFilterChain(sessionPrincipal,
|
||||||
updatedPrincipal);
|
updatedPrincipal, null);
|
||||||
|
|
||||||
// Prepare filter
|
// Prepare filter
|
||||||
HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
|
HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
|
||||||
|
@ -134,7 +174,7 @@ public class HttpSessionContextIntegrationFilterTests extends TestCase {
|
||||||
// Build a mock request
|
// Build a mock request
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
FilterChain chain = new MockFilterChain(null, updatedPrincipal);
|
FilterChain chain = new MockFilterChain(null, updatedPrincipal, null);
|
||||||
|
|
||||||
// Prepare filter
|
// Prepare filter
|
||||||
HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
|
HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
|
||||||
|
@ -157,7 +197,7 @@ public class HttpSessionContextIntegrationFilterTests extends TestCase {
|
||||||
// Build a mock request
|
// Build a mock request
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest(null, null);
|
MockHttpServletRequest request = new MockHttpServletRequest(null, null);
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
FilterChain chain = new MockFilterChain(null, null);
|
FilterChain chain = new MockFilterChain(null, null, null);
|
||||||
|
|
||||||
// Prepare filter
|
// Prepare filter
|
||||||
HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
|
HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
|
||||||
|
@ -185,7 +225,7 @@ public class HttpSessionContextIntegrationFilterTests extends TestCase {
|
||||||
"NOT_A_CONTEXT_OBJECT");
|
"NOT_A_CONTEXT_OBJECT");
|
||||||
|
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
FilterChain chain = new MockFilterChain(null, updatedPrincipal);
|
FilterChain chain = new MockFilterChain(null, updatedPrincipal, null);
|
||||||
|
|
||||||
// Prepare filter
|
// Prepare filter
|
||||||
HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
|
HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
|
||||||
|
@ -216,11 +256,13 @@ public class HttpSessionContextIntegrationFilterTests extends TestCase {
|
||||||
private class MockFilterChain extends TestCase implements FilterChain {
|
private class MockFilterChain extends TestCase implements FilterChain {
|
||||||
private Authentication changeContextHolder;
|
private Authentication changeContextHolder;
|
||||||
private Authentication expectedOnContextHolder;
|
private Authentication expectedOnContextHolder;
|
||||||
|
private IOException toThrowDuringChain;
|
||||||
|
|
||||||
public MockFilterChain(Authentication expectedOnContextHolder,
|
public MockFilterChain(Authentication expectedOnContextHolder,
|
||||||
Authentication changeContextHolder) {
|
Authentication changeContextHolder, IOException toThrowDuringChain) {
|
||||||
this.expectedOnContextHolder = expectedOnContextHolder;
|
this.expectedOnContextHolder = expectedOnContextHolder;
|
||||||
this.changeContextHolder = changeContextHolder;
|
this.changeContextHolder = changeContextHolder;
|
||||||
|
this.toThrowDuringChain = toThrowDuringChain;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MockFilterChain() {}
|
private MockFilterChain() {}
|
||||||
|
@ -237,6 +279,10 @@ public class HttpSessionContextIntegrationFilterTests extends TestCase {
|
||||||
sc.setAuthentication(changeContextHolder);
|
sc.setAuthentication(changeContextHolder);
|
||||||
SecurityContextHolder.setContext(sc);
|
SecurityContextHolder.setContext(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (toThrowDuringChain != null) {
|
||||||
|
throw toThrowDuringChain;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
<action dev="benalex" type="fix">Remove getters and setters from JdbcDaoImpl so IoC container cannot modify MappingSqlQuerys</action>
|
<action dev="benalex" type="fix">Remove getters and setters from JdbcDaoImpl so IoC container cannot modify MappingSqlQuerys</action>
|
||||||
<action dev="benalex" type="update">Refactor DAO authentication failure events under a consistent abstract superclass</action>
|
<action dev="benalex" type="update">Refactor DAO authentication failure events under a consistent abstract superclass</action>
|
||||||
<action dev="benalex" type="fix">JBoss container adapter to use getName() instead to toString() (see http://opensource.atlassian.com/projects/spring/browse/SEC-22)</action>
|
<action dev="benalex" type="fix">JBoss container adapter to use getName() instead to toString() (see http://opensource.atlassian.com/projects/spring/browse/SEC-22)</action>
|
||||||
|
<action dev="benalex" type="fix">HttpSessionContextIntegrationFilter elegantly handles IOExceptions and ServletExceptions within filter chain (see http://opensource.atlassian.com/projects/spring/browse/SEC-20)</action>
|
||||||
</release>
|
</release>
|
||||||
<release version="0.8.2" date="2005-04-20">
|
<release version="0.8.2" date="2005-04-20">
|
||||||
<action dev="benalex" type="fix">Correct location of AuthenticationSimpleHttpInvokerRequestExecutor in clientContext.xml</action>
|
<action dev="benalex" type="fix">Correct location of AuthenticationSimpleHttpInvokerRequestExecutor in clientContext.xml</action>
|
||||||
|
|
Loading…
Reference in New Issue