spring-cloud / spring-cloud/spring-cloud-config
Provide support for OAuth2 in Spring Config Client.
Nobody has claimed this yet.
- #2363 by @cobar79 — closed without merging
- Dominant language
- Java
- Stars
- 2k
- Forks
- 1.3k
- Avg merge
- 2d 59m
- Merged PRs (30d)
- 16
Description
I would like to implement OAuth2 resource server in the Spring Config Server and require JWT for all configuration requests.
Is your feature request related to a problem? Please describe.
I can't seem to find any method to implement a Spring Security OAuth2 Client Provider to the Spring Cloud Client call.
Overriding ConfigServicePropertySourceLocator
#177 and Adding Generic "Authorization" support for Config Client do not appear to work with current import connection framework "optional:configserver:http://${env.config.hostname}:${env.config.port}/config-server"
The call to the Configuration Server is made before the ConfigServicePropertySourceLocator is instantiated.
Describe the solution you'd like
I would like to use the same implementation used for Machine to Machine OAuth2 communication where by the Spring Security handles obtaining and refreshing the Bearer Token to be passed to the Spring Config Server calls on startup. Preferably a WebClient over RestTemplate solution.
@Bean
ReactiveClientRegistrationRepository clientRegistrations(
@Value("${spring.security.oauth2.client.provider.keycloak-client.token-uri}") String tokenUri,
@Value("${spring.security.oauth2.client.registration.keycloak-client.client-id}") String clientId,
@Value("${spring.security.oauth2.client.registration.keycloak-client.client-secret}") String clientSecret,
@Value("${spring.security.oauth2.client.registration.keycloak-client.scope}") String scope,
@Value("${spring.security.oauth2.client.registration.keycloak-client.authorization-grant-type}") String authorizationGrantType
) {
Collection<String> scopeList = Arrays.asList(scope.split(","));
ClientRegistration registration = ClientRegistration
.withRegistrationId(registrationId)
.tokenUri(tokenUri)
.clientId(clientId)
.clientSecret(clientSecret)
.scope(scopeList)
.authorizationGrantType(new AuthorizationGrantType(authorizationGrantType))
.build();
return new InMemoryReactiveClientRegistrationRepository(registration);
}
@Bean(value = "authWebClient")
WebClient authWebClient(ReactiveClientRegistrationRepository clientRegistrations) {
InMemoryReactiveOAuth2AuthorizedClientService clientService = new InMemoryReactiveOAuth2AuthorizedClientService(clientRegistrations);
AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager = new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(clientRegistrations, clientService);
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
oauth.setDefaultClientRegistrationId(registrationId);
return WebClient.builder()
.filter(oauth)
.baseUrl(baseUrl)
.build();
}
Describe alternatives you've considered
A method to intercept the Spring Config Server rest call, call the IDP and include the Bearer Token manually, there by bypassing the current RestTemplate and any Basic Authentication.
Additional context
Spring Boot 3.1.2, Spring Security 6.1.2
Keycloak OAuth2 implementation
Configuration Server Security
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector);
http.anonymous(AbstractHttpConfigurer::disable);
http.csrf(AbstractHttpConfigurer::disable);
http.authorizeHttpRequests(authorize -> authorize
.requestMatchers(mvcMatcherBuilder.pattern("/" + appName + "/actuator/**")).hasRole("actuator")
.requestMatchers(mvcMatcherBuilder.pattern("/" + appName + "/**")).hasRole("m2m")
//Permit webhook refresh access without authorization
.requestMatchers(mvcMatcherBuilder.pattern("/" + appName + "/monitor")).permitAll()
.anyRequest()
.authenticated()
);
http.oauth2ResourceServer(authorize ->
authorize.jwt(jwt -> jwt.jwtAuthenticationConverter(keycloakJwtTokenConverter))
.authenticationEntryPoint(customAuthenticationEntryPoint)
);
http.sessionManagement(session -> session
.sessionCreationPolicy(stateless? SessionCreationPolicy.STATELESS: SessionCreationPolicy.IF_REQUIRED)
);
return http.build();
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the import connection framework and the point where ConfigServicePropertySourceLocator is instantiated. Compare issue #177 and PR #474 with the OAuth2 client approach described here. Done means configuration requests made on startup obtain and refresh a bearer token and authenticate against the Config Server.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring, spring-boot
- Domain
- authentication, backend, cloud
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100