spring-addons: Using annotations in a cucumber test environment with MockMvcSupport does not create a Principal in Spring Boot
Describe the bug We have Keycloak configured in our Spring Boot micro-service. We use Cucumber to test our backend rest service endpoints. We use JWT tokens to secure endpoints. I use a very simple @WithMockKeycloakAuth({ “ROLE_user” }) annotation. When stepping in the controller, the Principal was not created (null). Hence, the annotation on a service method @RolesAllowed(“user”) fails.
Code sample
- failing test
@WithMockKeycloakAuth({ "ROLE_user" })
public List<ProductLightDTO> securedProductSearch(ProductFilter filter, String username, String password) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
String body = objectMapper.writeValueAsString(filter);
MvcResult result = api.perform(post("/products").contentType(APPLICATION_JSON_UTF8)
.content(body)).andReturn();
List<ProductLightDTO> productLightDTOS = Arrays.asList(objectMapper.readValue(result.getResponse().getContentAsString(), ProductLightDTO.class));
return productLightDTOS;
}
- Component under test
@RestController
@RequestMapping("/products")
public class ProductController {
private final ProductService productService;
@PostMapping("")
public List<ProductLightDTO> searchProducts(@RequestBody ProductFilter productFilter, Principal principal) {
return productService.search(productFilter);
}
The service method (never gets ther since Spring Security is doing it’s job)
@Service
@Log4j2
public class ProductService {
@RolesAllowed("user")
public List<ProductLightDTO> search(ProductFilter productFilter) {
..
}
- spring-security configuration involved (runtime and tests)
Runtime config:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(jsr250Enabled = true)
public class WebSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.cors().and().authorizeRequests()
.anyRequest()
.authenticated()
.and()
.httpBasic();
http.csrf().disable();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
@Bean
public KeycloakConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
}
Test config:
@Component
@Import({ ServletKeycloakAuthUnitTestingSupport.UnitTestConfig.class })
public class SearchApi {
...
@Autowired
MockMvcSupport api;
@WithMockKeycloakAuth({ "ROLE_user" })
public List<ProductLightDTO> securedProductSearch(ProductFilter filter) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
String body = objectMapper.writeValueAsString(filter);
MvcResult result = api.perform(post("/products").contentType(APPLICATION_JSON_UTF8)
.content(body)).andReturn();
List<ProductLightDTO> productLightDTOS = Arrays.asList(objectMapper.readValue(result.getResponse().getContentAsString(), ProductLightDTO.class));
return productLightDTOS;
}
Expected behavior
I expect to find a Principal in the controler with a role “user”.
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 27 (12 by maintainers)
don’t bother with the sample. I built one and figured out why security is not working:
WithSecurityContextTestExecutionListeneris not triggered by Cucumber JUnit test runner.I oppened a ticket on Cucumber-jvm: https://github.com/cucumber/cucumber-jvm/issues/2408
It is in your runtime config, but I can’t see your
WebSecurityConfigreferenced in test configuration you provided.If you share a small project, I might add it to samples in tests once we have it working.