François F.
François F.

Reputation: 229

Spring Security Test : Testing the annotation @Secured (or @PreAuthorize)

I've got a problem (of course :)). I have a spring 4.2 application with Spring Security and Spring MVC (with Rest API) and I want to test the effectiveness of the annotation @Secured(ROLE_FOO) present on a REST method. So I need to install spring-security-test library for this. OK. Then I follow up some tutorials (or doc) like the official one : http://docs.spring.io/autorepo/docs/spring-security/4.1.0.RC1/reference/htmlsingle/

Here my test code (I'am trying to remove all "uneccessary" code.

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@IntegrationTest
public class UserResourceIntTest {

    private MockMvc restUserMockMvc2;

   @Autowired
    private WebApplicationContext context;

....//Injection, Mocks declarations here

@Before
    public void setup() {




        this.restUserMockMvc2 = MockMvcBuilders.webAppContextSetup(context).apply(SecurityMockMvcConfigurers.springSecurity()).build();



    }


    @Test
    @WithMockUser(roles="ROLE_VIEWER")
    public void testGetUserListe() throws Exception {
        //here getAuthentication() returns null !!! why ???
        SecurityContextHolder.getContext().getAuthentication().getPrincipal();
//      restUserMockMvc2.perform(get("/api/users/liste")
//              .principal(SecurityContextHolder.getContext().getAuthentication()))
//                .accept(MediaType.APPLICATION_JSON))
//                .andExpect(status().isForbidden());
//                .andExpect(content().contentType("application/json"));
    }

Here the method I want to test :

@RestController
@RequestMapping("/api")
public class UserResource {

    @RequestMapping(value = "/users/liste", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @Timed
    @Transactional(readOnly = true)
    @Secured({ AuthoritiesConstants.TC_ADMIN })
    public ResponseEntity<List<ManagedUserDTO>> getUserListe(Pageable pageable, Principal principal) throws URISyntaxException {

        //doSomething...
    }

Can you tell me WHY in my test,

SecurityContextHolder.getContext().getAuthentication()

returns null ?? @WithMockUser should authenticate a user automatically (the principal hence)

Thanks

EDIT1 : the setup part of the test (concerning only the security instruction) :

@Inject
private FilterChainProxy springSecurityFilterChain;

@Inject
private PageableHandlerMethodArgumentResolver pageableArgumentResolver;

@Before
public void setup() {

....

this.restUserMockMvc2 = MockMvcBuilders
                .standaloneSetup(userResource2)
                .alwaysDo(print())              .apply(SecurityMockMvcConfigurers.springSecurity(springSecurityFilterChain))
                .setCustomArgumentResolvers(pageableArgumentResolver)
                .build();

...

}

EDIT2 : just to be clear on the class definition :

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@TestExecutionListeners(listeners={ServletTestExecutionListener.class,
        DependencyInjectionTestExecutionListener.class,
        DirtiesContextTestExecutionListener.class,
        TransactionalTestExecutionListener.class,
        WithSecurityContextTestExecutionListener.class})
public class UserResourceIntTest {
}

Upvotes: 1

Views: 2110

Answers (1)

Rob Winch
Rob Winch

Reputation: 21720

The problem is that Spring Security's WithSecurityContextTestExecutionListener is not being executed because @IntegrationTest is overriding the default TestExecutionListeners.

Most likely you don't need @IntegrationTest with MockMvc, so you should be able to remove it entirely and resolve your issue.

Alternatively you can resolve this by explicitly adding WithSecurityContextTestExecutionListener to your class like:

@TestExecutionListeners(listeners = { WithSecurityContextTestExecutionListener.class, IntegrationTestPropertiesListener.class,
        DirtiesContextBeforeModesTestExecutionListener.class,
        DependencyInjectionTestExecutionListener.class,
        DirtiesContextTestExecutionListener.class,
        TransactionalTestExecutionListener.class, SqlScriptsTestExecutionListener.class })
@IntegrationTest
public class UserResourceIntTest {

Upvotes: 1

Related Questions