Forráskód Böngészése

Make Settings implementations immutable

Closes gh-366
Joe Grandja 4 éve
szülő
commit
0d7727a7d4
42 módosított fájl, 670 hozzáadás és 641 törlés
  1. 4 4
      oauth2-authorization-server/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationEndpointConfigurer.java
  2. 11 11
      oauth2-authorization-server/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationServerConfigurer.java
  3. 1 1
      oauth2-authorization-server/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2ConfigurerUtils.java
  4. 2 2
      oauth2-authorization-server/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenEndpointConfigurer.java
  5. 1 1
      oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/JwtUtils.java
  6. 2 2
      oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeAuthenticationProvider.java
  7. 2 2
      oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProvider.java
  8. 1 1
      oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientAuthenticationProvider.java
  9. 1 1
      oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientCredentialsAuthenticationProvider.java
  10. 3 3
      oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2RefreshTokenAuthenticationProvider.java
  11. 6 6
      oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/client/JdbcRegisteredClientRepository.java
  12. 21 21
      oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/client/RegisteredClient.java
  13. 137 0
      oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/config/AbstractSettings.java
  14. 66 42
      oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/config/ClientSettings.java
  15. 130 103
      oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/config/ProviderSettings.java
  16. 0 104
      oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/config/Settings.java
  17. 92 73
      oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/config/TokenSettings.java
  18. 10 8
      oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationProvider.java
  19. 4 4
      oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/web/OidcProviderConfigurationEndpointFilter.java
  20. 6 6
      oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/OAuth2AuthorizationServerMetadataEndpointFilter.java
  21. 2 2
      oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/JwkSetTests.java
  22. 9 7
      oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationCodeGrantTests.java
  23. 1 1
      oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationServerMetadataTests.java
  24. 3 3
      oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenIntrospectionTests.java
  25. 2 2
      oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenRevocationTests.java
  26. 3 3
      oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcTests.java
  27. 5 2
      oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeAuthenticationProviderTests.java
  28. 5 4
      oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProviderTests.java
  29. 2 1
      oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientAuthenticationProviderTests.java
  30. 2 1
      oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2RefreshTokenAuthenticationProviderTests.java
  31. 4 4
      oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/client/JdbcRegisteredClientRepositoryTests.java
  32. 2 2
      oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/client/RegisteredClientTests.java
  33. 2 1
      oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/client/TestRegisteredClients.java
  34. 22 28
      oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/ClientSettingsTests.java
  35. 36 41
      oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/ProviderSettingsTests.java
  36. 0 78
      oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/SettingsTests.java
  37. 39 42
      oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/TokenSettingsTests.java
  38. 4 4
      oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationProviderTests.java
  39. 13 10
      oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/web/OidcProviderConfigurationEndpointFilterTests.java
  40. 8 6
      oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/web/OAuth2AuthorizationServerMetadataEndpointFilterTests.java
  41. 3 2
      samples/boot/oauth2-integration/authorizationserver-custom-consent-page/src/main/java/sample/config/AuthorizationServerConfig.java
  42. 3 2
      samples/boot/oauth2-integration/authorizationserver/src/main/java/sample/config/AuthorizationServerConfig.java

+ 4 - 4
oauth2-authorization-server/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationEndpointConfigurer.java

@@ -130,7 +130,7 @@ public final class OAuth2AuthorizationEndpointConfigurer extends AbstractOAuth2C
 	 *
 	 * <ul>
 	 * <li>It must be an HTTP POST</li>
-	 * <li>It must be submitted to {@link ProviderSettings#authorizationEndpoint()}</li>
+	 * <li>It must be submitted to {@link ProviderSettings#getAuthorizationEndpoint()} ()}</li>
 	 * <li>It must include the received {@code client_id} as an HTTP parameter</li>
 	 * <li>It must include the received {@code state} as an HTTP parameter</li>
 	 * <li>It must include the list of {@code scope}s the {@code Resource Owner}
@@ -150,10 +150,10 @@ public final class OAuth2AuthorizationEndpointConfigurer extends AbstractOAuth2C
 		ProviderSettings providerSettings = OAuth2ConfigurerUtils.getProviderSettings(builder);
 		this.requestMatcher = new OrRequestMatcher(
 				new AntPathRequestMatcher(
-						providerSettings.authorizationEndpoint(),
+						providerSettings.getAuthorizationEndpoint(),
 						HttpMethod.GET.name()),
 				new AntPathRequestMatcher(
-						providerSettings.authorizationEndpoint(),
+						providerSettings.getAuthorizationEndpoint(),
 						HttpMethod.POST.name()));
 
 		List<AuthenticationProvider> authenticationProviders =
@@ -172,7 +172,7 @@ public final class OAuth2AuthorizationEndpointConfigurer extends AbstractOAuth2C
 		OAuth2AuthorizationEndpointFilter authorizationEndpointFilter =
 				new OAuth2AuthorizationEndpointFilter(
 						authenticationManager,
-						providerSettings.authorizationEndpoint());
+						providerSettings.getAuthorizationEndpoint());
 		if (this.authorizationRequestConverter != null) {
 			authorizationEndpointFilter.setAuthenticationConverter(this.authorizationRequestConverter);
 		}

+ 11 - 11
oauth2-authorization-server/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationServerConfigurer.java

@@ -227,7 +227,7 @@ public final class OAuth2AuthorizationServerConfigurer<B extends HttpSecurityBui
 		this.configurers.values().forEach(configurer -> configurer.configure(builder));
 
 		ProviderSettings providerSettings = OAuth2ConfigurerUtils.getProviderSettings(builder);
-		if (providerSettings.issuer() != null) {
+		if (providerSettings.getIssuer() != null) {
 			OidcProviderConfigurationEndpointFilter oidcProviderConfigurationEndpointFilter =
 					new OidcProviderConfigurationEndpointFilter(providerSettings);
 			builder.addFilterBefore(postProcess(oidcProviderConfigurationEndpointFilter), AbstractPreAuthenticatedProcessingFilter.class);
@@ -240,7 +240,7 @@ public final class OAuth2AuthorizationServerConfigurer<B extends HttpSecurityBui
 		JWKSource<SecurityContext> jwkSource = OAuth2ConfigurerUtils.getJwkSource(builder);
 		NimbusJwkSetEndpointFilter jwkSetEndpointFilter = new NimbusJwkSetEndpointFilter(
 				jwkSource,
-				providerSettings.jwkSetEndpoint());
+				providerSettings.getJwkSetEndpoint());
 		builder.addFilterBefore(postProcess(jwkSetEndpointFilter), AbstractPreAuthenticatedProcessingFilter.class);
 
 		AuthenticationManager authenticationManager = builder.getSharedObject(AuthenticationManager.class);
@@ -257,20 +257,20 @@ public final class OAuth2AuthorizationServerConfigurer<B extends HttpSecurityBui
 		OAuth2TokenIntrospectionEndpointFilter tokenIntrospectionEndpointFilter =
 				new OAuth2TokenIntrospectionEndpointFilter(
 						authenticationManager,
-						providerSettings.tokenIntrospectionEndpoint());
+						providerSettings.getTokenIntrospectionEndpoint());
 		builder.addFilterAfter(postProcess(tokenIntrospectionEndpointFilter), FilterSecurityInterceptor.class);
 
 		OAuth2TokenRevocationEndpointFilter tokenRevocationEndpointFilter =
 				new OAuth2TokenRevocationEndpointFilter(
 						authenticationManager,
-						providerSettings.tokenRevocationEndpoint());
+						providerSettings.getTokenRevocationEndpoint());
 		builder.addFilterAfter(postProcess(tokenRevocationEndpointFilter), OAuth2TokenIntrospectionEndpointFilter.class);
 
 		// TODO Make OpenID Client Registration an "opt-in" feature
 		OidcClientRegistrationEndpointFilter oidcClientRegistrationEndpointFilter =
 				new OidcClientRegistrationEndpointFilter(
 						authenticationManager,
-						providerSettings.oidcClientRegistrationEndpoint());
+						providerSettings.getOidcClientRegistrationEndpoint());
 		builder.addFilterAfter(postProcess(oidcClientRegistrationEndpointFilter), OAuth2TokenRevocationEndpointFilter.class);
 	}
 
@@ -292,23 +292,23 @@ public final class OAuth2AuthorizationServerConfigurer<B extends HttpSecurityBui
 
 	private void initEndpointMatchers(ProviderSettings providerSettings) {
 		this.tokenIntrospectionEndpointMatcher = new AntPathRequestMatcher(
-				providerSettings.tokenIntrospectionEndpoint(), HttpMethod.POST.name());
+				providerSettings.getTokenIntrospectionEndpoint(), HttpMethod.POST.name());
 		this.tokenRevocationEndpointMatcher = new AntPathRequestMatcher(
-				providerSettings.tokenRevocationEndpoint(), HttpMethod.POST.name());
+				providerSettings.getTokenRevocationEndpoint(), HttpMethod.POST.name());
 		this.jwkSetEndpointMatcher = new AntPathRequestMatcher(
-				providerSettings.jwkSetEndpoint(), HttpMethod.GET.name());
+				providerSettings.getJwkSetEndpoint(), HttpMethod.GET.name());
 		this.oidcProviderConfigurationEndpointMatcher = new AntPathRequestMatcher(
 				"/.well-known/openid-configuration", HttpMethod.GET.name());
 		this.authorizationServerMetadataEndpointMatcher = new AntPathRequestMatcher(
 				"/.well-known/oauth-authorization-server", HttpMethod.GET.name());
 		this.oidcClientRegistrationEndpointMatcher = new AntPathRequestMatcher(
-				providerSettings.oidcClientRegistrationEndpoint(), HttpMethod.POST.name());
+				providerSettings.getOidcClientRegistrationEndpoint(), HttpMethod.POST.name());
 	}
 
 	private static void validateProviderSettings(ProviderSettings providerSettings) {
-		if (providerSettings.issuer() != null) {
+		if (providerSettings.getIssuer() != null) {
 			try {
-				new URI(providerSettings.issuer()).toURL();
+				new URI(providerSettings.getIssuer()).toURL();
 			} catch (Exception ex) {
 				throw new IllegalArgumentException("issuer must be a valid URL", ex);
 			}

+ 1 - 1
oauth2-authorization-server/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2ConfigurerUtils.java

@@ -124,7 +124,7 @@ final class OAuth2ConfigurerUtils {
 		if (providerSettings == null) {
 			providerSettings = getOptionalBean(builder, ProviderSettings.class);
 			if (providerSettings == null) {
-				providerSettings = new ProviderSettings();
+				providerSettings = ProviderSettings.builder().build();
 			}
 			builder.setSharedObject(ProviderSettings.class, providerSettings);
 		}

+ 2 - 2
oauth2-authorization-server/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenEndpointConfigurer.java

@@ -119,7 +119,7 @@ public final class OAuth2TokenEndpointConfigurer extends AbstractOAuth2Configure
 	<B extends HttpSecurityBuilder<B>> void init(B builder) {
 		ProviderSettings providerSettings = OAuth2ConfigurerUtils.getProviderSettings(builder);
 		this.requestMatcher = new AntPathRequestMatcher(
-				providerSettings.tokenEndpoint(), HttpMethod.POST.name());
+				providerSettings.getTokenEndpoint(), HttpMethod.POST.name());
 
 		List<AuthenticationProvider> authenticationProviders =
 				!this.authenticationProviders.isEmpty() ?
@@ -137,7 +137,7 @@ public final class OAuth2TokenEndpointConfigurer extends AbstractOAuth2Configure
 		OAuth2TokenEndpointFilter tokenEndpointFilter =
 				new OAuth2TokenEndpointFilter(
 						authenticationManager,
-						providerSettings.tokenEndpoint());
+						providerSettings.getTokenEndpoint());
 		if (this.accessTokenRequestConverter != null) {
 			tokenEndpointFilter.setAuthenticationConverter(this.accessTokenRequestConverter);
 		}

+ 1 - 1
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/JwtUtils.java

@@ -50,7 +50,7 @@ final class JwtUtils {
 			String issuer, String subject, Set<String> authorizedScopes) {
 
 		Instant issuedAt = Instant.now();
-		Instant expiresAt = issuedAt.plus(registeredClient.getTokenSettings().accessTokenTimeToLive());
+		Instant expiresAt = issuedAt.plus(registeredClient.getTokenSettings().getAccessTokenTimeToLive());
 
 		// @formatter:off
 		JwtClaimsSet.Builder claimsBuilder = JwtClaimsSet.builder();

+ 2 - 2
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeAuthenticationProvider.java

@@ -140,7 +140,7 @@ public final class OAuth2AuthorizationCodeAuthenticationProvider implements Auth
 			throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_GRANT));
 		}
 
-		String issuer = this.providerSettings != null ? this.providerSettings.issuer() : null;
+		String issuer = this.providerSettings != null ? this.providerSettings.getIssuer() : null;
 		Set<String> authorizedScopes = authorization.getAttribute(
 				OAuth2Authorization.AUTHORIZED_SCOPE_ATTRIBUTE_NAME);
 
@@ -174,7 +174,7 @@ public final class OAuth2AuthorizationCodeAuthenticationProvider implements Auth
 		OAuth2RefreshToken refreshToken = null;
 		if (registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.REFRESH_TOKEN)) {
 			refreshToken = OAuth2RefreshTokenAuthenticationProvider.generateRefreshToken(
-					registeredClient.getTokenSettings().refreshTokenTimeToLive());
+					registeredClient.getTokenSettings().getRefreshTokenTimeToLive());
 		}
 
 		Jwt jwtIdToken = null;

+ 2 - 2
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProvider.java

@@ -151,7 +151,7 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationProvider implemen
 							authorizationCodeRequestAuthentication, registeredClient, null);
 				}
 			}
-		} else if (registeredClient.getClientSettings().requireProofKey()) {
+		} else if (registeredClient.getClientSettings().isRequireProofKey()) {
 			throwError(OAuth2ErrorCodes.INVALID_REQUEST, PkceParameterNames.CODE_CHALLENGE, PKCE_ERROR_URI,
 					authorizationCodeRequestAuthentication, registeredClient, null);
 		}
@@ -341,7 +341,7 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationProvider implemen
 	private static boolean requireAuthorizationConsent(RegisteredClient registeredClient,
 			OAuth2AuthorizationRequest authorizationRequest, OAuth2AuthorizationConsent authorizationConsent) {
 
-		if (!registeredClient.getClientSettings().requireAuthorizationConsent()) {
+		if (!registeredClient.getClientSettings().isRequireAuthorizationConsent()) {
 			return false;
 		}
 		// 'openid' scope does not require consent

+ 1 - 1
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientAuthenticationProvider.java

@@ -150,7 +150,7 @@ public final class OAuth2ClientAuthenticationProvider implements AuthenticationP
 		String codeChallenge = (String) authorizationRequest.getAdditionalParameters()
 				.get(PkceParameterNames.CODE_CHALLENGE);
 		if (!StringUtils.hasText(codeChallenge) &&
-				registeredClient.getClientSettings().requireProofKey()) {
+				registeredClient.getClientSettings().isRequireProofKey()) {
 			throwInvalidClient();
 		}
 

+ 1 - 1
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientCredentialsAuthenticationProvider.java

@@ -113,7 +113,7 @@ public final class OAuth2ClientCredentialsAuthenticationProvider implements Auth
 			authorizedScopes = new LinkedHashSet<>(clientCredentialsAuthentication.getScopes());
 		}
 
-		String issuer = this.providerSettings != null ? this.providerSettings.issuer() : null;
+		String issuer = this.providerSettings != null ? this.providerSettings.getIssuer() : null;
 
 		JoseHeader.Builder headersBuilder = JwtUtils.headers();
 		JwtClaimsSet.Builder claimsBuilder = JwtUtils.accessTokenClaims(

+ 3 - 3
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2RefreshTokenAuthenticationProvider.java

@@ -147,7 +147,7 @@ public final class OAuth2RefreshTokenAuthenticationProvider implements Authentic
 			scopes = authorizedScopes;
 		}
 
-		String issuer = this.providerSettings != null ? this.providerSettings.issuer() : null;
+		String issuer = this.providerSettings != null ? this.providerSettings.getIssuer() : null;
 
 		JoseHeader.Builder headersBuilder = JwtUtils.headers();
 		JwtClaimsSet.Builder claimsBuilder = JwtUtils.accessTokenClaims(
@@ -178,8 +178,8 @@ public final class OAuth2RefreshTokenAuthenticationProvider implements Authentic
 		TokenSettings tokenSettings = registeredClient.getTokenSettings();
 
 		OAuth2RefreshToken currentRefreshToken = refreshToken.getToken();
-		if (!tokenSettings.reuseRefreshTokens()) {
-			currentRefreshToken = generateRefreshToken(tokenSettings.refreshTokenTimeToLive());
+		if (!tokenSettings.isReuseRefreshTokens()) {
+			currentRefreshToken = generateRefreshToken(tokenSettings.getRefreshTokenTimeToLive());
 		}
 
 		Jwt jwtIdToken = null;

+ 6 - 6
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/client/JdbcRegisteredClientRepository.java

@@ -39,6 +39,8 @@ import org.springframework.jdbc.core.SqlParameterValue;
 import org.springframework.security.jackson2.SecurityJackson2Modules;
 import org.springframework.security.oauth2.core.AuthorizationGrantType;
 import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
+import org.springframework.security.oauth2.server.authorization.config.ClientSettings;
+import org.springframework.security.oauth2.server.authorization.config.TokenSettings;
 import org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationServerJackson2Module;
 import org.springframework.util.Assert;
 import org.springframework.util.StringUtils;
@@ -211,12 +213,10 @@ public class JdbcRegisteredClientRepository implements RegisteredClientRepositor
 			// @formatter:on
 
 			Map<String, Object> clientSettingsMap = parseMap(rs.getString("client_settings"));
-			builder.clientSettings(clientSettings ->
-					clientSettings.settings().putAll(clientSettingsMap));
+			builder.clientSettings(ClientSettings.withSettings(clientSettingsMap).build());
 
 			Map<String, Object> tokenSettingsMap = parseMap(rs.getString("token_settings"));
-			builder.tokenSettings(tokenSettings ->
-					tokenSettings.settings().putAll(tokenSettingsMap));
+			builder.tokenSettings(TokenSettings.withSettings(tokenSettingsMap).build());
 
 			return builder.build();
 		}
@@ -303,8 +303,8 @@ public class JdbcRegisteredClientRepository implements RegisteredClientRepositor
 					new SqlParameterValue(Types.VARCHAR, StringUtils.collectionToCommaDelimitedString(authorizationGrantTypes)),
 					new SqlParameterValue(Types.VARCHAR, StringUtils.collectionToCommaDelimitedString(registeredClient.getRedirectUris())),
 					new SqlParameterValue(Types.VARCHAR, StringUtils.collectionToCommaDelimitedString(registeredClient.getScopes())),
-					new SqlParameterValue(Types.VARCHAR, writeMap(registeredClient.getClientSettings().settings())),
-					new SqlParameterValue(Types.VARCHAR, writeMap(registeredClient.getTokenSettings().settings())));
+					new SqlParameterValue(Types.VARCHAR, writeMap(registeredClient.getClientSettings().getSettings())),
+					new SqlParameterValue(Types.VARCHAR, writeMap(registeredClient.getTokenSettings().getSettings())));
 		}
 
 		public final void setObjectMapper(ObjectMapper objectMapper) {

+ 21 - 21
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/client/RegisteredClient.java

@@ -190,15 +190,15 @@ public class RegisteredClient implements Serializable {
 				Objects.equals(this.authorizationGrantTypes, that.authorizationGrantTypes) &&
 				Objects.equals(this.redirectUris, that.redirectUris) &&
 				Objects.equals(this.scopes, that.scopes) &&
-				Objects.equals(this.clientSettings.settings(), that.getClientSettings().settings()) &&
-				Objects.equals(this.tokenSettings.settings(), that.tokenSettings.settings());
+				Objects.equals(this.clientSettings, that.clientSettings) &&
+				Objects.equals(this.tokenSettings, that.tokenSettings);
 	}
 
 	@Override
 	public int hashCode() {
 		return Objects.hash(this.id, this.clientId, this.clientIdIssuedAt, this.clientSecret, this.clientSecretExpiresAt,
 				this.clientName, this.clientAuthenticationMethods, this.authorizationGrantTypes, this.redirectUris,
-				this.scopes, this.clientSettings.settings(), this.tokenSettings.settings());
+				this.scopes, this.clientSettings, this.tokenSettings);
 	}
 
 	@Override
@@ -211,8 +211,8 @@ public class RegisteredClient implements Serializable {
 				", authorizationGrantTypes=" + this.authorizationGrantTypes +
 				", redirectUris=" + this.redirectUris +
 				", scopes=" + this.scopes +
-				", clientSettings=" + this.clientSettings.settings() +
-				", tokenSettings=" + this.tokenSettings.settings() +
+				", clientSettings=" + this.clientSettings +
+				", tokenSettings=" + this.tokenSettings +
 				'}';
 	}
 
@@ -253,8 +253,8 @@ public class RegisteredClient implements Serializable {
 		private Set<AuthorizationGrantType> authorizationGrantTypes = new HashSet<>();
 		private Set<String> redirectUris = new HashSet<>();
 		private Set<String> scopes = new HashSet<>();
-		private ClientSettings clientSettings = new ClientSettings();
-		private TokenSettings tokenSettings = new TokenSettings();
+		private ClientSettings clientSettings;
+		private TokenSettings tokenSettings;
 
 		protected Builder(String id) {
 			this.id = id;
@@ -279,8 +279,8 @@ public class RegisteredClient implements Serializable {
 			if (!CollectionUtils.isEmpty(registeredClient.scopes)) {
 				this.scopes.addAll(registeredClient.scopes);
 			}
-			this.clientSettings = new ClientSettings(registeredClient.clientSettings.settings());
-			this.tokenSettings = new TokenSettings(registeredClient.tokenSettings.settings());
+			this.clientSettings = ClientSettings.withSettings(registeredClient.getClientSettings().getSettings()).build();
+			this.tokenSettings = TokenSettings.withSettings(registeredClient.getTokenSettings().getSettings()).build();
 		}
 
 		/**
@@ -444,26 +444,24 @@ public class RegisteredClient implements Serializable {
 		}
 
 		/**
-		 * A {@link Consumer} of the client configuration settings,
-		 * allowing the ability to add, replace, or remove.
+		 * Sets the {@link ClientSettings client configuration settings}.
 		 *
-		 * @param clientSettingsConsumer a {@link Consumer} of the client configuration settings
+		 * @param clientSettings the client configuration settings
 		 * @return the {@link Builder}
 		 */
-		public Builder clientSettings(Consumer<ClientSettings> clientSettingsConsumer) {
-			clientSettingsConsumer.accept(this.clientSettings);
+		public Builder clientSettings(ClientSettings clientSettings) {
+			this.clientSettings = clientSettings;
 			return this;
 		}
 
 		/**
-		 * A {@link Consumer} of the token configuration settings,
-		 * allowing the ability to add, replace, or remove.
+		 * Sets the {@link TokenSettings token configuration settings}.
 		 *
-		 * @param tokenSettingsConsumer a {@link Consumer} of the token configuration settings
+		 * @param tokenSettings the token configuration settings
 		 * @return the {@link Builder}
 		 */
-		public Builder tokenSettings(Consumer<TokenSettings> tokenSettingsConsumer) {
-			tokenSettingsConsumer.accept(this.tokenSettings);
+		public Builder tokenSettings(TokenSettings tokenSettings) {
+			this.tokenSettings = tokenSettings;
 			return this;
 		}
 
@@ -506,8 +504,10 @@ public class RegisteredClient implements Serializable {
 					new HashSet<>(this.redirectUris));
 			registeredClient.scopes = Collections.unmodifiableSet(
 					new HashSet<>(this.scopes));
-			registeredClient.clientSettings = new ClientSettings(this.clientSettings.settings());
-			registeredClient.tokenSettings = new TokenSettings(this.tokenSettings.settings());
+			registeredClient.clientSettings = this.clientSettings != null ?
+					this.clientSettings : ClientSettings.builder().build();
+			registeredClient.tokenSettings = this.tokenSettings != null ?
+					this.tokenSettings : TokenSettings.builder().build();
 
 			return registeredClient;
 		}

+ 137 - 0
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/config/AbstractSettings.java

@@ -0,0 +1,137 @@
+/*
+ * Copyright 2020-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.oauth2.server.authorization.config;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Consumer;
+
+import org.springframework.security.oauth2.core.Version;
+import org.springframework.util.Assert;
+
+/**
+ * Base implementation for configuration settings.
+ *
+ * @author Joe Grandja
+ * @since 0.0.2
+ */
+public abstract class AbstractSettings implements Serializable {
+	private static final long serialVersionUID = Version.SERIAL_VERSION_UID;
+	private final Map<String, Object> settings;
+
+	protected AbstractSettings(Map<String, Object> settings) {
+		Assert.notEmpty(settings, "settings cannot be empty");
+		this.settings = Collections.unmodifiableMap(new HashMap<>(settings));
+	}
+
+	/**
+	 * Returns a configuration setting.
+	 *
+	 * @param name the name of the setting
+	 * @param <T> the type of the setting
+	 * @return the value of the setting, or {@code null} if not available
+	 */
+	@SuppressWarnings("unchecked")
+	public <T> T getSetting(String name) {
+		Assert.hasText(name, "name cannot be empty");
+		return (T) getSettings().get(name);
+	}
+
+	/**
+	 * Returns a {@code Map} of the configuration settings.
+	 *
+	 * @return a {@code Map} of the configuration settings
+	 */
+	public Map<String, Object> getSettings() {
+		return this.settings;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj) {
+			return true;
+		}
+		if (obj == null || getClass() != obj.getClass()) {
+			return false;
+		}
+		AbstractSettings that = (AbstractSettings) obj;
+		return this.settings.equals(that.settings);
+	}
+
+	@Override
+	public int hashCode() {
+		return Objects.hash(this.settings);
+	}
+
+	@Override
+	public String toString() {
+		return "AbstractSettings {" +
+				"settings=" + this.settings +
+				'}';
+	}
+
+	/**
+	 * A builder for subclasses of {@link AbstractSettings}.
+	 */
+	protected static abstract class AbstractBuilder<T extends AbstractSettings, B extends AbstractBuilder<T, B>> {
+		private final Map<String, Object> settings = new HashMap<>();
+
+		protected AbstractBuilder() {
+		}
+
+		/**
+		 * Sets a configuration setting.
+		 *
+		 * @param name the name of the setting
+		 * @param value the value of the setting
+		 * @return the {@link AbstractBuilder} for further configuration
+		 */
+		public B setting(String name, Object value) {
+			Assert.hasText(name, "name cannot be empty");
+			Assert.notNull(value, "value cannot be null");
+			getSettings().put(name, value);
+			return getThis();
+		}
+
+		/**
+		 * A {@code Consumer} of the configuration settings {@code Map}
+		 * allowing the ability to add, replace, or remove.
+		 *
+		 * @param settingsConsumer a {@link Consumer} of the configuration settings {@code Map}
+		 * @return the {@link AbstractBuilder} for further configuration
+		 */
+		public B settings(Consumer<Map<String, Object>> settingsConsumer) {
+			settingsConsumer.accept(getSettings());
+			return getThis();
+		}
+
+		public abstract T build();
+
+		protected final Map<String, Object> getSettings() {
+			return this.settings;
+		}
+
+		@SuppressWarnings("unchecked")
+		protected final B getThis() {
+			return (B) this;
+		}
+
+	}
+
+}

+ 66 - 42
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/config/ClientSettings.java

@@ -15,34 +15,23 @@
  */
 package org.springframework.security.oauth2.server.authorization.config;
 
-import java.util.HashMap;
 import java.util.Map;
 
+import org.springframework.util.Assert;
+
 /**
  * A facility for client configuration settings.
  *
  * @author Joe Grandja
  * @since 0.0.2
- * @see Settings
+ * @see AbstractSettings
  */
-public class ClientSettings extends Settings {
+public final class ClientSettings extends AbstractSettings {
 	private static final String CLIENT_SETTING_BASE = "setting.client.";
 	public static final String REQUIRE_PROOF_KEY = CLIENT_SETTING_BASE.concat("require-proof-key");
 	public static final String REQUIRE_AUTHORIZATION_CONSENT = CLIENT_SETTING_BASE.concat("require-authorization-consent");
 
-	/**
-	 * Constructs a {@code ClientSettings}.
-	 */
-	public ClientSettings() {
-		this(defaultSettings());
-	}
-
-	/**
-	 * Constructs a {@code ClientSettings} using the provided parameters.
-	 *
-	 * @param settings the initial settings
-	 */
-	public ClientSettings(Map<String, Object> settings) {
+	private ClientSettings(Map<String, Object> settings) {
 		super(settings);
 	}
 
@@ -52,48 +41,83 @@ public class ClientSettings extends Settings {
 	 *
 	 * @return {@code true} if the client is required to provide a proof key challenge and verifier, {@code false} otherwise
 	 */
-	public boolean requireProofKey() {
-		return setting(REQUIRE_PROOF_KEY);
+	public boolean isRequireProofKey() {
+		return getSetting(REQUIRE_PROOF_KEY);
 	}
 
 	/**
-	 * Set to {@code true} if the client is required to provide a proof key challenge and verifier
-	 * when performing the Authorization Code Grant flow.
+	 * Returns {@code true} if authorization consent is required when the client requests access.
+	 * The default is {@code false}.
 	 *
-	 * @param requireProofKey {@code true} if the client is required to provide a proof key challenge and verifier, {@code false} otherwise
-	 * @return the {@link ClientSettings}
+	 * @return {@code true} if authorization consent is required when the client requests access, {@code false} otherwise
 	 */
-	public ClientSettings requireProofKey(boolean requireProofKey) {
-		setting(REQUIRE_PROOF_KEY, requireProofKey);
-		return this;
+	public boolean isRequireAuthorizationConsent() {
+		return getSetting(REQUIRE_AUTHORIZATION_CONSENT);
 	}
 
 	/**
-	 * Returns {@code true} if authorization consent is required when the client requests access.
-	 * The default is {@code false}.
+	 * Constructs a new {@link Builder} with the default settings.
 	 *
-	 * @return {@code true} if authorization consent is required when the client requests access, {@code false} otherwise
+	 * @return the {@link Builder}
 	 */
-	public boolean requireAuthorizationConsent() {
-		return setting(REQUIRE_AUTHORIZATION_CONSENT);
+	public static Builder builder() {
+		return new Builder()
+				.requireProofKey(false)
+				.requireAuthorizationConsent(false);
 	}
 
 	/**
-	 * Set to {@code true} if authorization consent is required when the client requests access.
-	 * This applies to all interactive flows (e.g. {@code authorization_code} and {@code device_code}).
+	 * Constructs a new {@link Builder} with the provided settings.
 	 *
-	 * @param requireAuthorizationConsent {@code true} if authorization consent is required when the client requests access, {@code false} otherwise
-	 * @return the {@link ClientSettings}
+	 * @param settings the settings to initialize the builder
+	 * @return the {@link Builder}
 	 */
-	public ClientSettings requireAuthorizationConsent(boolean requireAuthorizationConsent) {
-		setting(REQUIRE_AUTHORIZATION_CONSENT, requireAuthorizationConsent);
-		return this;
+	public static Builder withSettings(Map<String, Object> settings) {
+		Assert.notEmpty(settings, "settings cannot be empty");
+		return new Builder()
+				.settings(s -> s.putAll(settings));
 	}
 
-	protected static Map<String, Object> defaultSettings() {
-		Map<String, Object> settings = new HashMap<>();
-		settings.put(REQUIRE_PROOF_KEY, false);
-		settings.put(REQUIRE_AUTHORIZATION_CONSENT, false);
-		return settings;
+	/**
+	 * A builder for {@link ClientSettings}.
+	 */
+	public static class Builder extends AbstractBuilder<ClientSettings, Builder> {
+
+		private Builder() {
+		}
+
+		/**
+		 * Set to {@code true} if the client is required to provide a proof key challenge and verifier
+		 * when performing the Authorization Code Grant flow.
+		 *
+		 * @param requireProofKey {@code true} if the client is required to provide a proof key challenge and verifier, {@code false} otherwise
+		 * @return the {@link Builder} for further configuration
+		 */
+		public Builder requireProofKey(boolean requireProofKey) {
+			return setting(REQUIRE_PROOF_KEY, requireProofKey);
+		}
+
+		/**
+		 * Set to {@code true} if authorization consent is required when the client requests access.
+		 * This applies to all interactive flows (e.g. {@code authorization_code} and {@code device_code}).
+		 *
+		 * @param requireAuthorizationConsent {@code true} if authorization consent is required when the client requests access, {@code false} otherwise
+		 * @return the {@link Builder} for further configuration
+		 */
+		public Builder requireAuthorizationConsent(boolean requireAuthorizationConsent) {
+			return setting(REQUIRE_AUTHORIZATION_CONSENT, requireAuthorizationConsent);
+		}
+
+		/**
+		 * Builds the {@link ClientSettings}.
+		 *
+		 * @return the {@link ClientSettings}
+		 */
+		@Override
+		public ClientSettings build() {
+			return new ClientSettings(getSettings());
+		}
+
 	}
+
 }

+ 130 - 103
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/config/ProviderSettings.java

@@ -15,17 +15,19 @@
  */
 package org.springframework.security.oauth2.server.authorization.config;
 
-import java.util.HashMap;
 import java.util.Map;
 
+import org.springframework.util.Assert;
+
 /**
  * A facility for provider configuration settings.
  *
  * @author Daniel Garnier-Moiroux
+ * @author Joe Grandja
  * @since 0.1.0
- * @see Settings
+ * @see AbstractSettings
  */
-public class ProviderSettings extends Settings {
+public final class ProviderSettings extends AbstractSettings {
 	private static final String PROVIDER_SETTING_BASE = "setting.provider.";
 	public static final String ISSUER = PROVIDER_SETTING_BASE.concat("issuer");
 	public static final String AUTHORIZATION_ENDPOINT = PROVIDER_SETTING_BASE.concat("authorization-endpoint");
@@ -35,19 +37,7 @@ public class ProviderSettings extends Settings {
 	public static final String TOKEN_INTROSPECTION_ENDPOINT = PROVIDER_SETTING_BASE.concat("token-introspection-endpoint");
 	public static final String OIDC_CLIENT_REGISTRATION_ENDPOINT = PROVIDER_SETTING_BASE.concat("oidc-client-registration-endpoint");
 
-	/**
-	 * Constructs a {@code ProviderSettings}.
-	 */
-	public ProviderSettings() {
-		this(defaultSettings());
-	}
-
-	/**
-	 * Constructs a {@code ProviderSettings} using the provided parameters.
-	 *
-	 * @param settings the initial settings
-	 */
-	public ProviderSettings(Map<String, Object> settings) {
+	private ProviderSettings(Map<String, Object> settings) {
 		super(settings);
 	}
 
@@ -56,18 +46,8 @@ public class ProviderSettings extends Settings {
 	 *
 	 * @return the URL of the Provider's Issuer Identifier
 	 */
-	public String issuer() {
-		return setting(ISSUER);
-	}
-
-	/**
-	 * Sets the URL the Provider uses as its Issuer Identifier.
-	 *
-	 * @param issuer the URL the Provider uses as its Issuer Identifier.
-	 * @return the {@link ProviderSettings} for further configuration
-	 */
-	public ProviderSettings issuer(String issuer) {
-		return setting(ISSUER, issuer);
+	public String getIssuer() {
+		return getSetting(ISSUER);
 	}
 
 	/**
@@ -75,18 +55,8 @@ public class ProviderSettings extends Settings {
 	 *
 	 * @return the Authorization endpoint
 	 */
-	public String authorizationEndpoint() {
-		return setting(AUTHORIZATION_ENDPOINT);
-	}
-
-	/**
-	 * Sets the Provider's OAuth 2.0 Authorization endpoint.
-	 *
-	 * @param authorizationEndpoint the Authorization endpoint
-	 * @return the {@link ProviderSettings} for further configuration
-	 */
-	public ProviderSettings authorizationEndpoint(String authorizationEndpoint) {
-		return setting(AUTHORIZATION_ENDPOINT, authorizationEndpoint);
+	public String getAuthorizationEndpoint() {
+		return getSetting(AUTHORIZATION_ENDPOINT);
 	}
 
 	/**
@@ -94,18 +64,8 @@ public class ProviderSettings extends Settings {
 	 *
 	 * @return the Token endpoint
 	 */
-	public String tokenEndpoint() {
-		return setting(TOKEN_ENDPOINT);
-	}
-
-	/**
-	 * Sets the Provider's OAuth 2.0 Token endpoint.
-	 *
-	 * @param tokenEndpoint the Token endpoint
-	 * @return the {@link ProviderSettings} for further configuration
-	 */
-	public ProviderSettings tokenEndpoint(String tokenEndpoint) {
-		return setting(TOKEN_ENDPOINT, tokenEndpoint);
+	public String getTokenEndpoint() {
+		return getSetting(TOKEN_ENDPOINT);
 	}
 
 	/**
@@ -113,18 +73,8 @@ public class ProviderSettings extends Settings {
 	 *
 	 * @return the JWK Set endpoint
 	 */
-	public String jwkSetEndpoint() {
-		return setting(JWK_SET_ENDPOINT);
-	}
-
-	/**
-	 * Sets the Provider's JWK Set endpoint.
-	 *
-	 * @param jwkSetEndpoint the JWK Set endpoint
-	 * @return the {@link ProviderSettings} for further configuration
-	 */
-	public ProviderSettings jwkSetEndpoint(String jwkSetEndpoint) {
-		return setting(JWK_SET_ENDPOINT, jwkSetEndpoint);
+	public String getJwkSetEndpoint() {
+		return getSetting(JWK_SET_ENDPOINT);
 	}
 
 	/**
@@ -132,18 +82,8 @@ public class ProviderSettings extends Settings {
 	 *
 	 * @return the Token Revocation endpoint
 	 */
-	public String tokenRevocationEndpoint() {
-		return setting(TOKEN_REVOCATION_ENDPOINT);
-	}
-
-	/**
-	 * Sets the Provider's OAuth 2.0 Token Revocation endpoint.
-	 *
-	 * @param tokenRevocationEndpoint the Token Revocation endpoint
-	 * @return the {@link ProviderSettings} for further configuration
-	 */
-	public ProviderSettings tokenRevocationEndpoint(String tokenRevocationEndpoint) {
-		return setting(TOKEN_REVOCATION_ENDPOINT, tokenRevocationEndpoint);
+	public String getTokenRevocationEndpoint() {
+		return getSetting(TOKEN_REVOCATION_ENDPOINT);
 	}
 
 	/**
@@ -151,47 +91,134 @@ public class ProviderSettings extends Settings {
 	 *
 	 * @return the Token Introspection endpoint
 	 */
-	public String tokenIntrospectionEndpoint() {
-		return setting(TOKEN_INTROSPECTION_ENDPOINT);
+	public String getTokenIntrospectionEndpoint() {
+		return getSetting(TOKEN_INTROSPECTION_ENDPOINT);
 	}
 
 	/**
-	 * Sets the Provider's OAuth 2.0 Token Introspection endpoint.
+	 * Returns the Provider's OpenID Connect 1.0 Client Registration endpoint. The default is {@code /connect/register}.
 	 *
-	 * @param tokenIntrospectionEndpoint the Token Introspection endpoint
-	 * @return the {@link ProviderSettings} for further configuration
+	 * @return the OpenID Connect 1.0 Client Registration endpoint
 	 */
-	public ProviderSettings tokenIntrospectionEndpoint(String tokenIntrospectionEndpoint) {
-		return setting(TOKEN_INTROSPECTION_ENDPOINT, tokenIntrospectionEndpoint);
+	public String getOidcClientRegistrationEndpoint() {
+		return getSetting(OIDC_CLIENT_REGISTRATION_ENDPOINT);
 	}
 
 	/**
-	 * Returns the Provider's OpenID Connect 1.0 Client Registration endpoint. The default is {@code /connect/register}.
+	 * Constructs a new {@link Builder} with the default settings.
 	 *
-	 * @return the OpenID Connect 1.0 Client Registration endpoint
+	 * @return the {@link Builder}
 	 */
-	public String oidcClientRegistrationEndpoint() {
-		return setting(OIDC_CLIENT_REGISTRATION_ENDPOINT);
+	public static Builder builder() {
+		return new Builder()
+				.authorizationEndpoint("/oauth2/authorize")
+				.tokenEndpoint("/oauth2/token")
+				.jwkSetEndpoint("/oauth2/jwks")
+				.tokenRevocationEndpoint("/oauth2/revoke")
+				.tokenIntrospectionEndpoint("/oauth2/introspect")
+				.oidcClientRegistrationEndpoint("/connect/register");
 	}
 
 	/**
-	 * Sets the Provider's OpenID Connect 1.0 Client Registration endpoint.
+	 * Constructs a new {@link Builder} with the provided settings.
 	 *
-	 * @param oidcClientRegistrationEndpoint the OpenID Connect 1.0 Client Registration endpoint
-	 * @return the {@link ProviderSettings} for further configuration
-	 */
-	public ProviderSettings oidcClientRegistrationEndpoint(String oidcClientRegistrationEndpoint) {
-		return setting(OIDC_CLIENT_REGISTRATION_ENDPOINT, oidcClientRegistrationEndpoint);
-	}
+	 * @param settings the settings to initialize the builder
+	 * @return the {@link Builder}
+	 */
+	public static Builder withSettings(Map<String, Object> settings) {
+		Assert.notEmpty(settings, "settings cannot be empty");
+		return new Builder()
+				.settings(s -> s.putAll(settings));
+	}
+
+	/**
+	 * A builder for {@link ProviderSettings}.
+	 */
+	public static class Builder extends AbstractBuilder<ProviderSettings, Builder> {
+
+		private Builder() {
+		}
+
+		/**
+		 * Sets the URL the Provider uses as its Issuer Identifier.
+		 *
+		 * @param issuer the URL the Provider uses as its Issuer Identifier.
+		 * @return the {@link Builder} for further configuration
+		 */
+		public Builder issuer(String issuer) {
+			return setting(ISSUER, issuer);
+		}
+
+		/**
+		 * Sets the Provider's OAuth 2.0 Authorization endpoint.
+		 *
+		 * @param authorizationEndpoint the Authorization endpoint
+		 * @return the {@link Builder} for further configuration
+		 */
+		public Builder authorizationEndpoint(String authorizationEndpoint) {
+			return setting(AUTHORIZATION_ENDPOINT, authorizationEndpoint);
+		}
+
+		/**
+		 * Sets the Provider's OAuth 2.0 Token endpoint.
+		 *
+		 * @param tokenEndpoint the Token endpoint
+		 * @return the {@link Builder} for further configuration
+		 */
+		public Builder tokenEndpoint(String tokenEndpoint) {
+			return setting(TOKEN_ENDPOINT, tokenEndpoint);
+		}
+
+		/**
+		 * Sets the Provider's JWK Set endpoint.
+		 *
+		 * @param jwkSetEndpoint the JWK Set endpoint
+		 * @return the {@link Builder} for further configuration
+		 */
+		public Builder jwkSetEndpoint(String jwkSetEndpoint) {
+			return setting(JWK_SET_ENDPOINT, jwkSetEndpoint);
+		}
+
+		/**
+		 * Sets the Provider's OAuth 2.0 Token Revocation endpoint.
+		 *
+		 * @param tokenRevocationEndpoint the Token Revocation endpoint
+		 * @return the {@link Builder} for further configuration
+		 */
+		public Builder tokenRevocationEndpoint(String tokenRevocationEndpoint) {
+			return setting(TOKEN_REVOCATION_ENDPOINT, tokenRevocationEndpoint);
+		}
+
+		/**
+		 * Sets the Provider's OAuth 2.0 Token Introspection endpoint.
+		 *
+		 * @param tokenIntrospectionEndpoint the Token Introspection endpoint
+		 * @return the {@link Builder} for further configuration
+		 */
+		public Builder tokenIntrospectionEndpoint(String tokenIntrospectionEndpoint) {
+			return setting(TOKEN_INTROSPECTION_ENDPOINT, tokenIntrospectionEndpoint);
+		}
+
+		/**
+		 * Sets the Provider's OpenID Connect 1.0 Client Registration endpoint.
+		 *
+		 * @param oidcClientRegistrationEndpoint the OpenID Connect 1.0 Client Registration endpoint
+		 * @return the {@link Builder} for further configuration
+		 */
+		public Builder oidcClientRegistrationEndpoint(String oidcClientRegistrationEndpoint) {
+			return setting(OIDC_CLIENT_REGISTRATION_ENDPOINT, oidcClientRegistrationEndpoint);
+		}
+
+		/**
+		 * Builds the {@link ProviderSettings}.
+		 *
+		 * @return the {@link ProviderSettings}
+		 */
+		@Override
+		public ProviderSettings build() {
+			return new ProviderSettings(getSettings());
+		}
 
-	protected static Map<String, Object> defaultSettings() {
-		Map<String, Object> settings = new HashMap<>();
-		settings.put(AUTHORIZATION_ENDPOINT, "/oauth2/authorize");
-		settings.put(TOKEN_ENDPOINT, "/oauth2/token");
-		settings.put(JWK_SET_ENDPOINT, "/oauth2/jwks");
-		settings.put(TOKEN_REVOCATION_ENDPOINT, "/oauth2/revoke");
-		settings.put(TOKEN_INTROSPECTION_ENDPOINT, "/oauth2/introspect");
-		settings.put(OIDC_CLIENT_REGISTRATION_ENDPOINT, "/connect/register");
-		return settings;
 	}
+
 }

+ 0 - 104
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/config/Settings.java

@@ -1,104 +0,0 @@
-/*
- * Copyright 2020 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.security.oauth2.server.authorization.config;
-
-import org.springframework.security.oauth2.core.Version;
-import org.springframework.util.Assert;
-
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.function.Consumer;
-
-/**
- * A facility for configuration settings.
- *
- * @author Joe Grandja
- * @since 0.0.2
- */
-public class Settings implements Serializable {
-	private static final long serialVersionUID = Version.SERIAL_VERSION_UID;
-	private final Map<String, Object> settings;
-
-	/**
-	 * Constructs a {@code Settings}.
-	 */
-	public Settings() {
-		this.settings = new HashMap<>();
-	}
-
-	/**
-	 * Constructs a {@code Settings} using the provided parameters.
-	 *
-	 * @param settings the initial settings
-	 */
-	public Settings(Map<String, Object> settings) {
-		Assert.notNull(settings, "settings cannot be null");
-		this.settings = new HashMap<>(settings);
-	}
-
-	/**
-	 * Returns a configuration setting.
-	 *
-	 * @param name the name of the setting
-	 * @param <T> the type of the setting
-	 * @return the value of the setting, or {@code null} if not available
-	 */
-	@SuppressWarnings("unchecked")
-	public <T> T setting(String name) {
-		Assert.hasText(name, "name cannot be empty");
-		return (T) this.settings.get(name);
-	}
-
-	/**
-	 * Sets a configuration setting.
-	 *
-	 * @param name the name of the setting
-	 * @param value the value of the setting
-	 * @param <T> the type of the {@link Settings}
-	 * @return the {@link Settings}
-	 */
-	@SuppressWarnings("unchecked")
-	public <T extends Settings> T setting(String name, Object value) {
-		Assert.hasText(name, "name cannot be empty");
-		Assert.notNull(value, "value cannot be null");
-		this.settings.put(name, value);
-		return (T) this;
-	}
-
-	/**
-	 * Returns a {@code Map} of the configuration settings.
-	 *
-	 * @return a {@code Map} of the configuration settings
-	 */
-	public Map<String, Object> settings() {
-		return this.settings;
-	}
-
-	/**
-	 * A {@code Consumer} of the configuration settings {@code Map}
-	 * allowing the ability to add, replace, or remove.
-	 *
-	 * @param settingsConsumer a {@link Consumer} of the configuration settings {@code Map}
-	 * @param <T> the type of the {@link Settings}
-	 * @return the {@link Settings}
-	 */
-	@SuppressWarnings("unchecked")
-	public <T extends Settings> T settings(Consumer<Map<String, Object>> settingsConsumer) {
-		settingsConsumer.accept(this.settings);
-		return (T) this;
-	}
-}

+ 92 - 73
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/config/TokenSettings.java

@@ -16,7 +16,6 @@
 package org.springframework.security.oauth2.server.authorization.config;
 
 import java.time.Duration;
-import java.util.HashMap;
 import java.util.Map;
 
 import org.springframework.security.oauth2.core.oidc.OidcIdToken;
@@ -28,28 +27,16 @@ import org.springframework.util.Assert;
  *
  * @author Joe Grandja
  * @since 0.0.2
- * @see Settings
+ * @see AbstractSettings
  */
-public class TokenSettings extends Settings {
+public final class TokenSettings extends AbstractSettings {
 	private static final String TOKEN_SETTING_BASE = "setting.token.";
 	public static final String ACCESS_TOKEN_TIME_TO_LIVE = TOKEN_SETTING_BASE.concat("access-token-time-to-live");
 	public static final String REUSE_REFRESH_TOKENS = TOKEN_SETTING_BASE.concat("reuse-refresh-tokens");
 	public static final String REFRESH_TOKEN_TIME_TO_LIVE = TOKEN_SETTING_BASE.concat("refresh-token-time-to-live");
 	public static final String ID_TOKEN_SIGNATURE_ALGORITHM = TOKEN_SETTING_BASE.concat("id-token-signature-algorithm");
 
-	/**
-	 * Constructs a {@code TokenSettings}.
-	 */
-	public TokenSettings() {
-		this(defaultSettings());
-	}
-
-	/**
-	 * Constructs a {@code TokenSettings} using the provided parameters.
-	 *
-	 * @param settings the initial settings
-	 */
-	public TokenSettings(Map<String, Object> settings) {
+	private TokenSettings(Map<String, Object> settings) {
 		super(settings);
 	}
 
@@ -58,94 +45,126 @@ public class TokenSettings extends Settings {
 	 *
 	 * @return the time-to-live for an access token
 	 */
-	public Duration accessTokenTimeToLive() {
-		return setting(ACCESS_TOKEN_TIME_TO_LIVE);
-	}
-
-	/**
-	 * Set the time-to-live for an access token. Must be greater than {@code Duration.ZERO}.
-	 *
-	 * @param accessTokenTimeToLive the time-to-live for an access token
-	 * @return the {@link TokenSettings}
-	 */
-	public TokenSettings accessTokenTimeToLive(Duration accessTokenTimeToLive) {
-		Assert.notNull(accessTokenTimeToLive, "accessTokenTimeToLive cannot be null");
-		Assert.isTrue(accessTokenTimeToLive.getSeconds() > 0, "accessTokenTimeToLive must be greater than Duration.ZERO");
-		setting(ACCESS_TOKEN_TIME_TO_LIVE, accessTokenTimeToLive);
-		return this;
+	public Duration getAccessTokenTimeToLive() {
+		return getSetting(ACCESS_TOKEN_TIME_TO_LIVE);
 	}
 
 	/**
 	 * Returns {@code true} if refresh tokens are reused when returning the access token response,
 	 * or {@code false} if a new refresh token is issued. The default is {@code true}.
 	 */
-	public boolean reuseRefreshTokens() {
-		return setting(REUSE_REFRESH_TOKENS);
+	public boolean isReuseRefreshTokens() {
+		return getSetting(REUSE_REFRESH_TOKENS);
 	}
 
 	/**
-	 * Set to {@code true} if refresh tokens are reused when returning the access token response,
-	 * or {@code false} if a new refresh token is issued.
+	 * Returns the time-to-live for a refresh token. The default is 60 minutes.
 	 *
-	 * @param reuseRefreshTokens {@code true} to reuse refresh tokens, {@code false} to issue new refresh tokens
-	 * @return the {@link TokenSettings}
+	 * @return the time-to-live for a refresh token
 	 */
-	public TokenSettings reuseRefreshTokens(boolean reuseRefreshTokens) {
-		setting(REUSE_REFRESH_TOKENS, reuseRefreshTokens);
-		return this;
+	public Duration getRefreshTokenTimeToLive() {
+		return getSetting(REFRESH_TOKEN_TIME_TO_LIVE);
 	}
 
 	/**
-	 * Returns the time-to-live for a refresh token. The default is 60 minutes.
+	 * Returns the {@link SignatureAlgorithm JWS} algorithm for signing the {@link OidcIdToken ID Token}.
+	 * The default is {@link SignatureAlgorithm#RS256 RS256}.
 	 *
-	 * @return the time-to-live for a refresh token
+	 * @return the {@link SignatureAlgorithm JWS} algorithm for signing the {@link OidcIdToken ID Token}
 	 */
-	public Duration refreshTokenTimeToLive() {
-		return setting(REFRESH_TOKEN_TIME_TO_LIVE);
+	public SignatureAlgorithm getIdTokenSignatureAlgorithm() {
+		return getSetting(ID_TOKEN_SIGNATURE_ALGORITHM);
 	}
 
 	/**
-	 * Set the time-to-live for a refresh token. Must be greater than {@code Duration.ZERO}.
+	 * Constructs a new {@link Builder} with the default settings.
 	 *
-	 * @param refreshTokenTimeToLive the time-to-live for a refresh token
-	 * @return the {@link TokenSettings}
+	 * @return the {@link Builder}
 	 */
-	public TokenSettings refreshTokenTimeToLive(Duration refreshTokenTimeToLive) {
-		Assert.notNull(refreshTokenTimeToLive, "refreshTokenTimeToLive cannot be null");
-		Assert.isTrue(refreshTokenTimeToLive.getSeconds() > 0, "refreshTokenTimeToLive must be greater than Duration.ZERO");
-		setting(REFRESH_TOKEN_TIME_TO_LIVE, refreshTokenTimeToLive);
-		return this;
+	public static Builder builder() {
+		return new Builder()
+				.accessTokenTimeToLive(Duration.ofMinutes(5))
+				.reuseRefreshTokens(true)
+				.refreshTokenTimeToLive(Duration.ofMinutes(60))
+				.idTokenSignatureAlgorithm(SignatureAlgorithm.RS256);
 	}
 
 	/**
-	 * Returns the {@link SignatureAlgorithm JWS} algorithm for signing the {@link OidcIdToken ID Token}.
-	 * The default is {@link SignatureAlgorithm#RS256 RS256}.
+	 * Constructs a new {@link Builder} with the provided settings.
 	 *
-	 * @return the {@link SignatureAlgorithm JWS} algorithm for signing the {@link OidcIdToken ID Token}
+	 * @param settings the settings to initialize the builder
+	 * @return the {@link Builder}
 	 */
-	public SignatureAlgorithm idTokenSignatureAlgorithm() {
-		return setting(ID_TOKEN_SIGNATURE_ALGORITHM);
+	public static Builder withSettings(Map<String, Object> settings) {
+		Assert.notEmpty(settings, "settings cannot be empty");
+		return new Builder()
+				.settings(s -> s.putAll(settings));
 	}
 
 	/**
-	 * Sets the {@link SignatureAlgorithm JWS} algorithm for signing the {@link OidcIdToken ID Token}.
-	 *
-	 * @param idTokenSignatureAlgorithm the {@link SignatureAlgorithm JWS} algorithm for signing the {@link OidcIdToken ID Token}
-	 * @return the {@link TokenSettings}
+	 * A builder for {@link TokenSettings}.
 	 */
-	public TokenSettings idTokenSignatureAlgorithm(SignatureAlgorithm idTokenSignatureAlgorithm) {
-		Assert.notNull(idTokenSignatureAlgorithm, "idTokenSignatureAlgorithm cannot be null");
-		setting(ID_TOKEN_SIGNATURE_ALGORITHM, idTokenSignatureAlgorithm);
-		return this;
-	}
+	public static class Builder extends AbstractBuilder<TokenSettings, Builder> {
+
+		private Builder() {
+		}
+
+		/**
+		 * Set the time-to-live for an access token. Must be greater than {@code Duration.ZERO}.
+		 *
+		 * @param accessTokenTimeToLive the time-to-live for an access token
+		 * @return the {@link Builder} for further configuration
+		 */
+		public Builder accessTokenTimeToLive(Duration accessTokenTimeToLive) {
+			Assert.notNull(accessTokenTimeToLive, "accessTokenTimeToLive cannot be null");
+			Assert.isTrue(accessTokenTimeToLive.getSeconds() > 0, "accessTokenTimeToLive must be greater than Duration.ZERO");
+			return setting(ACCESS_TOKEN_TIME_TO_LIVE, accessTokenTimeToLive);
+		}
+
+		/**
+		 * Set to {@code true} if refresh tokens are reused when returning the access token response,
+		 * or {@code false} if a new refresh token is issued.
+		 *
+		 * @param reuseRefreshTokens {@code true} to reuse refresh tokens, {@code false} to issue new refresh tokens
+		 * @return the {@link Builder} for further configuration
+		 */
+		public Builder reuseRefreshTokens(boolean reuseRefreshTokens) {
+			return setting(REUSE_REFRESH_TOKENS, reuseRefreshTokens);
+		}
+
+		/**
+		 * Set the time-to-live for a refresh token. Must be greater than {@code Duration.ZERO}.
+		 *
+		 * @param refreshTokenTimeToLive the time-to-live for a refresh token
+		 * @return the {@link Builder} for further configuration
+		 */
+		public Builder refreshTokenTimeToLive(Duration refreshTokenTimeToLive) {
+			Assert.notNull(refreshTokenTimeToLive, "refreshTokenTimeToLive cannot be null");
+			Assert.isTrue(refreshTokenTimeToLive.getSeconds() > 0, "refreshTokenTimeToLive must be greater than Duration.ZERO");
+			return setting(REFRESH_TOKEN_TIME_TO_LIVE, refreshTokenTimeToLive);
+		}
+
+		/**
+		 * Sets the {@link SignatureAlgorithm JWS} algorithm for signing the {@link OidcIdToken ID Token}.
+		 *
+		 * @param idTokenSignatureAlgorithm the {@link SignatureAlgorithm JWS} algorithm for signing the {@link OidcIdToken ID Token}
+		 * @return the {@link Builder} for further configuration
+		 */
+		public Builder idTokenSignatureAlgorithm(SignatureAlgorithm idTokenSignatureAlgorithm) {
+			Assert.notNull(idTokenSignatureAlgorithm, "idTokenSignatureAlgorithm cannot be null");
+			return setting(ID_TOKEN_SIGNATURE_ALGORITHM, idTokenSignatureAlgorithm);
+		}
+
+		/**
+		 * Builds the {@link TokenSettings}.
+		 *
+		 * @return the {@link TokenSettings}
+		 */
+		@Override
+		public TokenSettings build() {
+			return new TokenSettings(getSettings());
+		}
 
-	protected static Map<String, Object> defaultSettings() {
-		Map<String, Object> settings = new HashMap<>();
-		settings.put(ACCESS_TOKEN_TIME_TO_LIVE, Duration.ofMinutes(5));
-		settings.put(REUSE_REFRESH_TOKENS, true);
-		settings.put(REFRESH_TOKEN_TIME_TO_LIVE, Duration.ofMinutes(60));
-		settings.put(ID_TOKEN_SIGNATURE_ALGORITHM, SignatureAlgorithm.RS256);
-		return settings;
 	}
 
 }

+ 10 - 8
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationProvider.java

@@ -40,6 +40,8 @@ import org.springframework.security.oauth2.server.authorization.OAuth2Authorizat
 import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
+import org.springframework.security.oauth2.server.authorization.config.ClientSettings;
+import org.springframework.security.oauth2.server.authorization.config.TokenSettings;
 import org.springframework.security.oauth2.server.resource.authentication.AbstractOAuth2TokenAuthenticationToken;
 import org.springframework.util.Assert;
 import org.springframework.util.CollectionUtils;
@@ -169,13 +171,13 @@ public final class OidcClientRegistrationAuthenticationProvider implements Authe
 		}
 
 		builder
-				.clientSettings(clientSettings ->
-						clientSettings
-								.requireProofKey(true)
-								.requireAuthorizationConsent(true))
-				.tokenSettings(tokenSettings ->
-						tokenSettings
-								.idTokenSignatureAlgorithm(SignatureAlgorithm.RS256));
+				.clientSettings(ClientSettings.builder()
+						.requireProofKey(true)
+						.requireAuthorizationConsent(true)
+						.build())
+				.tokenSettings(TokenSettings.builder()
+						.idTokenSignatureAlgorithm(SignatureAlgorithm.RS256)
+						.build());
 
 		return builder.build();
 		// @formatter:on
@@ -207,7 +209,7 @@ public final class OidcClientRegistrationAuthenticationProvider implements Authe
 
 		builder
 				.tokenEndpointAuthenticationMethod(registeredClient.getClientAuthenticationMethods().iterator().next().getValue())
-				.idTokenSignedResponseAlgorithm(registeredClient.getTokenSettings().idTokenSignatureAlgorithm().getName());
+				.idTokenSignedResponseAlgorithm(registeredClient.getTokenSettings().getIdTokenSignatureAlgorithm().getName());
 
 		return builder.build();
 		// @formatter:on

+ 4 - 4
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/web/OidcProviderConfigurationEndpointFilter.java

@@ -77,12 +77,12 @@ public final class OidcProviderConfigurationEndpointFilter extends OncePerReques
 		}
 
 		OidcProviderConfiguration providerConfiguration = OidcProviderConfiguration.builder()
-				.issuer(this.providerSettings.issuer())
-				.authorizationEndpoint(asUrl(this.providerSettings.issuer(), this.providerSettings.authorizationEndpoint()))
-				.tokenEndpoint(asUrl(this.providerSettings.issuer(), this.providerSettings.tokenEndpoint()))
+				.issuer(this.providerSettings.getIssuer())
+				.authorizationEndpoint(asUrl(this.providerSettings.getIssuer(), this.providerSettings.getAuthorizationEndpoint()))
+				.tokenEndpoint(asUrl(this.providerSettings.getIssuer(), this.providerSettings.getTokenEndpoint()))
 				.tokenEndpointAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue())
 				.tokenEndpointAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST.getValue())
-				.jwkSetUrl(asUrl(this.providerSettings.issuer(), this.providerSettings.jwkSetEndpoint()))
+				.jwkSetUrl(asUrl(this.providerSettings.getIssuer(), this.providerSettings.getJwkSetEndpoint()))
 				.responseType(OAuth2AuthorizationResponseType.CODE.getValue())
 				.grantType(AuthorizationGrantType.AUTHORIZATION_CODE.getValue())
 				.grantType(AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())

+ 6 - 6
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/OAuth2AuthorizationServerMetadataEndpointFilter.java

@@ -78,18 +78,18 @@ public final class OAuth2AuthorizationServerMetadataEndpointFilter extends OnceP
 		}
 
 		OAuth2AuthorizationServerMetadata authorizationServerMetadata = OAuth2AuthorizationServerMetadata.builder()
-				.issuer(this.providerSettings.issuer())
-				.authorizationEndpoint(asUrl(this.providerSettings.issuer(), this.providerSettings.authorizationEndpoint()))
-				.tokenEndpoint(asUrl(this.providerSettings.issuer(), this.providerSettings.tokenEndpoint()))
+				.issuer(this.providerSettings.getIssuer())
+				.authorizationEndpoint(asUrl(this.providerSettings.getIssuer(), this.providerSettings.getAuthorizationEndpoint()))
+				.tokenEndpoint(asUrl(this.providerSettings.getIssuer(), this.providerSettings.getTokenEndpoint()))
 				.tokenEndpointAuthenticationMethods(clientAuthenticationMethods())
-				.jwkSetUrl(asUrl(this.providerSettings.issuer(), this.providerSettings.jwkSetEndpoint()))
+				.jwkSetUrl(asUrl(this.providerSettings.getIssuer(), this.providerSettings.getJwkSetEndpoint()))
 				.responseType(OAuth2AuthorizationResponseType.CODE.getValue())
 				.grantType(AuthorizationGrantType.AUTHORIZATION_CODE.getValue())
 				.grantType(AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
 				.grantType(AuthorizationGrantType.REFRESH_TOKEN.getValue())
-				.tokenRevocationEndpoint(asUrl(this.providerSettings.issuer(), this.providerSettings.tokenRevocationEndpoint()))
+				.tokenRevocationEndpoint(asUrl(this.providerSettings.getIssuer(), this.providerSettings.getTokenRevocationEndpoint()))
 				.tokenRevocationEndpointAuthenticationMethods(clientAuthenticationMethods())
-				.tokenIntrospectionEndpoint(asUrl(this.providerSettings.issuer(), this.providerSettings.tokenIntrospectionEndpoint()))
+				.tokenIntrospectionEndpoint(asUrl(this.providerSettings.getIssuer(), this.providerSettings.getTokenIntrospectionEndpoint()))
 				.tokenIntrospectionEndpointAuthenticationMethods(clientAuthenticationMethods())
 				.codeChallengeMethod("plain")
 				.codeChallengeMethod("S256")

+ 2 - 2
oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/JwkSetTests.java

@@ -76,7 +76,7 @@ public class JwkSetTests {
 	public static void init() {
 		JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK);
 		jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
-		providerSettings = new ProviderSettings().jwkSetEndpoint("/test/jwks");
+		providerSettings = ProviderSettings.builder().jwkSetEndpoint("/test/jwks").build();
 		db = new EmbeddedDatabaseBuilder()
 				.generateUniqueName(true)
 				.setType(EmbeddedDatabaseType.HSQL)
@@ -108,7 +108,7 @@ public class JwkSetTests {
 	public void requestWhenJwkSetCustomEndpointThenReturnKeys() throws Exception {
 		this.spring.register(AuthorizationServerConfigurationCustomEndpoints.class).autowire();
 
-		assertJwkSetRequestThenReturnKeys(providerSettings.jwkSetEndpoint());
+		assertJwkSetRequestThenReturnKeys(providerSettings.getJwkSetEndpoint());
 	}
 
 	private void assertJwkSetRequestThenReturnKeys(String jwkSetEndpointUri) throws Exception {

+ 9 - 7
oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationCodeGrantTests.java

@@ -86,6 +86,7 @@ import org.springframework.security.oauth2.server.authorization.client.JdbcRegis
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
 import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients;
+import org.springframework.security.oauth2.server.authorization.config.ClientSettings;
 import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
 import org.springframework.security.oauth2.server.authorization.jackson2.TestingAuthenticationTokenMixin;
 import org.springframework.security.web.SecurityFilterChain;
@@ -167,9 +168,10 @@ public class OAuth2AuthorizationCodeGrantTests {
 		JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK);
 		jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
 		jwtEncoder = new NimbusJwsEncoder(jwkSource);
-		providerSettings = new ProviderSettings()
+		providerSettings = ProviderSettings.builder()
 				.authorizationEndpoint("/test/authorize")
-				.tokenEndpoint("/test/token");
+				.tokenEndpoint("/test/token")
+				.build();
 		authorizationRequestConverter = mock(AuthenticationConverter.class);
 		authorizationRequestAuthenticationProvider = mock(AuthenticationProvider.class);
 		authorizationResponseHandler = mock(AuthenticationSuccessHandler.class);
@@ -232,7 +234,7 @@ public class OAuth2AuthorizationCodeGrantTests {
 	public void requestWhenAuthorizationRequestCustomEndpointThenRedirectToClient() throws Exception {
 		this.spring.register(AuthorizationServerConfigurationCustomEndpoints.class).autowire();
 
-		assertAuthorizationRequestRedirectsToClient(providerSettings.authorizationEndpoint());
+		assertAuthorizationRequestRedirectsToClient(providerSettings.getAuthorizationEndpoint());
 	}
 
 	private void assertAuthorizationRequestRedirectsToClient(String authorizationEndpointUri) throws Exception {
@@ -287,7 +289,7 @@ public class OAuth2AuthorizationCodeGrantTests {
 		this.authorizationService.save(authorization);
 
 		assertTokenRequestReturnsAccessTokenResponse(
-				registeredClient, authorization, providerSettings.tokenEndpoint());
+				registeredClient, authorization, providerSettings.getTokenEndpoint());
 	}
 
 	private OAuth2AccessTokenResponse assertTokenRequestReturnsAccessTokenResponse(RegisteredClient registeredClient,
@@ -389,7 +391,7 @@ public class OAuth2AuthorizationCodeGrantTests {
 					scopes.add("message.read");
 					scopes.add("message.write");
 				})
-				.clientSettings(settings -> settings.requireAuthorizationConsent(true))
+				.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
 				.build();
 		this.registeredClientRepository.save(registeredClient);
 
@@ -416,7 +418,7 @@ public class OAuth2AuthorizationCodeGrantTests {
 					scopes.add("message.read");
 					scopes.add("message.write");
 				})
-				.clientSettings(settings -> settings.requireAuthorizationConsent(true))
+				.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
 				.build();
 		this.registeredClientRepository.save(registeredClient);
 
@@ -464,7 +466,7 @@ public class OAuth2AuthorizationCodeGrantTests {
 					scopes.add("message.read");
 					scopes.add("message.write");
 				})
-				.clientSettings(settings -> settings.requireAuthorizationConsent(true))
+				.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
 				.build();
 		this.registeredClientRepository.save(registeredClient);
 

+ 1 - 1
oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationServerMetadataTests.java

@@ -125,7 +125,7 @@ public class OAuth2AuthorizationServerMetadataTests {
 
 		@Bean
 		ProviderSettings providerSettings() {
-			return new ProviderSettings().issuer(issuerUrl);
+			return ProviderSettings.builder().issuer(issuerUrl).build();
 		}
 	}
 

+ 3 - 3
oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenIntrospectionTests.java

@@ -109,7 +109,7 @@ public class OAuth2TokenIntrospectionTests {
 	public static void init() {
 		JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK);
 		jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
-		providerSettings = new ProviderSettings().tokenIntrospectionEndpoint("/test/introspect");
+		providerSettings = ProviderSettings.builder().tokenIntrospectionEndpoint("/test/introspect").build();
 		db = new EmbeddedDatabaseBuilder()
 				.generateUniqueName(true)
 				.setType(EmbeddedDatabaseType.HSQL)
@@ -152,7 +152,7 @@ public class OAuth2TokenIntrospectionTests {
 		this.authorizationService.save(authorization);
 
 		// @formatter:off
-		MvcResult mvcResult = this.mvc.perform(post(providerSettings.tokenIntrospectionEndpoint())
+		MvcResult mvcResult = this.mvc.perform(post(providerSettings.getTokenIntrospectionEndpoint())
 				.params(getTokenIntrospectionRequestParameters(accessToken, OAuth2TokenType.ACCESS_TOKEN))
 				.with(httpBasic(introspectRegisteredClient.getClientId(), introspectRegisteredClient.getClientSecret())))
 				.andExpect(status().isOk())
@@ -192,7 +192,7 @@ public class OAuth2TokenIntrospectionTests {
 		this.authorizationService.save(authorization);
 
 		// @formatter:off
-		MvcResult mvcResult = this.mvc.perform(post(providerSettings.tokenIntrospectionEndpoint())
+		MvcResult mvcResult = this.mvc.perform(post(providerSettings.getTokenIntrospectionEndpoint())
 				.params(getTokenIntrospectionRequestParameters(refreshToken, OAuth2TokenType.REFRESH_TOKEN))
 				.with(httpBasic(introspectRegisteredClient.getClientId(), introspectRegisteredClient.getClientSecret())))
 				.andExpect(status().isOk())

+ 2 - 2
oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenRevocationTests.java

@@ -97,7 +97,7 @@ public class OAuth2TokenRevocationTests {
 	public static void init() {
 		JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK);
 		jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
-		providerSettings = new ProviderSettings().tokenRevocationEndpoint("/test/revoke");
+		providerSettings = ProviderSettings.builder().tokenRevocationEndpoint("/test/revoke").build();
 		db = new EmbeddedDatabaseBuilder()
 				.generateUniqueName(true)
 				.setType(EmbeddedDatabaseType.HSQL)
@@ -154,7 +154,7 @@ public class OAuth2TokenRevocationTests {
 	public void requestWhenRevokeAccessTokenCustomEndpointThenRevoked() throws Exception {
 		this.spring.register(AuthorizationServerConfigurationCustomEndpoints.class).autowire();
 
-		assertRevokeAccessTokenThenRevoked(providerSettings.tokenRevocationEndpoint());
+		assertRevokeAccessTokenThenRevoked(providerSettings.getTokenRevocationEndpoint());
 	}
 
 	private void assertRevokeAccessTokenThenRevoked(String tokenRevocationEndpointUri) throws Exception {

+ 3 - 3
oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcTests.java

@@ -333,7 +333,7 @@ public class OidcTests {
 
 		@Bean
 		ProviderSettings providerSettings() {
-			return new ProviderSettings().issuer(ISSUER_URL);
+			return ProviderSettings.builder().issuer(ISSUER_URL).build();
 		}
 	}
 
@@ -343,7 +343,7 @@ public class OidcTests {
 
 		@Bean
 		ProviderSettings providerSettings() {
-			return new ProviderSettings().issuer("urn:example");
+			return ProviderSettings.builder().issuer("urn:example").build();
 		}
 	}
 
@@ -353,7 +353,7 @@ public class OidcTests {
 
 		@Bean
 		ProviderSettings providerSettings() {
-			return new ProviderSettings().issuer("https://not a valid uri");
+			return ProviderSettings.builder().issuer("https://not a valid uri").build();
 		}
 	}
 }

+ 5 - 2
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeAuthenticationProviderTests.java

@@ -53,6 +53,7 @@ import org.springframework.security.oauth2.server.authorization.OAuth2TokenCusto
 import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
 import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients;
+import org.springframework.security.oauth2.server.authorization.config.TokenSettings;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -377,8 +378,10 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests {
 		Duration accessTokenTTL = Duration.ofHours(2);
 		Duration refreshTokenTTL = Duration.ofDays(1);
 		RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
-				.tokenSettings(tokenSettings ->
-						tokenSettings.accessTokenTimeToLive(accessTokenTTL).refreshTokenTimeToLive(refreshTokenTTL))
+				.tokenSettings(TokenSettings.builder()
+						.accessTokenTimeToLive(accessTokenTTL)
+						.refreshTokenTimeToLive(refreshTokenTTL)
+						.build())
 				.build();
 
 		OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient).build();

+ 5 - 4
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProviderTests.java

@@ -46,6 +46,7 @@ import org.springframework.security.oauth2.server.authorization.TestOAuth2Author
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
 import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients;
+import org.springframework.security.oauth2.server.authorization.config.ClientSettings;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -309,7 +310,7 @@ public class OAuth2AuthorizationCodeRequestAuthenticationProviderTests {
 	@Test
 	public void authenticateWhenPkceRequiredAndMissingCodeChallengeThenThrowOAuth2AuthorizationCodeRequestAuthenticationException() {
 		RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
-				.clientSettings(clientSettings -> clientSettings.requireProofKey(true))
+				.clientSettings(ClientSettings.builder().requireProofKey(true).build())
 				.build();
 		when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
 				.thenReturn(registeredClient);
@@ -365,7 +366,7 @@ public class OAuth2AuthorizationCodeRequestAuthenticationProviderTests {
 	@Test
 	public void authenticateWhenRequireAuthorizationConsentThenReturnAuthorizationConsent() {
 		RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
-				.clientSettings(clientSettings -> clientSettings.requireAuthorizationConsent(true))
+				.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
 				.build();
 		when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
 				.thenReturn(registeredClient);
@@ -412,7 +413,7 @@ public class OAuth2AuthorizationCodeRequestAuthenticationProviderTests {
 	@Test
 	public void authenticateWhenRequireAuthorizationConsentAndOnlyOpenidScopeRequestedThenAuthorizationConsentNotRequired() {
 		RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
-				.clientSettings(clientSettings -> clientSettings.requireAuthorizationConsent(true))
+				.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
 				.scopes(scopes -> {
 					scopes.clear();
 					scopes.add(OidcScopes.OPENID);
@@ -434,7 +435,7 @@ public class OAuth2AuthorizationCodeRequestAuthenticationProviderTests {
 	@Test
 	public void authenticateWhenRequireAuthorizationConsentAndAllPreviouslyApprovedThenAuthorizationConsentNotRequired() {
 		RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
-				.clientSettings(clientSettings -> clientSettings.requireAuthorizationConsent(true))
+				.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
 				.build();
 		when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
 				.thenReturn(registeredClient);

+ 2 - 1
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientAuthenticationProviderTests.java

@@ -36,6 +36,7 @@ import org.springframework.security.oauth2.server.authorization.TestOAuth2Author
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
 import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients;
+import org.springframework.security.oauth2.server.authorization.config.ClientSettings;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -209,7 +210,7 @@ public class OAuth2ClientAuthenticationProviderTests {
 	@Test
 	public void authenticateWhenPkceAndRequireProofKeyAndMissingCodeChallengeThenThrowOAuth2AuthenticationException() {
 		RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
-				.clientSettings(clientSettings -> clientSettings.requireProofKey(true))
+				.clientSettings(ClientSettings.builder().requireProofKey(true).build())
 				.build();
 		when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
 				.thenReturn(registeredClient);

+ 2 - 1
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2RefreshTokenAuthenticationProviderTests.java

@@ -52,6 +52,7 @@ import org.springframework.security.oauth2.server.authorization.OAuth2TokenCusto
 import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
 import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients;
+import org.springframework.security.oauth2.server.authorization.config.TokenSettings;
 
 import static org.assertj.core.api.Assertions.entry;
 import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
@@ -233,7 +234,7 @@ public class OAuth2RefreshTokenAuthenticationProviderTests {
 	@Test
 	public void authenticateWhenReuseRefreshTokensFalseThenReturnNewRefreshToken() {
 		RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
-				.tokenSettings(tokenSettings -> tokenSettings.reuseRefreshTokens(false))
+				.tokenSettings(TokenSettings.builder().reuseRefreshTokens(false).build())
 				.build();
 		OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient).build();
 		when(this.authorizationService.findByToken(

+ 4 - 4
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/client/JdbcRegisteredClientRepositoryTests.java

@@ -42,6 +42,8 @@ import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
 import org.springframework.security.jackson2.SecurityJackson2Modules;
 import org.springframework.security.oauth2.core.AuthorizationGrantType;
 import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
+import org.springframework.security.oauth2.server.authorization.config.ClientSettings;
+import org.springframework.security.oauth2.server.authorization.config.TokenSettings;
 import org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationServerJackson2Module;
 import org.springframework.util.StringUtils;
 
@@ -322,12 +324,10 @@ public class JdbcRegisteredClientRepositoryTests {
 				// @formatter:on
 
 				Map<String, Object> clientSettingsMap = parseMap(rs.getString("clientSettings"));
-				builder.clientSettings(clientSettings ->
-						clientSettings.settings().putAll(clientSettingsMap));
+				builder.clientSettings(ClientSettings.withSettings(clientSettingsMap).build());
 
 				Map<String, Object> tokenSettingsMap = parseMap(rs.getString("tokenSettings"));
-				builder.tokenSettings(tokenSettings ->
-						tokenSettings.settings().putAll(tokenSettingsMap));
+				builder.tokenSettings(TokenSettings.withSettings(tokenSettingsMap).build());
 
 				return builder.build();
 			}

+ 2 - 2
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/client/RegisteredClientTests.java

@@ -347,9 +347,9 @@ public class RegisteredClientTests {
 		assertThat(registration.getRedirectUris()).isNotSameAs(updated.getRedirectUris());
 		assertThat(registration.getScopes()).isEqualTo(updated.getScopes());
 		assertThat(registration.getScopes()).isNotSameAs(updated.getScopes());
-		assertThat(registration.getClientSettings().settings()).isEqualTo(updated.getClientSettings().settings());
+		assertThat(registration.getClientSettings()).isEqualTo(updated.getClientSettings());
 		assertThat(registration.getClientSettings()).isNotSameAs(updated.getClientSettings());
-		assertThat(registration.getTokenSettings().settings()).isEqualTo(updated.getTokenSettings().settings());
+		assertThat(registration.getTokenSettings()).isEqualTo(updated.getTokenSettings());
 		assertThat(registration.getTokenSettings()).isNotSameAs(updated.getTokenSettings());
 	}
 

+ 2 - 1
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/client/TestRegisteredClients.java

@@ -20,6 +20,7 @@ import java.time.temporal.ChronoUnit;
 
 import org.springframework.security.oauth2.core.AuthorizationGrantType;
 import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
+import org.springframework.security.oauth2.server.authorization.config.ClientSettings;
 
 /**
  * @author Anoop Garlapati
@@ -61,6 +62,6 @@ public class TestRegisteredClients {
 				.clientAuthenticationMethod(ClientAuthenticationMethod.NONE)
 				.redirectUri("https://example.com")
 				.scope("scope1")
-				.clientSettings(clientSettings -> clientSettings.requireProofKey(true));
+				.clientSettings(ClientSettings.builder().requireProofKey(true).build());
 	}
 }

+ 22 - 28
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/ClientSettingsTests.java

@@ -18,7 +18,6 @@ package org.springframework.security.oauth2.server.authorization.config;
 import org.junit.Test;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 /**
  * Tests for {@link ClientSettings}.
@@ -28,43 +27,38 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
 public class ClientSettingsTests {
 
 	@Test
-	public void constructorWhenDefaultThenDefaultsAreSet() {
-		ClientSettings clientSettings = new ClientSettings();
-		assertThat(clientSettings.settings()).hasSize(2);
-		assertThat(clientSettings.requireProofKey()).isFalse();
-		assertThat(clientSettings.requireAuthorizationConsent()).isFalse();
-	}
-
-	@Test
-	public void constructorWhenNullThenThrowIllegalArgumentException() {
-		assertThatThrownBy(() -> new ClientSettings(null))
-				.isInstanceOf(IllegalArgumentException.class)
-				.hasMessage("settings cannot be null");
+	public void buildWhenDefaultThenDefaultsAreSet() {
+		ClientSettings clientSettings = ClientSettings.builder().build();
+		assertThat(clientSettings.getSettings()).hasSize(2);
+		assertThat(clientSettings.isRequireProofKey()).isFalse();
+		assertThat(clientSettings.isRequireAuthorizationConsent()).isFalse();
 	}
 
 	@Test
 	public void requireProofKeyWhenTrueThenSet() {
-		ClientSettings clientSettings = new ClientSettings().requireProofKey(true);
-		assertThat(clientSettings.requireProofKey()).isTrue();
+		ClientSettings clientSettings = ClientSettings.builder()
+				.requireProofKey(true)
+				.build();
+		assertThat(clientSettings.isRequireProofKey()).isTrue();
 	}
 
 	@Test
 	public void requireAuthorizationConsentWhenTrueThenSet() {
-		ClientSettings clientSettings = new ClientSettings().requireAuthorizationConsent(true);
-		assertThat(clientSettings.requireAuthorizationConsent()).isTrue();
+		ClientSettings clientSettings = ClientSettings.builder()
+				.requireAuthorizationConsent(true)
+				.build();
+		assertThat(clientSettings.isRequireAuthorizationConsent()).isTrue();
 	}
 
 	@Test
-	public void settingWhenCalledThenReturnClientSettings() {
-		ClientSettings clientSettings = new ClientSettings()
-				.<ClientSettings>setting("name1", "value1")
-				.requireProofKey(true)
-				.<ClientSettings>settings(settings -> settings.put("name2", "value2"))
-				.requireAuthorizationConsent(true);
-		assertThat(clientSettings.settings()).hasSize(4);
-		assertThat(clientSettings.requireProofKey()).isTrue();
-		assertThat(clientSettings.requireAuthorizationConsent()).isTrue();
-		assertThat(clientSettings.<String>setting("name1")).isEqualTo("value1");
-		assertThat(clientSettings.<String>setting("name2")).isEqualTo("value2");
+	public void settingWhenCustomThenSet() {
+		ClientSettings clientSettings = ClientSettings.builder()
+				.setting("name1", "value1")
+				.settings(settings -> settings.put("name2", "value2"))
+				.build();
+		assertThat(clientSettings.getSettings()).hasSize(4);
+		assertThat(clientSettings.<String>getSetting("name1")).isEqualTo("value1");
+		assertThat(clientSettings.<String>getSetting("name2")).isEqualTo("value2");
 	}
+
 }

+ 36 - 41
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/ProviderSettingsTests.java

@@ -28,20 +28,20 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
 public class ProviderSettingsTests {
 
 	@Test
-	public void constructorWhenDefaultThenDefaultsAreSet() {
-		ProviderSettings providerSettings = new ProviderSettings();
-
-		assertThat(providerSettings.issuer()).isNull();
-		assertThat(providerSettings.authorizationEndpoint()).isEqualTo("/oauth2/authorize");
-		assertThat(providerSettings.tokenEndpoint()).isEqualTo("/oauth2/token");
-		assertThat(providerSettings.jwkSetEndpoint()).isEqualTo("/oauth2/jwks");
-		assertThat(providerSettings.tokenRevocationEndpoint()).isEqualTo("/oauth2/revoke");
-		assertThat(providerSettings.tokenIntrospectionEndpoint()).isEqualTo("/oauth2/introspect");
-		assertThat(providerSettings.oidcClientRegistrationEndpoint()).isEqualTo("/connect/register");
+	public void buildWhenDefaultThenDefaultsAreSet() {
+		ProviderSettings providerSettings = ProviderSettings.builder().build();
+
+		assertThat(providerSettings.getIssuer()).isNull();
+		assertThat(providerSettings.getAuthorizationEndpoint()).isEqualTo("/oauth2/authorize");
+		assertThat(providerSettings.getTokenEndpoint()).isEqualTo("/oauth2/token");
+		assertThat(providerSettings.getJwkSetEndpoint()).isEqualTo("/oauth2/jwks");
+		assertThat(providerSettings.getTokenRevocationEndpoint()).isEqualTo("/oauth2/revoke");
+		assertThat(providerSettings.getTokenIntrospectionEndpoint()).isEqualTo("/oauth2/introspect");
+		assertThat(providerSettings.getOidcClientRegistrationEndpoint()).isEqualTo("/connect/register");
 	}
 
 	@Test
-	public void settingsWhenProvidedThenSet() {
+	public void buildWhenSettingsProvidedThenSet() {
 		String authorizationEndpoint = "/oauth2/v1/authorize";
 		String tokenEndpoint = "/oauth2/v1/token";
 		String jwkSetEndpoint = "/oauth2/v1/jwks";
@@ -50,7 +50,7 @@ public class ProviderSettingsTests {
 		String oidcClientRegistrationEndpoint = "/connect/v1/register";
 		String issuer = "https://example.com:9000";
 
-		ProviderSettings providerSettings = new ProviderSettings()
+		ProviderSettings providerSettings = ProviderSettings.builder()
 				.issuer(issuer)
 				.authorizationEndpoint(authorizationEndpoint)
 				.tokenEndpoint(tokenEndpoint)
@@ -58,81 +58,76 @@ public class ProviderSettingsTests {
 				.tokenRevocationEndpoint(tokenRevocationEndpoint)
 				.tokenIntrospectionEndpoint(tokenIntrospectionEndpoint)
 				.tokenRevocationEndpoint(tokenRevocationEndpoint)
-				.oidcClientRegistrationEndpoint(oidcClientRegistrationEndpoint);
-
-		assertThat(providerSettings.issuer()).isEqualTo(issuer);
-		assertThat(providerSettings.authorizationEndpoint()).isEqualTo(authorizationEndpoint);
-		assertThat(providerSettings.tokenEndpoint()).isEqualTo(tokenEndpoint);
-		assertThat(providerSettings.jwkSetEndpoint()).isEqualTo(jwkSetEndpoint);
-		assertThat(providerSettings.tokenRevocationEndpoint()).isEqualTo(tokenRevocationEndpoint);
-		assertThat(providerSettings.tokenIntrospectionEndpoint()).isEqualTo(tokenIntrospectionEndpoint);
-		assertThat(providerSettings.oidcClientRegistrationEndpoint()).isEqualTo(oidcClientRegistrationEndpoint);
+				.oidcClientRegistrationEndpoint(oidcClientRegistrationEndpoint)
+				.build();
+
+		assertThat(providerSettings.getIssuer()).isEqualTo(issuer);
+		assertThat(providerSettings.getAuthorizationEndpoint()).isEqualTo(authorizationEndpoint);
+		assertThat(providerSettings.getTokenEndpoint()).isEqualTo(tokenEndpoint);
+		assertThat(providerSettings.getJwkSetEndpoint()).isEqualTo(jwkSetEndpoint);
+		assertThat(providerSettings.getTokenRevocationEndpoint()).isEqualTo(tokenRevocationEndpoint);
+		assertThat(providerSettings.getTokenIntrospectionEndpoint()).isEqualTo(tokenIntrospectionEndpoint);
+		assertThat(providerSettings.getOidcClientRegistrationEndpoint()).isEqualTo(oidcClientRegistrationEndpoint);
 	}
 
 	@Test
-	public void settingWhenCustomThenReturnAllSettings() {
-		ProviderSettings providerSettings = new ProviderSettings()
+	public void settingWhenCustomThenSet() {
+		ProviderSettings providerSettings = ProviderSettings.builder()
 				.setting("name1", "value1")
-				.settings(settings -> settings.put("name2", "value2"));
+				.settings(settings -> settings.put("name2", "value2"))
+				.build();
 
-		assertThat(providerSettings.settings()).hasSize(8);
-		assertThat(providerSettings.<String>setting("name1")).isEqualTo("value1");
-		assertThat(providerSettings.<String>setting("name2")).isEqualTo("value2");
+		assertThat(providerSettings.getSettings()).hasSize(8);
+		assertThat(providerSettings.<String>getSetting("name1")).isEqualTo("value1");
+		assertThat(providerSettings.<String>getSetting("name2")).isEqualTo("value2");
 	}
 
 	@Test
 	public void issuerWhenNullThenThrowIllegalArgumentException() {
-		ProviderSettings settings = new ProviderSettings();
 		assertThatIllegalArgumentException()
-				.isThrownBy(() -> settings.issuer(null))
+				.isThrownBy(() -> ProviderSettings.builder().issuer(null))
 				.withMessage("value cannot be null");
 	}
 
 	@Test
 	public void authorizationEndpointWhenNullThenThrowIllegalArgumentException() {
-		ProviderSettings settings = new ProviderSettings();
 		assertThatIllegalArgumentException()
-				.isThrownBy(() -> settings.authorizationEndpoint(null))
+				.isThrownBy(() -> ProviderSettings.builder().authorizationEndpoint(null))
 				.withMessage("value cannot be null");
 	}
 
 	@Test
 	public void tokenEndpointWhenNullThenThrowIllegalArgumentException() {
-		ProviderSettings settings = new ProviderSettings();
 		assertThatIllegalArgumentException()
-				.isThrownBy(() -> settings.tokenEndpoint(null))
+				.isThrownBy(() -> ProviderSettings.builder().tokenEndpoint(null))
 				.withMessage("value cannot be null");
 	}
 
 	@Test
 	public void tokenRevocationEndpointWhenNullThenThrowIllegalArgumentException() {
-		ProviderSettings settings = new ProviderSettings();
 		assertThatIllegalArgumentException()
-				.isThrownBy(() -> settings.tokenRevocationEndpoint(null))
+				.isThrownBy(() -> ProviderSettings.builder().tokenRevocationEndpoint(null))
 				.withMessage("value cannot be null");
 	}
 
 	@Test
 	public void tokenIntrospectionEndpointWhenNullThenThrowIllegalArgumentException() {
-		ProviderSettings settings = new ProviderSettings();
 		assertThatIllegalArgumentException()
-				.isThrownBy(() -> settings.tokenIntrospectionEndpoint(null))
+				.isThrownBy(() -> ProviderSettings.builder().tokenIntrospectionEndpoint(null))
 				.withMessage("value cannot be null");
 	}
 
 	@Test
 	public void oidcClientRegistrationEndpointWhenNullThenThrowIllegalArgumentException() {
-		ProviderSettings settings = new ProviderSettings();
 		assertThatIllegalArgumentException()
-				.isThrownBy(() -> settings.oidcClientRegistrationEndpoint(null))
+				.isThrownBy(() -> ProviderSettings.builder().oidcClientRegistrationEndpoint(null))
 				.withMessage("value cannot be null");
 	}
 
 	@Test
 	public void jwksEndpointWhenNullThenThrowIllegalArgumentException() {
-		ProviderSettings settings = new ProviderSettings();
 		assertThatIllegalArgumentException()
-				.isThrownBy(() -> settings.jwkSetEndpoint(null))
+				.isThrownBy(() -> ProviderSettings.builder().jwkSetEndpoint(null))
 				.withMessage("value cannot be null");
 	}
 

+ 0 - 78
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/SettingsTests.java

@@ -1,78 +0,0 @@
-/*
- * Copyright 2020 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.security.oauth2.server.authorization.config;
-
-import org.junit.Test;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.assertj.core.api.Assertions.entry;
-
-/**
- * Tests for {@link Settings}.
- *
- * @author Joe Grandja
- */
-public class SettingsTests {
-
-	@Test
-	public void constructorWhenNullThenThrowIllegalArgumentException() {
-		assertThatThrownBy(() -> new Settings(null))
-				.isInstanceOf(IllegalArgumentException.class)
-				.hasMessage("settings cannot be null");
-	}
-
-	@Test
-	public void constructorWhenSettingsProvidedThenSettingsAreSet() {
-		Map<String, Object> initialSettings = new HashMap<>();
-		initialSettings.put("setting1", "value1");
-		initialSettings.put("setting2", "value2");
-
-		Settings settings = new Settings(initialSettings)
-				.setting("setting3", "value3")
-				.settings(s -> s.put("setting4", "value4"));
-
-		assertThat(settings.settings()).contains(
-				entry("setting1", "value1"),
-				entry("setting2", "value2"),
-				entry("setting3", "value3"),
-				entry("setting4", "value4"));
-	}
-
-	@Test
-	public void getSettingWhenNameNullThenThrowIllegalArgumentException() {
-		assertThatThrownBy(() -> new Settings().setting(null))
-				.isInstanceOf(IllegalArgumentException.class)
-				.hasMessage("name cannot be empty");
-	}
-
-	@Test
-	public void setSettingWhenNameNullThenThrowIllegalArgumentException() {
-		assertThatThrownBy(() -> new Settings().setting(null, "value"))
-				.isInstanceOf(IllegalArgumentException.class)
-				.hasMessage("name cannot be empty");
-	}
-
-	@Test
-	public void setSettingWhenValueNullThenThrowIllegalArgumentException() {
-		assertThatThrownBy(() -> new Settings().setting("setting", null))
-				.isInstanceOf(IllegalArgumentException.class)
-				.hasMessage("value cannot be null");
-	}
-}

+ 39 - 42
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/TokenSettingsTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 the original author or authors.
+ * Copyright 2020-2021 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -32,42 +32,37 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
 public class TokenSettingsTests {
 
 	@Test
-	public void constructorWhenDefaultThenDefaultsAreSet() {
-		TokenSettings tokenSettings = new TokenSettings();
-		assertThat(tokenSettings.settings()).hasSize(4);
-		assertThat(tokenSettings.accessTokenTimeToLive()).isEqualTo(Duration.ofMinutes(5));
-		assertThat(tokenSettings.reuseRefreshTokens()).isTrue();
-		assertThat(tokenSettings.refreshTokenTimeToLive()).isEqualTo(Duration.ofMinutes(60));
-		assertThat(tokenSettings.idTokenSignatureAlgorithm()).isEqualTo(SignatureAlgorithm.RS256);
-	}
-
-	@Test
-	public void constructorWhenNullThenThrowIllegalArgumentException() {
-		assertThatThrownBy(() -> new TokenSettings(null))
-				.isInstanceOf(IllegalArgumentException.class)
-				.hasMessage("settings cannot be null");
+	public void buildWhenDefaultThenDefaultsAreSet() {
+		TokenSettings tokenSettings = TokenSettings.builder().build();
+		assertThat(tokenSettings.getSettings()).hasSize(4);
+		assertThat(tokenSettings.getAccessTokenTimeToLive()).isEqualTo(Duration.ofMinutes(5));
+		assertThat(tokenSettings.isReuseRefreshTokens()).isTrue();
+		assertThat(tokenSettings.getRefreshTokenTimeToLive()).isEqualTo(Duration.ofMinutes(60));
+		assertThat(tokenSettings.getIdTokenSignatureAlgorithm()).isEqualTo(SignatureAlgorithm.RS256);
 	}
 
 	@Test
 	public void accessTokenTimeToLiveWhenProvidedThenSet() {
 		Duration accessTokenTimeToLive = Duration.ofMinutes(10);
-		TokenSettings tokenSettings = new TokenSettings().accessTokenTimeToLive(accessTokenTimeToLive);
-		assertThat(tokenSettings.accessTokenTimeToLive()).isEqualTo(accessTokenTimeToLive);
+		TokenSettings tokenSettings = TokenSettings.builder()
+				.accessTokenTimeToLive(accessTokenTimeToLive)
+				.build();
+		assertThat(tokenSettings.getAccessTokenTimeToLive()).isEqualTo(accessTokenTimeToLive);
 	}
 
 	@Test
 	public void accessTokenTimeToLiveWhenNullOrZeroOrNegativeThenThrowIllegalArgumentException() {
-		assertThatThrownBy(() -> new TokenSettings().accessTokenTimeToLive(null))
+		assertThatThrownBy(() -> TokenSettings.builder().accessTokenTimeToLive(null))
 				.isInstanceOf(IllegalArgumentException.class)
 				.extracting(Throwable::getMessage)
 				.isEqualTo("accessTokenTimeToLive cannot be null");
 
-		assertThatThrownBy(() -> new TokenSettings().accessTokenTimeToLive(Duration.ZERO))
+		assertThatThrownBy(() -> TokenSettings.builder().accessTokenTimeToLive(Duration.ZERO))
 				.isInstanceOf(IllegalArgumentException.class)
 				.extracting(Throwable::getMessage)
 				.isEqualTo("accessTokenTimeToLive must be greater than Duration.ZERO");
 
-		assertThatThrownBy(() -> new TokenSettings().accessTokenTimeToLive(Duration.ofSeconds(-10)))
+		assertThatThrownBy(() -> TokenSettings.builder().accessTokenTimeToLive(Duration.ofSeconds(-10)))
 				.isInstanceOf(IllegalArgumentException.class)
 				.extracting(Throwable::getMessage)
 				.isEqualTo("accessTokenTimeToLive must be greater than Duration.ZERO");
@@ -75,30 +70,34 @@ public class TokenSettingsTests {
 
 	@Test
 	public void reuseRefreshTokensWhenFalseThenSet() {
-		TokenSettings tokenSettings = new TokenSettings().reuseRefreshTokens(false);
-		assertThat(tokenSettings.reuseRefreshTokens()).isFalse();
+		TokenSettings tokenSettings = TokenSettings.builder()
+				.reuseRefreshTokens(false)
+				.build();
+		assertThat(tokenSettings.isReuseRefreshTokens()).isFalse();
 	}
 
 	@Test
 	public void refreshTokenTimeToLiveWhenProvidedThenSet() {
 		Duration refreshTokenTimeToLive = Duration.ofDays(10);
-		TokenSettings tokenSettings = new TokenSettings().refreshTokenTimeToLive(refreshTokenTimeToLive);
-		assertThat(tokenSettings.refreshTokenTimeToLive()).isEqualTo(refreshTokenTimeToLive);
+		TokenSettings tokenSettings = TokenSettings.builder()
+				.refreshTokenTimeToLive(refreshTokenTimeToLive)
+				.build();
+		assertThat(tokenSettings.getRefreshTokenTimeToLive()).isEqualTo(refreshTokenTimeToLive);
 	}
 
 	@Test
 	public void refreshTokenTimeToLiveWhenNullOrZeroOrNegativeThenThrowIllegalArgumentException() {
-		assertThatThrownBy(() -> new TokenSettings().refreshTokenTimeToLive(null))
+		assertThatThrownBy(() -> TokenSettings.builder().refreshTokenTimeToLive(null))
 				.isInstanceOf(IllegalArgumentException.class)
 				.extracting(Throwable::getMessage)
 				.isEqualTo("refreshTokenTimeToLive cannot be null");
 
-		assertThatThrownBy(() -> new TokenSettings().refreshTokenTimeToLive(Duration.ZERO))
+		assertThatThrownBy(() -> TokenSettings.builder().refreshTokenTimeToLive(Duration.ZERO))
 				.isInstanceOf(IllegalArgumentException.class)
 				.extracting(Throwable::getMessage)
 				.isEqualTo("refreshTokenTimeToLive must be greater than Duration.ZERO");
 
-		assertThatThrownBy(() -> new TokenSettings().refreshTokenTimeToLive(Duration.ofSeconds(-10)))
+		assertThatThrownBy(() -> TokenSettings.builder().refreshTokenTimeToLive(Duration.ofSeconds(-10)))
 				.isInstanceOf(IllegalArgumentException.class)
 				.extracting(Throwable::getMessage)
 				.isEqualTo("refreshTokenTimeToLive must be greater than Duration.ZERO");
@@ -107,23 +106,21 @@ public class TokenSettingsTests {
 	@Test
 	public void idTokenSignatureAlgorithmWhenProvidedThenSet() {
 		SignatureAlgorithm idTokenSignatureAlgorithm = SignatureAlgorithm.RS512;
-		TokenSettings tokenSettings = new TokenSettings().idTokenSignatureAlgorithm(idTokenSignatureAlgorithm);
-		assertThat(tokenSettings.idTokenSignatureAlgorithm()).isEqualTo(idTokenSignatureAlgorithm);
+		TokenSettings tokenSettings = TokenSettings.builder()
+				.idTokenSignatureAlgorithm(idTokenSignatureAlgorithm)
+				.build();
+		assertThat(tokenSettings.getIdTokenSignatureAlgorithm()).isEqualTo(idTokenSignatureAlgorithm);
 	}
 
 	@Test
-	public void settingWhenCalledThenReturnTokenSettings() {
-		Duration accessTokenTimeToLive = Duration.ofMinutes(10);
-		TokenSettings tokenSettings = new TokenSettings()
-				.<TokenSettings>setting("name1", "value1")
-				.accessTokenTimeToLive(accessTokenTimeToLive)
-				.settings(settings -> settings.put("name2", "value2"));
-		assertThat(tokenSettings.settings()).hasSize(6);
-		assertThat(tokenSettings.accessTokenTimeToLive()).isEqualTo(accessTokenTimeToLive);
-		assertThat(tokenSettings.reuseRefreshTokens()).isTrue();
-		assertThat(tokenSettings.refreshTokenTimeToLive()).isEqualTo(Duration.ofMinutes(60));
-		assertThat(tokenSettings.idTokenSignatureAlgorithm()).isEqualTo(SignatureAlgorithm.RS256);
-		assertThat(tokenSettings.<String>setting("name1")).isEqualTo("value1");
-		assertThat(tokenSettings.<String>setting("name2")).isEqualTo("value2");
+	public void settingWhenCustomThenSet() {
+		TokenSettings tokenSettings = TokenSettings.builder()
+				.setting("name1", "value1")
+				.settings(settings -> settings.put("name2", "value2"))
+				.build();
+		assertThat(tokenSettings.getSettings()).hasSize(6);
+		assertThat(tokenSettings.<String>getSetting("name1")).isEqualTo("value1");
+		assertThat(tokenSettings.<String>getSetting("name2")).isEqualTo("value2");
 	}
+
 }

+ 4 - 4
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationProviderTests.java

@@ -264,9 +264,9 @@ public class OidcClientRegistrationAuthenticationProviderTests {
 		assertThat(registeredClientResult.getAuthorizationGrantTypes())
 				.containsExactlyInAnyOrder(AuthorizationGrantType.AUTHORIZATION_CODE, AuthorizationGrantType.CLIENT_CREDENTIALS);
 		assertThat(registeredClientResult.getScopes()).containsExactlyInAnyOrder("scope1", "scope2");
-		assertThat(registeredClientResult.getClientSettings().requireProofKey()).isTrue();
-		assertThat(registeredClientResult.getClientSettings().requireAuthorizationConsent()).isTrue();
-		assertThat(registeredClientResult.getTokenSettings().idTokenSignatureAlgorithm()).isEqualTo(SignatureAlgorithm.RS256);
+		assertThat(registeredClientResult.getClientSettings().isRequireProofKey()).isTrue();
+		assertThat(registeredClientResult.getClientSettings().isRequireAuthorizationConsent()).isTrue();
+		assertThat(registeredClientResult.getTokenSettings().getIdTokenSignatureAlgorithm()).isEqualTo(SignatureAlgorithm.RS256);
 
 		OidcClientRegistration clientRegistrationResult = authenticationResult.getClientRegistration();
 		assertThat(clientRegistrationResult.getClientId()).isEqualTo(registeredClientResult.getClientId());
@@ -289,7 +289,7 @@ public class OidcClientRegistrationAuthenticationProviderTests {
 		assertThat(clientRegistrationResult.getTokenEndpointAuthenticationMethod())
 				.isEqualTo(registeredClientResult.getClientAuthenticationMethods().iterator().next().getValue());
 		assertThat(clientRegistrationResult.getIdTokenSignedResponseAlgorithm())
-				.isEqualTo(registeredClientResult.getTokenSettings().idTokenSignatureAlgorithm().getName());
+				.isEqualTo(registeredClientResult.getTokenSettings().getIdTokenSignatureAlgorithm().getName());
 	}
 
 	private static Jwt createJwt() {

+ 13 - 10
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/web/OidcProviderConfigurationEndpointFilterTests.java

@@ -15,16 +15,17 @@
  */
 package org.springframework.security.oauth2.server.authorization.oidc.web;
 
+import javax.servlet.FilterChain;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
 import org.junit.Test;
+
 import org.springframework.http.MediaType;
 import org.springframework.mock.web.MockHttpServletRequest;
 import org.springframework.mock.web.MockHttpServletResponse;
 import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
 
-import javax.servlet.FilterChain;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
 import static org.mockito.ArgumentMatchers.any;
@@ -50,7 +51,7 @@ public class OidcProviderConfigurationEndpointFilterTests {
 	@Test
 	public void doFilterWhenNotConfigurationRequestThenNotProcessed() throws Exception {
 		OidcProviderConfigurationEndpointFilter filter =
-				new OidcProviderConfigurationEndpointFilter(new ProviderSettings());
+				new OidcProviderConfigurationEndpointFilter(ProviderSettings.builder().build());
 
 		String requestUri = "/path";
 		MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
@@ -66,7 +67,7 @@ public class OidcProviderConfigurationEndpointFilterTests {
 	@Test
 	public void doFilterWhenConfigurationRequestPostThenNotProcessed() throws Exception {
 		OidcProviderConfigurationEndpointFilter filter =
-				new OidcProviderConfigurationEndpointFilter(new ProviderSettings());
+				new OidcProviderConfigurationEndpointFilter(ProviderSettings.builder().build());
 
 		String requestUri = DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI;
 		MockHttpServletRequest request = new MockHttpServletRequest("POST", requestUri);
@@ -85,11 +86,12 @@ public class OidcProviderConfigurationEndpointFilterTests {
 		String tokenEndpoint = "/oauth2/v1/token";
 		String jwkSetEndpoint = "/oauth2/v1/jwks";
 
-		ProviderSettings providerSettings = new ProviderSettings()
+		ProviderSettings providerSettings = ProviderSettings.builder()
 				.issuer("https://example.com/issuer1")
 				.authorizationEndpoint(authorizationEndpoint)
 				.tokenEndpoint(tokenEndpoint)
-				.jwkSetEndpoint(jwkSetEndpoint);
+				.jwkSetEndpoint(jwkSetEndpoint)
+				.build();
 		OidcProviderConfigurationEndpointFilter filter =
 				new OidcProviderConfigurationEndpointFilter(providerSettings);
 
@@ -119,8 +121,9 @@ public class OidcProviderConfigurationEndpointFilterTests {
 
 	@Test
 	public void doFilterWhenProviderSettingsWithInvalidIssuerThenThrowIllegalArgumentException() {
-		ProviderSettings providerSettings = new ProviderSettings()
-				.issuer("https://this is an invalid URL");
+		ProviderSettings providerSettings = ProviderSettings.builder()
+				.issuer("https://this is an invalid URL")
+				.build();
 		OidcProviderConfigurationEndpointFilter filter =
 				new OidcProviderConfigurationEndpointFilter(providerSettings);
 

+ 8 - 6
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/web/OAuth2AuthorizationServerMetadataEndpointFilterTests.java

@@ -52,7 +52,7 @@ public class OAuth2AuthorizationServerMetadataEndpointFilterTests {
 	@Test
 	public void doFilterWhenNotAuthorizationServerMetadataRequestThenNotProcessed() throws Exception {
 		OAuth2AuthorizationServerMetadataEndpointFilter filter =
-				new OAuth2AuthorizationServerMetadataEndpointFilter(new ProviderSettings().issuer("https://example.com"));
+				new OAuth2AuthorizationServerMetadataEndpointFilter(ProviderSettings.builder().issuer("https://example.com").build());
 
 		String requestUri = "/path";
 		MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
@@ -68,7 +68,7 @@ public class OAuth2AuthorizationServerMetadataEndpointFilterTests {
 	@Test
 	public void doFilterWhenAuthorizationServerMetadataRequestPostThenNotProcessed() throws Exception {
 		OAuth2AuthorizationServerMetadataEndpointFilter filter =
-				new OAuth2AuthorizationServerMetadataEndpointFilter(new ProviderSettings().issuer("https://example.com"));
+				new OAuth2AuthorizationServerMetadataEndpointFilter(ProviderSettings.builder().issuer("https://example.com").build());
 
 		String requestUri = DEFAULT_OAUTH2_AUTHORIZATION_SERVER_METADATA_ENDPOINT_URI;
 		MockHttpServletRequest request = new MockHttpServletRequest("POST", requestUri);
@@ -89,13 +89,14 @@ public class OAuth2AuthorizationServerMetadataEndpointFilterTests {
 		String tokenRevocationEndpoint = "/oauth2/v1/revoke";
 		String tokenIntrospectionEndpoint = "/oauth2/v1/introspect";
 
-		ProviderSettings providerSettings = new ProviderSettings()
+		ProviderSettings providerSettings = ProviderSettings.builder()
 				.issuer("https://example.com/issuer1")
 				.authorizationEndpoint(authorizationEndpoint)
 				.tokenEndpoint(tokenEndpoint)
 				.jwkSetEndpoint(jwkSetEndpoint)
 				.tokenRevocationEndpoint(tokenRevocationEndpoint)
-				.tokenIntrospectionEndpoint(tokenIntrospectionEndpoint);
+				.tokenIntrospectionEndpoint(tokenIntrospectionEndpoint)
+				.build();
 		OAuth2AuthorizationServerMetadataEndpointFilter filter =
 				new OAuth2AuthorizationServerMetadataEndpointFilter(providerSettings);
 
@@ -127,8 +128,9 @@ public class OAuth2AuthorizationServerMetadataEndpointFilterTests {
 
 	@Test
 	public void doFilterWhenProviderSettingsWithInvalidIssuerThenThrowIllegalArgumentException() {
-		ProviderSettings providerSettings = new ProviderSettings()
-				.issuer("https://this is an invalid URL");
+		ProviderSettings providerSettings = ProviderSettings.builder()
+				.issuer("https://this is an invalid URL")
+				.build();
 		OAuth2AuthorizationServerMetadataEndpointFilter filter =
 				new OAuth2AuthorizationServerMetadataEndpointFilter(providerSettings);
 

+ 3 - 2
samples/boot/oauth2-integration/authorizationserver-custom-consent-page/src/main/java/sample/config/AuthorizationServerConfig.java

@@ -38,6 +38,7 @@ import org.springframework.security.oauth2.server.authorization.OAuth2Authorizat
 import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
+import org.springframework.security.oauth2.server.authorization.config.ClientSettings;
 import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
 import org.springframework.security.web.SecurityFilterChain;
 import org.springframework.security.web.util.matcher.RequestMatcher;
@@ -86,7 +87,7 @@ public class AuthorizationServerConfig {
 				.scope(OidcScopes.OPENID)
 				.scope("message.read")
 				.scope("message.write")
-				.clientSettings(clientSettings -> clientSettings.requireAuthorizationConsent(true))
+				.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
 				.build();
 		return new InMemoryRegisteredClientRepository(registeredClient);
 	}
@@ -101,7 +102,7 @@ public class AuthorizationServerConfig {
 
 	@Bean
 	public ProviderSettings providerSettings() {
-		return new ProviderSettings().issuer("http://auth-server:9000");
+		return ProviderSettings.builder().issuer("http://auth-server:9000").build();
 	}
 
 	@Bean

+ 3 - 2
samples/boot/oauth2-integration/authorizationserver/src/main/java/sample/config/AuthorizationServerConfig.java

@@ -45,6 +45,7 @@ import org.springframework.security.oauth2.server.authorization.OAuth2Authorizat
 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.security.oauth2.server.authorization.config.ClientSettings;
 import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
 import org.springframework.security.web.SecurityFilterChain;
 
@@ -77,7 +78,7 @@ public class AuthorizationServerConfig {
 				.scope(OidcScopes.OPENID)
 				.scope("message.read")
 				.scope("message.write")
-				.clientSettings(clientSettings -> clientSettings.requireAuthorizationConsent(true))
+				.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
 				.build();
 
 		// Save registered client in db as if in-memory
@@ -112,7 +113,7 @@ public class AuthorizationServerConfig {
 
 	@Bean
 	public ProviderSettings providerSettings() {
-		return new ProviderSettings().issuer("http://auth-server:9000");
+		return ProviderSettings.builder().issuer("http://auth-server:9000").build();
 	}
 
 	@Bean