I'm using the org.openapitools:openapi-generator-maven-plugin:7.0.1
to generate the controllers and request/response objects in a Spring Boot 3 project. This basically works fine but I have a problem with the security conifguration.
I'm overriding the *Delegate
class generated by the plugin like this:
@RestController
public class PingController implements PingApiDelegate {
@Override
@PreAuthorize("hasRole('ping')")
public ResponseEntity<String> ping() {
return ResponseEntity.status(HttpStatus.OK).body("pong");
}
}
As you can see in the following configuration class, all requests are authenticated by default and @EnableMethodSecurity
is set to use the @PreAuthorize
annotation.
RestSecurityConfiguration
@Configuration
@EnableMethodSecurity
@RequiredArgsConstructor
public class RestSecurityConfiguration {
private final JwtAuthConverter jwtAuthConverter;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
return httpSecurity
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(httpRequests -> httpRequests.anyRequest().authenticated())
.oauth2ResourceServer(oauth2ResourceServerCustomizer -> oauth2ResourceServerCustomizer.jwt(jwtCustomizer -> jwtCustomizer.jwtAuthenticationConverter(jwtAuthConverter)))
.sessionManagement(sessionManagementCustomizer -> sessionManagementCustomizer.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.build();
}
}
When testing the controller with a @WebMvcTest
, then I get a HTTP 401 instead of 403 when the passed role does not match. The same test passes if I made the following changes:
- Remove
@EnableMethodSecurity
and@PreAuthorize
- Adding
httpRequests.requestMatchers("/api/ping").hasRole("ping")
@WebMvcTest(PingController.class)
@Import({PingApiController.class})
class PingControllerTest extends AbstractControllerTest {
@Test
void should_return_pong() throws Exception {
mockMvc.perform(get("/api/ping")
.with(authentication(defaultAuthentication("wrong-role"))))
.andExpect(status().isForbidden());
}
protected static Authentication defaultAuthentication(String... authorities) {
Jwt jwt = Jwt.withTokenValue("token")
.header("alg", "none")
.claim("email", "[email protected]")
.build();
final List<String> rolePrefixedAuthorities = Arrays.stream(authorities).map(authority -> "ROLE_" + authority).toList();
return new JwtAuthenticationToken(jwt, AuthorityUtils.createAuthorityList(rolePrefixedAuthorities));
}
}