Skip to content

Commit

Permalink
conditional OAuth2AuthorizedClientBeans
Browse files Browse the repository at this point in the history
  • Loading branch information
ch4mpy committed Feb 10, 2024
1 parent 72efbff commit cfd6728
Show file tree
Hide file tree
Showing 15 changed files with 99 additions and 63 deletions.
4 changes: 4 additions & 0 deletions release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## `7.x` Branch

### `7.5.1`
- make `(Reactive)SpringAddonsOAuth2AuthorizedClientBeans` conditional on `com.c4-soft.springaddons.oidc.client.token-request-params` properties being present
- fix missing `SpringAddons(Reactive)JwtDecoderFactory` default bean

### `7.5.0`
- Create [spring-addons-starter-oidc README](https://github.com/ch4mpy/spring-addons/tree/master/spring-addons-starter-oidc)
- Replace `AuthoritiesMappingPropertiesResolver` with `OpenidProviderPropertiesResolver`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ spring:
provider:
keycloak:
issuer-uri: ${keycloak-issuer}
cognito:
issuer-uri: ${cognito-issuer}
auth0:
issuer-uri: ${auth0-issuer}
registration:
Expand All @@ -52,13 +50,6 @@ spring:
client-secret: ${keycloak-secret}
provider: keycloak
scope: openid,offline_access
cognito-confidential-user:
authorization-grant-type: authorization_code
client-name: Amazon Cognito
client-id: 12olioff63qklfe9nio746es9f
client-secret: ${cognito-secret}
provider: cognito
scope: openid,profile,email
auth0-confidential-user:
authorization-grant-type: authorization_code
client-name: Auth0
Expand All @@ -77,10 +68,6 @@ com:
authorities:
- path: $.realm_access.roles
- path: $.resource_access.*.roles
- iss: ${cognito-issuer}
username-claim: $.username
authorities:
- path: $.cognito:groups
- iss: ${auth0-issuer}
aud: demo.c4-soft.com
username-claim: $['https://c4-soft.com/user']['name']
Expand Down Expand Up @@ -127,6 +114,10 @@ com:
auth0-confidential-user:
- name: audience
value: demo.c4-soft.com
token-request-params:
auth0-confidential-user:
- name: audience
value: demo.c4-soft.com

logging:
level:
Expand Down
2 changes: 1 addition & 1 deletion spring-addons-starter-oidc/README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This project is a Spring Boot starter to use in addition to `spring-boot-starter

```xml
<properties>
<springaddons.version>7.5.0</springaddons.version>
<springaddons.version>7.5.1</springaddons.version>
</properties>

<dependencies>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.c4_soft.springaddons.security.oidc.starter.properties.condition;

public class HasOAuth2RegistrationPropertiesCondition extends HasPropertyPrefixCondition {

public HasOAuth2RegistrationPropertiesCondition() {
super("spring.security.oauth2.client.registration");
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.c4_soft.springaddons.security.oidc.starter.properties.condition.bean;
package com.c4_soft.springaddons.security.oidc.starter.properties.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
Expand All @@ -7,11 +7,14 @@
import org.springframework.core.env.PropertySource;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class HasOAuth2RegistrationPropertiesCondition implements Condition {
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class HasPropertyPrefixCondition implements Condition {
private final String prefix;

@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
final String prefix = "spring.security.oauth2.client.registration";
if (context.getEnvironment() instanceof ConfigurableEnvironment env) {
for (PropertySource<?> propertySource : env.getPropertySources()) {
if (propertySource instanceof EnumerablePropertySource enumerablePropertySource) {
Expand All @@ -25,4 +28,4 @@ public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata)
}
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.c4_soft.springaddons.security.oidc.starter.properties.condition;

public class HasTokenEdpointParametersPropertiesCondition extends HasPropertyPrefixCondition {

public HasTokenEdpointParametersPropertiesCondition() {
super("com.c4-soft.springaddons.oidc.client.token-request-params");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import org.springframework.context.annotation.Conditional;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;

import com.c4_soft.springaddons.security.oidc.starter.properties.condition.HasOAuth2RegistrationPropertiesCondition;

public class DefaultOAuth2AuthorizedClientManagerCondition extends AllNestedConditions {

public DefaultOAuth2AuthorizedClientManagerCondition() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import org.springframework.context.annotation.Conditional;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider;

import com.c4_soft.springaddons.security.oidc.starter.properties.condition.HasOAuth2RegistrationPropertiesCondition;

public class DefaultOAuth2AuthorizedClientProviderCondition extends AllNestedConditions {

public DefaultOAuth2AuthorizedClientProviderCondition() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import org.springframework.context.annotation.Conditional;
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager;

import com.c4_soft.springaddons.security.oidc.starter.properties.condition.HasOAuth2RegistrationPropertiesCondition;

public class DefaultReactiveOAuth2AuthorizedClientManagerCondition extends AllNestedConditions {

public DefaultReactiveOAuth2AuthorizedClientManagerCondition() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import org.springframework.context.annotation.Conditional;
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientProvider;

import com.c4_soft.springaddons.security.oidc.starter.properties.condition.HasOAuth2RegistrationPropertiesCondition;

public class DefaultReactiveOAuth2AuthorizedClientProviderCondition extends AllNestedConditions {

public DefaultReactiveOAuth2AuthorizedClientProviderCondition() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,33 +13,34 @@
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;

import com.c4_soft.springaddons.security.oidc.starter.properties.SpringAddonsOidcProperties;
import com.c4_soft.springaddons.security.oidc.starter.properties.condition.HasTokenEdpointParametersPropertiesCondition;
import com.c4_soft.springaddons.security.oidc.starter.properties.condition.bean.DefaultReactiveOAuth2AuthorizedClientManagerCondition;
import com.c4_soft.springaddons.security.oidc.starter.properties.condition.bean.DefaultReactiveOAuth2AuthorizedClientProviderCondition;
import com.c4_soft.springaddons.security.oidc.starter.properties.condition.configuration.IsReactiveOauth2ClientCondition;

@Conditional(IsReactiveOauth2ClientCondition.class)
@Conditional({ IsReactiveOauth2ClientCondition.class, HasTokenEdpointParametersPropertiesCondition.class })
@AutoConfiguration
public class ReactiveSpringAddonsOAuth2AuthorizedClientBeans {

@Conditional(DefaultReactiveOAuth2AuthorizedClientManagerCondition.class)
@Bean
ReactiveOAuth2AuthorizedClientManager authorizedClientManager(
ReactiveClientRegistrationRepository clientRegistrationRepository,
ServerOAuth2AuthorizedClientRepository authorizedClientRepository,
ReactiveOAuth2AuthorizedClientProvider oauth2AuthorizedClientProvider) {

final var authorizedClientManager = new DefaultReactiveOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(oauth2AuthorizedClientProvider);

return authorizedClientManager;
}

@Conditional(DefaultReactiveOAuth2AuthorizedClientProviderCondition.class)
@Bean
ReactiveOAuth2AuthorizedClientProvider oauth2AuthorizedClientProvider(
SpringAddonsOidcProperties addonsProperties,
InMemoryReactiveClientRegistrationRepository clientRegistrationRepository) {
return new PerRegistrationReactiveOAuth2AuthorizedClientProvider(clientRegistrationRepository, addonsProperties, Map.of());
}
@Conditional(DefaultReactiveOAuth2AuthorizedClientManagerCondition.class)
@Bean
ReactiveOAuth2AuthorizedClientManager authorizedClientManager(
ReactiveClientRegistrationRepository clientRegistrationRepository,
ServerOAuth2AuthorizedClientRepository authorizedClientRepository,
ReactiveOAuth2AuthorizedClientProvider oauth2AuthorizedClientProvider) {

final var authorizedClientManager = new DefaultReactiveOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(oauth2AuthorizedClientProvider);

return authorizedClientManager;
}

@Conditional(DefaultReactiveOAuth2AuthorizedClientProviderCondition.class)
@Bean
ReactiveOAuth2AuthorizedClientProvider oauth2AuthorizedClientProvider(
SpringAddonsOidcProperties addonsProperties,
InMemoryReactiveClientRegistrationRepository clientRegistrationRepository) {
return new PerRegistrationReactiveOAuth2AuthorizedClientProvider(clientRegistrationRepository, addonsProperties, Map.of());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,12 @@ ResourceServerReactiveHttpSecurityPostProcessor httpPostProcessor() {
return serverHttpSecurity -> serverHttpSecurity;
}

@ConditionalOnMissingBean
@Bean
SpringAddonsReactiveJwtDecoderFactory springAddonsJwtDecoderFactory() {
return new DefaultSpringAddonsReactiveJwtDecoderFactory();
}

/**
* Provides with multi-tenancy: builds a ReactiveAuthenticationManagerResolver per provided OIDC issuer URI
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@

import com.c4_soft.springaddons.security.oidc.starter.OpenidProviderPropertiesResolver;
import com.c4_soft.springaddons.security.oidc.starter.synchronised.resourceserver.JWTClaimsSetAuthenticationManager.JWTClaimsSetAuthenticationManagerResolver;
import com.c4_soft.springaddons.security.oidc.starter.synchronised.resourceserver.SpringAddonsJwtDecoderFactory;

import reactor.core.publisher.Mono;

/**
* <p>
* An {@link ReactiveAuthenticationManagerResolver} always resolving the same {@link ReactiveJWTClaimsSetAuthenticationManager} which relies on
* {@link JWTClaimsSetAuthenticationManagerResolver}, itself using {@link SpringAddonsJwtDecoderFactory} and a {@link Converter Converter@lt;Jwt,
* {@link JWTClaimsSetAuthenticationManagerResolver}, itself using {@link SpringAddonsReactiveJwtDecoderFactory} and a {@link Converter Converter@lt;Jwt,
* AbstractAuthenticationToken&gt;}.
* </p>
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,31 +13,33 @@
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;

import com.c4_soft.springaddons.security.oidc.starter.properties.SpringAddonsOidcProperties;
import com.c4_soft.springaddons.security.oidc.starter.properties.condition.HasTokenEdpointParametersPropertiesCondition;
import com.c4_soft.springaddons.security.oidc.starter.properties.condition.bean.DefaultOAuth2AuthorizedClientManagerCondition;
import com.c4_soft.springaddons.security.oidc.starter.properties.condition.bean.DefaultOAuth2AuthorizedClientProviderCondition;
import com.c4_soft.springaddons.security.oidc.starter.properties.condition.configuration.IsServletOauth2ClientCondition;

@Conditional(IsServletOauth2ClientCondition.class)
@Conditional({ IsServletOauth2ClientCondition.class, HasTokenEdpointParametersPropertiesCondition.class })
@AutoConfiguration
public class SpringAddonsOAuth2AuthorizedClientBeans {

@Conditional(DefaultOAuth2AuthorizedClientManagerCondition.class)
@Bean
OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository,
OAuth2AuthorizedClientProvider oauth2AuthorizedClientProvider) {

final var authorizedClientManager = new DefaultOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(oauth2AuthorizedClientProvider);

return authorizedClientManager;
}

@Conditional(DefaultOAuth2AuthorizedClientProviderCondition.class)
@Bean
OAuth2AuthorizedClientProvider
oauth2AuthorizedClientProvider(SpringAddonsOidcProperties addonsProperties, InMemoryClientRegistrationRepository clientRegistrationRepository) {
return new PerRegistrationOAuth2AuthorizedClientProvider(clientRegistrationRepository, addonsProperties, Map.of());
}
@Conditional(DefaultOAuth2AuthorizedClientManagerCondition.class)
@Bean
OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository,
OAuth2AuthorizedClientProvider oauth2AuthorizedClientProvider) {

final var authorizedClientManager = new DefaultOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(oauth2AuthorizedClientProvider);

return authorizedClientManager;
}

@Conditional(DefaultOAuth2AuthorizedClientProviderCondition.class)
@Bean
OAuth2AuthorizedClientProvider oauth2AuthorizedClientProvider(
SpringAddonsOidcProperties addonsProperties,
InMemoryClientRegistrationRepository clientRegistrationRepository) {
return new PerRegistrationOAuth2AuthorizedClientProvider(clientRegistrationRepository, addonsProperties, Map.of());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@
* configuration. It applies to all routes not listed in "permit-all" property configuration. Default requires users to be authenticated. <b>This is a bean to
* provide in your application configuration if you prefer to define fine-grained access control rules with Java configuration rather than methods
* security.</b></li>
* <li>httpPostProcessor: a bean of type {@link ResourceServerSynchronizedHttpSecurityPostProcessor} to override anything from above auto-configuration. It is called just
* before the security filter-chain is returned. Default is a no-op.</li>
* <li>httpPostProcessor: a bean of type {@link ResourceServerSynchronizedHttpSecurityPostProcessor} to override anything from above auto-configuration. It is
* called just before the security filter-chain is returned. Default is a no-op.</li>
* <li>jwtAuthenticationConverter: a converter from a {@link Jwt} to something inheriting from {@link AbstractAuthenticationToken}. The default instantiate a
* {@link JwtAuthenticationToken} with username and authorities as configured for the issuer of thi token. The easiest to override the type of
* {@link AbstractAuthenticationToken}, is to provide with an Converter&lt;Jwt, ? extends AbstractAuthenticationToken&gt; bean.</li>
Expand Down Expand Up @@ -183,6 +183,12 @@ ResourceServerSynchronizedHttpSecurityPostProcessor httpPostProcessor() {
return httpSecurity -> httpSecurity;
}

@ConditionalOnMissingBean
@Bean
SpringAddonsJwtDecoderFactory springAddonsJwtDecoderFactory() {
return new DefaultSpringAddonsJwtDecoderFactory();
}

/**
* Provides with multi-tenancy: builds a AuthenticationManagerResolver<HttpServletRequest> per provided OIDC issuer URI
*
Expand Down

0 comments on commit cfd6728

Please sign in to comment.