SEC-1307: Modify context saving logic in HttpSessionSecurityContextRepository to check the SecurityContext and its contents (the Authentication) against the respective values when the request first arrived at the SecurityContextPersistenceFilter. As explained in the issue, this allows a definite decision to be made about whether the current thread has modified the context information during the request, indicating that it should be saved.

Also removed deprecated HttpSessionContextIntegrationFilter and tests.
This commit is contained in:
Luke Taylor
2010-02-25 21:51:46 +00:00
parent 5aae545949
commit e2f9be9015
3 changed files with 22 additions and 521 deletions

View File

@@ -1,313 +0,0 @@
/* 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.web.context;
import static org.junit.Assert.*;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.MockFilterConfig;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
/**
* Tests {@link HttpSessionContextIntegrationFilter}.
*
* @author Ben Alex
*/
@SuppressWarnings("deprecation")
public class HttpSessionContextIntegrationFilterTests {
// Build an Authentication object we simulate came from HttpSession
private UsernamePasswordAuthenticationToken sessionPrincipal = new UsernamePasswordAuthenticationToken(
"someone",
"password",
AuthorityUtils.createAuthorityList("SOME_ROLE"));
//~ Methods ========================================================================================================
private static void executeFilterInContainerSimulator(
FilterConfig filterConfig, Filter filter, ServletRequest request,
ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// filter.init(filterConfig);
filter.doFilter(request, response, filterChain);
// filter.destroy();
}
@Test
public void testDetectsIncompatibleSessionProperties() throws Exception {
HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
try {
filter.setAllowSessionCreation(false);
filter.setForceEagerSessionCreation(true);
filter.afterPropertiesSet();
fail("Shown have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
filter.setAllowSessionCreation(true);
filter.afterPropertiesSet();
assertTrue(true);
}
@Test
public void testDetectsMissingOrInvalidContext() throws Exception {
HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
try {
filter.setContextClass(null);
filter.afterPropertiesSet();
fail("Shown have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
try {
filter.setContextClass(Integer.class);
assertEquals(Integer.class, filter.getContextClass());
filter.afterPropertiesSet();
fail("Shown have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
}
@Test
public void testExceptionWithinFilterChainStillClearsSecurityContextHolder() throws Exception {
// 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.SPRING_SECURITY_CONTEXT_KEY,
sc);
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain chain = new MockFilterChain(sessionPrincipal, null,
new IOException());
// Prepare filter
HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
filter.setContextClass(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());
assertNull("Should have cleared FILTER_APPLIED",
request.getAttribute(HttpSessionContextIntegrationFilter.FILTER_APPLIED));
}
@Test
public void testExistingContextContentsCopiedIntoContextHolderFromSessionAndChangesToContextCopiedBackToSession()
throws Exception {
// Build an Authentication object we simulate came from HttpSession
UsernamePasswordAuthenticationToken updatedPrincipal = new UsernamePasswordAuthenticationToken(
"someone",
"password",
AuthorityUtils.createAuthorityList("SOME_DIFFERENT_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.SPRING_SECURITY_CONTEXT_KEY,
sc);
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain chain = new MockFilterChain(sessionPrincipal,
updatedPrincipal, null);
// Prepare filter
HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
filter.setContextClass(SecurityContextImpl.class);
filter.afterPropertiesSet();
// Execute filter
executeFilterInContainerSimulator(new MockFilterConfig(), filter,
request, response, chain);
// Obtain new/update Authentication from HttpSession
SecurityContext context = (SecurityContext) request.getSession().getAttribute(
HttpSessionContextIntegrationFilter.SPRING_SECURITY_CONTEXT_KEY);
assertEquals(updatedPrincipal, ((SecurityContext) context).getAuthentication());
}
@Test
public void testHttpSessionCreatedWhenContextHolderChanges() throws Exception {
// Build an Authentication object we simulate our Authentication changed it to
UsernamePasswordAuthenticationToken updatedPrincipal = new UsernamePasswordAuthenticationToken(
"someone",
"password",
AuthorityUtils.createAuthorityList("SOME_ROLE"));
// Build a mock request
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain chain = new MockFilterChain(null, updatedPrincipal, null);
// Prepare filter
HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
filter.setContextClass(SecurityContextImpl.class);
// don't call afterPropertiesSet to test case when Spring filter.afterPropertiesSet(); isn't called
// Execute filter
executeFilterInContainerSimulator(new MockFilterConfig(), filter, request, response, chain);
// Obtain new/updated Authentication from HttpSession
SecurityContext context = (SecurityContext) request.getSession(false).getAttribute(
HttpSessionContextIntegrationFilter.SPRING_SECURITY_CONTEXT_KEY);
assertEquals(updatedPrincipal, ((SecurityContext) context).getAuthentication());
}
@Test
public void testHttpSessionEagerlyCreatedWhenDirected() throws Exception {
// Build a mock request
MockHttpServletRequest request = new MockHttpServletRequest(null, null);
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain chain = new MockFilterChain(null, null, null);
// Prepare filter
HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
filter.setContextClass(SecurityContextImpl.class);
filter.setForceEagerSessionCreation(true); // non-default
filter.afterPropertiesSet();
// Execute filter
executeFilterInContainerSimulator(new MockFilterConfig(), filter,
request, response, chain);
// Check the session is not null
assertNotNull(request.getSession(false));
}
@Test
public void testHttpSessionNotCreatedUnlessContextHolderChanges() throws Exception {
// Build a mock request
MockHttpServletRequest request = new MockHttpServletRequest(null, null);
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain chain = new MockFilterChain(null, null, null);
// Prepare filter
HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
filter.setContextClass(SecurityContextImpl.class);
filter.afterPropertiesSet();
// Execute filter
executeFilterInContainerSimulator(new MockFilterConfig(), filter,
request, response, chain);
// Check the session is null
assertNull(request.getSession(false));
}
@Test
public void testHttpSessionWithNonContextInWellKnownLocationIsOverwritten() throws Exception {
// Build an Authentication object we simulate our Authentication changed it to
UsernamePasswordAuthenticationToken updatedPrincipal = new UsernamePasswordAuthenticationToken(
"someone",
"password",
AuthorityUtils.createAuthorityList("SOME_DIFFERENT_ROLE"));
// Build a mock request
MockHttpServletRequest request = new MockHttpServletRequest();
request.getSession().setAttribute(
HttpSessionContextIntegrationFilter.SPRING_SECURITY_CONTEXT_KEY,
"NOT_A_CONTEXT_OBJECT");
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain chain = new MockFilterChain(null, updatedPrincipal, null);
// Prepare filter
HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
filter.setContextClass(SecurityContextImpl.class);
filter.afterPropertiesSet();
// Execute filter
executeFilterInContainerSimulator(new MockFilterConfig(), filter, request, response, chain);
// Obtain new/update Authentication from HttpSession
SecurityContext context = (SecurityContext) request.getSession().getAttribute(
HttpSessionContextIntegrationFilter.SPRING_SECURITY_CONTEXT_KEY);
assertEquals(updatedPrincipal, ((SecurityContext) context).getAuthentication());
}
//~ Inner Classes ==================================================================================================
private class MockFilterChain implements FilterChain {
private Authentication changeContextHolder;
private Authentication expectedOnContextHolder;
private IOException toThrowDuringChain;
public MockFilterChain(Authentication expectedOnContextHolder,
Authentication changeContextHolder,
IOException toThrowDuringChain) {
this.expectedOnContextHolder = expectedOnContextHolder;
this.changeContextHolder = changeContextHolder;
this.toThrowDuringChain = toThrowDuringChain;
}
public void doFilter(ServletRequest arg0, ServletResponse arg1) throws IOException, ServletException {
if (expectedOnContextHolder != null) {
assertEquals(expectedOnContextHolder, SecurityContextHolder.getContext().getAuthentication());
}
if (changeContextHolder != null) {
SecurityContext sc = SecurityContextHolder.getContext();
sc.setAuthentication(changeContextHolder);
SecurityContextHolder.setContext(sc);
}
if (toThrowDuringChain != null) {
throw toThrowDuringChain;
}
}
}
}