diff --git a/pom.xml b/pom.xml index 3251f5770..d02635ee7 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.c4-soft.springaddons spring-addons - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT pom spring-addons Set of tools I find useful to work with Spring (mostly spring-security for OpenID) diff --git a/release-notes.md b/release-notes.md index c2cacd1f7..5ba300a42 100644 --- a/release-notes.md +++ b/release-notes.md @@ -2,7 +2,7 @@ ## `7.x` Branch -### `7.6.1` +### `7.6.3` - Spring Boot 3.2.3 - add `com.c4-soft.springaddons.oidc.client.pkce-forced` property. Default to `false`. When `true`, PKCE is used by clients for authorization-code flows, even by confidential clients - move [the BFF tutorial to Baeldung](https://www.baeldung.com/spring-cloud-gateway-bff-oauth2). It is also refreshed and now contains sample implementations for React (Next.js) and Vue (Vite). diff --git a/samples/pom.xml b/samples/pom.xml index 43c2e4d04..388e7a98d 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -4,7 +4,7 @@ com.c4-soft.springaddons spring-addons - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. com.c4-soft.springaddons.samples diff --git a/samples/tutorials/pom.xml b/samples/tutorials/pom.xml index 47e452bc0..f05bf1446 100644 --- a/samples/tutorials/pom.xml +++ b/samples/tutorials/pom.xml @@ -4,7 +4,7 @@ com.c4-soft.springaddons.samples spring-addons-samples - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. com.c4-soft.springaddons.samples.tutorials diff --git a/samples/tutorials/reactive-client/pom.xml b/samples/tutorials/reactive-client/pom.xml index feae9b42d..a1b981ba8 100644 --- a/samples/tutorials/reactive-client/pom.xml +++ b/samples/tutorials/reactive-client/pom.xml @@ -4,7 +4,7 @@ com.c4-soft.springaddons.samples.tutorials tutorials - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. reactive-client diff --git a/samples/tutorials/reactive-resource-server/pom.xml b/samples/tutorials/reactive-resource-server/pom.xml index 9e24bcd4f..a9ee37dfa 100644 --- a/samples/tutorials/reactive-resource-server/pom.xml +++ b/samples/tutorials/reactive-resource-server/pom.xml @@ -4,7 +4,7 @@ com.c4-soft.springaddons.samples.tutorials tutorials - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. reactive-resource-server diff --git a/samples/tutorials/resource-server_multitenant_dynamic/pom.xml b/samples/tutorials/resource-server_multitenant_dynamic/pom.xml index cac7c416c..dd6a8bfc8 100644 --- a/samples/tutorials/resource-server_multitenant_dynamic/pom.xml +++ b/samples/tutorials/resource-server_multitenant_dynamic/pom.xml @@ -4,7 +4,7 @@ com.c4-soft.springaddons.samples.tutorials tutorials - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. resource-server_multitenant_dynamic diff --git a/samples/tutorials/resource-server_with_additional-header/pom.xml b/samples/tutorials/resource-server_with_additional-header/pom.xml index c1dba3d84..b54fc481f 100644 --- a/samples/tutorials/resource-server_with_additional-header/pom.xml +++ b/samples/tutorials/resource-server_with_additional-header/pom.xml @@ -4,7 +4,7 @@ com.c4-soft.springaddons.samples.tutorials tutorials - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. resource-server_with_additional-header diff --git a/samples/tutorials/resource-server_with_introspection/pom.xml b/samples/tutorials/resource-server_with_introspection/pom.xml index d11aee2d4..844fdd933 100644 --- a/samples/tutorials/resource-server_with_introspection/pom.xml +++ b/samples/tutorials/resource-server_with_introspection/pom.xml @@ -4,7 +4,7 @@ com.c4-soft.springaddons.samples.tutorials tutorials - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. resource-server_with_introspection diff --git a/samples/tutorials/resource-server_with_oauthentication/pom.xml b/samples/tutorials/resource-server_with_oauthentication/pom.xml index 1b96c368d..e8a6153dc 100644 --- a/samples/tutorials/resource-server_with_oauthentication/pom.xml +++ b/samples/tutorials/resource-server_with_oauthentication/pom.xml @@ -4,7 +4,7 @@ com.c4-soft.springaddons.samples.tutorials tutorials - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. resource-server_with_oauthentication diff --git a/samples/tutorials/resource-server_with_specialized_oauthentication/pom.xml b/samples/tutorials/resource-server_with_specialized_oauthentication/pom.xml index 6da72b4af..483969a2b 100644 --- a/samples/tutorials/resource-server_with_specialized_oauthentication/pom.xml +++ b/samples/tutorials/resource-server_with_specialized_oauthentication/pom.xml @@ -4,7 +4,7 @@ com.c4-soft.springaddons.samples.tutorials tutorials - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. resource-server_with_specialized_oauthentication diff --git a/samples/tutorials/resource-server_with_ui/pom.xml b/samples/tutorials/resource-server_with_ui/pom.xml index a5c609217..c65217f12 100644 --- a/samples/tutorials/resource-server_with_ui/pom.xml +++ b/samples/tutorials/resource-server_with_ui/pom.xml @@ -4,7 +4,7 @@ com.c4-soft.springaddons.samples.tutorials tutorials - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. resource-server_with_ui diff --git a/samples/tutorials/resource-server_with_ui/src/main/resources/application.yml b/samples/tutorials/resource-server_with_ui/src/main/resources/application.yml index cd8a220ba..3cfdd5352 100644 --- a/samples/tutorials/resource-server_with_ui/src/main/resources/application.yml +++ b/samples/tutorials/resource-server_with_ui/src/main/resources/application.yml @@ -101,6 +101,7 @@ com: post-login-redirect-path: /ui/greet post-logout-redirect-path: /ui/greet multi-tenancy-enabled: true + pkce-forced: true oauth2-logout: cognito-confidential-user: uri: https://spring-addons.auth.us-west-2.amazoncognito.com/logout @@ -123,7 +124,7 @@ logging: level: org: springframework: - security: INFO + security: DEBUG boot: INFO management: diff --git a/samples/tutorials/servlet-client/pom.xml b/samples/tutorials/servlet-client/pom.xml index b01fc1868..5f1bf5384 100644 --- a/samples/tutorials/servlet-client/pom.xml +++ b/samples/tutorials/servlet-client/pom.xml @@ -4,7 +4,7 @@ com.c4-soft.springaddons.samples.tutorials tutorials - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. servlet-client diff --git a/samples/tutorials/servlet-resource-server/pom.xml b/samples/tutorials/servlet-resource-server/pom.xml index bb9c530a4..f5b576fbc 100644 --- a/samples/tutorials/servlet-resource-server/pom.xml +++ b/samples/tutorials/servlet-resource-server/pom.xml @@ -4,7 +4,7 @@ com.c4-soft.springaddons.samples.tutorials tutorials - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. servlet-resource-server diff --git a/samples/webflux-introspecting-default/pom.xml b/samples/webflux-introspecting-default/pom.xml index 4bae5bd70..491e75eda 100644 --- a/samples/webflux-introspecting-default/pom.xml +++ b/samples/webflux-introspecting-default/pom.xml @@ -3,7 +3,7 @@ com.c4-soft.springaddons.samples spring-addons-samples - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. diff --git a/samples/webflux-introspecting-oauthentication/pom.xml b/samples/webflux-introspecting-oauthentication/pom.xml index f921ed630..f0474814d 100644 --- a/samples/webflux-introspecting-oauthentication/pom.xml +++ b/samples/webflux-introspecting-oauthentication/pom.xml @@ -3,7 +3,7 @@ com.c4-soft.springaddons.samples spring-addons-samples - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. diff --git a/samples/webflux-jwt-default/pom.xml b/samples/webflux-jwt-default/pom.xml index 13fd7f486..caaac8bb9 100644 --- a/samples/webflux-jwt-default/pom.xml +++ b/samples/webflux-jwt-default/pom.xml @@ -3,7 +3,7 @@ com.c4-soft.springaddons.samples spring-addons-samples - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. diff --git a/samples/webflux-jwt-oauthentication/pom.xml b/samples/webflux-jwt-oauthentication/pom.xml index f3a9cffcc..ebab44e4a 100644 --- a/samples/webflux-jwt-oauthentication/pom.xml +++ b/samples/webflux-jwt-oauthentication/pom.xml @@ -3,7 +3,7 @@ com.c4-soft.springaddons.samples spring-addons-samples - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. diff --git a/samples/webmvc-introspecting-default/pom.xml b/samples/webmvc-introspecting-default/pom.xml index a3f05d326..b2c50e608 100644 --- a/samples/webmvc-introspecting-default/pom.xml +++ b/samples/webmvc-introspecting-default/pom.xml @@ -4,7 +4,7 @@ com.c4-soft.springaddons.samples spring-addons-samples - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. diff --git a/samples/webmvc-introspecting-oauthentication/pom.xml b/samples/webmvc-introspecting-oauthentication/pom.xml index 608ee6813..26c59a605 100644 --- a/samples/webmvc-introspecting-oauthentication/pom.xml +++ b/samples/webmvc-introspecting-oauthentication/pom.xml @@ -4,7 +4,7 @@ com.c4-soft.springaddons.samples spring-addons-samples - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. diff --git a/samples/webmvc-jwt-default-jpa-authorities/pom.xml b/samples/webmvc-jwt-default-jpa-authorities/pom.xml index 731775e33..368b2f8a3 100644 --- a/samples/webmvc-jwt-default-jpa-authorities/pom.xml +++ b/samples/webmvc-jwt-default-jpa-authorities/pom.xml @@ -4,7 +4,7 @@ com.c4-soft.springaddons.samples spring-addons-samples - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. diff --git a/samples/webmvc-jwt-default/pom.xml b/samples/webmvc-jwt-default/pom.xml index 2062efa3f..867121b24 100644 --- a/samples/webmvc-jwt-default/pom.xml +++ b/samples/webmvc-jwt-default/pom.xml @@ -4,7 +4,7 @@ com.c4-soft.springaddons.samples spring-addons-samples - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. diff --git a/samples/webmvc-jwt-oauthentication/pom.xml b/samples/webmvc-jwt-oauthentication/pom.xml index d810ca6bf..95c531712 100644 --- a/samples/webmvc-jwt-oauthentication/pom.xml +++ b/samples/webmvc-jwt-oauthentication/pom.xml @@ -4,7 +4,7 @@ com.c4-soft.springaddons.samples spring-addons-samples - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. diff --git a/spring-addons-oauth2-test/pom.xml b/spring-addons-oauth2-test/pom.xml index c1317ff37..7b809e777 100644 --- a/spring-addons-oauth2-test/pom.xml +++ b/spring-addons-oauth2-test/pom.xml @@ -5,7 +5,7 @@ com.c4-soft.springaddons spring-addons - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. spring-addons-oauth2-test diff --git a/spring-addons-oauth2/pom.xml b/spring-addons-oauth2/pom.xml index f663a9f8a..a95cc5180 100644 --- a/spring-addons-oauth2/pom.xml +++ b/spring-addons-oauth2/pom.xml @@ -4,7 +4,7 @@ com.c4-soft.springaddons spring-addons - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. spring-addons-oauth2 diff --git a/spring-addons-starter-oidc-test/pom.xml b/spring-addons-starter-oidc-test/pom.xml index 1c3869427..dd6433c82 100644 --- a/spring-addons-starter-oidc-test/pom.xml +++ b/spring-addons-starter-oidc-test/pom.xml @@ -3,7 +3,7 @@ com.c4-soft.springaddons spring-addons - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. spring-addons-starter-oidc-test diff --git a/spring-addons-starter-oidc/README.MD b/spring-addons-starter-oidc/README.MD index 0194b2c79..3c56d8eaf 100644 --- a/spring-addons-starter-oidc/README.MD +++ b/spring-addons-starter-oidc/README.MD @@ -4,7 +4,7 @@ This project is a Spring Boot starter to use in addition to `spring-boot-starter ```xml - 7.6.1 + 7.6.3 diff --git a/spring-addons-starter-oidc/pom.xml b/spring-addons-starter-oidc/pom.xml index f84e5c03b..51d7d89d4 100644 --- a/spring-addons-starter-oidc/pom.xml +++ b/spring-addons-starter-oidc/pom.xml @@ -3,7 +3,7 @@ com.c4-soft.springaddons spring-addons - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. spring-addons-starter-oidc diff --git a/spring-addons-starter-oidc/src/main/java/com/c4_soft/springaddons/security/oidc/starter/AdditionalParamsAuthorizationRequestCustomizer.java b/spring-addons-starter-oidc/src/main/java/com/c4_soft/springaddons/security/oidc/starter/AdditionalParamsAuthorizationRequestCustomizer.java new file mode 100644 index 000000000..b8ecd5929 --- /dev/null +++ b/spring-addons-starter-oidc/src/main/java/com/c4_soft/springaddons/security/oidc/starter/AdditionalParamsAuthorizationRequestCustomizer.java @@ -0,0 +1,26 @@ +package com.c4_soft.springaddons.security.oidc.starter; + +import java.util.Collection; +import java.util.function.Consumer; + +import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; +import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest.Builder; + +import com.c4_soft.springaddons.security.oidc.starter.properties.SpringAddonsOidcClientProperties.RequestParam; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class AdditionalParamsAuthorizationRequestCustomizer implements Consumer { + private final Collection additionalParams; + + @Override + public void accept(Builder t) { + t.additionalParameters(params -> { + for (var reqParam : additionalParams) { + params.put(reqParam.getName(), reqParam.getValue()); + } + }); + } + +} diff --git a/spring-addons-starter-oidc/src/main/java/com/c4_soft/springaddons/security/oidc/starter/CompositeOAuth2AuthorizationRequestCustomizer.java b/spring-addons-starter-oidc/src/main/java/com/c4_soft/springaddons/security/oidc/starter/CompositeOAuth2AuthorizationRequestCustomizer.java new file mode 100644 index 000000000..b8062b404 --- /dev/null +++ b/spring-addons-starter-oidc/src/main/java/com/c4_soft/springaddons/security/oidc/starter/CompositeOAuth2AuthorizationRequestCustomizer.java @@ -0,0 +1,31 @@ +package com.c4_soft.springaddons.security.oidc.starter; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; + +import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; +import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest.Builder; + +public class CompositeOAuth2AuthorizationRequestCustomizer implements Consumer { + private final List> delegates; + + public CompositeOAuth2AuthorizationRequestCustomizer(Consumer... customizers) { + delegates = new ArrayList<>(customizers.length + 3); + Collections.addAll(delegates, customizers); + } + + @Override + public void accept(Builder t) { + for (var consumer : delegates) { + consumer.accept(t); + } + } + + public CompositeOAuth2AuthorizationRequestCustomizer addCustomizer(Consumer customizer) { + this.delegates.add(customizer); + return this; + } + +} diff --git a/spring-addons-starter-oidc/src/main/java/com/c4_soft/springaddons/security/oidc/starter/reactive/client/ReactiveSpringAddonsOidcClientWithLoginBeans.java b/spring-addons-starter-oidc/src/main/java/com/c4_soft/springaddons/security/oidc/starter/reactive/client/ReactiveSpringAddonsOidcClientWithLoginBeans.java index f3429c0aa..01375114f 100644 --- a/spring-addons-starter-oidc/src/main/java/com/c4_soft/springaddons/security/oidc/starter/reactive/client/ReactiveSpringAddonsOidcClientWithLoginBeans.java +++ b/spring-addons-starter-oidc/src/main/java/com/c4_soft/springaddons/security/oidc/starter/reactive/client/ReactiveSpringAddonsOidcClientWithLoginBeans.java @@ -5,6 +5,7 @@ import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties; import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; @@ -62,8 +63,8 @@ *
  • clientAuthorizePostProcessor: a {@link ClientAuthorizeExchangeSpecPostProcessor} post processor to fine tune access control from java * configuration. It applies to all routes not listed in "permit-all" property configuration. Default requires users to be * authenticated.
  • - *
  • clientHttpPostProcessor: a {@link ClientReactiveHttpSecurityPostProcessor} to override anything from above auto-configuration. It is called - * just before the security filter-chain is returned. Default is a no-op.
  • + *
  • clientHttpPostProcessor: a {@link ClientReactiveHttpSecurityPostProcessor} to override anything from above auto-configuration. It is + * called just before the security filter-chain is returned. Default is a no-op.
  • *
  • authorizationRequestResolver: a {@link ServerOAuth2AuthorizationRequestResolver} to add custom parameters (from application * properties) to authorization code request
  • * @@ -245,8 +246,9 @@ WebFilter csrfCookieWebFilter() { @ConditionalOnMissingBean @Bean - ServerOAuth2AuthorizationRequestResolver authorizationRequestResolver(ReactiveClientRegistrationRepository clientRegistrationRepository, SpringAddonsOidcProperties addonsProperties) { - return new SpringAddonsServerOAuth2AuthorizationRequestResolver(clientRegistrationRepository, addonsProperties.getClient()); + ServerOAuth2AuthorizationRequestResolver authorizationRequestResolver( + OAuth2ClientProperties bootClientProperties, ReactiveClientRegistrationRepository clientRegistrationRepository, SpringAddonsOidcProperties addonsProperties) { + return new SpringAddonsServerOAuth2AuthorizationRequestResolver(bootClientProperties, clientRegistrationRepository, addonsProperties.getClient()); } @ConditionalOnMissingBean diff --git a/spring-addons-starter-oidc/src/main/java/com/c4_soft/springaddons/security/oidc/starter/reactive/client/SpringAddonsServerOAuth2AuthorizationRequestResolver.java b/spring-addons-starter-oidc/src/main/java/com/c4_soft/springaddons/security/oidc/starter/reactive/client/SpringAddonsServerOAuth2AuthorizationRequestResolver.java index 649ddcc67..e813149bf 100644 --- a/spring-addons-starter-oidc/src/main/java/com/c4_soft/springaddons/security/oidc/starter/reactive/client/SpringAddonsServerOAuth2AuthorizationRequestResolver.java +++ b/spring-addons-starter-oidc/src/main/java/com/c4_soft/springaddons/security/oidc/starter/reactive/client/SpringAddonsServerOAuth2AuthorizationRequestResolver.java @@ -4,25 +4,29 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.function.Consumer; import java.util.regex.Pattern; import java.util.stream.Collectors; +import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties; import org.springframework.http.server.RequestPath; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestCustomizers; import org.springframework.security.oauth2.client.web.server.DefaultServerOAuth2AuthorizationRequestResolver; +import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizationRequestResolver; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; import org.springframework.security.web.server.authentication.ServerAuthenticationFailureHandler; import org.springframework.security.web.server.authentication.ServerAuthenticationSuccessHandler; +import org.springframework.security.web.server.util.matcher.PathPatternParserServerWebExchangeMatcher; +import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher; import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebSession; import org.springframework.web.util.UriComponentsBuilder; +import com.c4_soft.springaddons.security.oidc.starter.AdditionalParamsAuthorizationRequestCustomizer; +import com.c4_soft.springaddons.security.oidc.starter.CompositeOAuth2AuthorizationRequestCustomizer; import com.c4_soft.springaddons.security.oidc.starter.properties.SpringAddonsOidcClientProperties; -import com.c4_soft.springaddons.security.oidc.starter.properties.SpringAddonsOidcClientProperties.RequestParam; import lombok.extern.slf4j.Slf4j; import reactor.core.publisher.Mono; @@ -30,117 +34,135 @@ /** * Serves three purposes: *
      - *
    • Use the {@link SpringAddonsOidcClientProperties#clientUri SpringAddonsOidcClientProperties#client-uri} to set the base URI of - * authorization-code callback (of interest for instance when using an ingress or another gateway in front of the OAuth2 client with - * oauth2Login)
    • + *
    • Use the {@link SpringAddonsOidcClientProperties#clientUri SpringAddonsOidcClientProperties#client-uri} to set the base URI of authorization-code callback + * (of interest for instance when using an ingress or another gateway in front of the OAuth2 client with oauth2Login)
    • *
    • Add the query params taken from authorization-request-params in application properties
    • - *
    • Save in session post-login URIs provided as header ({@link SpringAddonsOidcClientProperties#POST_AUTHENTICATION_SUCCESS_URI_HEADER} - * and {@link SpringAddonsOidcClientProperties#POST_AUTHENTICATION_FAILURE_URI_HEADER}) or request param + *
    • Save in session post-login URIs provided as header ({@link SpringAddonsOidcClientProperties#POST_AUTHENTICATION_SUCCESS_URI_HEADER} and + * {@link SpringAddonsOidcClientProperties#POST_AUTHENTICATION_FAILURE_URI_HEADER}) or request param * ({@link SpringAddonsOidcClientProperties#POST_AUTHENTICATION_SUCCESS_URI_PARAM} and - * {@link SpringAddonsOidcClientProperties#POST_AUTHENTICATION_FAILURE_URI_PARAM}). If both are provided, header wins. The key used in - * session are {@link SpringAddonsOidcClientProperties#POST_AUTHENTICATION_SUCCESS_URI_SESSION_ATTRIBUTE} and + * {@link SpringAddonsOidcClientProperties#POST_AUTHENTICATION_FAILURE_URI_PARAM}). If both are provided, header wins. The key used in session are + * {@link SpringAddonsOidcClientProperties#POST_AUTHENTICATION_SUCCESS_URI_SESSION_ATTRIBUTE} and * {@link SpringAddonsOidcClientProperties#POST_AUTHENTICATION_FAILURE_URI_SESSION_ATTRIBUTE}.
    • *
    * The post-login URIs are used by the default {@link ServerAuthenticationSuccessHandler} and {@link ServerAuthenticationFailureHandler} * * @author Jerome Wacongne ch4mp@c4-soft.com - * @see SpringAddonsOidcClientProperties for header and request parameter constants definitions - * @see SpringAddonsOauth2ServerAuthenticationSuccessHandler - * @see SpringAddonsOauth2ServerAuthenticationFailureHandler + * @see SpringAddonsOidcClientProperties for header and request parameter constants definitions + * @see SpringAddonsOauth2ServerAuthenticationSuccessHandler + * @see SpringAddonsOauth2ServerAuthenticationFailureHandler */ @Slf4j -public class SpringAddonsServerOAuth2AuthorizationRequestResolver extends DefaultServerOAuth2AuthorizationRequestResolver { - - private static final Pattern authorizationRequestPattern = Pattern.compile("\\/oauth2\\/authorization\\/([^\\/]+)"); - private static final Consumer noOpCustomizer = builder -> { - }; - - private final URI clientUri; - private final Map> authRequestCustomizers; - - public SpringAddonsServerOAuth2AuthorizationRequestResolver( - ReactiveClientRegistrationRepository clientRegistrationRepository, - SpringAddonsOidcClientProperties addonsClientProperties) { - super(clientRegistrationRepository); - this.clientUri = addonsClientProperties.getClientUri(); - authRequestCustomizers = addonsClientProperties.getAuthorizationRequestParams().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> { - final var params = addonsClientProperties.getAuthorizationRequestParams().get(e.getKey()); - return e.getValue() == null ? null : requestParamAuthorizationRequestCustomizer(params); - })); - - if (addonsClientProperties.isPkceForced()) { - super.setAuthorizationRequestCustomizer(OAuth2AuthorizationRequestCustomizers.withPkce()); - } - } - - private Mono savePostLoginUrisInSession(ServerWebExchange exchange) { - final var request = exchange.getRequest(); - final var headers = request.getHeaders(); - final var params = request.getQueryParams(); - return exchange.getSession().map(session -> { - Optional.ofNullable( - Optional.ofNullable(headers.getFirst(SpringAddonsOidcClientProperties.POST_AUTHENTICATION_SUCCESS_URI_HEADER)) - .orElse(Optional.ofNullable(params.getFirst(SpringAddonsOidcClientProperties.POST_AUTHENTICATION_SUCCESS_URI_PARAM)).orElse(null))) - .filter(StringUtils::hasText).map(URI::create).ifPresent(postLoginSuccessUri -> { - session.getAttributes().put(SpringAddonsOidcClientProperties.POST_AUTHENTICATION_SUCCESS_URI_SESSION_ATTRIBUTE, postLoginSuccessUri); - }); - - Optional.ofNullable( - Optional.ofNullable(headers.getFirst(SpringAddonsOidcClientProperties.POST_AUTHENTICATION_FAILURE_URI_HEADER)) - .orElse(Optional.ofNullable(params.getFirst(SpringAddonsOidcClientProperties.POST_AUTHENTICATION_FAILURE_URI_PARAM)).orElse(null))) - .filter(StringUtils::hasText).map(URI::create).ifPresent(postLoginFailureUri -> { - session.getAttributes().put(SpringAddonsOidcClientProperties.POST_AUTHENTICATION_FAILURE_URI_SESSION_ATTRIBUTE, postLoginFailureUri); - }); - - return session; - }); - } - - private OAuth2AuthorizationRequest postProcess(OAuth2AuthorizationRequest request) { - final var modified = OAuth2AuthorizationRequest.from(request); - - final var original = URI.create(request.getRedirectUri()); - final var redirectUri = - UriComponentsBuilder.fromUri(clientUri).path(original.getPath()).query(original.getQuery()).fragment(original.getFragment()).build().toString(); - modified.redirectUri(redirectUri); - - log.debug("Changed OAuth2AuthorizationRequest redirectUri from {} to {}", original, redirectUri); - return modified.build(); - } - - @Override - public Mono resolve(ServerWebExchange exchange, String clientRegistrationId) { - setAuthorizationRequestCustomizer(authRequestCustomizer(clientRegistrationId)); - return savePostLoginUrisInSession(exchange).then(super.resolve(exchange, clientRegistrationId).map(this::postProcess)); - } - - Consumer authRequestCustomizer(ServerWebExchange exchange) { - return authRequestCustomizer(resolveRegistrationId(exchange)); - } - - Consumer authRequestCustomizer(String registrationId) { - if (registrationId == null) { - return noOpCustomizer; - } - return authRequestCustomizers.getOrDefault(registrationId, noOpCustomizer); - } - - static String resolveRegistrationId(ServerWebExchange exchange) { - final var requestPath = Optional.ofNullable(exchange.getRequest()).map(ServerHttpRequest::getPath).map(RequestPath::toString).orElse(""); - return resolveRegistrationId(requestPath); - } - - static String resolveRegistrationId(String requestPath) { - final var matcher = authorizationRequestPattern.matcher(requestPath); - return matcher.matches() ? matcher.group(1) : null; - } - - private static Consumer requestParamAuthorizationRequestCustomizer(List additionalParams) { - return customizer -> customizer.additionalParameters(params -> { - for (var reqParam : additionalParams) { - params.put(reqParam.getName(), reqParam.getValue()); - } - }); - } +public class SpringAddonsServerOAuth2AuthorizationRequestResolver implements ServerOAuth2AuthorizationRequestResolver { + + private static final Pattern authorizationRequestPattern = Pattern.compile("\\/oauth2\\/authorization\\/([^\\/]+)"); + + private final URI clientUri; + private final Map delegates; + private final ServerWebExchangeMatcher authorizationRequestMatcher; + + public SpringAddonsServerOAuth2AuthorizationRequestResolver( + OAuth2ClientProperties bootClientProperties, + ReactiveClientRegistrationRepository clientRegistrationRepository, + SpringAddonsOidcClientProperties addonsClientProperties) { + this.clientUri = addonsClientProperties.getClientUri(); + this.authorizationRequestMatcher = new PathPatternParserServerWebExchangeMatcher( + DefaultServerOAuth2AuthorizationRequestResolver.DEFAULT_AUTHORIZATION_REQUEST_PATTERN); + + this.delegates = bootClientProperties.getRegistration().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, registrationEntry -> { + final var requestCustomizer = new CompositeOAuth2AuthorizationRequestCustomizer(); + + final var additionalProperties = addonsClientProperties.getAuthorizationRequestParams().getOrDefault(registrationEntry.getKey(), List.of()); + if (additionalProperties.size() > 0) { + requestCustomizer.addCustomizer(new AdditionalParamsAuthorizationRequestCustomizer(additionalProperties)); + } + + if (addonsClientProperties.isPkceForced()) { + requestCustomizer.addCustomizer(OAuth2AuthorizationRequestCustomizers.withPkce()); + } + + final var delegate = new DefaultServerOAuth2AuthorizationRequestResolver(clientRegistrationRepository); + + delegate.setAuthorizationRequestCustomizer(requestCustomizer); + + return delegate; + })); + } + + private Mono savePostLoginUrisInSession(ServerWebExchange exchange) { + final var request = exchange.getRequest(); + final var headers = request.getHeaders(); + final var params = request.getQueryParams(); + return exchange.getSession().map(session -> { + Optional + .ofNullable( + Optional + .ofNullable(headers.getFirst(SpringAddonsOidcClientProperties.POST_AUTHENTICATION_SUCCESS_URI_HEADER)) + .orElse(Optional.ofNullable(params.getFirst(SpringAddonsOidcClientProperties.POST_AUTHENTICATION_SUCCESS_URI_PARAM)).orElse(null))) + .filter(StringUtils::hasText) + .map(URI::create) + .ifPresent(postLoginSuccessUri -> { + session.getAttributes().put(SpringAddonsOidcClientProperties.POST_AUTHENTICATION_SUCCESS_URI_SESSION_ATTRIBUTE, postLoginSuccessUri); + }); + + Optional + .ofNullable( + Optional + .ofNullable(headers.getFirst(SpringAddonsOidcClientProperties.POST_AUTHENTICATION_FAILURE_URI_HEADER)) + .orElse(Optional.ofNullable(params.getFirst(SpringAddonsOidcClientProperties.POST_AUTHENTICATION_FAILURE_URI_PARAM)).orElse(null))) + .filter(StringUtils::hasText) + .map(URI::create) + .ifPresent(postLoginFailureUri -> { + session.getAttributes().put(SpringAddonsOidcClientProperties.POST_AUTHENTICATION_FAILURE_URI_SESSION_ATTRIBUTE, postLoginFailureUri); + }); + + return session; + }); + } + + private OAuth2AuthorizationRequest postProcess(OAuth2AuthorizationRequest request) { + final var modified = OAuth2AuthorizationRequest.from(request); + + final var original = URI.create(request.getRedirectUri()); + final var redirectUri = UriComponentsBuilder + .fromUri(clientUri) + .path(original.getPath()) + .query(original.getQuery()) + .fragment(original.getFragment()) + .build() + .toString(); + modified.redirectUri(redirectUri); + + log.debug("Changed OAuth2AuthorizationRequest redirectUri from {} to {}", original, redirectUri); + return modified.build(); + } + + @Override + public Mono resolve(ServerWebExchange exchange) { + // @formatter:off + return this.authorizationRequestMatcher + .matches(exchange) + .filter((matchResult) -> matchResult.isMatch()) + .map(ServerWebExchangeMatcher.MatchResult::getVariables) + .map((variables) -> variables.get(DefaultServerOAuth2AuthorizationRequestResolver.DEFAULT_REGISTRATION_ID_URI_VARIABLE_NAME)) + .cast(String.class) + .flatMap((clientRegistrationId) -> resolve(exchange, clientRegistrationId)); + // @formatter:on + } + + @Override + public Mono resolve(ServerWebExchange exchange, String clientRegistrationId) { + final var delegate = delegates.get(clientRegistrationId); + return savePostLoginUrisInSession(exchange).then(delegate.resolve(exchange, clientRegistrationId).map(this::postProcess)); + } + + static String resolveRegistrationId(ServerWebExchange exchange) { + final var requestPath = Optional.ofNullable(exchange.getRequest()).map(ServerHttpRequest::getPath).map(RequestPath::toString).orElse(""); + return resolveRegistrationId(requestPath); + } + + static String resolveRegistrationId(String requestPath) { + final var matcher = authorizationRequestPattern.matcher(requestPath); + return matcher.matches() ? matcher.group(1) : null; + } } diff --git a/spring-addons-starter-oidc/src/main/java/com/c4_soft/springaddons/security/oidc/starter/synchronised/client/SpringAddonsOAuth2AuthorizationRequestResolver.java b/spring-addons-starter-oidc/src/main/java/com/c4_soft/springaddons/security/oidc/starter/synchronised/client/SpringAddonsOAuth2AuthorizationRequestResolver.java index edad64b48..c0bdb2b7c 100644 --- a/spring-addons-starter-oidc/src/main/java/com/c4_soft/springaddons/security/oidc/starter/synchronised/client/SpringAddonsOAuth2AuthorizationRequestResolver.java +++ b/spring-addons-starter-oidc/src/main/java/com/c4_soft/springaddons/security/oidc/starter/synchronised/client/SpringAddonsOAuth2AuthorizationRequestResolver.java @@ -4,9 +4,9 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.function.Consumer; import java.util.stream.Collectors; +import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizationRequestResolver; import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestCustomizers; @@ -19,131 +19,151 @@ import org.springframework.util.StringUtils; import org.springframework.web.util.UriComponentsBuilder; +import com.c4_soft.springaddons.security.oidc.starter.AdditionalParamsAuthorizationRequestCustomizer; +import com.c4_soft.springaddons.security.oidc.starter.CompositeOAuth2AuthorizationRequestCustomizer; import com.c4_soft.springaddons.security.oidc.starter.properties.SpringAddonsOidcClientProperties; -import com.c4_soft.springaddons.security.oidc.starter.properties.SpringAddonsOidcClientProperties.RequestParam; import jakarta.servlet.http.HttpServletRequest; /** * Support three features: *
      - *
    • Use the {@link SpringAddonsOidcClientProperties#clientUri SpringAddonsOidcClientProperties#client-uri} to set the base URI of - * authorization-code callback (of interest for instance when using an ingress or another gateway in front of the OAuth2 client with - * oauth2Login)
    • + *
    • Use the {@link SpringAddonsOidcClientProperties#clientUri SpringAddonsOidcClientProperties#client-uri} to set the base URI of authorization-code callback + * (of interest for instance when using an ingress or another gateway in front of the OAuth2 client with oauth2Login)
    • *
    • Defining authorization request additional parameters from properties (like audience for Auth0)
    • - *
    • Save in session post-login URIs provided as header ({@link SpringAddonsOidcClientProperties#POST_AUTHENTICATION_SUCCESS_URI_HEADER} - * and {@link SpringAddonsOidcClientProperties#POST_AUTHENTICATION_FAILURE_URI_HEADER}) or request param + *
    • Save in session post-login URIs provided as header ({@link SpringAddonsOidcClientProperties#POST_AUTHENTICATION_SUCCESS_URI_HEADER} and + * {@link SpringAddonsOidcClientProperties#POST_AUTHENTICATION_FAILURE_URI_HEADER}) or request param * ({@link SpringAddonsOidcClientProperties#POST_AUTHENTICATION_SUCCESS_URI_PARAM} and - * {@link SpringAddonsOidcClientProperties#POST_AUTHENTICATION_FAILURE_URI_PARAM}). If both are provided, header wins. The key used in - * session are {@link SpringAddonsOidcClientProperties#POST_AUTHENTICATION_SUCCESS_URI_SESSION_ATTRIBUTE} and + * {@link SpringAddonsOidcClientProperties#POST_AUTHENTICATION_FAILURE_URI_PARAM}). If both are provided, header wins. The key used in session are + * {@link SpringAddonsOidcClientProperties#POST_AUTHENTICATION_SUCCESS_URI_SESSION_ATTRIBUTE} and * {@link SpringAddonsOidcClientProperties#POST_AUTHENTICATION_FAILURE_URI_SESSION_ATTRIBUTE}
    • *
    * The post-login URIs are used by the default {@link AuthenticationSuccessHandler} and {@link AuthenticationFailureHandler} * * @author Jerome Wacongne ch4mp@c4-soft.com - * @see SpringAddonsOidcClientProperties for header and request parameter constants definitions - * @see SpringAddonsOauth2AuthenticationSuccessHandler - * @see SpringAddonsOauth2AuthenticationFailureHandler + * @see SpringAddonsOidcClientProperties for header and request parameter constants definitions + * @see SpringAddonsOauth2AuthenticationSuccessHandler + * @see SpringAddonsOauth2AuthenticationFailureHandler */ public class SpringAddonsOAuth2AuthorizationRequestResolver implements OAuth2AuthorizationRequestResolver { - private static final String REGISTRATION_ID_URI_VARIABLE_NAME = "registrationId"; - - private final URI clientUri; - private final DefaultOAuth2AuthorizationRequestResolver delegate; - private final Map> authRequestCustomizers; - private final AntPathRequestMatcher authorizationRequestMatcher = new AntPathRequestMatcher( - OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI + "/{" + REGISTRATION_ID_URI_VARIABLE_NAME + "}"); - - public SpringAddonsOAuth2AuthorizationRequestResolver( - ClientRegistrationRepository clientRegistrationRepository, - SpringAddonsOidcClientProperties addonsClientProperties) { - - this.clientUri = addonsClientProperties.getClientUri(); - - authRequestCustomizers = addonsClientProperties.getAuthorizationRequestParams().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> { - final var params = addonsClientProperties.getAuthorizationRequestParams().get(e.getKey()); - return e.getValue() == null ? null : requestParamAuthorizationRequestCustomizer(params); - })); - - delegate = new DefaultOAuth2AuthorizationRequestResolver( - clientRegistrationRepository, - OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI); - - if (addonsClientProperties.isPkceForced()) { - delegate.setAuthorizationRequestCustomizer(OAuth2AuthorizationRequestCustomizers.withPkce()); - } - } - - private Optional getFirstParam(HttpServletRequest request, String paramName) { - final var values = request.getParameterValues(paramName); - if (values == null || values.length < 1) { - return Optional.empty(); - } - return Optional.of(values[0]); - } - - private void savePostLoginUrisInSession(HttpServletRequest request) { - final var session = request.getSession(); - Optional.ofNullable( - Optional.ofNullable(request.getHeader(SpringAddonsOidcClientProperties.POST_AUTHENTICATION_SUCCESS_URI_HEADER)) - .orElse(getFirstParam(request, SpringAddonsOidcClientProperties.POST_AUTHENTICATION_SUCCESS_URI_PARAM).orElse(null))) - .filter(StringUtils::hasText).map(URI::create).ifPresent(postLoginSuccessUri -> { - session.setAttribute(SpringAddonsOidcClientProperties.POST_AUTHENTICATION_SUCCESS_URI_SESSION_ATTRIBUTE, postLoginSuccessUri); - }); - - Optional.ofNullable( - Optional.ofNullable(request.getHeader(SpringAddonsOidcClientProperties.POST_AUTHENTICATION_FAILURE_URI_HEADER)) - .orElse(getFirstParam(request, SpringAddonsOidcClientProperties.POST_AUTHENTICATION_FAILURE_URI_PARAM).orElse(null))) - .filter(StringUtils::hasText).map(URI::create).ifPresent(postLoginFailureUri -> { - session.setAttribute(SpringAddonsOidcClientProperties.POST_AUTHENTICATION_FAILURE_URI_SESSION_ATTRIBUTE, postLoginFailureUri); - }); - } - - @Override - public OAuth2AuthorizationRequest resolve(HttpServletRequest request) { - savePostLoginUrisInSession(request); - final var registrationId = resolveRegistrationId(request); - delegate.setAuthorizationRequestCustomizer(authRequestCustomizers.getOrDefault(registrationId, b -> { - })); - final var resolved = delegate.resolve(request); - final var absolute = toAbsolute(resolved, request); - return absolute; - } - - @Override - public OAuth2AuthorizationRequest resolve(HttpServletRequest request, String clientRegistrationId) { - savePostLoginUrisInSession(request); - delegate.setAuthorizationRequestCustomizer(authRequestCustomizers.getOrDefault(clientRegistrationId, b -> { - })); - final var resolved = delegate.resolve(request, clientRegistrationId); - final var absolute = toAbsolute(resolved, request); - return absolute; - } - - private OAuth2AuthorizationRequest toAbsolute(OAuth2AuthorizationRequest defaultAuthorizationRequest, HttpServletRequest request) { - if (defaultAuthorizationRequest == null || clientUri == null) { - return defaultAuthorizationRequest; - } - - final var original = URI.create(defaultAuthorizationRequest.getRedirectUri()); - final var redirectUri = - UriComponentsBuilder.fromUri(clientUri).path(original.getPath()).query(original.getQuery()).fragment(original.getFragment()).build().toString(); - return OAuth2AuthorizationRequest.from(defaultAuthorizationRequest).redirectUri(redirectUri) - .authorizationRequestUri(defaultAuthorizationRequest.getAuthorizationRequestUri()).build(); - } - - private String resolveRegistrationId(HttpServletRequest request) { - if (this.authorizationRequestMatcher.matches(request)) { - return this.authorizationRequestMatcher.matcher(request).getVariables().get(REGISTRATION_ID_URI_VARIABLE_NAME); - } - return null; - } - - private static Consumer requestParamAuthorizationRequestCustomizer(List additionalParams) { - return customizer -> customizer.additionalParameters(params -> { - for (var reqParam : additionalParams) { - params.put(reqParam.getName(), reqParam.getValue()); - } - }); - } + private static final String REGISTRATION_ID_URI_VARIABLE_NAME = "registrationId"; + + private final URI clientUri; + private final Map delegates; + private final AntPathRequestMatcher authorizationRequestMatcher = new AntPathRequestMatcher( + OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI + "/{" + REGISTRATION_ID_URI_VARIABLE_NAME + "}"); + + public SpringAddonsOAuth2AuthorizationRequestResolver( + OAuth2ClientProperties bootClientProperties, + ClientRegistrationRepository clientRegistrationRepository, + SpringAddonsOidcClientProperties addonsClientProperties) { + + this.clientUri = addonsClientProperties.getClientUri(); + + this.delegates = bootClientProperties.getRegistration().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, registrationEntry -> { + final var requestCustomizer = new CompositeOAuth2AuthorizationRequestCustomizer(); + + final var additionalProperties = addonsClientProperties.getAuthorizationRequestParams().getOrDefault(registrationEntry.getKey(), List.of()); + if (additionalProperties.size() > 0) { + requestCustomizer.addCustomizer(new AdditionalParamsAuthorizationRequestCustomizer(additionalProperties)); + } + + if (addonsClientProperties.isPkceForced()) { + requestCustomizer.addCustomizer(OAuth2AuthorizationRequestCustomizers.withPkce()); + } + + final var delegate = new DefaultOAuth2AuthorizationRequestResolver( + clientRegistrationRepository, + OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI); + + delegate.setAuthorizationRequestCustomizer(requestCustomizer); + + return delegate; + })); + } + + private Optional getFirstParam(HttpServletRequest request, String paramName) { + final var values = request.getParameterValues(paramName); + if (values == null || values.length < 1) { + return Optional.empty(); + } + return Optional.of(values[0]); + } + + private void savePostLoginUrisInSession(HttpServletRequest request) { + final var session = request.getSession(); + Optional + .ofNullable( + Optional + .ofNullable(request.getHeader(SpringAddonsOidcClientProperties.POST_AUTHENTICATION_SUCCESS_URI_HEADER)) + .orElse(getFirstParam(request, SpringAddonsOidcClientProperties.POST_AUTHENTICATION_SUCCESS_URI_PARAM).orElse(null))) + .filter(StringUtils::hasText) + .map(URI::create) + .ifPresent(postLoginSuccessUri -> { + session.setAttribute(SpringAddonsOidcClientProperties.POST_AUTHENTICATION_SUCCESS_URI_SESSION_ATTRIBUTE, postLoginSuccessUri); + }); + + Optional + .ofNullable( + Optional + .ofNullable(request.getHeader(SpringAddonsOidcClientProperties.POST_AUTHENTICATION_FAILURE_URI_HEADER)) + .orElse(getFirstParam(request, SpringAddonsOidcClientProperties.POST_AUTHENTICATION_FAILURE_URI_PARAM).orElse(null))) + .filter(StringUtils::hasText) + .map(URI::create) + .ifPresent(postLoginFailureUri -> { + session.setAttribute(SpringAddonsOidcClientProperties.POST_AUTHENTICATION_FAILURE_URI_SESSION_ATTRIBUTE, postLoginFailureUri); + }); + } + + @Override + public OAuth2AuthorizationRequest resolve(HttpServletRequest request) { + savePostLoginUrisInSession(request); + final var clientRegistrationId = resolveRegistrationId(request); + final var delegate = delegates.get(clientRegistrationId); + if (delegate == null) { + return null; + } + final var resolved = delegate.resolve(request); + final var absolute = toAbsolute(resolved, request); + return absolute; + } + + @Override + public OAuth2AuthorizationRequest resolve(HttpServletRequest request, String clientRegistrationId) { + savePostLoginUrisInSession(request); + final var delegate = delegates.get(clientRegistrationId); + if (delegate == null) { + return null; + } + final var resolved = delegate.resolve(request, clientRegistrationId); + final var absolute = toAbsolute(resolved, request); + return absolute; + } + + private OAuth2AuthorizationRequest toAbsolute(OAuth2AuthorizationRequest defaultAuthorizationRequest, HttpServletRequest request) { + if (defaultAuthorizationRequest == null || clientUri == null) { + return defaultAuthorizationRequest; + } + + final var original = URI.create(defaultAuthorizationRequest.getRedirectUri()); + final var redirectUri = UriComponentsBuilder + .fromUri(clientUri) + .path(original.getPath()) + .query(original.getQuery()) + .fragment(original.getFragment()) + .build() + .toString(); + return OAuth2AuthorizationRequest + .from(defaultAuthorizationRequest) + .redirectUri(redirectUri) + .authorizationRequestUri(defaultAuthorizationRequest.getAuthorizationRequestUri()) + .build(); + } + + private String resolveRegistrationId(HttpServletRequest request) { + if (this.authorizationRequestMatcher.matches(request)) { + return this.authorizationRequestMatcher.matcher(request).getVariables().get(REGISTRATION_ID_URI_VARIABLE_NAME); + } + return null; + } } diff --git a/spring-addons-starter-oidc/src/main/java/com/c4_soft/springaddons/security/oidc/starter/synchronised/client/SpringAddonsOidcClientWithLoginBeans.java b/spring-addons-starter-oidc/src/main/java/com/c4_soft/springaddons/security/oidc/starter/synchronised/client/SpringAddonsOidcClientWithLoginBeans.java index 38e8146d3..aa08bb5ac 100644 --- a/spring-addons-starter-oidc/src/main/java/com/c4_soft/springaddons/security/oidc/starter/synchronised/client/SpringAddonsOidcClientWithLoginBeans.java +++ b/spring-addons-starter-oidc/src/main/java/com/c4_soft/springaddons/security/oidc/starter/synchronised/client/SpringAddonsOidcClientWithLoginBeans.java @@ -7,6 +7,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; +import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties; import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; @@ -57,8 +58,8 @@ *
  • clientAuthorizePostProcessor: a {@link ClientExpressionInterceptUrlRegistryPostProcessor} post processor to fine tune access control * from java configuration. It applies to all routes not listed in "permit-all" property configuration. Default requires users to be * authenticated.
  • - *
  • clientHttpPostProcessor: a {@link ClientSynchronizedHttpSecurityPostProcessor} to override anything from above auto-configuration. It is called - * just before the security filter-chain is returned. Default is a no-op.
  • + *
  • clientHttpPostProcessor: a {@link ClientSynchronizedHttpSecurityPostProcessor} to override anything from above auto-configuration. It + * is called just before the security filter-chain is returned. Default is a no-op.
  • * * * @author Jerome Wacongne ch4mp@c4-soft.com @@ -161,15 +162,18 @@ SecurityFilterChain springAddonsClientFilterChain( *
  • spport defining additionl authorization request parameters from properties
  • * * + * @param bootClientProperties "standard" Spring Boot OAuth2 client properties * @param clientRegistrationRepository - * @param addonsProperties + * @param addonsProperties "spring-addons" OAuth2 client properties * @return {@link SpringAddonsOAuth2AuthorizationRequestResolver} */ @ConditionalOnMissingBean @Bean - OAuth2AuthorizationRequestResolver - oAuth2AuthorizationRequestResolver(ClientRegistrationRepository clientRegistrationRepository, SpringAddonsOidcProperties addonsProperties) { - return new SpringAddonsOAuth2AuthorizationRequestResolver(clientRegistrationRepository, addonsProperties.getClient()); + OAuth2AuthorizationRequestResolver oAuth2AuthorizationRequestResolver( + OAuth2ClientProperties bootClientProperties, + ClientRegistrationRepository clientRegistrationRepository, + SpringAddonsOidcProperties addonsProperties) { + return new SpringAddonsOAuth2AuthorizationRequestResolver(bootClientProperties, clientRegistrationRepository, addonsProperties.getClient()); } /** diff --git a/spring-addons-starter-rest/pom.xml b/spring-addons-starter-rest/pom.xml index cba1d8c8a..0721f0ec2 100644 --- a/spring-addons-starter-rest/pom.xml +++ b/spring-addons-starter-rest/pom.xml @@ -5,7 +5,7 @@ com.c4-soft.springaddons spring-addons - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. spring-addons-starter-rest diff --git a/starters/pom.xml b/starters/pom.xml index b526a0201..2dae9c91a 100644 --- a/starters/pom.xml +++ b/starters/pom.xml @@ -4,7 +4,7 @@ com.c4-soft.springaddons spring-addons - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. starters diff --git a/starters/spring-addons-starters-recaptcha/pom.xml b/starters/spring-addons-starters-recaptcha/pom.xml index 4ac590ec9..435a0dac6 100644 --- a/starters/spring-addons-starters-recaptcha/pom.xml +++ b/starters/spring-addons-starters-recaptcha/pom.xml @@ -5,7 +5,7 @@ com.c4-soft.springaddons starters - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. com.c4-soft.springaddons.starter diff --git a/starters/spring-addons-starters-webclient/pom.xml b/starters/spring-addons-starters-webclient/pom.xml index 992f4310e..2fe78e211 100644 --- a/starters/spring-addons-starters-webclient/pom.xml +++ b/starters/spring-addons-starters-webclient/pom.xml @@ -5,7 +5,7 @@ com.c4-soft.springaddons starters - 7.6.2-SNAPSHOT + 7.6.3-SNAPSHOT .. com.c4-soft.springaddons.starter