Using annotations in a cucumber test environment with MockMvcSupport does not create a Principal in Spring Boot
See original GitHub issueDescribe 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”.
Issue Analytics
- State:
- Created 2 years ago
- Comments:27 (12 by maintainers)
Top Results From Across the Web
Cucumber Tests in Spring Boot with Dependency Injection
The @CucumberContextConfiguration annotation tells Cucumber to use this class as the test context configuration for Spring. In our case, we don' ...
Read more >Set Up and Run Cucumber Tests In Spring Boot Application
Step 1: Create a Spring Boot Project using Spring Initializer. ... '@CucumberOptions' annotation is used to configure the directory that ...
Read more >46. Testing - Spring
Test annotations are already annotated with it. By default, @SpringBootTest will not start a server. You can use the webEnvironment attribute of @SpringBootTest...
Read more >Spring Cucumber ActiveProfiles annotation ... - Stack Overflow
I've solved the issue by separating the packages a bit, and creating separate StepInitializer classes for both testsets. Current setup: Test ...
Read more >Four Methods to Disable Spring Security in JUnit Tests
Execute the tests with Spring Security using Mock Authentication. ... does not prevent auto-detection of @SpringBootConfiguration .
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
don’t bother with the sample. I built one and figured out why security is not working:
WithSecurityContextTestExecutionListener
is 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
WebSecurityConfig
referenced in test configuration you provided.If you share a small project, I might add it to samples in tests once we have it working.