Open LouisVN opened 6 years ago
I can confirm this issue. As described by @LouisVN , the spring-security MockMVC test methods operate directly on the MockMVC MockRequest instead of the SessionRepositoryRequestWrapper. Therefore the test methods (e.g. authenticated()
) cannot see the session created through spring-session.
Is my scenario below the same issue?
My application works normally, only tests fail. I'm using Spring Session JDBC with H2 in memory.
My tests:
@AutoConfigureMockMvc
@TestInstance(Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.Alphanumeric.class)
@TestPropertySource("/application-test.properties")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class LoginControllerIT extends IdpApplicationTest {
@Test
public void test010_DoesNotLogIn_UserNotFound() throws Exception {
MvcResult result = mockMvc.perform(post(LOGIN_URL)
.contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE)
.param("username", "22222222222"))
.andExpect(status().is3xxRedirection())
.andReturn();
HttpSession session = result.getRequest().getSession(false);
// PROBLEM HERE: WebAttributes.AUTHENTICATION_EXCEPTION attribute
// is null on session, but my AuthenticationFailureHandler is filling it
AuthenticationException exception = (AuthenticationException) session.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
assertEquals("Invalid username or password.", exception.getMessage());
}
}
The session is serialized on the BD.
Summary
SessionRepositoryFilter
wraps the incomingHttpServletRequest
and alters the expectedSecurityContext
retrieval when performingMockMvc
requests.Configuration
Once setting up Spring Security + Spring Session + Spring Session JDBC, I had to force the
SessionRepositoryFilter
to kick in before Spring Security's filter chain as follow :Problem
Tests written with
MockMvc
cannot leverage from Spring Security's authentication validation and requires 'cumbersome' reflection to get through authentication details.Tests written withMockMvc
The
SecurityMockMvcResultMatchers
and/orWebTestUtils
are able to retrieve theHttpSessionSecurityContextRepository
from theMvcResult
. However, theMockHttpServletRequest
contains a nullMockHttpSession
which is whatHttpSessionSecurityContextRepository.loadContext
is 'ultimately' checking.Therefore, it will return null as well instead of the valid
SecurityContext
which is meant - in such setup - to be found through theHttpSession
(attached as a request attribute - key = "org.springframework.session.SessionRepository.CURRENT_SESSION").Here is an example of problematic test :
Workaround
All classes are closed from extension with
private
orfinal
. It makes sense but makes testing difficult. In order to retrieve a validSecurityContext
with authentication, I used the following 'trick' :Ideally expected
HttpSession
or theSecurityContext
.HttpSession
creation in a similar setup 🤔 ?Disclaimer : I shortened the configuration/setup to only highlights the key-points. Please let me know if you need a more comprehensive example or if the idea is explicit enough 😃