瀏覽代碼

Polish gh-1377

Joe Grandja 1 年之前
父節點
當前提交
9757e33f09
共有 10 個文件被更改,包括 91 次插入301 次删除
  1. 9 7
      oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientCredentialsAuthenticationContext.java
  2. 0 58
      oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientCredentialsAuthenticationException.java
  3. 13 12
      oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientCredentialsAuthenticationProvider.java
  4. 13 29
      oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientCredentialsAuthenticationValidator.java
  5. 2 1
      oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OAuth2TokenEndpointConfigurer.java
  6. 0 88
      oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientCredentialsAuthenticationContextTests.java
  7. 34 17
      oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientCredentialsAuthenticationProviderTests.java
  8. 0 70
      oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientCredentialsAuthenticationValidatorTest.java
  9. 7 9
      oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/client/TestRegisteredClients.java
  10. 13 10
      oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OidcClientRegistrationTests.java

+ 9 - 7
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientCredentialsAuthenticationContext.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2020-2022 the original author or authors.
+ * Copyright 2020-2024 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.
@@ -15,19 +15,21 @@
  */
 package org.springframework.security.oauth2.server.authorization.authentication;
 
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Consumer;
+
 import org.springframework.lang.Nullable;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
 import org.springframework.util.Assert;
 
-import java.util.Map;
-import java.util.function.Consumer;
-
 /**
  * An {@link OAuth2AuthenticationContext} that holds an {@link OAuth2ClientCredentialsAuthenticationToken} and additional information
- * and is used when validating the OAuth 2.0 Authorization Request used in the Client Credentials Grant.
+ * and is used when validating the OAuth 2.0 Client Credentials Grant Request.
  *
  * @author Adam Pilling
- * @since 1.3.0
+ * @since 1.3
  * @see OAuth2AuthenticationContext
  * @see OAuth2ClientCredentialsAuthenticationToken
  * @see OAuth2ClientCredentialsAuthenticationProvider#setAuthenticationValidator(Consumer)
@@ -36,7 +38,7 @@ public final class OAuth2ClientCredentialsAuthenticationContext implements OAuth
 	private final Map<Object, Object> context;
 
 	private OAuth2ClientCredentialsAuthenticationContext(Map<Object, Object> context) {
-		this.context = Map.copyOf(context);
+		this.context = Collections.unmodifiableMap(new HashMap<>(context));
 	}
 
 	@SuppressWarnings("unchecked")

+ 0 - 58
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientCredentialsAuthenticationException.java

@@ -1,58 +0,0 @@
-/*
- * 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.authentication;
-
-import org.springframework.lang.Nullable;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
-import org.springframework.security.oauth2.core.OAuth2Error;
-
-/**
- * This exception is thrown by {@link OAuth2ClientCredentialsAuthenticationProvider}
- * when an attempt to authenticate the OAuth 2.0 Authorization Request (or Consent) fails.
- *
- * @author Adam Pilling
- * @since 1.3.0
- * @see OAuth2ClientCredentialsAuthenticationToken
- * @see OAuth2ClientCredentialsAuthenticationProvider
- */
-public class OAuth2ClientCredentialsAuthenticationException extends OAuth2AuthenticationException {
-	private final OAuth2ClientCredentialsAuthenticationToken authorizationCodeRequestAuthentication;
-
-	/**
-	 * Constructs an {@code OAuth2ClientCredentialsAuthenticationException} using the provided parameters.
-	 *
-	 * @param error the {@link OAuth2Error OAuth 2.0 Error}
-	 * @param authorizationCodeRequestAuthentication the {@link Authentication} instance of the OAuth 2.0 Authorization Request (or Consent)
-	 */
-	public OAuth2ClientCredentialsAuthenticationException(
-			OAuth2Error error,
-			@Nullable OAuth2ClientCredentialsAuthenticationToken authorizationCodeRequestAuthentication) {
-		super(error);
-		this.authorizationCodeRequestAuthentication = authorizationCodeRequestAuthentication;
-	}
-
-	/**
-	 * Returns the {@link Authentication} instance of the OAuth 2.0 Authorization Request (or Consent), or {@code null} if not available.
-	 *
-	 * @return the {@link OAuth2AuthorizationCodeRequestAuthenticationToken}
-	 */
-	@Nullable
-	public OAuth2ClientCredentialsAuthenticationToken getClientCredentialsAuthentication() {
-		return this.authorizationCodeRequestAuthentication;
-	}
-
-}

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

@@ -1,5 +1,5 @@
 /*
- * Copyright 2020-2022 the original author or authors.
+ * Copyright 2020-2024 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.
@@ -15,8 +15,13 @@
  */
 package org.springframework.security.oauth2.server.authorization.authentication;
 
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.function.Consumer;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+
 import org.springframework.security.authentication.AuthenticationProvider;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
@@ -37,9 +42,6 @@ import org.springframework.security.oauth2.server.authorization.token.OAuth2Toke
 import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
 import org.springframework.util.Assert;
 
-import java.util.Set;
-import java.util.function.Consumer;
-
 import static org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthenticationProviderUtils.getAuthenticatedClientElseThrowInvalidClient;
 
 /**
@@ -99,14 +101,14 @@ public final class OAuth2ClientCredentialsAuthenticationProvider implements Auth
 				OAuth2ClientCredentialsAuthenticationContext.with(clientCredentialsAuthentication)
 						.registeredClient(registeredClient)
 						.build();
-		authenticationValidator.accept(authenticationContext);
+		this.authenticationValidator.accept(authenticationContext);
+
+		Set<String> authorizedScopes = new LinkedHashSet<>(clientCredentialsAuthentication.getScopes());
 
 		if (this.logger.isTraceEnabled()) {
 			this.logger.trace("Validated token request parameters");
 		}
 
-		Set<String> authorizedScopes = Set.copyOf(clientCredentialsAuthentication.getScopes());
-
 		// @formatter:off
 		OAuth2TokenContext tokenContext = DefaultOAuth2TokenContext.builder()
 				.registeredClient(registeredClient)
@@ -167,16 +169,15 @@ public final class OAuth2ClientCredentialsAuthenticationProvider implements Auth
 
 	/**
 	 * Sets the {@code Consumer} providing access to the {@link OAuth2ClientCredentialsAuthenticationContext}
-	 * and is responsible for validating specific OAuth 2.0 Client Credentials parameters
+	 * and is responsible for validating specific OAuth 2.0 Client Credentials Grant Request parameters
 	 * associated in the {@link OAuth2ClientCredentialsAuthenticationToken}.
 	 * The default authentication validator is {@link OAuth2ClientCredentialsAuthenticationValidator}.
 	 *
 	 * <p>
-	 * <b>NOTE:</b> The authentication validator MUST throw {@link OAuth2ClientCredentialsAuthenticationException} if validation fails.
+	 * <b>NOTE:</b> The authentication validator MUST throw {@link OAuth2AuthenticationException} if validation fails.
 	 *
-	 * @param authenticationValidator the {@code Consumer} providing access to the {@link OAuth2ClientCredentialsAuthenticationContext}
-	 *                                   and is responsible for validating specific OAuth 2.0 Authorization Request parameters
-	 * @since 1.3.0
+	 * @param authenticationValidator the {@code Consumer} providing access to the {@link OAuth2ClientCredentialsAuthenticationContext} and is responsible for validating specific OAuth 2.0 Client Credentials Grant Request parameters
+	 * @since 1.3
 	 */
 	public void setAuthenticationValidator(Consumer<OAuth2ClientCredentialsAuthenticationContext> authenticationValidator) {
 		Assert.notNull(authenticationValidator, "authenticationValidator cannot be null");

+ 13 - 29
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientCredentialsAuthenticationValidator.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2020-2023 the original author or authors.
+ * Copyright 2020-2024 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.
@@ -15,37 +15,34 @@
  */
 package org.springframework.security.oauth2.server.authorization.authentication;
 
+import java.util.Set;
+import java.util.function.Consumer;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+
 import org.springframework.core.log.LogMessage;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.oauth2.core.OAuth2Error;
+import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
 import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
-import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
 
-import java.util.Set;
-import java.util.function.Consumer;
-
 /**
  * A {@code Consumer} providing access to the {@link OAuth2ClientCredentialsAuthenticationContext}
  * containing an {@link OAuth2ClientCredentialsAuthenticationToken}
  * and is the default {@link OAuth2ClientCredentialsAuthenticationProvider#setAuthenticationValidator(Consumer) authentication validator}
- * used for validating specific OAuth 2.0 Client Credentials parameters used in the Client Credentials Grant.
+ * used for validating specific OAuth 2.0 Client Credentials Grant Request parameters.
  *
  * <p>
- * The default compares the provided scopes with those configured in the RegisteredClient.
- * If validation fails, an {@link OAuth2ClientCredentialsAuthenticationException} is thrown.
+ * The default implementation validates {@link OAuth2ClientCredentialsAuthenticationToken#getScopes()}.
+ * If validation fails, an {@link OAuth2AuthenticationException} is thrown.
  *
  * @author Adam Pilling
- * @since 1.3.0
+ * @since 1.3
  * @see OAuth2ClientCredentialsAuthenticationContext
- * @see RegisteredClient
  * @see OAuth2ClientCredentialsAuthenticationToken
  * @see OAuth2ClientCredentialsAuthenticationProvider#setAuthenticationValidator(Consumer)
  */
 public final class OAuth2ClientCredentialsAuthenticationValidator implements Consumer<OAuth2ClientCredentialsAuthenticationContext> {
-	private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2.1";
 	private static final Log LOGGER = LogFactory.getLog(OAuth2ClientCredentialsAuthenticationValidator.class);
 
 	/**
@@ -62,32 +59,19 @@ public final class OAuth2ClientCredentialsAuthenticationValidator implements Con
 	}
 
 	private static void validateScope(OAuth2ClientCredentialsAuthenticationContext authenticationContext) {
-		OAuth2ClientCredentialsAuthenticationToken clientCredentialsAuthenticationToken =
+		OAuth2ClientCredentialsAuthenticationToken clientCredentialsAuthentication =
 				authenticationContext.getAuthentication();
 		RegisteredClient registeredClient = authenticationContext.getRegisteredClient();
 
-		Set<String> requestedScopes = clientCredentialsAuthenticationToken.getScopes();
+		Set<String> requestedScopes = clientCredentialsAuthentication.getScopes();
 		Set<String> allowedScopes = registeredClient.getScopes();
 		if (!requestedScopes.isEmpty() && !allowedScopes.containsAll(requestedScopes)) {
 			if (LOGGER.isDebugEnabled()) {
 				LOGGER.debug(LogMessage.format("Invalid request: requested scope is not allowed" +
 						" for registered client '%s'", registeredClient.getId()));
 			}
-			throwError(OAuth2ErrorCodes.INVALID_SCOPE, OAuth2ParameterNames.SCOPE, clientCredentialsAuthenticationToken);
+			throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_SCOPE);
 		}
 	}
 
-	private static void throwError(String errorCode, String parameterName,
-			OAuth2ClientCredentialsAuthenticationToken clientCredentialsAuthenticationToken) {
-		OAuth2Error error = new OAuth2Error(errorCode, "OAuth 2.0 Parameter: " + parameterName, ERROR_URI);
-		OAuth2ClientCredentialsAuthenticationToken authorizationCodeRequestAuthenticationResult =
-				new OAuth2ClientCredentialsAuthenticationToken(
-						(Authentication) clientCredentialsAuthenticationToken.getPrincipal(),
-						clientCredentialsAuthenticationToken.getScopes(),
-						clientCredentialsAuthenticationToken.getAdditionalParameters());
-		authorizationCodeRequestAuthenticationResult.setAuthenticated(true);
-
-		throw new OAuth2ClientCredentialsAuthenticationException(error, authorizationCodeRequestAuthenticationResult);
-	}
-
 }

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

@@ -20,6 +20,7 @@ import java.util.List;
 import java.util.function.Consumer;
 
 import jakarta.servlet.http.HttpServletRequest;
+
 import org.springframework.http.HttpMethod;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.AuthenticationProvider;
@@ -216,7 +217,7 @@ public final class OAuth2TokenEndpointConfigurer extends AbstractOAuth2Configure
 		return authenticationConverters;
 	}
 
-	private List<AuthenticationProvider> createDefaultAuthenticationProviders(HttpSecurity httpSecurity) {
+	private static List<AuthenticationProvider> createDefaultAuthenticationProviders(HttpSecurity httpSecurity) {
 		List<AuthenticationProvider> authenticationProviders = new ArrayList<>();
 
 		OAuth2AuthorizationService authorizationService = OAuth2ConfigurerUtils.getAuthorizationService(httpSecurity);

+ 0 - 88
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientCredentialsAuthenticationContextTests.java

@@ -1,88 +0,0 @@
-/*
- * Copyright 2020-2022 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.authentication;
-
-import java.security.Principal;
-import java.util.Map;
-import java.util.Set;
-
-import org.junit.jupiter.api.Test;
-
-import org.springframework.security.core.Authentication;
-import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
-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 static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-/**
- * Tests for {@link OAuth2ClientCredentialsAuthenticationContext}.
- *
- * @author Steve Riesenberg
- * @author Joe Grandja
- */
-public class OAuth2ClientCredentialsAuthenticationContextTests {
-	private final RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
-	private final OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(this.registeredClient).build();
-	private final Authentication principal = this.authorization.getAttribute(Principal.class.getName());
-	private final OAuth2ClientCredentialsAuthenticationToken authorizationConsentAuthentication =
-			new OAuth2ClientCredentialsAuthenticationToken(this.principal, Set.of("a_scope"), Map.of("a_key", "a_value"));
-
-	@Test
-	public void withWhenAuthenticationNullThenThrowIllegalArgumentException() {
-		assertThatThrownBy(() -> OAuth2ClientCredentialsAuthenticationContext.with(null))
-				.isInstanceOf(IllegalArgumentException.class)
-				.hasMessage("authentication cannot be null");
-	}
-
-	@Test
-	public void setWhenValueNullThenThrowIllegalArgumentException() {
-		OAuth2ClientCredentialsAuthenticationContext.Builder builder =
-				OAuth2ClientCredentialsAuthenticationContext.with(this.authorizationConsentAuthentication);
-
-		assertThatThrownBy(() -> builder.registeredClient(null))
-				.isInstanceOf(IllegalArgumentException.class);
-		assertThatThrownBy(() -> builder.put(null, ""))
-				.isInstanceOf(IllegalArgumentException.class);
-	}
-
-	@Test
-	public void buildWhenRequiredValueNullThenThrowIllegalArgumentException() {
-		OAuth2ClientCredentialsAuthenticationContext.Builder builder =
-				OAuth2ClientCredentialsAuthenticationContext.with(this.authorizationConsentAuthentication);
-		assertThatThrownBy(builder::build)
-				.isInstanceOf(IllegalArgumentException.class)
-				.hasMessage("registeredClient cannot be null");
-	}
-
-	@Test
-	public void buildWhenAllValuesProvidedThenAllValuesAreSet() {
-		OAuth2ClientCredentialsAuthenticationContext context =
-				OAuth2ClientCredentialsAuthenticationContext.with(this.authorizationConsentAuthentication)
-						.registeredClient(this.registeredClient)
-						.put("custom-key-1", "custom-value-1")
-						.context(ctx -> ctx.put("custom-key-2", "custom-value-2"))
-						.build();
-
-		assertThat(context.<Authentication>getAuthentication()).isEqualTo(this.authorizationConsentAuthentication);
-		assertThat(context.getRegisteredClient()).isEqualTo(this.registeredClient);
-		assertThat(context.<String>get("custom-key-1")).isEqualTo("custom-value-1");
-		assertThat(context.<String>get("custom-key-2")).isEqualTo("custom-value-2");
-	}
-
-}

+ 34 - 17
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientCredentialsAuthenticationProviderTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2020-2022 the original author or authors.
+ * Copyright 2020-2024 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.
@@ -15,10 +15,17 @@
  */
 package org.springframework.security.oauth2.server.authorization.authentication;
 
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.Collections;
+import java.util.Set;
+import java.util.function.Consumer;
+
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.mockito.ArgumentCaptor;
+
 import org.springframework.security.authentication.TestingAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.oauth2.core.AuthorizationGrantType;
@@ -50,12 +57,6 @@ import org.springframework.security.oauth2.server.authorization.token.OAuth2Toke
 import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer;
 import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
 
-import java.time.Instant;
-import java.time.temporal.ChronoUnit;
-import java.util.Collections;
-import java.util.Set;
-import java.util.function.Consumer;
-
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.ArgumentMatchers.any;
@@ -132,6 +133,13 @@ public class OAuth2ClientCredentialsAuthenticationProviderTests {
 		assertThat(this.authenticationProvider.supports(OAuth2AuthorizationCodeAuthenticationToken.class)).isFalse();
 	}
 
+	@Test
+	public void setAuthenticationValidatorWhenNullThenThrowIllegalArgumentException() {
+		assertThatThrownBy(() -> this.authenticationProvider.setAuthenticationValidator(null))
+				.isInstanceOf(IllegalArgumentException.class)
+				.hasMessage("authenticationValidator cannot be null");
+	}
+
 	@Test
 	public void authenticateWhenClientPrincipalNotOAuth2ClientAuthenticationTokenThenThrowOAuth2AuthenticationException() {
 		RegisteredClient registeredClient = TestRegisteredClients.registeredClient2().build();
@@ -211,16 +219,6 @@ public class OAuth2ClientCredentialsAuthenticationProviderTests {
 		assertThat(accessTokenAuthentication.getAccessToken().getScopes()).isEqualTo(requestedScope);
 	}
 
-	@Test
-	public void authenticateWhenCustomAuthenticationValidatorThenInvokeValidator() {
-		Consumer<OAuth2ClientCredentialsAuthenticationContext> validator = mock(Consumer.class);
-		this.authenticationProvider.setAuthenticationValidator(validator);
-
-		authenticateWhenScopeRequestedThenAccessTokenContainsScope();
-
-		verify(validator).accept(any(OAuth2ClientCredentialsAuthenticationContext.class));
-	}
-
 	@Test
 	public void authenticateWhenNoScopeRequestedThenAccessTokenDoesNotContainScope() {
 		RegisteredClient registeredClient = TestRegisteredClients.registeredClient2().build();
@@ -314,6 +312,25 @@ public class OAuth2ClientCredentialsAuthenticationProviderTests {
 		verify(this.accessTokenCustomizer).customize(any());
 	}
 
+	@Test
+	public void authenticateWhenCustomAuthenticationValidatorThenUsed() {
+		RegisteredClient registeredClient = TestRegisteredClients.registeredClient2().build();
+		OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
+				registeredClient, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, registeredClient.getClientSecret());
+		OAuth2ClientCredentialsAuthenticationToken authentication =
+				new OAuth2ClientCredentialsAuthenticationToken(clientPrincipal, registeredClient.getScopes(), null);
+
+		@SuppressWarnings("unchecked")
+		Consumer<OAuth2ClientCredentialsAuthenticationContext> authenticationValidator = mock(Consumer.class);
+		this.authenticationProvider.setAuthenticationValidator(authenticationValidator);
+
+		when(this.jwtEncoder.encode(any())).thenReturn(createJwt(registeredClient.getScopes()));
+
+		this.authenticationProvider.authenticate(authentication);
+
+		verify(authenticationValidator).accept(any(OAuth2ClientCredentialsAuthenticationContext.class));
+	}
+
 	private static Jwt createJwt(Set<String> scope) {
 		Instant issuedAt = Instant.now();
 		Instant expiresAt = issuedAt.plus(1, ChronoUnit.HOURS);

+ 0 - 70
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientCredentialsAuthenticationValidatorTest.java

@@ -1,70 +0,0 @@
-/*
- * Copyright 2020-2022 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.authentication;
-
-import org.junit.Test;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.Arguments;
-import org.junit.jupiter.params.provider.MethodSource;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
-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 java.security.Principal;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Stream;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatNoException;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients.SCOPE_1;
-import static org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients.SCOPE_2;
-
-public class OAuth2ClientCredentialsAuthenticationValidatorTest {
-	private final RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
-	private final OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(this.registeredClient).build();
-	private final Authentication principal = this.authorization.getAttribute(Principal.class.getName());
-	private final OAuth2ClientCredentialsAuthenticationValidator validator = new OAuth2ClientCredentialsAuthenticationValidator();
-
-	@ParameterizedTest
-	@MethodSource("validScopes")
-	public void acceptWhenRequestScopesAreEmptyOrValidThenDoesNotThrowException(Set<String> testScopes) {
-		OAuth2ClientCredentialsAuthenticationToken token =
-				new OAuth2ClientCredentialsAuthenticationToken(this.principal, testScopes, Map.of());
-		OAuth2ClientCredentialsAuthenticationContext context = OAuth2ClientCredentialsAuthenticationContext.with(token).registeredClient(registeredClient).build();
-
-		assertThatNoException().isThrownBy(() -> validator.accept(context));
-	}
-
-	@Test
-	public void acceptWhenRequestScopesAreNotAllValidThenThrowException() {
-		OAuth2ClientCredentialsAuthenticationToken token =
-				new OAuth2ClientCredentialsAuthenticationToken(this.principal, Set.of(SCOPE_1, SCOPE_2), Map.of());
-		OAuth2ClientCredentialsAuthenticationContext context = OAuth2ClientCredentialsAuthenticationContext.with(token).registeredClient(registeredClient).build();
-
-		assertThatThrownBy(() -> validator.accept(context))
-				.isInstanceOfSatisfying(OAuth2ClientCredentialsAuthenticationException.class,
-						t -> assertThat(t.getClientCredentialsAuthentication()).isEqualTo(token));
-	}
-
-	static Stream<Arguments> validScopes() {
-		return Stream.of(Arguments.of(new HashSet<>()), Arguments.of(Set.of(SCOPE_1)));
-	}
-}

+ 7 - 9
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/client/TestRegisteredClients.java

@@ -15,19 +15,17 @@
  */
 package org.springframework.security.oauth2.server.authorization.client;
 
+import java.time.Instant;
+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.settings.ClientSettings;
 
-import java.time.Instant;
-import java.time.temporal.ChronoUnit;
-
 /**
  * @author Anoop Garlapati
  */
 public class TestRegisteredClients {
-	public static final String SCOPE_1 = "scope1";
-	public static final String SCOPE_2 = "scope2";
 
 	public static RegisteredClient.Builder registeredClient() {
 		return RegisteredClient.withId("registration-1")
@@ -41,7 +39,7 @@ public class TestRegisteredClients {
 				.redirectUri("https://example.com/callback-2")
 				.redirectUri("https://example.com/callback-3")
 				.postLogoutRedirectUri("https://example.com/oidc-post-logout")
-				.scope(SCOPE_1);
+				.scope("scope1");
 	}
 
 	public static RegisteredClient.Builder registeredClient2() {
@@ -56,8 +54,8 @@ public class TestRegisteredClients {
 				.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
 				.redirectUri("https://example.com")
 				.postLogoutRedirectUri("https://example.com/oidc-post-logout")
-				.scope(SCOPE_1)
-				.scope(SCOPE_2);
+				.scope("scope1")
+				.scope("scope2");
 	}
 
 	public static RegisteredClient.Builder registeredPublicClient() {
@@ -67,7 +65,7 @@ public class TestRegisteredClients {
 				.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
 				.clientAuthenticationMethod(ClientAuthenticationMethod.NONE)
 				.redirectUri("https://example.com")
-				.scope(SCOPE_1)
+				.scope("scope1")
 				.clientSettings(ClientSettings.builder().requireProofKey(true).build());
 	}
 }

+ 13 - 10
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OidcClientRegistrationTests.java

@@ -15,10 +15,21 @@
  */
 package org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers;
 
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+
+import javax.crypto.spec.SecretKeySpec;
+
+import jakarta.servlet.http.HttpServletResponse;
+
 import com.nimbusds.jose.jwk.JWKSet;
 import com.nimbusds.jose.jwk.source.JWKSource;
 import com.nimbusds.jose.proc.SecurityContext;
-import jakarta.servlet.http.HttpServletResponse;
 import okhttp3.mockwebserver.MockResponse;
 import okhttp3.mockwebserver.MockWebServer;
 import org.junit.jupiter.api.AfterAll;
@@ -28,6 +39,7 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.ArgumentCaptor;
+
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -99,15 +111,6 @@ import org.springframework.test.web.servlet.MvcResult;
 import org.springframework.util.CollectionUtils;
 import org.springframework.web.util.UriComponentsBuilder;
 
-import javax.crypto.spec.SecretKeySpec;
-import java.time.Instant;
-import java.time.temporal.ChronoUnit;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Consumer;
-
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.mockito.ArgumentMatchers.any;