oauth2Logout = new HashMap<>();
+
+ /**
+ *
+ * If true, AOP is used to instrument authorized client repository and keep the principalName current user has for each issuer he
+ * authenticates on.
+ *
+ *
+ * This is useful only if you allow a user to authenticate on more than one OpenID Provider at a time. For instance, user logs in on Google
+ * and on an authorization server of your own and your client sends direct queries to Google APIs (with an access token issued by Google)
+ * and resource servers of your own (with an access token from your authorization server).
+ *
+ */
+ private boolean multiTenancyEnabled = false;
+
+ /**
+ * Whether to enable a security filter-chain and a controller (intercepting POST requests to "/backchannel_logout") to implement the client
+ * side of a Back-Channel Logout
+ */
+ // private boolean backChannelLogoutEnabled = false;
+
+ /**
+ * Path matchers for the routes accessible to anonymous requests
+ */
+ private String[] permitAll = { "/login/**", "/oauth2/**" };
+
+ /**
+ * CSRF protection configuration for the auto-configured client filter-chain
+ */
+ private Csrf csrf = Csrf.DEFAULT;
+
+ /**
+ * Fine grained CORS configuration
+ */
+ private CorsProperties[] cors = {};
+
+ /**
+ * Additional parameters to send with authorization request, mapped by client registration IDs
+ */
+ private Map authorizationRequestParams = new HashMap<>();
+
+ /**
+ * Logout properties for OpenID Providers which do not implement the RP-Initiated Logout spec
+ *
+ * @author Jerome Wacongne ch4mp@c4-soft.com
+ */
+ @Data
+ public static class OAuth2LogoutProperties {
+
+ /**
+ * URI on the authorization server where to redirect the user for logout
+ */
+ private URI uri;
+
+ /**
+ * request param name for client-id
+ */
+ private Optional clientIdRequestParam = Optional.empty();
+
+ /**
+ * request param name for post-logout redirect URI (where the user should be redirected after his session is closed on the authorization
+ * server)
+ */
+ private Optional postLogoutUriRequestParam = Optional.empty();
+
+ /**
+ * request param name for setting an ID-Token hint
+ */
+ private Optional idTokenHintRequestParam = Optional.empty();
+ }
+
+ /**
+ * Request parameter
+ *
+ * @author Jerome Wacongne ch4mp@c4-soft.com
+ */
+ @Data
+ public static class RequestParam {
+ /**
+ * request parameter name
+ */
+ private String name;
+
+ /**
+ * request parameter value
+ */
+ private String value;
+ }
+
+ @Data
+ @ConfigurationProperties("com.c4-soft.springaddons.oidc.client.oauth2-redirections")
+ public static class OAuth2RedirectionProperties {
+
+ /**
+ * Status for the 1st response in authorization code flow, with location to get authorization code from authorization server
+ */
+ private HttpStatus preAuthorizationCode = HttpStatus.FOUND;
+
+ /**
+ * Status for the response after authorization code, with location to the UI
+ */
+ private HttpStatus postAuthorizationCode = HttpStatus.FOUND;
+
+ /**
+ * Status for the response after BFF logout, with location to authorization server logout endpoint
+ */
+ private HttpStatus rpInitiatedLogout = HttpStatus.FOUND;
+ }
+
+ public Optional getLogoutProperties(String clientRegistrationId) {
+ return Optional.ofNullable(oauth2Logout.get(clientRegistrationId));
+ }
}
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 644f5b6f0..95342019a 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
@@ -133,11 +133,10 @@ static String resolveRegistrationId(String requestPath) {
}
private static Consumer requestParamAuthorizationRequestCustomizer(RequestParam[] additionalParams) {
- return customizer -> customizer.authorizationRequestUri(authorizationRequestUri -> {
+ return customizer -> customizer.additionalParameters(params -> {
for (var reqParam : additionalParams) {
- authorizationRequestUri.queryParam(reqParam.getName(), reqParam.getValue());
+ params.put(reqParam.getName(), reqParam.getValue());
}
- return authorizationRequestUri.build();
});
}
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 dd4451df2..bbecf4771 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
@@ -25,133 +25,119 @@
/**
* 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);
- }
-
- 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(RequestParam[] additionalParams) {
- return customizer -> customizer.authorizationRequestUri(authorizationRequestUri -> {
- for (var reqParam : additionalParams) {
- authorizationRequestUri.queryParam(reqParam.getName(), reqParam.getValue());
- }
- return authorizationRequestUri.build();
- });
- }
+ 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);
+ }
+
+ 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(RequestParam[] additionalParams) {
+ return customizer -> customizer.additionalParameters(params -> {
+ for (var reqParam : additionalParams) {
+ params.put(reqParam.getName(), reqParam.getValue());
+ }
+ });
+ }
}