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