2

I am using:

request.IsUserInRole("ADMIN")

in one of my controllers to determine the response to the request. I tried to mock the request in my test like:

@Mock
private HttpServletRequest httpRequest;

and to use Springs annotation @WithMockUser:

@Test
@WithMockUser(roles={"USER, ADMIN"})
public void getAccountsTest() throws Exception {...}

Both didn't work.

Question 1: How can I mock request.IsUserInRole("ADMIN") in a JUnit test?

Question 2: What influence does @WithMockUser have on the request and request.IsUserInRole("ADMIN")?

Thanks and best regards

---- edit ----

"Didn't work" means I have a test method:

@Test
@WithMockUser(username = "user", roles={"USER"})
public void getAccountsReturnForbiddenTest() throws Exception {
    mockMvc.perform(get("/accounts/"))
        .andExpect(status().isForbidden());
}

which should return 403, not allowed because of the controller:

@RequestMapping(method=RequestMethod.GET)
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<PagedResources<AccountResource>> getAccounts(...){...}

But the request returns 200, OK.

And I am using Spring Boot 1.4.1.

---- edit 2 ----

My JUnit Test-class:

@Transactional
@ContextConfiguration
public class AccountControllerTestDoc extends AbstractControllerTest {

    @InjectMocks
    private AccountController accountController;

    @Mock
    private AccountService accountService;

    private String uriBase = ""; 

    @Before
    public void setup() {
        // Initialize Mockito annotated components
        MockitoAnnotations.initMocks(this);
        // Prepare the Spring MVC Mock components for standalone testing
        setup(accountController);
    }

    @Test
    @WithMockUser(username = "user", roles={"USER"})
    public void getAccountsReturnForbiddenTest() throws Exception {
        String uri = uriBase + "/accounts";
        mockMvc.perform(get(uri))
            .andExpect(status().isForbidden());
    }

}

with AbstractControllerTest:

@WebAppConfiguration
public abstract class AbstractControllerTest extends AbstractTest  {

    protected MockMvc mockMvc;

    @Autowired
    protected WebApplicationContext wac;

    protected void setup() {
        mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    }

    protected void setup(BaseController controller) {
        mockMvc = MockMvcBuilders.standaloneSetup(controller))
                .build();
    }
}

and AbstractTest:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public abstract class AbstractTest {

    protected Logger LOG = LoggerFactory.getLogger(this.getClass());

}

---- solution ----

MockMvc standaloneSetup isn't aware of the web application context and therefore not aware of the security filter chain. One has to setup MockMvc with the web application context and the security filter chain to be able to test security aspects.

Here is my now working solution, I edited the AbstractControllerTest:

@WebAppConfiguration
public abstract class AbstractControllerTest extends AbstractTest  {

    protected MockMvc mockMvc;

    @Autowired
    protected WebApplicationContext wac;

    @Autowired
    FilterChainProxy springSecurityFilterChain;

    protected void setup() {
        mockMvc = MockMvcBuilders
            .webAppContextSetup(wac)
            .addFilters(springSecurityFilterChain)
            .build();
    }

    protected void setup(BaseController controller) {
        mockMvc = MockMvcBuilders.standaloneSetup(controller))
                .build();
    }
}
Maciej Kowalski
  • 25,605
  • 12
  • 54
  • 63
user1337
  • 460
  • 6
  • 22

2 Answers2

2

You should add the springSecurityFilterChain while creating the MockMvc

protected MockMvc mockMvc;

@Autowired
protected WebApplicationContext wac;

@Autowired
protected Filter springSecurityFilterChain;

protected void setup() {
    mockMvc = MockMvcBuilders
   .webAppContextSetup(wac)
   .addFilters(springSecurityFilterChain)
   .build();
}
shazin
  • 21,379
  • 3
  • 54
  • 71
  • Thank you for the answer! Little bit more background regarding standalone setup for MockMvc from http://stackoverflow.com/a/34316901/3139759 I added the solution in my initial post. – user1337 Oct 17 '16 at 11:27
0
@Test
@WithMockUser(username="xx", roles= {"TIMESHEET"})
public void createNew() throws FailingHttpStatusCodeException, MalformedURLException, IOException {
    
    assertTrue(Constants.isUserInRole("ROLE_TIMESHEET"), "user not in correct role");

Where Constants.isUserInRole is defined as

public static Boolean isUserInRole(String role) {
    return Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication()).map(x->x.getAuthorities()).get()
            .stream().anyMatch(x->x.getAuthority().equals(role));
}

Then use this isUserInRole rather than request.isUserInRole.