Bläddra i källkod

Polish gh-1376

Joe Grandja 1 år sedan
förälder
incheckning
74058e555c

+ 13 - 21
docs/modules/ROOT/pages/guides/how-to-dynamic-client-registration.adoc

@@ -23,32 +23,24 @@ To enable, add the following configuration:
 include::{examples-dir}/main/java/sample/registration/SecurityConfig.java[]
 include::{examples-dir}/main/java/sample/registration/SecurityConfig.java[]
 ----
 ----
 
 
-<1> Enable the xref:protocol-endpoints.adoc#oidc-client-registration-endpoint[OpenID Connect 1.0 Client Registration Endpoint] with client registration endpoint authentication providers for providing custom metadata. Providing custom metadata is optional.
+<1> Enable the xref:protocol-endpoints.adoc#oidc-client-registration-endpoint[OpenID Connect 1.0 Client Registration Endpoint] with the default configuration.
+<2> Optionally, customize the default ``AuthenticationProvider``'s to support custom client metadata parameters.
 
 
-In order to accept custom client metadata when registering a client, a few additional implementation details
-are necessary.
+In order to support custom client metadata parameters when registering a client, a few additional implementation details are required.
 
 
-[NOTE]
-====
-The following example depicts custom metadata `logo_uri` (string type) and `contacts` (string array type)
-====
-
-Create a set of custom `Converter` classes in order to retain custom client claims.
+The following example shows a sample implementation of ``Converter``'s that support custom client metadata parameters (`logo_uri` and `contacts`) and are configured in `OidcClientRegistrationAuthenticationProvider` and `OidcClientConfigurationAuthenticationProvider`.
 
 
-[[sample.CustomMetadataConfig]]
+[[sample.CustomClientMetadataConfig]]
 [source,java]
 [source,java]
 ----
 ----
-include::{examples-dir}/main/java/sample/registration/CustomMetadataConfig.java[]
+include::{examples-dir}/main/java/sample/registration/CustomClientMetadataConfig.java[]
 ----
 ----
 
 
-<1> Create a `Consumer<List<AuthenticationProvider>>` implementation.
-<2> Identify custom fields that should be accepted during client registration.
-<3> Filter for `OidcClientRegistrationAuthenticationProvider` and `OidcClientConfigurationAuthenticationProvider` instances.
-<4> Add a custom registered client `Converter` (implementation in #7)
-<5> Add a custom client registration `Converter` to `OidcClientRegistrationAuthenticationProvider` (implementation in #8)
-<6> Add a custom client registration `Converter` to `OidcClientConfigurationAuthenticationProvider` (implementation in #8)
-<7> Custom registered client `Converter` implementation that adds custom claims to registered client settings.
-<8> Custom client registration `Converter` implementation that modifies client registration claims with custom metadata.
+<1> Define a `Consumer<List<AuthenticationProvider>>` providing the ability to customize the default ``AuthenticationProvider``'s.
+<2> Define custom client metadata parameters that are supported for client registration.
+<3> Configure `OidcClientRegistrationAuthenticationProvider.setRegisteredClientConverter()` with a `CustomRegisteredClientConverter`.
+<4> Configure `OidcClientRegistrationAuthenticationProvider.setClientRegistrationConverter()` with a `CustomClientRegistrationConverter`.
+<5> Configure `OidcClientConfigurationAuthenticationProvider.setClientRegistrationConverter()` with a `CustomClientRegistrationConverter`.
 
 
 [[configure-client-registrar]]
 [[configure-client-registrar]]
 == Configure client registrar
 == Configure client registrar
@@ -114,8 +106,8 @@ After the client is registered, the access token is invalidated.
 include::{examples-dir}/main/java/sample/registration/ClientRegistrar.java[]
 include::{examples-dir}/main/java/sample/registration/ClientRegistrar.java[]
 ----
 ----
 
 
-<1> A minimal representation of a client registration request. You may add additional client metadata parameters as per https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationRequest[Client Registration Request]. This example request contains custom metadata fields `logo_uri` and `contacts`.
-<2> A minimal representation of a client registration response. You may add additional client metadata parameters as per https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationResponse[Client Registration Response]. This example response contains custom metadata fields `logo_uri` and `contacts`.
+<1> A minimal representation of a client registration request. You may add additional client metadata parameters as per https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationRequest[Client Registration Request]. This example request contains custom client metadata parameters `logo_uri` and `contacts`.
+<2> A minimal representation of a client registration response. You may add additional client metadata parameters as per https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationResponse[Client Registration Response]. This example response contains custom client metadata parameters `logo_uri` and `contacts`.
 <3> Example demonstrating client registration and client retrieval.
 <3> Example demonstrating client registration and client retrieval.
 <4> A sample client registration request object.
 <4> A sample client registration request object.
 <5> Register the client using the "initial" access token and client registration request object.
 <5> Register the client using the "initial" access token and client registration request object.

+ 1 - 1
docs/src/main/java/sample/registration/ClientRegistrar.java

@@ -78,7 +78,7 @@ public class ClientRegistrar {
 		assert (clientRegistrationResponse.redirectUris().contains("https://client.example.org/callback2"));
 		assert (clientRegistrationResponse.redirectUris().contains("https://client.example.org/callback2"));
 		assert (!clientRegistrationResponse.registrationAccessToken().isEmpty());
 		assert (!clientRegistrationResponse.registrationAccessToken().isEmpty());
 		assert (!clientRegistrationResponse.registrationClientUri().isEmpty());
 		assert (!clientRegistrationResponse.registrationClientUri().isEmpty());
-		assert (clientRegistrationResponse.logoUri().contentEquals("https://client.example.org/logo")); // <6>
+		assert (clientRegistrationResponse.logoUri().contentEquals("https://client.example.org/logo"));
 		assert (clientRegistrationResponse.contacts().size() == 2);
 		assert (clientRegistrationResponse.contacts().size() == 2);
 		assert (clientRegistrationResponse.contacts().contains("contact-1"));
 		assert (clientRegistrationResponse.contacts().contains("contact-1"));
 		assert (clientRegistrationResponse.contacts().contains("contact-2"));
 		assert (clientRegistrationResponse.contacts().contains("contact-2"));

+ 46 - 39
docs/src/main/java/sample/registration/CustomMetadataConfig.java → docs/src/main/java/sample/registration/CustomClientMetadataConfig.java

@@ -15,6 +15,13 @@
  */
  */
 package sample.registration;
 package sample.registration;
 
 
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
 import org.springframework.core.convert.converter.Converter;
 import org.springframework.core.convert.converter.Converter;
 import org.springframework.security.authentication.AuthenticationProvider;
 import org.springframework.security.authentication.AuthenticationProvider;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
@@ -26,84 +33,84 @@ import org.springframework.security.oauth2.server.authorization.oidc.converter.R
 import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
 import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.CollectionUtils;
 
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.stream.Collectors;
+public class CustomClientMetadataConfig {
 
 
-public class CustomMetadataConfig {
-	public static Consumer<List<AuthenticationProvider>> registeredClientConverters() {
-		List<String> customClientMetadata = List.of("logo_uri", "contacts"); // <1>
+	public static Consumer<List<AuthenticationProvider>> configureCustomClientMetadataConverters() {	// <1>
+		List<String> customClientMetadata = List.of("logo_uri", "contacts");	// <2>
 
 
-		return authenticationProviders -> // <2>
-		{
-			CustomRegisteredClientConverter registeredClientConverter = new CustomRegisteredClientConverter(customClientMetadata);
-			CustomClientRegistrationConverter clientRegistrationConverter = new CustomClientRegistrationConverter(customClientMetadata);
+		return (authenticationProviders) -> {
+			CustomRegisteredClientConverter registeredClientConverter =
+					new CustomRegisteredClientConverter(customClientMetadata);
+			CustomClientRegistrationConverter clientRegistrationConverter =
+					new CustomClientRegistrationConverter(customClientMetadata);
 
 
-			authenticationProviders.forEach(authenticationProvider -> {
-				if (authenticationProvider instanceof OidcClientRegistrationAuthenticationProvider provider) { // <3>
-					provider.setRegisteredClientConverter(registeredClientConverter); // <4>
-					provider.setClientRegistrationConverter(clientRegistrationConverter); // <5>
+			authenticationProviders.forEach((authenticationProvider) -> {
+				if (authenticationProvider instanceof OidcClientRegistrationAuthenticationProvider provider) {
+					provider.setRegisteredClientConverter(registeredClientConverter);	// <3>
+					provider.setClientRegistrationConverter(clientRegistrationConverter);	// <4>
 				}
 				}
-
 				if (authenticationProvider instanceof OidcClientConfigurationAuthenticationProvider provider) {
 				if (authenticationProvider instanceof OidcClientConfigurationAuthenticationProvider provider) {
-					provider.setClientRegistrationConverter(clientRegistrationConverter); // <6>
+					provider.setClientRegistrationConverter(clientRegistrationConverter);	// <5>
 				}
 				}
 			});
 			});
 		};
 		};
 	}
 	}
 
 
-	static class CustomRegisteredClientConverter implements Converter<OidcClientRegistration, RegisteredClient> { // <7>
-		private final List<String> customMetadata;
+	private static class CustomRegisteredClientConverter
+			implements Converter<OidcClientRegistration, RegisteredClient> {
 
 
+		private final List<String> customClientMetadata;
 		private final OidcClientRegistrationRegisteredClientConverter delegate;
 		private final OidcClientRegistrationRegisteredClientConverter delegate;
 
 
-		CustomRegisteredClientConverter(List<String> customMetadata) {
-			this.customMetadata = customMetadata;
+		private CustomRegisteredClientConverter(List<String> customClientMetadata) {
+			this.customClientMetadata = customClientMetadata;
 			this.delegate = new OidcClientRegistrationRegisteredClientConverter();
 			this.delegate = new OidcClientRegistrationRegisteredClientConverter();
 		}
 		}
 
 
+		@Override
 		public RegisteredClient convert(OidcClientRegistration clientRegistration) {
 		public RegisteredClient convert(OidcClientRegistration clientRegistration) {
-			RegisteredClient convertedClient = delegate.convert(clientRegistration);
-			ClientSettings.Builder clientSettingsBuilder = ClientSettings
-					.withSettings(convertedClient.getClientSettings().getSettings());
-
-			if (!CollectionUtils.isEmpty(this.customMetadata)) {
+			RegisteredClient registeredClient = this.delegate.convert(clientRegistration);
+			ClientSettings.Builder clientSettingsBuilder = ClientSettings.withSettings(
+					registeredClient.getClientSettings().getSettings());
+			if (!CollectionUtils.isEmpty(this.customClientMetadata)) {
 				clientRegistration.getClaims().forEach((claim, value) -> {
 				clientRegistration.getClaims().forEach((claim, value) -> {
-					if (this.customMetadata.contains(claim)) {
+					if (this.customClientMetadata.contains(claim)) {
 						clientSettingsBuilder.setting(claim, value);
 						clientSettingsBuilder.setting(claim, value);
 					}
 					}
 				});
 				});
 			}
 			}
 
 
-			return RegisteredClient.from(convertedClient).clientSettings(clientSettingsBuilder.build()).build();
+			return RegisteredClient.from(registeredClient)
+					.clientSettings(clientSettingsBuilder.build())
+					.build();
 		}
 		}
 	}
 	}
 
 
-	static class CustomClientRegistrationConverter implements Converter<RegisteredClient, OidcClientRegistration> { // <8>
-		private final List<String> customMetadata;
+	private static class CustomClientRegistrationConverter
+			implements Converter<RegisteredClient, OidcClientRegistration> {
 
 
+		private final List<String> customClientMetadata;
 		private final RegisteredClientOidcClientRegistrationConverter delegate;
 		private final RegisteredClientOidcClientRegistrationConverter delegate;
 
 
-		CustomClientRegistrationConverter(List<String> customMetadata) {
-			this.customMetadata = customMetadata;
+		private CustomClientRegistrationConverter(List<String> customClientMetadata) {
+			this.customClientMetadata = customClientMetadata;
 			this.delegate = new RegisteredClientOidcClientRegistrationConverter();
 			this.delegate = new RegisteredClientOidcClientRegistrationConverter();
 		}
 		}
 
 
+		@Override
 		public OidcClientRegistration convert(RegisteredClient registeredClient) {
 		public OidcClientRegistration convert(RegisteredClient registeredClient) {
-			var clientRegistration = delegate.convert(registeredClient);
+			OidcClientRegistration clientRegistration = this.delegate.convert(registeredClient);
 			Map<String, Object> claims = new HashMap<>(clientRegistration.getClaims());
 			Map<String, Object> claims = new HashMap<>(clientRegistration.getClaims());
-			if (!CollectionUtils.isEmpty(customMetadata)) {
+			if (!CollectionUtils.isEmpty(this.customClientMetadata)) {
 				ClientSettings clientSettings = registeredClient.getClientSettings();
 				ClientSettings clientSettings = registeredClient.getClientSettings();
-
-				claims.putAll(customMetadata.stream()
-						.filter(metadatum -> clientSettings.getSetting(metadatum) != null)
+				claims.putAll(this.customClientMetadata.stream()
+						.filter(metadata -> clientSettings.getSetting(metadata) != null)
 						.collect(Collectors.toMap(Function.identity(), clientSettings::getSetting)));
 						.collect(Collectors.toMap(Function.identity(), clientSettings::getSetting)));
 			}
 			}
+
 			return OidcClientRegistration.withClaims(claims).build();
 			return OidcClientRegistration.withClaims(claims).build();
 		}
 		}
+
 	}
 	}
 
 
 }
 }

+ 6 - 6
docs/src/main/java/sample/registration/SecurityConfig.java

@@ -24,7 +24,7 @@ import org.springframework.security.oauth2.server.authorization.config.annotatio
 import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
 import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
 import org.springframework.security.web.SecurityFilterChain;
 import org.springframework.security.web.SecurityFilterChain;
 
 
-import static sample.registration.CustomMetadataConfig.registeredClientConverters;
+import static sample.registration.CustomClientMetadataConfig.configureCustomClientMetadataConverters;
 
 
 @Configuration
 @Configuration
 @EnableWebSecurity
 @EnableWebSecurity
@@ -33,13 +33,13 @@ public class SecurityConfig {
 	@Bean
 	@Bean
 	public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
 	public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
 		OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
 		OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
-
 		http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
 		http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
-				.oidc(oidc -> oidc.clientRegistrationEndpoint(endpoint -> {
-					endpoint.authenticationProviders(registeredClientConverters());	// <1>
+				.oidc(oidc -> oidc.clientRegistrationEndpoint(clientRegistrationEndpoint -> {	// <1>
+					clientRegistrationEndpoint
+							.authenticationProviders(configureCustomClientMetadataConverters());	// <2>
 				}));
 				}));
-
-		http.oauth2ResourceServer(oauth2ResourceServer -> oauth2ResourceServer.jwt(Customizer.withDefaults()));
+		http.oauth2ResourceServer(oauth2ResourceServer ->
+				oauth2ResourceServer.jwt(Customizer.withDefaults()));
 
 
 		return http.build();
 		return http.build();
 	}
 	}

+ 1 - 1
docs/src/test/java/sample/registration/DynamicClientRegistrationTests.java

@@ -56,7 +56,7 @@ public class DynamicClientRegistrationTests {
 	private String port;
 	private String port;
 
 
 	@Test
 	@Test
-	public void dynamicallyRegisterClientWithCustomMetadata() throws Exception {
+	public void dynamicallyRegisterClientWithCustomClientMetadata() throws Exception {
 		MockHttpServletResponse tokenResponse = this.mvc.perform(post("/oauth2/token")
 		MockHttpServletResponse tokenResponse = this.mvc.perform(post("/oauth2/token")
 						.with(httpBasic("registrar-client", "secret"))
 						.with(httpBasic("registrar-client", "secret"))
 						.param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
 						.param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())