I have a workaround that seems to completely solve this problem for spring-boot: 1.1.4, spring-security: 3.2.4 and thymeleaf: 2.1.3 (although this is a bit of a hack).
This is a modified unit test class:
@RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = Application.class) @WebAppConfiguration public class AppControllersTest { @Autowired public WebApplicationContext context; @Autowired private FilterChainProxy springSecurityFilter; private MockMvc mockMvc; @Before public void setup() { assertNotNull(context); assertNotNull(springSecurityFilter);
The magic here makes WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE be the actual context of the web application (which I entered). This allows me to work with the actual sec attributes: BUT my second test, where I try to set permissions so that the user is logged in, fails (it looks like the user is still ANONYMOUS).
UPDATE
There was something missing (which, in my opinion, is a gap in the way spring protection works), but this is a pretty good task (although it's a bit of a hack). See This for more details on the issue: Spring Test and Security: How to simulate authentication?
I needed to add a method that creates a session layout for the test. This method will set Principal / Authentication security and force the SecurityContext to be added to the HttpSession , which can then be added to the test request (see below for a test example and an example for the NamedOAuthPrincipal class).
public MockHttpSession makeAuthSession(String username, String... roles) { if (StringUtils.isEmpty(username)) { username = "azeckoski"; } MockHttpSession session = new MockHttpSession(); session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext()); Collection<GrantedAuthority> authorities = new HashSet<>(); if (roles != null && roles.length > 0) { for (String role : roles) { authorities.add(new SimpleGrantedAuthority(role)); } } //Authentication authToken = new UsernamePasswordAuthenticationToken("azeckoski", "password", authorities); // causes a NPE when it tries to access the Principal Principal principal = new NamedOAuthPrincipal(username, authorities, "key", "signature", "HMAC-SHA-1", "signaturebase", "token"); Authentication authToken = new UsernamePasswordAuthenticationToken(principal, null, authorities); SecurityContextHolder.getContext().setAuthentication(authToken); return session; }
Class for creating Principal (with OAuth support through ConsumerCredentials). If you are not using OAuth, you can skip the ConsumerCredentials part only to implement the principal (but you must return the GrantedAuthority collection).
public static class NamedOAuthPrincipal extends ConsumerCredentials implements Principal { public String name; public Collection<GrantedAuthority> authorities; public NamedOAuthPrincipal(String name, Collection<GrantedAuthority> authorities, String consumerKey, String signature, String signatureMethod, String signatureBaseString, String token) { super(consumerKey, signature, signatureMethod, signatureBaseString, token); this.name = name; this.authorities = authorities; } @Override public String getName() { return name; } public Collection<? extends GrantedAuthority> getAuthorities() { return authorities; } }
And then modify the test as follows (to create a session, and then set it to the mock request):
@Test public void testLoadRootWithAuth() throws Exception { // Test basic home controller request with a session and logged in user MockHttpSession session = makeAuthSession("azeckoski", "ROLE_USER"); MvcResult result = this.mockMvc.perform(get("/").session(session)) .andExpect(status().isOk()) .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML)) .andReturn(); String content = result.getResponse().getContentAsString(); assertNotNull(content); assertTrue(content.contains("Hello Spring Boot")); }