package org.zalando.problem.spring.web.advice.security; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; import org.zalando.problem.ProblemModule; import org.zalando.problem.spring.web.advice.MediaTypes; import org.zalando.problem.spring.web.advice.ProblemHandling; import java.util.List; import static org.hamcrest.Matchers.is; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.anonymous; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration @WebAppConfiguration public final class SecurityAdviceTraitTest { @Configuration @EnableWebMvc @EnableWebSecurity @Import({MvcConfiguration.class, SecurityConfiguration.class}) public static class TestConfiguration extends WebMvcConfigurationSupport { @Bean public MockMvc mvc(final WebApplicationContext context) { return MockMvcBuilders .webAppContextSetup(context) .apply(springSecurity()) .build(); } } @Configuration @Import({TestController.class, ExceptionHandling.class}) public static class MvcConfiguration extends WebMvcConfigurationSupport { @Override protected void configureMessageConverters(final List<HttpMessageConverter<?>> converters) { converters.clear(); converters.add(new MappingJackson2HttpMessageConverter(new ObjectMapper() .registerModule(new ProblemModule()))); } } @Configuration @Import(SecurityProblemSupport.class) public static class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Autowired private SecurityProblemSupport problemSupport; @Override public void configure(final HttpSecurity http) throws Exception { http.csrf().disable(); http.httpBasic().disable(); http.sessionManagement().disable(); http.authorizeRequests() .antMatchers("/greet").hasRole("ADMIN") .anyRequest().authenticated(); http.exceptionHandling() .authenticationEntryPoint(problemSupport) .accessDeniedHandler(problemSupport); } } @ControllerAdvice public static class ExceptionHandling implements ProblemHandling { } @RestController public static class TestController { @RequestMapping("/greet") public String greet(@RequestParam final String name) { return "Hello " + name + "!"; } } @Autowired private MockMvc mvc; @Test public void notAuthenticated() throws Exception { mvc.perform(post("/").with(anonymous())) .andExpect(status().isUnauthorized()) .andExpect(content().contentType(MediaTypes.PROBLEM)) .andExpect(jsonPath("$.title", is("Unauthorized"))) .andExpect(jsonPath("$.status", is(401))) .andExpect(jsonPath("$.detail", is("Full authentication is required to access this resource"))); } @Test public void notAuthorized() throws Exception { mvc.perform(get("/greet").param("name", "Alice").with(user("user").roles("USER"))) .andExpect(status().isForbidden()) .andExpect(content().contentType(MediaTypes.PROBLEM)) .andExpect(jsonPath("$.title", is("Forbidden"))) .andExpect(jsonPath("$.status", is(403))) .andExpect(jsonPath("$.detail", is("Access is denied"))); } }