For Spring Boot 4
- Transient dependencies defined by Boot
4.0.6
- gh-294 Customize CSRF header name
- Transient dependencies defined by Boot
4.0.5
- [gh-291] Ease the configuration of the RestTemplate instance used during OpenID configuration & JWK-set retrieval:
@Bean
DefaultSpringAddonsJwtDecoderFactory springAddonsJwtDecoderFactory() {
var restOperations = new RestTemplate();
// further configuration of the RestTemplate to use during OpenID connect configuration
// retrieval: timeouts, SSL bundles, HTTP proxy, ...
return new DefaultSpringAddonsJwtDecoderFactory(restOperations);
}- Transient dependencies defined by Boot
4.0.3
- gh-284 Configurable Back-Channel
LogoutHandlerbean
- enable overriding the default HTTP status of OAuth2 client responses with
response_http_statusrequest parameter (in addition toX-RESPONSE-STATUSheader). This enables to ask a specific status for instance when setting thelocationof a browser tab, or the action of a<form>tag.
- Apply
isSecure(https instead of http) andcsrfto MockMvcSupport when using.get(...),.post(...), etc.
- Add SSL bundle auto-configuration for
RestClientandWebClient. See the manual for details.
- gh-281 Compatibility with Spring Boot 4
For Spring Boot 3
- Transient dependencies defined by Boot
3.5.11 - [gh-291] Ease the configuration of the RestTemplate instance used during OpenID configuration & JWK-set retrieval:
@Bean
DefaultSpringAddonsJwtDecoderFactory springAddonsJwtDecoderFactory() {
var restOperations = new RestTemplate();
// further configuration of the RestTemplate to use during OpenID connect configuration
// retrieval: timeouts, SSL bundles, HTTP proxy, ...
return new DefaultSpringAddonsJwtDecoderFactory(restOperations);
}- gh-286 Extended CSRF cookie customization via a new
Cookie[Server]CsrfTokenRepositoryPostProcessorinterface for an optional bean. Sample usage:
@Bean
CookieCsrfTokenRepositoryPostProcessor csrfCookiePostProcessor() {
return csrfCookieRepo -> {
csrfCookieRepo.setCookieCustomizer(csrfCookie -> csrfCookie.sameSite("Strict"));
return csrfCookieRepo;
};
}- gh-284 Configurable Back-Channel
LogoutHandlerbean - Boot
3.5.5as transient dependency
- enable overriding the default HTTP status of OAuth2 client responses with
response_http_statusrequest parameter (in addition toX-RESPONSE-STATUSheader). This enables to ask a specific status for instance when setting thelocationof a browser tab, or the action of a<form>tag.
- Apply
isSecure(https instead of http) andcsrfto MockMvcSupport when using.get(...),.post(...), etc.
- Add SSL bundle auto-configuration for
RestClientandWebClient. See the manual for details. - Transitive dependencies manage by Spring Boot
3.5.4
- Transitive dependencies manage by Spring Boot
3.5.3(after the regression on application properties in3.5.1&3.5.2)
- gh-276 Some authorization servers allow the definition of roles containing spaces or even commas.
ConfigurableJwtGrantedAuthoritiesConverternow splits on(space) or,onlyStringclaims (and not the values ofList<String>claims any more).
- gh-271
RestClient&WebClientauto-configured byspring-addons-starter-restnow scope tokens issued with client credentials to the application (Spring Security's default is user, which is a waste of resources and a source of latency).
- gh-273: Use
servlet.context-pathorwebflux.base-pathwhen building default OAuth2 URIs. Starting from Spring Boot3.5.0, the OAuth2 URIs are relative by default, which solves compatibility issues with reverse proxies. Only the post-logout URI should contain an authority as it is provided to the authorization server so that it redirects back to the UI after RP-Initiated Logout (⚠️ when removing theclient-uriproperty or when setting it with a relative URI, set thepost-login-redirect-hostwith a URI containing an authority). The URIs built by spring-addons are now using the 1st provided value in the following order:spring-addons-starter-oidc'sclient-uriproperty- Spring Boot Web's
server.servlet.context-pathorserver.webflux.base-pathdepending on the application type /
- Spring Boot
3.5.0to manage default transitive dependencies (designed to work with Spring Cloud2025.0.0)
- gh-267 Prevent Open Redirect (CWE-601) attacks. The post login/logout URIs must now be part of whitelists defined with
post-login-allowed-uri-patternsandpost-logout-allowed-uri-patternsproperties. For backward compatibility, if these properties are left blank, all post login/logout URIs composed of only a path (no scheme / authority) as well as those with the same scheme and authority as theclient-uriproperty are allowed.
Sample configuration stricter than defaults:
reverse-proxy: https://localhost
com:
c4-soft:
springaddons:
oidc:
client:
client-uri: ${reverse-proxy}/bff
post-login-allowed-uri-patterns:
# Each entry is compiled into a java.util.regex.Pattern
# The following is stricter than the defaults, which are ^${reverse-proxy}(/.*)?$ and ^/.*$
- ^${reverse-proxy}/ui(/.*)?$
- ^/ui(/.*)?$
post-login-redirect-path: /ui/greet
post-logout-allowed-uri-patterns:
- ^${reverse-proxy}/ui(/.*)?$
- ^/ui(/.*)?$
post-logout-redirect-path: /ui/Each post-login-allowed-uri-patterns/post-logout-allowed-uri-patterns entry is compiled into a java.util.regex.Pattern.
post-login-redirect-host, post-login-redirect-path, post-logout-redirect-host, and post-logout-redirect-path are validated at startup. An exception is thrown in case of mismatch.
In case of mismatch of post login/logout headers & request params, the authentication request is answered with a 401.
- Configurable CSRF cookie name and path to solve collisions in case of multiple applications served from the same host. Using a custom cookie name is usually enough and easier as browsers' security will require the cookie path to be a prefix (for instance
/foo) shared by:- the UI assets, for the CSRF token value to be accessible from the SPA Javascript (for instance
/foo/ui/**) - the backend secured with
oauth2Login, for the cookie to be attached with the request to this backend (for instance/foo/bff/v1/**)
- the UI assets, for the CSRF token value to be accessible from the SPA Javascript (for instance
- Boot
3.4.5as default transient dependency
- gh-264 Use
RestClient.BuilderandWebClient.Builderexposed by the "official" Boot starter as base for those exposed byspring-addons
- gh-263 Support empty security context with WebClient auto-configured with
forward-bearer=true
- gh-258 Class cast exception with
@WithMockJwtAuthmeta-annotaions
- gh-254 Inject the authorized client manager and repository to SpringAddonsRestClientBeanDefinitionRegistryPostProcessor only when OAuth2 authorization is configured to use a registration.
- gh-253 Fix the scope of
spring-security-configwhich was declared twice inspring-addons-oauth2,spring-addons-oauth2-testandspring-addons-starter-oidcpoms: once withcompileand a then asoptional&provided. Only the 2nd is necessary, so removed 1st.
- gh-249 Add a property to disable SSL certificates validation for auto-configured REST clients. When
client-http-request-factory-impl=jdk, only root authority validation is disabled (not the hostname, so the certificate CN or altnames must match the URL hostame). For other request factory implementations (jdkandjetty), both root authority and hostname validations are disabled. - Bump transient dependency on Spring Boot to
3.4.4
- gh-247
WebClientbeans auto-configured byspring-addons-starter-restshould take the(Reactive)OAuth2AuthorizedClientManagerfrom the application context instead of building one from authorized client service and repo.
- Boot
3.4.3as transient dependency
- restore the custom
ServerCsrfTokenRequestAttributeHandlerfor reactive applications configured withHttpOnly=falseCSRF cookie
- Drop the multi-tenancy support for
oauth2Login. Spring Security is way too targetted to single tenancy and the work-arounds are a nightmare to maintain. So, when configuring more than oneregistrationwithauthorization_code, make sure that a user is logged out before allowing him to log in again. Theresource-server_with_uiis modified with this new paradigm. - Fix the URIs generated by the default
InvalidSessionStrategyintroduced in8.1.0 - Switch from the deprecated
OAuth2AuthorizedClientProvider(usingRestTemplate) to the recent ones usingRestClient - Make the
RestClient/WebClientused by the(Reactive)OAuth2AuthorizedClientProvidereasily configurable
- Change the default
InvalidSessionStrategyin the auto-configured security filter chain for servlets withoauth2Login. The new behavior is to create a new (anonymous) session and redirect to the same URI (retry with a new session cookie). This sensible default in most cases (including the servlet version of Spring Cloud Gateway configured as an OAuth2 BFF) and can be modified withinvalid-sessionproperties. For instance, to return a401with aLocationheader pointing to the/loginendpoint (which should be included amongsecurity-matcherandpermit-all):
com:
c4-soft:
springaddons:
oidc:
ops:
- iss: ${sso-issuer}
authorities:
- path: $.realm_access.roles
client:
client-uri: ${gateway-uri}
security-matchers:
- /login/**
- /oauth2/**
- /logout/**
permit-all:
- /login/**
- /oauth2/**
invalid-session:
location: ${gateway-uri}/login
status: UNAUTHORIZEDcom.c4-soft.springaddons.oidc.client.oauth2-redirections.invalid-session-strategyis removed (replaced bycom.c4-soft.springaddons.oidc.client.invalid-session.status)- Make
ClientHttpRequestFactoryconfigurable inspring-addons-starter-rest:- if the application conf contains such a bean, none is auto-configured
- the default implementation for the auto-configured bean (
JdkClientHttpRequestFactory) can be switched toHttpComponentsClientHttpRequestFactory(requiresorg.apache.httpcomponents.client5:httpclient5to be on the class-path) orJettyClientHttpRequestFactory(requiresorg.eclipse.jetty:jetty-clientto be on the class-path) using properties:
com:
c4-soft:
springaddons:
rest:
client:
machin-client:
http:
# requires org.apache.httpcomponents.client5:httpclient5 to be on the class-path
client-http-request-factory-impl: http-components
bidule-client:
http:
# requires org.eclipse.jetty:jetty-client to be on the class-path
client-http-request-factory-impl: jetty- Spring Boot
3.4.2as transitive dependency
- Support multiple
FormattingConversionServiceinspring-addons-starter-openapi(when usingspring-boot-starter-data-restfor instance, there are at least two)
- Replace SimpleClientHttpRequestFactory with JdkClientHttpRequestFactory in auto-configured RestClient to support PATCH requests
- Remove the chunk-size configuration property (it is ignored by most underlying HTTP clients)
- Auto-configure static headers with
spring-addons-starter-rest. Sample:
com:
c4-soft:
springaddons:
rest:
client:
greet-client:
base-url: ${client-uri}/api
headers:
X-API-KEY: change-me- Fix the token params for apps without
oauth2Loginand the newcom.c4-soft.springaddons.oidc.client.token-paramsproperty (the params where applied only with the deprecatedcom.c4-soft.springaddons.oidc.client.token-request-params)
spring-addons-starter-restnow expose as@BeansomeRestClientandWebClientinstances (or builders) with the following configured using application properties:- Base URI
BasicorBearerauthorization. For the second, with a choice of using an OAuth2 client registration or forwarding the access token in the security context.- Connection & read timeouts
- HTTP or SOCKS proxy, with consideration of the standard
HTTP_PROXYandNO_PROXYenvironment variables (finer-grained configuration can be applied with custom properties)
spring-addons-starter-oidcauto-configuration foroauth2Loginis improved with:- Working Back-Channel Logout, even with cookie-based CSRF protection and
logout+jwttokens (which makes it finally usable with OAuth2 BFF & Keycloak). - Configurable status for unauthorized requests. The default is still
302 Found(redirect to login), but it's a snap to change it to401 Unauthorized(like REST APIs should return, even stateful ones).
- Working Back-Channel Logout, even with cookie-based CSRF protection and
OAuthenticationnow extendsAbstractOAuth2TokenAuthenticationTokenfor a better integration with the rest of the Spring Security ecosystem. See the migration guide for details.
For Spring Boot 3.3.x.
spring-addons-starter-rest provides "incubating" tooling for RestClient, WebClient and @HttpExchange proxy generation.
- Fix some issues related to
clientUriand RP-Initiated Logout on servlets withoauth2Login
- Boot
3.3.4as transitive dependency
- Boot
3.3.3as transitive dependency
- Fix gh-226: broken introspection response parsing in reactive applications
- Boot
3.3.2as transitive dependency
- Refactor CORS configuration:
- expose a
Cors(Web)Filterbean instead of configuring the(Server)HttpSecurityindependently for client and resource serverSecurity(Web)FilterChainwith CORS config - deprecate
com.c4-soft.springaddons.oidc.clientandcom.c4-soft.springaddons.oidc.resourceserverin favor ofcom.c4-soft.springaddons.oidc(the filter applies to all requests, and is the same whatever the filter-chain securing a given request) - for backward compatibility, all 3 configuration sources are merged into a single collection
- a default
Cors(Web)Filterbean is configured only if some CORS configuration properties are present (same as before) and if noCors(Web)Filterbean is registered already (this is new)In other words, regarding CORS,spring-addonsbacks-of if a CORS filter is registered in application already, or if spring-addons CORS conf properties are omitted
- expose a
com:
c4-soft:
springaddons:
oidc:
cors:
- path: /machin/**
allowed-origin-patterns: "*"
- path: /truc/**
allowed-origin-patterns:
- "http://localhost:4200"
- "http://*.chose.com"- Fix gh-203: CSRF protection for SPAs on
spring-cloud-gatewaywas breaking requests forwarding when content-type wasapplication/x-www-form-urlencoded
- Fix gh-219: cast timestamp claims to
Longinstead ofIntegerin@WithJwtAuthentication factory
- Spring Boot
3.3.1and Cloud2023.0.2as transitive dependencies
- Add a configuration property for the internal URI used during Back-Channel Logout to actually disconnect the user
- Fix default authorization failure handler auto-configuration
- Add a
errorquery parameter to authorization failure URI
- Spring Boot
3.3.0as transitive dependency
- gh-213: native-images compatibility:
- add missing
@NestedConfigurationPropertytoSpringAddonsOidcProperties#clientandSpringAddonsOidcProperties#resourceserver - declare all other
@ConfigurationPropertyas nested classes of eitherSpringAddonsOidcProperties,SpringAddonsOidcClientPropertiesorSpringAddonsOidcResourceServerProperties
- add missing
- Spring Boot
3.2.4
- Improve the declaration of additional parameters for authorization and token requests:
com:
c4-soft:
springaddons:
oidc:
client:
authorization-request-params:
auth0-confidential-user:
- name: audience
value: demo.c4-soft.com
token-request-params:
auth0-confidential-user:
- name: audience
value: demo.c4-soft.combecomes:
com:
c4-soft:
springaddons:
oidc:
client:
authorization-params:
auth0-confidential-user:
audience: demo.c4-soft.com
token-params:
auth0-confidential-user:
audience: demo.c4-soft.comFor backward compatibility, the enhanced syntax is available from new parameters (authorization-request-params => authorization-params and token-request-params => token-params).
Note that multi-valued parameters are correctly handle for token endpoints, but there is a limitation in the way Spring's OAuth2AuthorizationRequest additional params are processed forcing to use single-valued parameters. If providing with a string array in spring-addons authorization-params properties, it is joined using comas.
SpringAddons(Server)OAuth2AuthorizationRequestResolvernow exposesgetOAuth2AuthorizationRequestCustomizer(HttpServletRequest request, String clientRegistrationId). To add parameters depending on the request, in addition to the PKCE token (if enabled) and "static" parameters defined in spring-addons properties, you can expose something like:
@Component
public class MyOAuth2AuthorizationRequestResolver extends SpringAddonsOAuth2AuthorizationRequestResolver {
public MyOAuth2AuthorizationRequestResolver(
OAuth2ClientProperties bootClientProperties,
ClientRegistrationRepository clientRegistrationRepository,
SpringAddonsOidcClientProperties addonsClientProperties) {
super(bootClientProperties, clientRegistrationRepository, addonsClientProperties);
}
@Override
protected Consumer<Builder> getOAuth2AuthorizationRequestCustomizer(HttpServletRequest request, String clientRegistrationId) {
return new CompositeOAuth2AuthorizationRequestCustomizer(
getCompositeOAuth2AuthorizationRequestCustomizer(clientRegistrationId),
new MyDynamicCustomizer(request));
}
static class MyDynamicCustomizer implements Consumer<OAuth2AuthorizationRequest.Builder> {
private final HttpServletRequest request;
public MyDynamicCustomizer(HttpServletRequest request) {
this.request = request;
}
@Override
public void accept(OAuth2AuthorizationRequest.Builder authorizationRequest) {
authorizationRequest.additionalParameters(params -> {
// TODO: add parameters depending on the request
});
}
}
}- gh-196 Fix NullPointerException when an HTTP request does not have an X-XSRF-TOKEN header in reactive clients configured with XSRF protection
- Fix gh-195: RP-Initiated Logout disabling condition was incorrectly modified (not working when logout conf was missing)
- gh-195 Fix the possibility to override the logout request uri (end_session endpoint)
- gh-192
spring-security-oauth2-resource-server,spring-security-oauth2-clientandspring-webfluxshould beoptionaldependencies
- add a micro-starter to walk around
springdoc-openapilimitations with enums (only for servlets for now)
- Spring Boot 3.2.3
- add
com.c4-soft.springaddons.oidc.client.pkce-forcedproperty. Default tofalse. Whentrue, PKCE is used by clients for authorization-code flows, even by confidential clients - move the BFF tutorial to Baeldung. It is also refreshed and now contains sample implementations for React (Next.js) and Vue (Vite).
- move the experimental support for
RestClientandWebClientto a dedicated starter:spring-addons-starter-rest. The reasons for that are:spring-addons-starter-oidcis not necessary to use this helpers- OAuth2 authorization is optional for REST clients
- experimental support beans for
RestClientandWebClient
- gh-188 Fix unnecessarily required audience in
JWTClaimsSetAuthenticationManagerResolver
- make
(Reactive)SpringAddonsOAuth2AuthorizedClientBeansconditional oncom.c4-soft.springaddons.oidc.client.token-request-paramsproperties being present - fix missing
SpringAddons(Reactive)JwtDecoderFactorydefault bean
- Create spring-addons-starter-oidc README
- Replace
AuthoritiesMappingPropertiesResolverwithOpenidProviderPropertiesResolver OpenidProviderPropertiesResolvermakes multi-tenancy much simpler to implement, including in "dynamic" scenarios (see spring-addons-starter-oidc README)- Fix names of
(Server)HttpSecurityPostProcessor(synchronised impl where prefixed withServerwhich it shouldn't and reactive weren't when it should)- renamed
HttpSecurityPostProcessor,ClientHttpSecurityPostProcessorandResourceServerHttpSecurityPostProcessorfromreactivepackages toReactiveHttpSecurityPostProcessor,ClientReactiveHttpSecurityPostProcessorandResourceServerReactiveHttpSecurityPostProcessor - renamed
ServerHttpSecurityPostProcessor,ClientHttpSecurityPostProcessorandResourceServerHttpSecurityPostProcessorfromsynchronizedpackages toSynchronizedHttpSecurityPostProcessor,ClientSynchronizedHttpSecurityPostProcessorandResourceServerSynchronizedHttpSecurityPostProcessor
- renamed
- gh-183 Allow anonymous CORS preflight requests (
OPTIONSrequests to a path configured with CORS) - gh-184 Configuration properties to add parameters to token requests (necessary for instance to add an
audiencewhen using client-credentials with Auth0) - Fix Back-Channel Logout activation
- Change arrays for lists in spring-addons properties. Apparently, configuration properties meta-data is better generated for Lists...
- Fix properties documentation issues (
resource-serverinstead ofresourceserver)
- gh-182doubled path-prefix by SpringAddonsServerOAuth2AuthorizationRequestResolver
- Add a
com.c4-soft.springaddons.oidc.client.back-channel-logout.enabledproperty to opt-in Spring Security implementation of Back-Channel Logout.Customizer.withDefaults()is used unless you provide one as a bean.
- Boot
3.2.2as transitive dependency
- gh-178
authorization-request-paramsignored
- gh-176 Exception thrown when
post-logout-redirect-pathis null - gh-177 Post-login success & failure URI params and headers on authentication request are ignored in reactive applications
- gh-174 Fix a regression on request to exchange authorization-code for tokens in servlet applications
- gh-166
@WithMockJwtAuthauthentication factory uses the authentication converter in the context or aJwtAuthenticationConverterif none is found@WithMockBearerTokenAuthenticationauthentication factory uses theOpaqueTokenAuthenticationConverterin the context
- gh-169 Per request post-login and post-logout URIs. It is now possible to set post-login success / failure URIs as header or request param when initiating
oauth2Login. This URIs are saved in session and used by the default authentication success / failure handlers. Similarly, when using RP-Initiated Logout, the default logout success handler scans for a post-logout URI in headers and query params to override the default value in properties. The name for these headers, query params and session attributes are exposed by SpringAddonsOidcClientProperties.
- Spring boot
3.2.0as transient dependency
- gh-155 Configurable HTTP status for responses to authorization_code flow initiation, authorization-code callback and logout. This makes BFF configuration easier for single page and mobile applications. Default OAuth2 response status (
302 Found) can be overriden with:
com:
c4-soft:
springaddons:
oidc:
ops:
client:
oauth2-redirections:
pre-authorization-code: FOUND
post-authorization-code: FOUND
rp-initiated-logout: ACCEPTEDA per-request override can be done by setting X-RESPONSE-STATUS header with either a status code or label (for instance, both 201 and ACCEPTED are accepted as value).
- update CSRF configuration for SPAs as instructed by spring-security team in spring-projects/spring-security#14125
- gh-153 have the default opaque tokens introspector accept
Integer,Long,InstantandDateas value type foriatandexpclaims
- Spring boot
3.1.5as transient dependency - gh-151 scan application context for
authenticationEntryPointandaccessDeniedHandlerto auto-configure resource servers (default returns401for unauthorized requests instead of302 redirect to login).
- Spring boot
3.1.4as transient dependency - gh-147 prevent addons test security conf to be auto-configured (complicates integration testing with test containers)
- Fix servlet resource server with introspection auto-configuration
- Enable to configure post-login and post-logout host (defaulted to client URI for backward compatibility)
- Spring Boot 3.1.3
- gh-144 remove useless dependency on spring-session.
- Remove Back-Channel Logout experimental support. Follow the PR on Spring Security for official support.
- Multi-tenancy support on OAuth2 clients is now optional and disabled by default. Set
com.c4-soft.springaddons.oidc.client.multi-tenancy-enabled=trueto keep it activated. - gh-140: use AOP instead of custom authorized-client repositories to support multi-tenancy on OAuth2 clients. That way, any configured authorized-client repository is instrumented (no need to proxy or extend spring-addons one).
- client
SecurityFilterChainwithLOWEST_PRIORITY - 1(instead ofHIGHEST_PRIORITY + 1) WWW_Authenticateheader withBearervalue for resource servers unauthorized requests (instead ofBasic)
- Spring Boot 3.1.2
- force usage of
AntPathRequestMatcherwhen definingpermit-allin servlet implementations because of https://spring.io/security/cve-2023-34035 (Spring6.1.2)
- Fix a confusion between user subject and principal name in
SpringAddons(Server)OAuth2AuthorizedClientRepositorywhich could cause an authorized client not to be found when using another claim than subject as principal name.
- Fix the condition to add a filter inserting CSRF protection cookie to responses
See the migration guide
- merge all 6 starters into a single one
- reduce test libs count to 2: one with just annotations and another to ease testing of apps using the starter
- Spring Boot 3.1.3
- force usage of
AntPathRequestMatcherwhen definingpermit-allin servlet implementations because of https://spring.io/security/cve-2023-34035 (Spring6.1.2)
- Spring Boot 3.1.2
- Fix a confusion between user subject and principal name in
SpringAddons(Server)OAuth2AuthorizedClientRepositorywhich could cause an authorized client not to be found when using another claim than subject as principal name.
- remove
OAuth2AuthenticationFactory: instead, useConverter<Jwt, ? extends AbstractAuthenticationToken>,Converter<Jwt, ? extends Mono<? extends AbstractAuthenticationToken>>,OpaqueTokenAuthenticationConverterorReactiveOpaqueTokenAuthenticationConverter - create
@WithJwtto build OAuth2Authenticationduring tests, using a JSON string or file on the classpath and submitting it to the JWT authentication converter. All samples and tutorials are updated with this new annotation. - deprecate
@WithMockJwtand@OpenId(use the new@WithJwtinstead) - remove the archetypes
- gh-133 Add a property to auto-configure an
audienceJWT validator (if present, theaudclaim in the token will be checked to contain the URI provided in the conf)
- gh-129 Auto-configure (with application properties) additional parameters for authorization-code request. This allows, for instance, to send an
audienceas required by Auth0. Additional parameters are defined for each client registration. In the following sample,client-registrationaandbreferences an existing entries in spring.security.oauth2.client.registration:
com:
c4-soft:
springaddons:
security:
client:
authorization-request-params:
client-registration-a:
- name: audience
value: demo.c4-soft.com
client-registration-b:
- name: kc_idp_hint
value: google
- name: machin
value: chose- gh-128 add
@ClasspathClaimsto load claims from a JSON file in the classpath (test resources for instance).
@Test
@WithMockJwtAuth(
authorities = "ROLE_AUTHORIZED_PERSONNEL",
claims = @OpenIdClaims(
usernameClaim = "$['https://c4-soft.com/user']['name']",
jsonFile = @ClasspathClaims("ch4mp.json")))
void givenUserIsAuthenticatedWithJsonClaims_whenGetClaims_thenOk() throws Exception {
api.get("/greet").andExpect(status().isOk()).andExpect(content().string("Hello Ch4mp! You are granted with [ROLE_AUTHORIZED_PERSONNEL]."));
}- gh-127 add a
jsonproperty to @OpenIdClaims to define all claims with a JSON string
@WithMockJwtAuth(
authorities = { "ROLE_AUTHORIZED_PERSONNEL" },
claims = @OpenIdClaims(
usernameClaim = "$['https://c4-soft.com/user']['name']",
json = """
{
"https://c4-soft.com/user": {
"name": "Ch4mp",
"email": "ch4mp@c4-soft.com"
},
"aud": "https://localhost:7082"
}"""))- gh-125 Split claims used as
GrantedAuthoritysource on comma and space (for instance,scopeclaim is usually a single string with comma separated scopes).
- gh-122 Support for parametrized OAuth2 Authentications in
@ParameterizedTest. In the following sample, mind the@JwtAuthenticationSource(decoring test) and@ParameterizedJwtAuth(decoring test method parameter). The first annotation defines the different authentication instances, the second inserts the one for the current test in the security context and provides it as test method parameter:
@ParameterizedTest
@JwtAuthenticationSource({ @WithMockJwtAuth("NICE"), @WithMockJwtAuth("VERY_NICE") })
void givenUserIsGrantedWithAnyNiceAuthority_whenGetRestricted_thenOk(@ParameterizedJwtAuth JwtAuthenticationToken auth) throws Exception {
api.perform(get("/restricted"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.body").value("You are so nice!"));
}The above will run two distinct tests in sequence, one with each of the provided @WithMockJwtAuth. Same for:
@WithMockBearerTokenAuthenticationwith@BearerAuthenticationSourceand@ParameterizedBearerAuth@OpenIdwith@OpenIdAuthenticationSourceand@ParameterizedOpenId@WithOAuth2Loginwith@OAuth2LoginAuthenticationSourceand@ParameterizedOAuth2Login@WithOidcLoginwith@OidcLoginAuthenticationSourceand@ParameterizedOidcLogin
- Spring Boot 3.1.0
- Spring Boot 3.0.7
- gh-112 fix CSRF token exposed to Javascript in servlets applications. Thanks to @giovannicandido for spotting and fixing this.
- Spring Boot 3.0.6
- create
ServletConfigurationSupportandReactiveConfigurationSupportinspring-addons-{webmvc|webflux}-coreto remove code duplication from starters
- add new helpers to type private claims in test annotations for
Double,URIs,URLsandDate - add 1 level of nested claims to
@Claims, the test annotation to define private claims in OAuth2 test annotations. It is not possible to describe recursive structures with annotation (annotation with a node of the same type as itself), which is an issue to describe a JSON document. To configure further nested claims, it is still possible to use@JsonObjectClaimwith serialized JSON strings. Sample usage with all possible types of claims (hopefully, it will never be necessary to configure as many claims in a single test):
@WithMockJwtAuth(authorities = "ROLE_AUTHORIZED_PERSONNEL", claims = @OpenIdClaims(sub = "Ch4mpy", otherClaims = @Claims(
intClaims = { @IntClaim(name = "int1", value = 42), @IntClaim(name = "int2", value = 51) },
longClaims = { @LongClaim(name = "long1", value = 42), @LongClaim(name = "long2", value = 51) },
doubleClaims = { @DoubleClaim(name = "double1", value = 4.2), @DoubleClaim(name = "double2", value = 5.1) },
stringClaims = { @StringClaim(name = "str1", value = "String 1"), @StringClaim(name = "str2", value = "String 2") },
uriClaims = { @StringClaim(name = "uri1", value = "https://localhost:8080/greet"), @StringClaim(name = "uri2", value = "https://localhost:4200/home#greet") },
urlClaims = { @StringClaim(name = "url1", value = "https://localhost:8080/greet"), @StringClaim(name = "url2", value = "https://localhost:4200/home") },
epochSecondClaims = { @IntClaim(name = "epoch1", value = 1670978400), @IntClaim(name = "epoch2", value = 1680648172)},
dateClaims = { @StringClaim(name = "date1", value = "2022-12-14T00:40:00.000+00:00"), @StringClaim(name = "date1", value = "2023-04-04T00:42:00.000+00:00") },
stringArrayClaims = { @StringArrayClaim(name = "strArr1", value = { "a", "b", "c" }), @StringArrayClaim(name = "strArr2", value = { "D", "E", "F" }) },
jsonObjectClaims = { @JsonObjectClaim(name = "obj1", value = obj1), @JsonObjectClaim(name = "obj2", value = obj2)},
jsonObjectArrayClaims = @JsonObjectArrayClaim(name = "objArr1", value = { obj3, obj4}),
nestedClaims = { @NestedClaims(
name = "https://c4-soft.com/user",
intClaims = { @IntClaim(name = "nested_int1", value = 42), @IntClaim(name = "nested_int2", value = 51) },
longClaims = { @LongClaim(name = "nested_long1", value = 42), @LongClaim(name = "nested_long2", value = 51) },
doubleClaims = { @DoubleClaim(name = "nested_double1", value = 4.2), @DoubleClaim(name = "nested_double2", value = 5.1) },
stringClaims = { @StringClaim(name = "nested_str1", value = "String 1"), @StringClaim(name = "nested_str2", value = "String 2") },
uriClaims = { @StringClaim(name = "nested_uri1", value = "https://localhost:8080/greet"), @StringClaim(name = "nested_uri2", value = "https://localhost:4200/home#greet") },
urlClaims = { @StringClaim(name = "nested_url1", value = "https://localhost:8080/greet"), @StringClaim(name = "nested_url2", value = "https://localhost:4200/home") },
epochSecondClaims = { @IntClaim(name = "nested_epoch1", value = 1670978400), @IntClaim(name = "nested_epoch2", value = 1680648172)},
dateClaims = { @StringClaim(name = "nested_date1", value = "2022-12-14T00:40:00.000+00:00"), @StringClaim(name = "nested_date1", value = "2023-04-04T00:42:00.000+00:00") },
stringArrayClaims = { @StringArrayClaim(name = "nested_strArr1", value = { "a", "b", "c" }), @StringArrayClaim(name = "nested_strArr2", value = { "D", "E", "F" }) },
jsonObjectClaims = { @JsonObjectClaim(name = "nested_obj1", value = obj1), @JsonObjectClaim(name = "nested_obj2", value = obj2)},
jsonObjectArrayClaims = @JsonObjectArrayClaim(name = "nested_objArr1", value = { obj3, obj4}))})))- gh-106: Properties to disable spring-addons security filter-chain auto-configuration:
- for clients: empty path-matchers array or
com.c4-soft.springaddons.security.client.enabled=false - for resource servers:
com.c4-soft.springaddons.security.enabled=false
- for clients: empty path-matchers array or
- fix CSRF protection configuration (apply https://docs.spring.io/spring-security/reference/5.8/migration/servlet/exploits.html#_i_am_using_a_single_page_application_with_cookiecsrftokenrepository and https://docs.spring.io/spring-security/reference/5.8/migration/reactive.html#_i_am_using_angularjs_or_another_javascript_framework)
- rework the Javadoc and README of all 6 OAuth2 starters
- introduce a Back-Channel Logout client implementation to both client starters
- rework BFF and resource server & client tutorials with spring-addons client starters
- boot 3.0.4
- add a BFF tutorial
- add spring-addons-webmvc-client
- add spring-addons-webflux-client
- in both client starters, add a logout handler for OP with RP-Initiated logout implementations which do not comply with OIDC standard. This handler is configurable from properties (logout end-point and post-logout URIs). See
resource-server_with_uitutorial for details.
- breaking change in properties: authorities mapping is now configured per claim JSON path (instead of per issuer). This enables to use different prefix (and case) for different claims (for instance
SCOPE_forscopeclaim andROLE_forrealm_access.rolesone). As a consequence,com.c4-soft.springaddons.security.issuers[].authorities.claims[]is replaced withcom.c4-soft.springaddons.security.issuers[].authorities[].path.Also,prefixas well ascaseare put at the same level as (JSON)path.
Sample migration with YAML:
com:
c4-soft:
springaddons:
security:
issuers:
- location: ${keycloak-issuer}
username-claim: preferred_username
authorities:
prefix: ROLE_
claims:
- realm_access.roles
- resource_access.client1.rolesBecomes:
com:
c4-soft:
springaddons:
security:
issuers:
- location: ${keycloak-issuer}
username-claim: $.preferred_username
authorities:
- path: $.realm_access.roles
prefix: ROLE_
- path: $.resource_access.client1.roles
prefix: ROLE_- "pseudo" JSON path for username and authorities claims is now actual JSON path. This means that
$.resource_access.*.roleswill be successfully accepted. Thanks to JSON path syntax, this is not a breaking change ($.resource_access.client1.rolesandresource_access.client1.rolesare interpreted the same) - bump to Spring Boot 3.0.3
- Add a
username-clameconfiguration property to define, per issuer, from which claim of the access token should be retrieved the username (what is returned byAuthentication::getName). Default is subject for backward compatibility
- gh-100 prevent a NPE in reactive resource-server using JWT spring-addons starter when the issuer in an access token is not listed in conf. All credits go to lArtiquel who spotted the bug and submitted the fix.
- create
ServerHttpRequestSupportandHttpServletRequestSupportto help statically access to the request in current context (usage in authentication converters for instance
- add
@WithOAuth2Loginand@WithOidcLoginto populate test security-context with anOAuth2AuthenticationTokeninstance (with respectivelyDefaultOAuth2UserandDefaultOidcUseras principal) - bump to spring-boot
3.0.2 - default authorities collection in tests annotations,
MockMvcpost-processors andWebTestClientmutators is set to empty array (instead of{ "ROLE_USER" })
- gh-86
OAuthentication::setDetailsshould not throw until spring-security 6.1 is released - gh-87 spring-addons JWT starters should start even if
spring.security.oauth2.resourceserver.jwt.issuer-uriis set in configuration properties
- gh-83 do not force traffic to http when SSL is not enabled (just force https when SSL is enabled)
- Make OAuthentication immutable
- release with spring-boot 3.0.0 GA as transitive dependency
- samples for all combinations of:
- webmvc / webflux
- JWT decoder / access token introspection
OAuthentication<OpenidClaimSet>/ Spring defaultAuthenticationimplementation (JwtAuthenticationTokenfor JWT decoder orBearerTokenAuthenticationfor token introspection)
- minor fixes (@WithMockAuthentication and reactive + introspection starter)
- Switch to spring-boot 3 (and spring-security 6)
- Stop supporting the very deprecated Keycloak libs for spring
This branch is not maintained anymore. Only versions compatible with Spring 6.1.x (Boot 3.1.x) and JDK >= 17 are maintained.
- gh-100 prevent a NPE in reactive resource-server using JWT spring-addons starter when the issuer in an access token is not listed in conf. All credits go to lArtiquel who spotted the bug and submitted the fix.
- Use a single bean name for
ServletSecurityBeansandReactiveSecurityBeans: AddonsSecurityBeans@AutoConfigureAddonsSecurity{Webmvc|Weblux}{Jwt|Introspecting}:@AutoConfigureAddonsSecurity
- Add
@AutoConfigureAddonsWebSecurityto do the same as existing@AutoConfigureAddonsSecuritywhich now loads authorities converter only (useful to unit-test @Components that are not @Controller). - More options for CSRF configuration (enum property instead of a boolean) and CSRF disabled by default when session-management is state-less.
- Compatibility with JDK 1.8 and spring-boot 2.6 (get version 6.x for spring-boot 3 and JDK 17)
- webflux dependencies cleanup (were pulling some servlet dependencies)
- All samples now demo @Service and @Repository unit-tests in addition to @Controller ones.
Use JwtAuthenticationToken or BearerAuthenticationToken by default in resource-server starters. For some reason, OAuthentication<OpenidClaimSet> frightens rookies.
- make
OAuth2AuthenticationFactory@Beanoptional. - remove
OAuth2ClaimsConverter(interface definition and @ConditionalOnMissingBean) - remove the recently added
oauth2-authentication-factory-enabledproperty (instead, evaluate if anOAuth2AuthenticationFactorybean was provided)
- resource-server starter main beans (
Security(Web)FilterChain) are no-longer "conditional on missing": if you dan't want it, don't pull starter lib. - add
oauth2-authentication-factory-enabledflag to easily fall-back to Spring default OAuth2Authenticationimplementations (JwtAuthenticationTokenandBearerTokenAuthenticationfor resource-servers with respectively JWT decoder or opaque token introspection)
- keycloak 19
- release with JDK 17 and boot 2.7.2
- release with JDK 1.8 and boot 2.6.10
- Support token introspection for resource-servers.
- Rename
spring-addons-*-jwt-resource-server-testtospring-addons-*-testas it apply for both JWT and introspection
Rename modules to:
- have all module names start with
spring-addonsprefix, then intermediate module if any (archetypes,samples,starters,webmvcorwebflux) and last what leaf module aims at - better reflect what it does
For instance, spring-security-oauth2-webmvc-addons only applies to resource-servers secured with JWTs (not to opaque tokens) -> renamed to spring-addons-webmvc-jwt-resource-server
Rename com.c4-soft.springaddons.security.token-issuers configuration properties to com.c4-soft.springaddons.security.issuers for the same reason: only accepts JWT token issuers (and not opaque token issuers with introspection end-point for instance)
CSRF enabled by default, using CookieCsrfTokenRepository if session management is "stateless".
add reCAPTCHA validation spring-boot starter
rename @WithMockOidcAuth to shorter and more expressive @OpenId: it populates test security context with an OAuth2 Àuthentication containing an OpenID claim-set
- rename
OpenidClaimSettoOpenidClaimSet: more expressive as this class contains OpenID token claims only - rename
OAuthenticationtoOAuthentication: it has no more adherence to OpenID (just specific to authentication with encoded claims in a bearer string)
Slight properties rework. Now, to configure issuers and authorities mapping:
# should be set to where your authorization-server is
com.c4-soft.springaddons.security.issuers[0].location=https://localhost:8443/realms/master
# should be configured with a list of private-claims this authorization-server puts user roles into
# below is default Keycloak conf for a `spring-addons` client with client roles mapper enabled
com.c4-soft.springaddons.security.issuers[0].authorities.claims=realm_access.roles,resource_access.spring-addons-public.roles,resource_access.spring-addons-confidential.roles
# use IDE auto-completion or see SpringAddonsSecurityProperties javadoc for complete configuration properties listwhere caze is one of unchanged, upper or lower
- gh-50: One entry per authorization-server for authorities mapping (see samples
application.propertiesfiles for new configuration structure). - gh-51: Group archetypes, webmvc and webflux modules.
- gh-49: Samples in dedicated modules. All samples are moved from libs tests to
samplesmodule, with one sub-module per sample.
Cleanup and prepare for spring-boot 3:
- gh-46: split webmvc & webflux content from
spring-addons-oauth2 - gh-47: provide
SecurityFilterChainbean instead of extendingWebSecurityConfigurerAdapter - gh-48: make use of spring-boot
@AutoConfiguration
- Replace multiple JWT issuers JwtDecoder (from 4.1.4) with
AuthenticationManagerResolver@Beans
- JwtDecoder for configuring multiple JWT issuers (single resource server accepting IDs from two or more authorization-servers)
- finer configuration control with
SpringAddonsSecurityProperties
- move keycloak related code to
spring-addons-keycloak
- Master branch back to single JDK: 17
- Create
jdk1.8andjdk11branches
- Add spring-addons-archetypes-webmvc-multimodule to boostrap native-ready Spring REST API with webmvc, JPA, OpenAPI and OpenID security.
- Add a sample with
OpenidClaimSetspecialisation (parse private claims in addition to authorities).
- Improve
OidcReactiveApiSecurityConfigandOidcServletApiSecurityConfigusability: ease security beans replacement (including authorities and authentication converter for use cases where OAuthentication is not enough)
- Rename
SecurityPropertiesto less conflictingSpringAddonsSecurityProperties
- Turn
AbstractOidc...ApiSecurityConfigintoOidc...ApiSecurityConfigwith default authorities mapper being keycloak or Auth0 depending oncom.c4-soft.springaddons.security.keycloak.client-idbeing set or not - More CORS and authorities mapping configuration in
SecurityProperties
- Fix missing JTI claim mapping from
@OpenIdClaims(gh-35).
- Add
AbstractOidcReactiveApiSecurityConfigtospring-addons-oauth2. It provides with reasonable default WebSecurityConfig for a reactive (weblux) based API secured with OAuthentication.
- Add
AbstractOidcServletApiSecurityConfigtospring-addons-oauth2. It provides with reasonable default WebSecurityConfig for a servlet based API secured with OAuthentication.
- lombok with provided scope (gh-31)
- spring-boot 2.6.1
- release with JDK version (compilation and runtime target)
- spring-boot 2.6
- in OAuth2 related test annotations all claims are now grouped under a single
claims = @OpenIdClaims(...) @WithMockJwtAuthin addition to@WithMockKeycloakAuthand@WithMockOidcAuth- some code cleanup, quite a bunch of code removed and some renaming (including breaking changes, reason for new major version)
- import spring-boot 2.5.5 BOM (instead of inheriting 2.5.4 POM)
- Downgrade Java compatibility to 1.8
- spring-boot 2.5.4
- replace
KeycloakOidcIdAuthenticationConverterwithSynchronizedJwt2OidcIdAuthenticationConverterand complement it withReactiveJwt2OidcIdAuthenticationConverter - remove references to Keycloak from
spring-addons-oauth2(implementations where mostly useless)
- bump Keycloak BOM to 14.0.0
- bump spring-boot to 2.5
- introduce
@JsonObjectClaimand@JsonArrayClaimto configure complex private claims. Sample:@WithMockKeycloakAuth(otherClaims = @ClaimSet(jsonObjectClaims = @JsonObjectClaim(name = "foo", value = "{\"bar\":\"bad\", \"nested\":{\"deep\":\"her\"}, \"arr\":[1,2,3]}")))or@WithMockOidcId(privateClaims = @JsonObjectClaim(name = "foo", value = "{\"bar\":\"bad\", \"nested\":{\"deep\":\"her\"}, \"arr\":[1,2,3]}"))
- issue #14 added jti and nbf (from JWT spec) to @IdTokenClaims (an ID token is a JWT)
- issue #14 added session_state to @IdTokenClaims as per https://openid.net/specs/openid-connect-session-1_0.html#CreatingUpdatingSessions
- issue #14 rename
privateClaimstootherClaimsin@WithMockKeycloakAuth - issue #15
GrantedAuthoritiesMapperis now optional in test config. Defaulted toNullAuthoritiesMapper
- rename
ServletKeycloakAuthUnitTestingSupport::keycloakAuthenticationToken()toauthentication()to improve API fluidity (api.with(keycloak.authentication()).get(...))
- implementation closer to open ID specs: split claims into
@IdTokenClaimsand@OidcStandardClaims - re-use OIDC ID annotations into
@WithMockKeycloakAuth
OidcId::getName()returnssubjectclaim instead ofpreferred_username- replace
namewithsubjectin@WithMockOidcId - replace
namefrom@WithMockKeycloakAuthwithpreferedUsernamein@WithAccessToken - support for private claims in
@WithMockOidcIdand@WithMockKeycloakAuth(claims with values of typeint,long,StringandString[]only) - add missing subject claim in Keycloak access and ID tokens
- compose
@WithAccessTokenwith@WithKeycloakIDTokeninstead of repeating properties (AccessTokenextendsIDToken) - add advanced
@WithMockKeycloakAuthsample usage inspring-addons-oauth2-testREADME
- fix Keycloak typo (was wrongly spelled Keycloack at many places)
- add samples with authorities retrieved from a DB instead of the JWT for both OAuthentication and JwtAuthenticationToken
- add sample involving
keycloak-spring-boot-starterandkeycloak-spring-security-adapter
This release is still focused on unit-testing Spring OAuth2 applications
@WithMockAuthenticationannotation along withmockAuthentication()servlet (webmvc) and reactive (webflux) flow APIs. You choose theAuthenticationtype, the framework feeds the security context with a Mockito mock. This is dead simple but should cover 99% of test cases. I wonder why I didn't think of it sooner...- Focus solely on adding to Spring
Authenticationimplementations and tests tooling (no more alternatives, with an exception forOidcIdwhich overlaps Spring'sOidcIdToken) - Split
webmvc(servlets) andwebflux(reactive) code in distinct libs to ease dependency management - Re-shuffle packages and jars (less code, less jars, more expressive package names)
- WIP: Extensives samples and tests. Samples are boot apps under
src/testto keep jars small - Use Keycloak as authorisation-server for all resource-server samples, each of which configuring a specific
Authenticationimpl
Note that I chose Keycloak because it's a feature rich, easy to setup authorisation-server.
It should not be much of an effort to migrate sample resource-servers to another one, with an exception to those using KeycloakAuthenticationToken as authentication impl, of course.