Ensure request context is setup before security filter runs

Previously, OrderedRequestContextFilter was ordered such that it
ran after Spring Security's Filter. This meant that the request
context was unavailable to any Filters in Spring Security's Filter
chain. Specifically, this caused a failure when using @EnableOAuth2Sso
as OAuth2ClientAuthenticationProcessingFilter, which is added to
Spring Security's Filter chain would be unable to use the
request-scoped bean upon which it depends.

This commit updates the order of OrderedRequestContextFilter so that
the request context is set up before Spring Security's Filter runs.
The tests for SampleGitHubApplication have been updated to use
TestRestTemplate rather than MockMvc. This is necessary as the latter,
via ServletTestExecutionListener, automatically populates the request
context holder, masking the fact that the request context filter was
setting it up too late.

Closes gh-4270
pull/4304/merge
Andy Wilkinson 9 years ago
parent fdf75d3ede
commit d9d4cc2ef5

@ -16,65 +16,58 @@
package sample.web.secure.github; package sample.web.secure.github;
import org.junit.Before; import java.net.URI;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.boot.test.TestRestTemplate;
import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter; import org.springframework.boot.test.WebIntegrationTest;
import org.springframework.security.web.FilterChainProxy; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.hamcrest.Matchers.equalTo;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern; import static org.hamcrest.Matchers.is;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.hamcrest.Matchers.startsWith;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; import static org.junit.Assert.assertThat;
/** /**
* Basic integration tests for github sso application. * Basic integration tests for GitHub SSO application.
* *
* @author Dave Syer * @author Dave Syer
* @author Andy Wilkinson
*/ */
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(SampleGithubSecureApplication.class) @SpringApplicationConfiguration(SampleGithubSecureApplication.class)
@WebAppConfiguration @WebIntegrationTest(randomPort = true)
@DirtiesContext @DirtiesContext
public class SampleGithubApplicationTests { public class SampleGithubApplicationTests {
@Autowired @Value("${local.server.port}")
private WebApplicationContext context; private int port;
@Autowired
private FilterChainProxy filterChain;
@Autowired
private OAuth2ClientContextFilter filter;
private MockMvc mvc;
@Before
public void setUp() {
this.mvc = webAppContextSetup(this.context)
.addFilters(this.filter, this.filterChain).build();
SecurityContextHolder.clearContext();
}
@Test @Test
public void everythingIsSecuredByDefault() throws Exception { public void everythingIsSecuredByDefault() throws Exception {
this.mvc.perform(get("/")).andExpect(status().isFound()) TestRestTemplate restTemplate = new TestRestTemplate();
.andExpect(redirectedUrlPattern("**/login")); ResponseEntity<Void> entity = restTemplate
.getForEntity("http://localhost:" + this.port, Void.class);
assertThat(entity.getStatusCode(), is(HttpStatus.FOUND));
assertThat(entity.getHeaders().getLocation(),
is(equalTo(URI.create("http://localhost:" + this.port + "/login"))));
} }
@Test @Test
public void loginRedirectsToGithub() throws Exception { public void loginRedirectsToGithub() throws Exception {
this.mvc.perform(get("/login")).andExpect(status().isFound()) TestRestTemplate restTemplate = new TestRestTemplate();
.andExpect(redirectedUrlPattern("https://github.com/**")); ResponseEntity<Void> entity = restTemplate
.getForEntity("http://localhost:" + this.port + "/login", Void.class);
assertThat(entity.getStatusCode(), is(HttpStatus.FOUND));
assertThat(entity.getHeaders().getLocation().toString(),
startsWith("https://github.com/login/oauth"));
} }
} }

@ -29,7 +29,7 @@ import org.springframework.web.filter.RequestContextFilter;
public class OrderedRequestContextFilter extends RequestContextFilter implements Ordered { public class OrderedRequestContextFilter extends RequestContextFilter implements Ordered {
// Order defaults to after Spring Session filter // Order defaults to after Spring Session filter
private int order = FilterRegistrationBean.REQUEST_WRAPPER_FILTER_MAX_ORDER + 5; private int order = FilterRegistrationBean.REQUEST_WRAPPER_FILTER_MAX_ORDER - 105;
@Override @Override
public int getOrder() { public int getOrder() {

Loading…
Cancel
Save