Explorar el Código

Add validation for requested issuer in multitenancy how-to guide

Issue gh-663
Joe Grandja hace 1 año
padre
commit
a080cda45e

+ 6 - 0
docs/modules/ROOT/pages/guides/how-to-multitenancy.adoc

@@ -65,6 +65,8 @@ We will use the following class in each of the delegating implementations below:
 include::{examples-dir}/main/java/sample/multitenancy/TenantPerIssuerComponentRegistry.java[]
 ----
 
+<1> Component registration implicitly enables an allowlist of approved issuers that can be used.
+
 TIP: This registry is designed to allow components to be easily registered at startup to support adding tenants statically, but also supports xref:guides/how-to-multitenancy.adoc#multi-tenant-add-tenants-dynamically[adding tenants dynamically] at runtime.
 
 [[multi-tenant-create-components]]
@@ -98,6 +100,7 @@ TIP: Click on the "Expand folded text" icon in the code sample above to display
 <2> A `JdbcRegisteredClientRepository` instance mapped to issuer identifier `issuer2` and using a dedicated `DataSource`.
 <3> A composite implementation of a `RegisteredClientRepository` that delegates to a `JdbcRegisteredClientRepository` mapped to the _"requested"_ issuer identifier.
 <4> Obtain the `JdbcRegisteredClientRepository` that is mapped to the _"requested"_ issuer identifier indicated by `AuthorizationServerContext.getIssuer()`.
+<5> If unable to find `JdbcRegisteredClientRepository`, then error since the _"requested"_ issuer identifier is not in the allowlist of approved issuers.
 
 IMPORTANT: Explicitly configuring the issuer identifier via `AuthorizationServerSettings.builder().issuer("http://localhost:9000")` forces to a single-tenant configuration. Avoid explicitly configuring the issuer identifier when using a multi-tenant hosting configuration.
 
@@ -132,6 +135,7 @@ include::{examples-dir}/main/java/sample/multitenancy/OAuth2AuthorizationService
 <2> A `JdbcOAuth2AuthorizationService` instance mapped to issuer identifier `issuer2` and using a dedicated `DataSource`.
 <3> A composite implementation of an `OAuth2AuthorizationService` that delegates to a `JdbcOAuth2AuthorizationService` mapped to the _"requested"_ issuer identifier.
 <4> Obtain the `JdbcOAuth2AuthorizationService` that is mapped to the _"requested"_ issuer identifier indicated by `AuthorizationServerContext.getIssuer()`.
+<5> If unable to find `JdbcOAuth2AuthorizationService`, then error since the _"requested"_ issuer identifier is not in the allowlist of approved issuers.
 
 [[multi-tenant-oauth2-authorization-consent-service]]
 === Multi-tenant OAuth2AuthorizationConsentService
@@ -148,6 +152,7 @@ include::{examples-dir}/main/java/sample/multitenancy/OAuth2AuthorizationConsent
 <2> A `JdbcOAuth2AuthorizationConsentService` instance mapped to issuer identifier `issuer2` and using a dedicated `DataSource`.
 <3> A composite implementation of an `OAuth2AuthorizationConsentService` that delegates to a `JdbcOAuth2AuthorizationConsentService` mapped to the _"requested"_ issuer identifier.
 <4> Obtain the `JdbcOAuth2AuthorizationConsentService` that is mapped to the _"requested"_ issuer identifier indicated by `AuthorizationServerContext.getIssuer()`.
+<5> If unable to find `JdbcOAuth2AuthorizationConsentService`, then error since the _"requested"_ issuer identifier is not in the allowlist of approved issuers.
 
 [[multi-tenant-jwk-source]]
 === Multi-tenant JWKSource
@@ -164,6 +169,7 @@ include::{examples-dir}/main/java/sample/multitenancy/JWKSourceConfig.java[]
 <2> A `JWKSet` instance mapped to issuer identifier `issuer2`.
 <3> A composite implementation of an `JWKSource<SecurityContext>` that uses the `JWKSet` mapped to the _"requested"_ issuer identifier.
 <4> Obtain the `JWKSet` that is mapped to the _"requested"_ issuer identifier indicated by `AuthorizationServerContext.getIssuer()`.
+<5> If unable to find `JWKSet`, then error since the _"requested"_ issuer identifier is not in the allowlist of approved issuers.
 
 [[multi-tenant-add-tenants-dynamically]]
 == Add Tenants Dynamically

+ 5 - 4
docs/src/main/java/sample/multitenancy/JWKSourceConfig.java

@@ -19,7 +19,6 @@ import java.security.KeyPair;
 import java.security.KeyPairGenerator;
 import java.security.interfaces.RSAPrivateKey;
 import java.security.interfaces.RSAPublicKey;
-import java.util.Collections;
 import java.util.List;
 import java.util.UUID;
 
@@ -33,6 +32,7 @@ import com.nimbusds.jose.proc.SecurityContext;
 
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.util.Assert;
 
 @Configuration(proxyBeanMethods = false)
 public class JWKSourceConfig {
@@ -77,12 +77,13 @@ public class JWKSourceConfig {
 
 		@Override
 		public List<JWK> get(JWKSelector jwkSelector, SecurityContext context) throws KeySourceException {
-			JWKSet jwkSet = getJwkSet();
-			return (jwkSet != null) ? jwkSelector.select(jwkSet) : Collections.emptyList();
+			return jwkSelector.select(getJwkSet());
 		}
 
 		private JWKSet getJwkSet() {
-			return this.componentRegistry.get(JWKSet.class);	// <4>
+			JWKSet jwkSet = this.componentRegistry.get(JWKSet.class);	// <4>
+			Assert.state(jwkSet != null, "JWKSet not found for \"requested\" issuer identifier.");	// <5>
+			return jwkSet;
 		}
 
 	}

+ 9 - 13
docs/src/main/java/sample/multitenancy/OAuth2AuthorizationConsentServiceConfig.java

@@ -25,6 +25,7 @@ import org.springframework.security.oauth2.server.authorization.JdbcOAuth2Author
 import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent;
 import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
+import org.springframework.util.Assert;
 
 @Configuration(proxyBeanMethods = false)
 public class OAuth2AuthorizationConsentServiceConfig {
@@ -56,30 +57,25 @@ public class OAuth2AuthorizationConsentServiceConfig {
 
 		@Override
 		public void save(OAuth2AuthorizationConsent authorizationConsent) {
-			OAuth2AuthorizationConsentService authorizationConsentService = getAuthorizationConsentService();
-			if (authorizationConsentService != null) {
-				authorizationConsentService.save(authorizationConsent);
-			}
+			getAuthorizationConsentService().save(authorizationConsent);
 		}
 
 		@Override
 		public void remove(OAuth2AuthorizationConsent authorizationConsent) {
-			OAuth2AuthorizationConsentService authorizationConsentService = getAuthorizationConsentService();
-			if (authorizationConsentService != null) {
-				authorizationConsentService.remove(authorizationConsent);
-			}
+			getAuthorizationConsentService().remove(authorizationConsent);
 		}
 
 		@Override
 		public OAuth2AuthorizationConsent findById(String registeredClientId, String principalName) {
-			OAuth2AuthorizationConsentService authorizationConsentService = getAuthorizationConsentService();
-			return (authorizationConsentService != null) ?
-					authorizationConsentService.findById(registeredClientId, principalName) :
-					null;
+			return getAuthorizationConsentService().findById(registeredClientId, principalName);
 		}
 
 		private OAuth2AuthorizationConsentService getAuthorizationConsentService() {
-			return this.componentRegistry.get(OAuth2AuthorizationConsentService.class);	// <4>
+			OAuth2AuthorizationConsentService authorizationConsentService =
+					this.componentRegistry.get(OAuth2AuthorizationConsentService.class);	// <4>
+			Assert.state(authorizationConsentService != null,
+					"OAuth2AuthorizationConsentService not found for \"requested\" issuer identifier.");	// <5>
+			return authorizationConsentService;
 		}
 
 	}

+ 10 - 17
docs/src/main/java/sample/multitenancy/OAuth2AuthorizationServiceConfig.java

@@ -26,6 +26,7 @@ import org.springframework.security.oauth2.server.authorization.OAuth2Authorizat
 import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
 import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
+import org.springframework.util.Assert;
 
 @Configuration(proxyBeanMethods = false)
 public class OAuth2AuthorizationServiceConfig {
@@ -57,38 +58,30 @@ public class OAuth2AuthorizationServiceConfig {
 
 		@Override
 		public void save(OAuth2Authorization authorization) {
-			OAuth2AuthorizationService authorizationService = getAuthorizationService();
-			if (authorizationService != null) {
-				authorizationService.save(authorization);
-			}
+			getAuthorizationService().save(authorization);
 		}
 
 		@Override
 		public void remove(OAuth2Authorization authorization) {
-			OAuth2AuthorizationService authorizationService = getAuthorizationService();
-			if (authorizationService != null) {
-				authorizationService.remove(authorization);
-			}
+			getAuthorizationService().remove(authorization);
 		}
 
 		@Override
 		public OAuth2Authorization findById(String id) {
-			OAuth2AuthorizationService authorizationService = getAuthorizationService();
-			return (authorizationService != null) ?
-					authorizationService.findById(id) :
-					null;
+			return getAuthorizationService().findById(id);
 		}
 
 		@Override
 		public OAuth2Authorization findByToken(String token, OAuth2TokenType tokenType) {
-			OAuth2AuthorizationService authorizationService = getAuthorizationService();
-			return (authorizationService != null) ?
-					authorizationService.findByToken(token, tokenType) :
-					null;
+			return getAuthorizationService().findByToken(token, tokenType);
 		}
 
 		private OAuth2AuthorizationService getAuthorizationService() {
-			return this.componentRegistry.get(OAuth2AuthorizationService.class);	// <4>
+			OAuth2AuthorizationService authorizationService =
+					this.componentRegistry.get(OAuth2AuthorizationService.class);	// <4>
+			Assert.state(authorizationService != null,
+					"OAuth2AuthorizationService not found for \"requested\" issuer identifier.");	// <5>
+			return authorizationService;
 		}
 
 	}

+ 9 - 13
docs/src/main/java/sample/multitenancy/RegisteredClientRepositoryConfig.java

@@ -28,6 +28,7 @@ import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
 import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
+import org.springframework.util.Assert;
 
 @Configuration(proxyBeanMethods = false)
 public class RegisteredClientRepositoryConfig {
@@ -88,30 +89,25 @@ public class RegisteredClientRepositoryConfig {
 
 		@Override
 		public void save(RegisteredClient registeredClient) {
-			RegisteredClientRepository registeredClientRepository = getRegisteredClientRepository();
-			if (registeredClientRepository != null) {
-				registeredClientRepository.save(registeredClient);
-			}
+			getRegisteredClientRepository().save(registeredClient);
 		}
 
 		@Override
 		public RegisteredClient findById(String id) {
-			RegisteredClientRepository registeredClientRepository = getRegisteredClientRepository();
-			return (registeredClientRepository != null) ?
-					registeredClientRepository.findById(id) :
-					null;
+			return getRegisteredClientRepository().findById(id);
 		}
 
 		@Override
 		public RegisteredClient findByClientId(String clientId) {
-			RegisteredClientRepository registeredClientRepository = getRegisteredClientRepository();
-			return (registeredClientRepository != null) ?
-					registeredClientRepository.findByClientId(clientId) :
-					null;
+			return getRegisteredClientRepository().findByClientId(clientId);
 		}
 
 		private RegisteredClientRepository getRegisteredClientRepository() {
-			return this.componentRegistry.get(RegisteredClientRepository.class);	// <4>
+			RegisteredClientRepository registeredClientRepository =
+					this.componentRegistry.get(RegisteredClientRepository.class);	// <4>
+			Assert.state(registeredClientRepository != null,
+					"RegisteredClientRepository not found for \"requested\" issuer identifier.");	// <5>
+			return registeredClientRepository;
 		}
 
 	}

+ 1 - 1
docs/src/main/java/sample/multitenancy/TenantPerIssuerComponentRegistry.java

@@ -29,7 +29,7 @@ import org.springframework.util.Assert;
 public class TenantPerIssuerComponentRegistry {
 	private final ConcurrentMap<String, Map<Class<?>, Object>> registry = new ConcurrentHashMap<>();
 
-	public <T> void register(String tenantId, Class<T> componentClass, T component) {
+	public <T> void register(String tenantId, Class<T> componentClass, T component) {	// <1>
 		Assert.hasText(tenantId, "tenantId cannot be empty");
 		Assert.notNull(componentClass, "componentClass cannot be null");
 		Assert.notNull(component, "component cannot be null");