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

  1. 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;
    }
  1. 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) {
..
    }
  1. 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)

Most upvoted comments

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.