Skip to content

Commit

Permalink
Optional authorized-client manager in REST starter
Browse files Browse the repository at this point in the history
  • Loading branch information
ch4mpy committed Apr 10, 2024
1 parent 43172b1 commit 858fad9
Show file tree
Hide file tree
Showing 9 changed files with 35 additions and 21 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<connection>scm:git:git://github.com/ch4mpy/spring-addons.git</connection>
<developerConnection>scm:git:[email protected]:ch4mpy/spring-addons.git</developerConnection>
<url>https://github.com/ch4mpy/spring-addons</url>
<tag>spring-addons-7.6.11</tag>
<tag>HEAD</tag>
</scm>

<distributionManagement>
Expand Down
2 changes: 1 addition & 1 deletion samples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

<properties>
<java.version>17</java.version>
<spring-cloud.version>2023.0.0</spring-cloud.version>
<spring-cloud.version>2023.0.1</spring-cloud.version>

<!-- OpenAPI -->
<io.swagger.core.v3.version>2.2.19</io.swagger.core.v3.version>
Expand Down
1 change: 1 addition & 0 deletions samples/springdoc-openapi-2494-reactive/openapi.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"openapi":"3.0.1","info":{"title":"OpenAPI definition","version":"v0"},"servers":[{"url":"http://localhost:8080","description":"Generated server url"}],"paths":{"/demo":{"get":{"tags":["demo-controller"],"operationId":"getDemo","parameters":[{"name":"nameRequestParam","in":"query","required":true,"schema":{"type":"string","enum":["name a","name b"]}},{"name":"strRequestParam","in":"query","required":true,"schema":{"type":"string","enum":["str a","str b"]}},{"name":"bijRequestParam","in":"query","required":true,"schema":{"type":"string","enum":["bij a","bij b"]}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/Dto"}}}}}},"put":{"tags":["demo-controller"],"operationId":"putDemo","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Dto"}}},"required":true},"responses":{"200":{"description":"OK"}}}}},"components":{"schemas":{"Dto":{"required":["bij","name","str"],"type":"object","properties":{"name":{"type":"string","enum":["name a","name b"]},"str":{"type":"string","enum":["str a","str b"]},"bij":{"type":"string","enum":["bij a","bij b"]}}}}}}
1 change: 1 addition & 0 deletions samples/springdoc-openapi-2494-servlet/openapi.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"openapi":"3.0.1","info":{"title":"OpenAPI definition","version":"v0"},"servers":[{"url":"http://localhost:8080","description":"Generated server url"}],"paths":{"/demo":{"get":{"tags":["demo-controller"],"operationId":"getDemo","parameters":[{"name":"nameRequestParam","in":"query","required":true,"schema":{"type":"string","enum":["A","B"]}},{"name":"strRequestParam","in":"query","required":true,"schema":{"type":"string","enum":["A","B"]}},{"name":"bijRequestParam","in":"query","required":true,"schema":{"type":"string","enum":["bij a","bij b"]}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/Dto"}}}}}},"put":{"tags":["demo-controller"],"operationId":"putDemo","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Dto"}}},"required":true},"responses":{"200":{"description":"OK"}}}}},"components":{"schemas":{"Dto":{"required":["bij","name","str"],"type":"object","properties":{"name":{"type":"string","enum":["A","B"]},"str":{"type":"string","enum":["str a","str b"]},"bij":{"type":"string","enum":["bij a","bij b"]}}}}}}
1 change: 0 additions & 1 deletion spring-addons-starter-rest/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.c4_soft.springaddons.rest;

import java.util.Optional;

import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager;
import org.springframework.util.StringUtils;
import org.springframework.web.reactive.function.client.ClientRequest;
Expand All @@ -8,6 +10,8 @@
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.service.annotation.HttpExchange;

import reactor.core.publisher.Mono;

/**
* <p>
* Provides with {@link WebClient} builder instances pre-configured with:
Expand All @@ -30,21 +34,21 @@
*/
public class ReactiveSpringAddonsWebClientSupport extends AbstractSpringAddonsWebClientSupport {

private final ReactiveOAuth2AuthorizedClientManager authorizedClientManager;
private final Optional<ReactiveOAuth2AuthorizedClientManager> authorizedClientManager;

public ReactiveSpringAddonsWebClientSupport(
SpringAddonsRestProperties addonsProperties,
BearerProvider forwardingBearerProvider,
ReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
Optional<ReactiveOAuth2AuthorizedClientManager> authorizedClientManager) {
super(addonsProperties, forwardingBearerProvider);
this.authorizedClientManager = authorizedClientManager;
}

@Override
protected ExchangeFilterFunction oauth2RegistrationFilter(String registrationId) {
return (ClientRequest request, ExchangeFunction next) -> {
final var provider = new ReactiveAuthorizedClientBearerProvider(authorizedClientManager, registrationId);
return provider.getBearer().defaultIfEmpty("").flatMap(bearer -> {
final var provider = Mono.justOrEmpty(authorizedClientManager.map(acm -> new ReactiveAuthorizedClientBearerProvider(acm, registrationId)));
return provider.flatMap(ReactiveAuthorizedClientBearerProvider::getBearer).defaultIfEmpty("").flatMap(bearer -> {
if (StringUtils.hasText(bearer)) {
final var modified = ClientRequest.from(request).headers(headers -> headers.setBearerAuth(bearer)).build();
return next.exchange(modified);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.c4_soft.springaddons.rest;

import java.util.Optional;

import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
Expand All @@ -23,7 +25,7 @@ BearerProvider bearerProvider() {
SpringAddonsRestClientSupport restClientSupport(
SpringAddonsRestProperties addonsProperties,
BearerProvider forwardingBearerProvider,
OAuth2AuthorizedClientManager authorizedClientManager) {
Optional<OAuth2AuthorizedClientManager> authorizedClientManager) {
return new SpringAddonsRestClientSupport(addonsProperties, forwardingBearerProvider, authorizedClientManager);
}

Expand All @@ -32,7 +34,7 @@ SpringAddonsRestClientSupport restClientSupport(
SpringAddonsWebClientSupport webClientSupport(
SpringAddonsRestProperties addonsProperties,
BearerProvider forwardingBearerProvider,
OAuth2AuthorizedClientManager authorizedClientManager) {
Optional<OAuth2AuthorizedClientManager> authorizedClientManager) {
return new SpringAddonsWebClientSupport(addonsProperties, forwardingBearerProvider, authorizedClientManager);
}

Expand All @@ -41,7 +43,7 @@ SpringAddonsWebClientSupport webClientSupport(
ReactiveSpringAddonsWebClientSupport reactiveWebClientSupport(
SpringAddonsRestProperties addonsProperties,
BearerProvider forwardingBearerProvider,
ReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
Optional<ReactiveOAuth2AuthorizedClientManager> authorizedClientManager) {
return new ReactiveSpringAddonsWebClientSupport(addonsProperties, forwardingBearerProvider, authorizedClientManager);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.c4_soft.springaddons.rest.SpringAddonsRestProperties.ClientProperties.AuthorizationProperties;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

/**
* <p>
Expand All @@ -51,6 +52,7 @@
* @author Jerome Wacongne chl4mp&#64;c4-soft.com
*/
@Data
@Slf4j
public class SpringAddonsRestClientSupport {

private final SpringAddonsRestProperties addonsProperties;
Expand All @@ -60,7 +62,7 @@ public class SpringAddonsRestClientSupport {
*/
private final BearerProvider forwardingBearerProvider;

private final OAuth2AuthorizedClientManager authorizedClientManager;
private final Optional<OAuth2AuthorizedClientManager> authorizedClientManager;

public RestClient.Builder client() {
final var builder = RestClient.builder();
Expand Down Expand Up @@ -140,7 +142,7 @@ protected void oauth2(RestClient.Builder clientBuilder, AuthorizationProperties.
"REST OAuth2 authorization configuration for %s can be made for either a registration-id or resource server Bearer forwarding, but not both at a time"
.formatted(clientName));
}
oauth2Props.getOauth2RegistrationId().map(this::oauth2RequestInterceptor).ifPresent(clientBuilder::requestInterceptor);
oauth2Props.getOauth2RegistrationId().flatMap(this::oauth2RequestInterceptor).ifPresent(clientBuilder::requestInterceptor);
if (oauth2Props.isForwardBearer()) {
clientBuilder.requestInterceptor((request, body, execution) -> {
forwardingBearerProvider.getBearer().ifPresent(bearer -> {
Expand All @@ -151,14 +153,17 @@ protected void oauth2(RestClient.Builder clientBuilder, AuthorizationProperties.
}
}

protected ClientHttpRequestInterceptor oauth2RequestInterceptor(String registrationId) {
return (request, body, execution) -> {
final var provider = new AuthorizedClientBearerProvider(authorizedClientManager, registrationId);
protected Optional<ClientHttpRequestInterceptor> oauth2RequestInterceptor(String registrationId) {
if (authorizedClientManager.isEmpty()) {
log.warn("OAuth2 client missconfiguration. Can't setup an OAuth2 Bearer request interceptor because there is no authorizedClientManager bean.");
}
return authorizedClientManager.map(acm -> (request, body, execution) -> {
final var provider = new AuthorizedClientBearerProvider(acm, registrationId);
provider.getBearer().ifPresent(bearer -> {
request.getHeaders().setBearerAuth(bearer);
});
return execution.execute(request, body);
};
});
}

protected void basic(RestClient.Builder clientBuilder, AuthorizationProperties.BasicAuthProperties authProps, String clientName) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.c4_soft.springaddons.rest;

import java.util.Optional;

import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
Expand Down Expand Up @@ -29,22 +31,22 @@
*/
public class SpringAddonsWebClientSupport extends AbstractSpringAddonsWebClientSupport {

private final OAuth2AuthorizedClientManager authorizedClientManager;
private final Optional<OAuth2AuthorizedClientManager> authorizedClientManager;

public SpringAddonsWebClientSupport(
SpringAddonsRestProperties addonsProperties,
BearerProvider forwardingBearerProvider,
OAuth2AuthorizedClientManager authorizedClientManager) {
Optional<OAuth2AuthorizedClientManager> authorizedClientManager) {
super(addonsProperties, forwardingBearerProvider);
this.authorizedClientManager = authorizedClientManager;
}

@Override
protected ExchangeFilterFunction oauth2RegistrationFilter(String registrationId) {
return (ClientRequest request, ExchangeFunction next) -> {
final var provider = new AuthorizedClientBearerProvider(authorizedClientManager, registrationId);
if (provider.getBearer().isPresent()) {
final var modified = ClientRequest.from(request).headers(headers -> headers.setBearerAuth(provider.getBearer().get())).build();
final var provider = authorizedClientManager.map(acm -> new AuthorizedClientBearerProvider(acm, registrationId));
if (provider.flatMap(AuthorizedClientBearerProvider::getBearer).isPresent()) {
final var modified = ClientRequest.from(request).headers(headers -> headers.setBearerAuth(provider.get().getBearer().get())).build();
return next.exchange(modified);
}
return next.exchange(request);
Expand Down

0 comments on commit 858fad9

Please sign in to comment.