diff --git a/pom.xml b/pom.xml index 2380ec548..4e2d31875 100644 --- a/pom.xml +++ b/pom.xml @@ -29,7 +29,7 @@ scm:git:git://github.com/ch4mpy/spring-addons.git scm:git:git@github.com:ch4mpy/spring-addons.git https://github.com/ch4mpy/spring-addons - spring-addons-7.6.11 + HEAD diff --git a/samples/pom.xml b/samples/pom.xml index bccc58791..b568b9c16 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -13,7 +13,7 @@ 17 - 2023.0.0 + 2023.0.1 2.2.19 diff --git a/samples/springdoc-openapi-2494-reactive/openapi.json b/samples/springdoc-openapi-2494-reactive/openapi.json new file mode 100644 index 000000000..a028f5cc2 --- /dev/null +++ b/samples/springdoc-openapi-2494-reactive/openapi.json @@ -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"]}}}}}} \ No newline at end of file diff --git a/samples/springdoc-openapi-2494-servlet/openapi.json b/samples/springdoc-openapi-2494-servlet/openapi.json new file mode 100644 index 000000000..fa0a32292 --- /dev/null +++ b/samples/springdoc-openapi-2494-servlet/openapi.json @@ -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"]}}}}}} \ No newline at end of file diff --git a/spring-addons-starter-rest/pom.xml b/spring-addons-starter-rest/pom.xml index 6720fa075..bd2448e8a 100644 --- a/spring-addons-starter-rest/pom.xml +++ b/spring-addons-starter-rest/pom.xml @@ -44,7 +44,6 @@ org.springframework.security spring-security-oauth2-client - true org.springframework.security diff --git a/spring-addons-starter-rest/src/main/java/com/c4_soft/springaddons/rest/ReactiveSpringAddonsWebClientSupport.java b/spring-addons-starter-rest/src/main/java/com/c4_soft/springaddons/rest/ReactiveSpringAddonsWebClientSupport.java index 8d77a4a2b..75eecdd91 100644 --- a/spring-addons-starter-rest/src/main/java/com/c4_soft/springaddons/rest/ReactiveSpringAddonsWebClientSupport.java +++ b/spring-addons-starter-rest/src/main/java/com/c4_soft/springaddons/rest/ReactiveSpringAddonsWebClientSupport.java @@ -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; @@ -8,6 +10,8 @@ import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.service.annotation.HttpExchange; +import reactor.core.publisher.Mono; + /** *

* Provides with {@link WebClient} builder instances pre-configured with: @@ -30,12 +34,12 @@ */ public class ReactiveSpringAddonsWebClientSupport extends AbstractSpringAddonsWebClientSupport { - private final ReactiveOAuth2AuthorizedClientManager authorizedClientManager; + private final Optional authorizedClientManager; public ReactiveSpringAddonsWebClientSupport( SpringAddonsRestProperties addonsProperties, BearerProvider forwardingBearerProvider, - ReactiveOAuth2AuthorizedClientManager authorizedClientManager) { + Optional authorizedClientManager) { super(addonsProperties, forwardingBearerProvider); this.authorizedClientManager = authorizedClientManager; } @@ -43,8 +47,8 @@ public ReactiveSpringAddonsWebClientSupport( @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); diff --git a/spring-addons-starter-rest/src/main/java/com/c4_soft/springaddons/rest/SpringAddonsRestBeans.java b/spring-addons-starter-rest/src/main/java/com/c4_soft/springaddons/rest/SpringAddonsRestBeans.java index 53215710b..69ba424d5 100644 --- a/spring-addons-starter-rest/src/main/java/com/c4_soft/springaddons/rest/SpringAddonsRestBeans.java +++ b/spring-addons-starter-rest/src/main/java/com/c4_soft/springaddons/rest/SpringAddonsRestBeans.java @@ -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; @@ -23,7 +25,7 @@ BearerProvider bearerProvider() { SpringAddonsRestClientSupport restClientSupport( SpringAddonsRestProperties addonsProperties, BearerProvider forwardingBearerProvider, - OAuth2AuthorizedClientManager authorizedClientManager) { + Optional authorizedClientManager) { return new SpringAddonsRestClientSupport(addonsProperties, forwardingBearerProvider, authorizedClientManager); } @@ -32,7 +34,7 @@ SpringAddonsRestClientSupport restClientSupport( SpringAddonsWebClientSupport webClientSupport( SpringAddonsRestProperties addonsProperties, BearerProvider forwardingBearerProvider, - OAuth2AuthorizedClientManager authorizedClientManager) { + Optional authorizedClientManager) { return new SpringAddonsWebClientSupport(addonsProperties, forwardingBearerProvider, authorizedClientManager); } @@ -41,7 +43,7 @@ SpringAddonsWebClientSupport webClientSupport( ReactiveSpringAddonsWebClientSupport reactiveWebClientSupport( SpringAddonsRestProperties addonsProperties, BearerProvider forwardingBearerProvider, - ReactiveOAuth2AuthorizedClientManager authorizedClientManager) { + Optional authorizedClientManager) { return new ReactiveSpringAddonsWebClientSupport(addonsProperties, forwardingBearerProvider, authorizedClientManager); } } diff --git a/spring-addons-starter-rest/src/main/java/com/c4_soft/springaddons/rest/SpringAddonsRestClientSupport.java b/spring-addons-starter-rest/src/main/java/com/c4_soft/springaddons/rest/SpringAddonsRestClientSupport.java index 485bf6a4a..aaabd8dbf 100644 --- a/spring-addons-starter-rest/src/main/java/com/c4_soft/springaddons/rest/SpringAddonsRestClientSupport.java +++ b/spring-addons-starter-rest/src/main/java/com/c4_soft/springaddons/rest/SpringAddonsRestClientSupport.java @@ -27,6 +27,7 @@ import com.c4_soft.springaddons.rest.SpringAddonsRestProperties.ClientProperties.AuthorizationProperties; import lombok.Data; +import lombok.extern.slf4j.Slf4j; /** *

@@ -51,6 +52,7 @@ * @author Jerome Wacongne chl4mp@c4-soft.com */ @Data +@Slf4j public class SpringAddonsRestClientSupport { private final SpringAddonsRestProperties addonsProperties; @@ -60,7 +62,7 @@ public class SpringAddonsRestClientSupport { */ private final BearerProvider forwardingBearerProvider; - private final OAuth2AuthorizedClientManager authorizedClientManager; + private final Optional authorizedClientManager; public RestClient.Builder client() { final var builder = RestClient.builder(); @@ -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 -> { @@ -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 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) { diff --git a/spring-addons-starter-rest/src/main/java/com/c4_soft/springaddons/rest/SpringAddonsWebClientSupport.java b/spring-addons-starter-rest/src/main/java/com/c4_soft/springaddons/rest/SpringAddonsWebClientSupport.java index 9a4f08c01..ac6d06d85 100644 --- a/spring-addons-starter-rest/src/main/java/com/c4_soft/springaddons/rest/SpringAddonsWebClientSupport.java +++ b/spring-addons-starter-rest/src/main/java/com/c4_soft/springaddons/rest/SpringAddonsWebClientSupport.java @@ -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; @@ -29,12 +31,12 @@ */ public class SpringAddonsWebClientSupport extends AbstractSpringAddonsWebClientSupport { - private final OAuth2AuthorizedClientManager authorizedClientManager; + private final Optional authorizedClientManager; public SpringAddonsWebClientSupport( SpringAddonsRestProperties addonsProperties, BearerProvider forwardingBearerProvider, - OAuth2AuthorizedClientManager authorizedClientManager) { + Optional authorizedClientManager) { super(addonsProperties, forwardingBearerProvider); this.authorizedClientManager = authorizedClientManager; } @@ -42,9 +44,9 @@ public SpringAddonsWebClientSupport( @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);