All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.c4_soft.springaddons.security.oidc.starter.properties.SpringAddonsOidcClientProperties Maven / Gradle / Ivy

There is a newer version: 8.0-RC1
Show newest version
package com.c4_soft.springaddons.security.oidc.starter.properties;

import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.http.HttpStatus;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriComponentsBuilder;

import lombok.Data;

/**
 * Auto-configuration for an OAuth2 client (secured with session, not access token) Security(Web)FilterChain with @Order(Ordered.LOWEST_PRECEDENCE - 1).
 * Typical use-cases are spring-cloud-gateway used as BFF and applications with Thymeleaf or another server-side rendering framework. Default configuration
 * includes: enabled sessions, CSRF protection, "oauth2Login", "logout". securityMatchers must be set for this filter-chain @Bean and its dependencies to be
 * defined. Properties defined here are a complement for spring.security.oauth2.client.* (which are required when enabling spring-addons client
 * filter-chain).
 *
 * @author Jerome Wacongne ch4mp@c4-soft.com
 */
@Data
@ConfigurationProperties
public class SpringAddonsOidcClientProperties {
    public static final String RESPONSE_STATUS_HEADER = "X-RESPONSE-STATUS";

    public static final String POST_AUTHENTICATION_SUCCESS_URI_HEADER = "X-POST-LOGIN-SUCCESS-URI";
    public static final String POST_AUTHENTICATION_SUCCESS_URI_PARAM = "post_login_success_uri";
    public static final String POST_AUTHENTICATION_SUCCESS_URI_SESSION_ATTRIBUTE = POST_AUTHENTICATION_SUCCESS_URI_PARAM;

    public static final String POST_AUTHENTICATION_FAILURE_URI_HEADER = "X-POST-LOGIN-FAILURE-URI";
    public static final String POST_AUTHENTICATION_FAILURE_URI_PARAM = "post_login_failure_uri";
    public static final String POST_AUTHENTICATION_FAILURE_URI_SESSION_ATTRIBUTE = POST_AUTHENTICATION_FAILURE_URI_PARAM;
    public static final String POST_AUTHENTICATION_FAILURE_CAUSE_ATTRIBUTE = "error";

    public static final String POST_LOGOUT_SUCCESS_URI_HEADER = "X-POST-LOGOUT-SUCCESS-URI";
    public static final String POST_LOGOUT_SUCCESS_URI_PARAM = "post_logout_success_uri";

    /**
     * Path matchers for the routes secured with the auto-configured client filter-chain. If left empty, OAuth2 client auto-configuration is disabled. It should
     * include "/login/**" and "/oauth2/**" for login process. Can be set to "/**" to intercept all requests (OAuth2 client only application, no REST API
     * secured with access tokens).
     */
    private List securityMatchers = List.of();

    /**
     * Fully qualified URI of the configured OAuth2 client.
     */
    private URI clientUri = URI.create("/");

    /**
     * URI at which a login can be performed. If left empty, ${client-uri}/login is used. Can be changed to the URI on a SPA or a mobile application deep-link
     */
    private Optional loginUri = Optional.empty();

    /**
     * URI containing scheme, host and port where the user should be redirected after a successful login (defaults to the client URI)
     */
    private Optional postLoginRedirectHost = Optional.empty();

    /**
     * Where to redirect the user after successful login
     */
    private Optional postLoginRedirectPath = Optional.empty();

    /**
     * Where to redirect the user after login failure
     */
    private Optional loginErrorRedirectPath = Optional.empty();

    /**
     * HTTP status for redirections in OAuth2 login and logout. You might set this to something in 2xx range (like OK, ACCEPTED, NO_CONTENT, ...) for single
     * page and mobile applications to handle this redirection as it wishes (change the user-agent, clear some headers, ...).
     */
    private OAuth2RedirectionProperties oauth2Redirections = new OAuth2RedirectionProperties();

    public URI getPostLoginRedirectHost() {
        return postLoginRedirectHost.orElse(clientUri);
    }

    public Optional getPostLoginRedirectUri() {
        if (postLoginRedirectHost.isEmpty() && postLoginRedirectPath.isEmpty()) {
            return Optional.empty();
        }
        final var uri = UriComponentsBuilder.fromUri(getPostLoginRedirectHost());
        postLoginRedirectPath.ifPresent(uri::path);

        return Optional.of(uri.build(Map.of()));
    }

    /**
     * URI containing scheme, host and port where the user should be redirected after a successful logout (defaults to the client URI)
     */
    private Optional postLogoutRedirectHost = Optional.empty();

    /**
     * Path (relative to clientUri) where the user should be redirected after being logged out from authorization server(s)
     */
    private Optional postLogoutRedirectPath = Optional.empty();

    public URI getPostLogoutRedirectHost() {
        return postLogoutRedirectHost.orElse(clientUri);
    }

    public URI getPostLogoutRedirectUri() {
        var uri = UriComponentsBuilder.fromUri(getPostLogoutRedirectHost());
        postLogoutRedirectPath.ifPresent(uri::path);

        return uri.build(Map.of());
    }

    /**
     * Map of logout properties indexed by client registration ID (must match a registration in Spring Boot OAuth2 client configuration).
     * {@link OAuth2LogoutProperties} are configuration for authorization server not strictly following the
     * RP-Initiated Logout standard, but exposing a logout end-point expecting an
     * authorized GET request with following request params:
     * 
    *
  • "client-id" (required)
  • *
  • post-logout redirect URI (optional)
  • *
*/ private Map 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; /** * Path matchers for the routes accessible to anonymous requests */ private List permitAll = List.of("/login/**", "/oauth2/**"); /** * CSRF protection configuration for the auto-configured client filter-chain */ private Csrf csrf = Csrf.DEFAULT; /** * When true, PKCE is enabled (by default, Spring enables it only for "public" clients) */ private boolean pkceForced = false; /** * Fine grained CORS configuration * * @deprecated use com.c4-soft.springaddons.oidc.cors instead */ @Deprecated(forRemoval = true) private List cors = List.of(); /** * Additional parameters to send with authorization request, mapped by client registration IDs * * @deprecated use the more concise authorization-params syntax */ @Deprecated private Map> authorizationRequestParams = new HashMap<>(); /** *

* Additional parameters to send with authorization request, mapped by client registration IDs. *

*

* {@link OAuth2AuthorizationRequest#getAdditionalParameters()} return a Map<String, Object>, when it should probably be Map<String, * List<String>>. Also the serializer does not handle collections correctly (serializes using {@link Object#toString()} instead of repeating the * parameter with each value toString()). What spring-addons does is joining the String values with a comma. *

*/ private Map>> authorizationParams = new HashMap<>(); public MultiValueMap getExtraAuthorizationParameters(String registrationId) { return getExtraParameters(registrationId, authorizationRequestParams, authorizationParams); } /** * Additional parameters to send with token request, mapped by client registration IDs * * @deprecated use the more concise token-params syntax */ @Deprecated private Map> tokenRequestParams = new HashMap<>(); /** * Additional parameters to send with authorization request, mapped by client registration IDs */ private Map>> tokenParams = new HashMap<>(); public MultiValueMap getExtraTokenParameters(String registrationId) { return getExtraParameters(registrationId, tokenRequestParams, tokenParams); } private static MultiValueMap getExtraParameters( String registrationId, Map> requestParams, Map>> requestParamsMap) { final var extraParameters = Optional.ofNullable(requestParamsMap.get(registrationId)).map(LinkedMultiValueMap::new).orElse(new LinkedMultiValueMap<>()); for (final var param : requestParams.getOrDefault(registrationId, List.of())) { if (StringUtils.hasText(param.getName())) { extraParameters.add(param.getName(), param.getValue()); } } return extraParameters; } /** * Logout properties for OpenID Providers which do not implement the RP-Initiated Logout spec * * @author Jerome Wacongne ch4mp@c4-soft.com */ @Data @ConfigurationProperties 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(); /** * RP-Initiated Logout is enabled by default. Setting this to false disables it. */ private boolean enabled = true; } private BackChannelLogoutProperties backChannelLogout = new BackChannelLogoutProperties(); @Data @ConfigurationProperties public static class BackChannelLogoutProperties { private boolean enabled = false; /** * The URI for a loop of the Spring client to itself in which it actually ends the user session. Overriding this can be useful to force the scheme and * port in the case where the client is behind a reverse proxy with different scheme and port (default URI uses the original Back-Channel Logout request * scheme and ports). */ private Optional internalLogoutUri = Optional.empty(); private Optional cookieName = Optional.empty(); } /** * Request parameter * * @author Jerome Wacongne ch4mp@c4-soft.com */ @Data @ConfigurationProperties public static class RequestParam { /** * request parameter name */ private String name; /** * request parameter value */ private String value; } @Data @ConfigurationProperties public static class OAuth2RedirectionProperties { /** * Defines {@link AuthenticationEntryPoint} or {@link ServerAuthenticationEntryPoint} behavior */ private HttpStatus authenticationEntryPoint = HttpStatus.FOUND; /** * 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 an authorization failure */ private HttpStatus postAuthorizationFailure = HttpStatus.FOUND; /** * Status for the response after BFF logout, with location to authorization server logout endpoint */ private HttpStatus rpInitiatedLogout = HttpStatus.FOUND; /** * Used only in servlet applications */ private HttpStatus invalidSessionStrategy = HttpStatus.FOUND; } public Optional getLogoutProperties(String clientRegistrationId) { return Optional.ofNullable(oauth2Logout.get(clientRegistrationId)); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy