19

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?

cloudy_weather
  • 2,837
  • 12
  • 38
  • 63

2 Answers2

12

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.

KhAn SaAb
  • 5,248
  • 5
  • 31
  • 52
Emanuele Ivaldi
  • 1,332
  • 10
  • 15
  • 1
    Hi Emanuele, thanks for your answer, I ended up exactly with the same solution. – cloudy_weather Aug 16 '13 at 13:08
  • The code sample you provided was extremely useful for me! Thank you! – weekens Mar 02 '14 at 15:51
  • It's nice the way you login to get a session, and then make your endpoint call. I was hoping to create a mock session without having to perform a login - then spoof the credentials. The login is performed by a different service than the one I'm testing, so this won't work for me. – Kieveli May 10 '16 at 16:50
  • Hi, you should be able to create a mock session and fill it with everything you need and then set it the context when doing the request. – Emanuele Ivaldi May 11 '16 at 07:18
3

Add in pom.xml

<repository>
    <id>spring-snaspho</id>
    <url>http://repo.springsource.org/libs-milestone/</url>
</repository>

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-test</artifactId>
    <version>4.0.0.M1</version>
</dependency>

and use org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors for authorization request. See the sample usage here, and Spring.io jira ticket SEC-2592.

Grigory Kislin
  • 16,647
  • 10
  • 125
  • 197
  • 1
    Spring Security has improved test support in current version (4.0.1.RELEASE). Its documentation is available Setting Up MockMvc and Spring Security(http://docs.spring.io/spring-security/site/docs/4.0.1.RELEASE/reference/htmlsingle/#test-mockmvc-setup) and using Mocked user (http://docs.spring.io/spring-security/site/docs/4.0.1.RELEASE/reference/htmlsingle/#test-method) – Reva Jun 28 '15 at 05:37