trying to write some integration test with Spock framework for my controller that has @PreAuthorize annotation on it. When I run the app, this tag is working like a charm. However, when I run integration test I get 403.
My SecurityConfig.java
:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/test/**")
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable();
}
@Bean
@Override
protected AuthenticationManager authenticationManager() {
return new ProviderManager(Arrays.asList(getAuthenticationProvider()));
}
}
My Controller:
@RestController
@Validated
@RequestMapping("/test")
public class TestController {
@PreAuthorize("hasPermission(#object, '')")
@RequestMapping(method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE,
headers = { "Accept=application/json", "Content-Type=application/json" })
public ResponseEntity<List<String>> testController(@RequestBody @Valid TestObject object,
@RequestHeader(ACCOUNT) String account)
throws ResourceNotFoundException, ServletRequestBindingException,
MethodArgumentNotValidException, NoSuchMethodException, SecurityException {
//return statement here!!
}
}
and my PermissionEvaluator impl as follows:
@Component
public class TestPermissionEvaluator implements PermissionEvaluator {
private HttpServletRequest request;
private TestRepository<AccountRoles> repository;
@Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object
permission) {
AccountRole accountRole;
TestObject object = (TestObject) targetDomainObject;
try {
accountRole = repository.find(object.getAccountID(), id);
} catch (ResourceNotFoundException e) {
// throw new Exception here
}
return true;
}
@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String
targetType, Object permission) {
return false;
}
}
And finally my test class looks as follows:
@ContextConfiguration(locations = ['file:src/main/webapp/WEB-INF/spring/testWebmvc-config.xml',
'file:src/main/webapp/WEB-INF/spring/appContext/servlet-context.xml'])
@WebAppConfiguration
public class TestControllerIntegration extends Specification {
TestController controller
MockMvc mockMvc
@Inject
WebApplicationContext wac
@Inject
ObjectMapper mapper
@Autowired
private FilterChainProxy filterChainProxy
def setup() {
controller = new TestController()
mockMvc = MockMvcBuilders.webAppContextSetup(wac).addFilters(filterChainProxy).apply(SecurityMockMvcConfigurers.springSecurity()).build()
SecurityContextHolder.clearContext()
SecurityContextHolder.getContext().setAuthentication(new TestAuthenticationToken("145214741"))
}
@Unroll
def 'valid post to /test'() {
when:
MvcResult result = mockMvc.perform(post('/test').
content(readJsonFromFile(jsonFileLocation)).
contentType(APPLICATION_JSON).
header('account', account).
accept(APPLICATION_JSON)).
andDo(print()).
andReturn()
then:
def ids = mapper.readValue(result.response.getContentAsString(), List.class)
}
Everytime I try to run this test i get a 403 with following stacktrace:
MockHttpServletResponse:
Status = 403
Error message = Access Denied
Headers = {X-Content-Type-Options=[nosniff], X-XSS-Protection=[1; mode=block], Cache-Control=[no-cache, no-store, max-age=0, must-revalidate], Pragma=[no-cache], Expires=[0], X-Frame-Options=[DENY]}
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
com.fasterxml.jackson.databind.JsonMappingException: No content to map due to end-of-input
at [Source: ; line: 1, column: 1]
What am I missing here, thanks in advance!!