How to Mock the security context in Spring MVC for testing

junit, spring, spring-mvc, spring-security, spring-test-mvc

Solution

This is something I wrote few days ago. I think that could be helpful (I tested the same thing against the login form, using the session for the second request) see loginUser1Ok(..))

See MvcTest.java in

m4nuv/easy-bank.

Problem

I need to test some protected urls, therefore I need to set up a mock security context in my tests (junit). In particular I need perform some gets and post against my web application, using an authenticated user. Below there is my code, I am able to create a such security context but I need to inject it in the 'MockMvc' object. I set the authentication object in the security context and it works, the output result of 'SecurityContextHolder.getContext().getAuthentication().getPrincipal()' is chanelle.evans@616747.com but when I call the GET on /profile I have an assertion error because I am redirected to my login page, and not to /profile. ``` @WebAppConfiguration @ContextConfiguration(locations = {"classpath:spring/security.xml", "classpath:spring/view.xml"}) @ActiveProfiles("default") @RunWith(SpringJUnit4ClassRunner.class) public class AuthenticationTest { @Autowired WebApplicationContext ctx; private MockMvc mockMvc; @Autowired private FilterChainProxy springSecurityFilterChain; @BeforeClass public static void setUpBeforeClass() throws Exception { } @AfterClass public static void tearDownAfterClass() throws Exception { } @Before public void setUp() throws Exception { mockMvc = MockMvcBuilders.webAppContextSetup(ctx).addFilters(springSecurityFilterChain).build(); //@formatter:off UserDetailsLogic userDetailsLogic = null; userDetailsLogic = ctx.getBean(UserDetailsLogic.class); final UserDetailsImp userDetailsImp = new UserDetailsImp(); userDetailsImp.setAccountId(1001); userDetailsImp.setUserId(8001); userDetailsImp.setPassword("a378c92df7531df6fdf351f7ae1713f91f2dd2d45b9c6e1a8b02736ee3afec6595ff60465e9cb8da"); userDetailsImp.setUsername("chanelle.evans@616747.com"); userDetailsImp.setEmail("chanelle.evans@616747.com"); final Collection<GrantedAuthorityImplementation> authorities= new ArrayList<GrantedAuthorityImplementation>(); authorities.add(new GrantedAuthorityImplementation("ROLE_USER")); userDetailsImp.setAuthorities(authorities); userDetailsImp.setAccountNonExpired(true); userDetailsImp.setAccountNonLocked(true); userDetailsImp.setCredentialsNonExpired(true); userDetailsImp.setEnabled(true); final Authentication authToken = new UsernamePasswordAuthenticationToken (userDetailsImp.getUsername(), userDetailsImp.getPassword(), userDetailsImp.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(authToken); System.out.println("principal:"+SecurityContextHolder.getContext().getAuthentication().getPrincipal()); mockMvc.perform(get("/profile").principal(authToken) .contentType(MediaType.TEXT_HTML) .accept(MediaType.TEXT_HTML)) .andDo(print()) .andExpect(status().isOk()) .andExpect(redirectedUrl(null)) .andExpect(forwardedUrl(null)); //@formatter:on } ``` I guess that I should put my authentication object inside the MockMvc object, but I do not know how Does anyone have any idea?

Original source