There is a braking change in starters properties in 6.1.0. Authorities-mapping configuration has changed. See Release Notes.
The OAuth2 client features introduced with 6.1 (boot starters & tutorials) are getting mature. Usage is illustrated in BFF and Resource Server & Client tutorials. It comes with pretty cool features like RP-Initiated Logout for "almost" standard OPs (like Auth0 or Cognito) and also Back-Channel Logout implementation.
@WithMockKeycloakAuth
, to be used with the deprecated Keycloak libs for spring, is not provided any-more in 6.x (it is still available from 5.x): Keycloak libs are too far behind. Generic OpenID resource-server starters from this lib have been used with Keycloak for more than two years now, including in production.
Do not hesitate to fork this repo and send pull requests, even for things as small as a typo in READMEs or Javadoc. This would promote you as contributor.
The libraries hosted in this repo shine in two domains:
- provide with annotations to mock OAuth2
Authentication
during tests (@WithMockJwtAuth
,@WithOAuth2Login
,@WithMockBearerTokenAuthentication
, etc.), which allow to test method security on any@Component
. Details below. - push Spring Boot OAuth2 auto-configuration to the next level. As shown in Tutorials, with 0 Java conf (just properties), we can configure a REST API (servlet or reactive) or an OAuth2 client (servlet or reactive, including
spring-cloud-gateway
used as BFF) with:- authorities mapping (source claims, prefix and case transformation), without having to provide authentication converter, user service or
GrantedAuthoritiesMapper
in each app - fine grained CORS configuration (per path matcher), which enables to override allowed origins as environment variable when switching from
localhost
todev
orprod
environments - sessions & CSRF disabled by default on resource server and enabled on clients. If a cookie repo is chosen for CSRF (as required by Angular, React, Vue, etc.), then the right request handler is configured and a filter to actually set the cookie is added
- basic access control:
permitAll
for a list of path matchers andauthenticated
as default (to be fine tuned with method security or a configuration post-processor bean) - for clients only:
- logout success handler for OPs not strictly following the standard (exotic parameter names or missing
end_session_endpoint
in OpenID configuration). Auth0 and Amazon Cognito are samples of such OPs. - an implementation for client side of the Back-Channel Logout
- client host and port explicitly provided in login configuration to avoid redirection issues when the client does not use 8080 (or 8443 if SSL is enabled)
- logout success handler for OPs not strictly following the standard (exotic parameter names or missing
- authorities mapping (source claims, prefix and case transformation), without having to provide authentication converter, user service or
Jump to:
- 1. Unit & Integration Testing With Security
- 2. Spring Boot OAuth2 Starters
- 3. Where to Start
- 4. Versions & Requirements
- 5. Additional Modules
- 6. Release Notes
- 7. Maven-Central Reminders
Testing method security (@PreAuthorize
, @PostFilter
, etc.) requires to configure the security context. Spring-security-test
provides with MockMvc
request post-processors and WebTestClient
mutators to to do so, but this requires the context of a request, which limits its usage to testing secured controllers.
To test method security on any type of @Component
(@Controller
, off course, but also @Service
and @Repository
) there are only two options: build tests security context by yourself and populate it with stubbed / mocked authentications, or use annotations.
An article covering the usage of OAuth2 test annotations from this lib was published on Baeldung. This, along with all samples and tutorials source-code (which contain a lot of unit and integration testing), should be enough to get you started.
This repo contains thin wrappers around spring-boot-starter-oauth2-resource-server
or spring-boot-starter-oauth2-client
:
- spring-addons-webflux-client to be used in reactive applications rendering templates on the server (Thymeleaf, JSF, etc.), or in
spring-cloud-gateway
used as BFF (server-side OAuth2 confidential client securing a browser application with sessions and replacing session cookies with OAuth2 access tokens before forwarding requests from browsers to resource servers) - spring-addons-webflux-introspecting-resource-server to be used in reactive REST APIs secured with access token introspection
- spring-addons-webflux-jwt-resource-server to be used in reactive REST APIs secured with JWT decoders
- spring-addons-webmvc-client to be used in servlet applications rendering templates on the server (Thymeleaf, JSF, etc.)
- spring-addons-webmvc-introspecting-resource-server to be used in servlet REST APIs secured with access token introspection
- spring-addons-webmvc-jwt-resource-server to be used in servlet REST APIs secured with JWT decoders
This starters are designed to push auto-configuration one step further. In most cases, you should need 0 Java conf. An effort was made to make tutorials, Javadoc and modules READMEs as informative as possible. Please refer there for more details.
Tutorials which cover:
- just enough OAuth2 theory
- dev environment configuration (SSL certificate, Keycloak)
- various resource-servers security configuration scenarios
- security rules unit-testing
Samples cover:
@Controller
,@Service
and@Repository
unit testing- integration testing (
@SpringBootTest
) with mocked authentication - all combinations with choices from the following 3 points:
- webmvc / webflux
- JWT decoder / access token introspection
OAuthentication<OpenidClaimSet>
/ Spring defaultAuthentication
implementation (JwtAuthenticationToken
for JWT decoder orBearerTokenAuthentication
for token introspection)
6.x branch is designed for spring-boot 3 and requires JDK 17 as minimum.
If locked wtih a lower JDK or spring-boot version, you'll have to use a 5.4.x release wich are made with JDK 1.8 and spring 2.6 (boot auto loading mechanisms have change with 2.7). But be aware that some of the features documented on main branch can be missing or behave differently.
I could forget to update README before releasing, so please refer to maven central to pick latest available release
<properties>
<springaddons.version>6.1.7</springaddons.version>
<app-type>webmvc</app-type><!-- alternative value is webflux !-->
<token>jwt</token><!-- alternative value is introspecting !-->
</properties>
<dependencies>
<!-- to pull resource-server stater with its companion for unit-tests -->
<dependency>
<groupId>com.c4-soft.springaddons</groupId>
<artifactId>spring-addons-${app-type}-${token}-resource-server</artifactId>
<version>${springaddons.version}</version>
</dependency>
<dependency>
<groupId>com.c4-soft.springaddons</groupId>
<artifactId>spring-addons-${app-type}-${token}-test</artifactId>
<version>${springaddons.version}</version>
<scope>test</scope>
</dependency>
<!-- If you don't want starters but need @WithMockJwtAuth or WithMockBearerTokenAuthentication -->
<!-- instead of the two preceding, you can pull test annotations only -->
<dependency>
<groupId>com.c4-soft.springaddons</groupId>
<artifactId>spring-addons-oauth2-test</artifactId>
<version>${springaddons.version}</version>
</dependency>
</dependencies>
5.1. archetypes
A set of archetypes for webflux and webmvc apps, initiated either as multi or single module maven projects. All generate projects focused on REST micro-services:
- Servlet or reactive @RestController
- OpenID security
- default conf providing with enabled CORS, "stateless" sessions (user "session" state in access token only), disabled CSRF (because no session on the resource-server), 401 instead of redirect to login, ...
- Spring exception-handling
- spring-native for smaller / faster booted services
- bootstraped JPA and unit tests
5.2. starters
A set of re-usable @Components
(mostly @Service
and @ConfigurationProperties
) with spring-boot @AutoConfiguration
:
- WebClient.Builder factory with proxy configuration from properties
- reCAPTCHA Uses Webclient starter to provide with Google reCAPTCHA validation Service (secret & proxy configuration from properties)
Using such libs is dead simple: just declare depedency on one of those libs and use @Components just as if were declared in your app package (define properties and auto-wire components as usual in your boot project).
2.0 comes with a noticeable amount of breaking changes. So lets start tracking features.
- create
ServletConfigurationSupport
andReactiveConfigurationSupport
inspring-addons-{webmvc|webflux}-core
to remove code duplication from starters
- add new helpers to type private claims in test annotations for
Double
,URIs
,URLs
andDate
- 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@JsonObjectClaim
with 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/spring-addons",
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_ui
tutorial 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_
forscope
claim andROLE_
forrealm_access.roles
one). As a consequence,com.c4-soft.springaddons.security.issuers[].authorities.claims[]
is replaced withcom.c4-soft.springaddons.security.issuers[].authorities[].path
.Also,prefix
as well ascase
are 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.roles
Becomes:
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.*.roles
will be successfully accepted. Thanks to JSON path syntax, this is not a breaking change ($.resource_access.client1.roles
andresource_access.client1.roles
are interpreted the same) - bump to Spring Boot 3.0.3
- Add a
username-clame
configuration 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
ServerHttpRequestSupport
andHttpServletRequestSupport
to help statically access to the request in current context (usage in authentication converters for instance
- add
@WithOAuth2Login
and@WithOidcLogin
to populate test security-context with anOAuth2AuthenticationToken
instance (with respectivelyDefaultOAuth2User
andDefaultOidcUser
as principal) - bump to spring-boot
3.0.2
- default authorities collection in tests annotations,
MockMvc
post-processors andWebTestClient
mutators is set to empty array (instead of{ "ROLE_USER" }
)
- gh-86
OAuthentication::setDetails
should 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-uri
is 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 defaultAuthentication
implementation (JwtAuthenticationToken
for JWT decoder orBearerTokenAuthentication
for 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
- Use a single bean name for
ServletSecurityBeans
andReactiveSecurityBeans
: AddonsSecurityBeans@AutoConfigureAddonsSecurity{Webmvc|Weblux}{Jwt|Introspecting}
:@AutoConfigureAddonsSecurity
- Add
@AutoConfigureAddonsWebSecurity
to do the same as existing@AutoConfigureAddonsSecurity
which 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
@Bean
optional. - remove
OAuth2ClaimsConverter
(interface definition and @ConditionalOnMissingBean) - remove the recently added
oauth2-authentication-factory-enabled
property (instead, evaluate if anOAuth2AuthenticationFactory
bean 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-enabled
flag to easily fall-back to Spring default OAuth2Authentication
implementations (JwtAuthenticationToken
andBearerTokenAuthentication
for 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-test
tospring-addons-*-test
as it apply for both JWT and introspection
Rename modules to:
- have all module names start with
spring-addons
prefix, then intermediate module if any (archetypes
,samples
,starters
,webmvc
orwebflux
) and last what leaf module aims at - better reflect what it do
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
OpenidClaimSet
toOpenidClaimSet
: more expressive as this class contains OpenID token claims only - rename
OAuthentication
toOAuthentication
: 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 list
where caze
is one of unchanged
, upper
or lower
- gh-50: One entry per authorization-server for authorities mapping (see samples
application.properties
files 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
samples
module, 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
SecurityFilterChain
bean 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.8
andjdk11
branches
- Add spring-addons-archetypes-webmvc-multimodule to boostrap native-ready Spring REST API with webmvc, JPA, OpenAPI and OpenID security.
- Add a sample with
OpenidClaimSet
specialisation (parse private claims in addition to authorities).
- Improve
OidcReactiveApiSecurityConfig
andOidcServletApiSecurityConfig
usability: ease security beans replacement (including authorities and authentication converter for use cases where OAuthentication is not enough)
- Rename
SecurityProperties
to less conflictingSpringAddonsSecurityProperties
- Turn
AbstractOidc...ApiSecurityConfig
intoOidc...ApiSecurityConfig
with default authorities mapper being keycloak or Auth0 depending oncom.c4-soft.springaddons.security.keycloak.client-id
being set or not - More CORS and authorities mapping configuration in
SecurityProperties
- Fix missing JTI claim mapping from
@OpenIdClaims
(gh-35).
- Add
AbstractOidcReactiveApiSecurityConfig
tospring-addons-oauth2
. It provides with reasonable default WebSecurityConfig for a reactive (weblux) based API secured with OAuthentication.
- Add
AbstractOidcServletApiSecurityConfig
tospring-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(...)
@WithMockJwtAuth
in addition to@WithMockKeycloakAuth
and@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
KeycloakOidcIdAuthenticationConverter
withSynchronizedJwt2OidcIdAuthenticationConverter
and 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
@JsonObjectClaim
and@JsonArrayClaim
to 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
privateClaims
tootherClaims
in@WithMockKeycloakAuth
- issue #15
GrantedAuthoritiesMapper
is 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
@IdTokenClaims
and@OidcStandardClaims
- re-use OIDC ID annotations into
@WithMockKeycloakAuth
OidcId::getName()
returnssubject
claim instead ofpreferred_username
- replace
name
withsubject
in@WithMockOidcId
- replace
name
from@WithMockKeycloakAuth
withpreferedUsername
in@WithAccessToken
- support for private claims in
@WithMockOidcId
and@WithMockKeycloakAuth
(claims with values of typeint
,long
,String
andString[]
only) - add missing subject claim in Keycloak access and ID tokens
- compose
@WithAccessToken
with@WithKeycloakIDToken
instead of repeting properties (AccessToken
extendsIDToken
) - add advanced
@WithMockKeycloakAuth
sample usage inspring-addons-oauth2-test
README
- fix Keycloak typo (was wrongly spelled Keycloack at many places)
- add samples with authrities retieved from a DB instead of the JWT for both OAuthentication and JwtAuthenticationToken
- add sample involving
keycloak-spring-boot-starter
andkeycloak-spring-security-adapter
These release is still focused on unit-testing Spring OAuth2 applications
@WithMockAuthentication
annotation along withmockAuthentication()
servlet (webmvc) and reactive (webflux) flow APIs. You choose theAuthentication
type, 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
Authentication
implementations and tests tooling (no more alternatives, with an exception forOidcId
which 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/test
to keep jars small - Use Keycloak as authorisation-server for all resource-server samples, each of which configuring a specific
Authentication
impl
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 of those using KeycloakAuthenticationToken
as authentication impl, of course.
Cheat-sheets for me when setting up a new development environment
gpg --list-keys
# if key absent, then generate one with
gpg --gen-key
# publish public key to one of supported servers
export GPG_PUB_KEY=(replace with "pub" key)
gpg --keyserver http://pgp.mit.edu:11371/ --send-keys $GPG_PUB_KEY
gpg --keyserver http://keyserver.ubuntu.com:11371/ --send-keys $GPG_PUB_KEY
gpg --keyserver https://keys.openpgp.org/ --send-keys $GPG_PUB_KEY
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<servers>
<server>
<!-- OSSRH Jira account -->
<id>ossrh</id>
<username>ch4mpy</username>
<password>${env.OSSRH_PWD}</password><!-- password retrieved from environment variable -->
</server>
</servers>
<profiles>
<profile>
<id>ossrh</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<gpg.executable>gpg</gpg.executable>
<gpg.passphrase>${env.GPG_PWD}</gpg.passphrase><!-- password retrieved from environment variable -->
</properties>
</profile>
</profiles>
</settings>
Add-opens for releasing with JDK 17:
export JDK_JAVA_OPTIONS='--add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.base/java.text=ALL-UNNAMED --add-opens java.desktop/java.awt.font=ALL-UNNAMED'