Pārlūkot izejas kodu

Fix package tangle

Closes gh-1615
Joe Grandja 1 gadu atpakaļ
vecāks
revīzija
64b20ae3eb

+ 20 - 13
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/token/DefaultOAuth2TokenClaimsConsumer.java → oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/DefaultOAuth2TokenCustomizers.java

@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.springframework.security.oauth2.server.authorization.token;
+package org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers;
 
 import java.security.MessageDigest;
 import java.security.cert.X509Certificate;
@@ -22,7 +22,6 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.Map;
-import java.util.function.Consumer;
 
 import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
 import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
@@ -32,28 +31,36 @@ import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
 import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
 import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenExchangeActor;
 import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenExchangeCompositeAuthenticationToken;
+import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext;
+import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimNames;
+import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimsContext;
+import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext;
+import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer;
 
 /**
  * @author Joe Grandja
+ * @author Steve Riesenberg
  * @since 1.3
  */
-final class DefaultOAuth2TokenClaimsConsumer implements Consumer<Map<String, Object>> {
-	private final OAuth2TokenContext context;
+final class DefaultOAuth2TokenCustomizers {
 
-	DefaultOAuth2TokenClaimsConsumer(OAuth2TokenContext context) {
-		this.context = context;
+	static OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer() {
+		return (context) -> context.getClaims().claims((claims) -> customize(context, claims));
 	}
 
-	@Override
-	public void accept(Map<String, Object> claims) {
+	static OAuth2TokenCustomizer<OAuth2TokenClaimsContext> accessTokenCustomizer() {
+		return (context) -> context.getClaims().claims((claims) -> customize(context, claims));
+	}
+
+	private static void customize(OAuth2TokenContext tokenContext, Map<String, Object> claims) {
 		// Add 'cnf' claim for Mutual-TLS Client Certificate-Bound Access Tokens
-		if (OAuth2TokenType.ACCESS_TOKEN.equals(this.context.getTokenType()) &&
-				this.context.getAuthorizationGrant() != null &&
-				this.context.getAuthorizationGrant().getPrincipal() instanceof OAuth2ClientAuthenticationToken clientAuthentication) {
+		if (OAuth2TokenType.ACCESS_TOKEN.equals(tokenContext.getTokenType()) &&
+				tokenContext.getAuthorizationGrant() != null &&
+				tokenContext.getAuthorizationGrant().getPrincipal() instanceof OAuth2ClientAuthenticationToken clientAuthentication) {
 
 			if ((ClientAuthenticationMethod.TLS_CLIENT_AUTH.equals(clientAuthentication.getClientAuthenticationMethod()) ||
 					ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH.equals(clientAuthentication.getClientAuthenticationMethod())) &&
-					this.context.getRegisteredClient().getTokenSettings().isX509CertificateBoundAccessTokens()) {
+					tokenContext.getRegisteredClient().getTokenSettings().isX509CertificateBoundAccessTokens()) {
 
 				X509Certificate[] clientCertificateChain = (X509Certificate[]) clientAuthentication.getCredentials();
 				try {
@@ -71,7 +78,7 @@ final class DefaultOAuth2TokenClaimsConsumer implements Consumer<Map<String, Obj
 
 		// Add 'act' claim for delegation use case of Token Exchange Grant.
 		// If more than one actor is present, we create a chain of delegation by nesting "act" claims.
-		if (this.context.getPrincipal() instanceof OAuth2TokenExchangeCompositeAuthenticationToken compositeAuthenticationToken) {
+		if (tokenContext.getPrincipal() instanceof OAuth2TokenExchangeCompositeAuthenticationToken compositeAuthenticationToken) {
 			Map<String, Object> currentClaims = claims;
 			for (OAuth2TokenExchangeActor actor : compositeAuthenticationToken.getActors()) {
 				Map<String, Object> actorClaims = actor.getClaims();

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

@@ -105,10 +105,7 @@ final class OAuth2ConfigurerUtils {
 			if (tokenGenerator == null) {
 				JwtGenerator jwtGenerator = getJwtGenerator(httpSecurity);
 				OAuth2AccessTokenGenerator accessTokenGenerator = new OAuth2AccessTokenGenerator();
-				OAuth2TokenCustomizer<OAuth2TokenClaimsContext> accessTokenCustomizer = getAccessTokenCustomizer(httpSecurity);
-				if (accessTokenCustomizer != null) {
-					accessTokenGenerator.setAccessTokenCustomizer(accessTokenCustomizer);
-				}
+				accessTokenGenerator.setAccessTokenCustomizer(getAccessTokenCustomizer(httpSecurity));
 				OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator();
 				if (jwtGenerator != null) {
 					tokenGenerator = new DelegatingOAuth2TokenGenerator(
@@ -129,10 +126,7 @@ final class OAuth2ConfigurerUtils {
 			JwtEncoder jwtEncoder = getJwtEncoder(httpSecurity);
 			if (jwtEncoder != null) {
 				jwtGenerator = new JwtGenerator(jwtEncoder);
-				OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer = getJwtCustomizer(httpSecurity);
-				if (jwtCustomizer != null) {
-					jwtGenerator.setJwtCustomizer(jwtCustomizer);
-				}
+				jwtGenerator.setJwtCustomizer(getJwtCustomizer(httpSecurity));
 				httpSecurity.setSharedObject(JwtGenerator.class, jwtGenerator);
 			}
 		}
@@ -170,13 +164,29 @@ final class OAuth2ConfigurerUtils {
 	}
 
 	private static OAuth2TokenCustomizer<JwtEncodingContext> getJwtCustomizer(HttpSecurity httpSecurity) {
+		final OAuth2TokenCustomizer<JwtEncodingContext> defaultJwtCustomizer = DefaultOAuth2TokenCustomizers.jwtCustomizer();
 		ResolvableType type = ResolvableType.forClassWithGenerics(OAuth2TokenCustomizer.class, JwtEncodingContext.class);
-		return getOptionalBean(httpSecurity, type);
+		final OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer = getOptionalBean(httpSecurity, type);
+		if (jwtCustomizer == null) {
+			return defaultJwtCustomizer;
+		}
+		return (context) -> {
+			defaultJwtCustomizer.customize(context);
+			jwtCustomizer.customize(context);
+		};
 	}
 
 	private static OAuth2TokenCustomizer<OAuth2TokenClaimsContext> getAccessTokenCustomizer(HttpSecurity httpSecurity) {
+		final OAuth2TokenCustomizer<OAuth2TokenClaimsContext> defaultAccessTokenCustomizer = DefaultOAuth2TokenCustomizers.accessTokenCustomizer();
 		ResolvableType type = ResolvableType.forClassWithGenerics(OAuth2TokenCustomizer.class, OAuth2TokenClaimsContext.class);
-		return getOptionalBean(httpSecurity, type);
+		OAuth2TokenCustomizer<OAuth2TokenClaimsContext> accessTokenCustomizer = getOptionalBean(httpSecurity, type);
+		if (accessTokenCustomizer == null) {
+			return defaultAccessTokenCustomizer;
+		}
+		return (context) -> {
+			defaultAccessTokenCustomizer.customize(context);
+			accessTokenCustomizer.customize(context);
+		};
 	}
 
 	static AuthorizationServerSettings getAuthorizationServerSettings(HttpSecurity httpSecurity) {

+ 1 - 2
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/token/JwtGenerator.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2020-2024 the original author or authors.
+ * Copyright 2020-2023 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.
@@ -144,7 +144,6 @@ public final class JwtGenerator implements OAuth2TokenGenerator<Jwt> {
 				}
 			}
 		}
-		claimsBuilder.claims(new DefaultOAuth2TokenClaimsConsumer(context));
 		// @formatter:on
 
 		JwsHeader.Builder jwsHeaderBuilder = JwsHeader.with(jwsAlgorithm);

+ 1 - 2
oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/token/OAuth2AccessTokenGenerator.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2020-2024 the original author or authors.
+ * 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.
@@ -84,7 +84,6 @@ public final class OAuth2AccessTokenGenerator implements OAuth2TokenGenerator<OA
 		if (!CollectionUtils.isEmpty(context.getAuthorizedScopes())) {
 			claimsBuilder.claim(OAuth2ParameterNames.SCOPE, context.getAuthorizedScopes());
 		}
-		claimsBuilder.claims(new DefaultOAuth2TokenClaimsConsumer(context));
 		// @formatter:on
 
 		if (this.accessTokenCustomizer != null) {

+ 239 - 0
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/DefaultOAuth2TokenCustomizersTests.java

@@ -0,0 +1,239 @@
+/*
+ * 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.
+ * 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.annotation.web.configurers;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import org.springframework.security.authentication.TestingAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
+import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
+import org.springframework.security.oauth2.jwt.JwsHeader;
+import org.springframework.security.oauth2.jwt.JwtClaimNames;
+import org.springframework.security.oauth2.jwt.JwtClaimsSet;
+import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
+import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
+import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientCredentialsAuthenticationToken;
+import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenExchangeActor;
+import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenExchangeAuthenticationToken;
+import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenExchangeCompositeAuthenticationToken;
+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.settings.ClientSettings;
+import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
+import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext;
+import org.springframework.security.oauth2.server.authorization.util.TestX509Certificates;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for {@link DefaultOAuth2TokenCustomizers}.
+ *
+ * @author Steve Riesenberg
+ * @author Joe Grandja
+ */
+class DefaultOAuth2TokenCustomizersTests {
+	private static final String ISSUER_1 = "issuer-1";
+	private static final String ISSUER_2 = "issuer-2";
+	private JwsHeader.Builder jwsHeaderBuilder;
+	private JwtClaimsSet.Builder jwtClaimsBuilder;
+
+	@BeforeEach
+	void setUp() {
+		this.jwsHeaderBuilder = JwsHeader.with(SignatureAlgorithm.RS256);
+		this.jwtClaimsBuilder = JwtClaimsSet.builder().issuer(ISSUER_1);
+	}
+
+	@Test
+	void customizeWhenTokenTypeIsRefreshTokenThenNoClaimsAdded() {
+		// @formatter:off
+		JwtEncodingContext tokenContext = JwtEncodingContext.with(this.jwsHeaderBuilder, this.jwtClaimsBuilder)
+				.tokenType(OAuth2TokenType.REFRESH_TOKEN)
+				.build();
+		// @formatter:on
+		DefaultOAuth2TokenCustomizers.jwtCustomizer().customize(tokenContext);
+		JwtClaimsSet jwtClaimsSet = this.jwtClaimsBuilder.build();
+		assertThat(jwtClaimsSet.getClaims()).containsOnly(entry(JwtClaimNames.ISS, ISSUER_1));
+	}
+
+	@Test
+	void customizeWhenAuthorizationGrantIsNullThenNoClaimsAdded() {
+		// @formatter:off
+		JwtEncodingContext tokenContext = JwtEncodingContext.with(this.jwsHeaderBuilder, this.jwtClaimsBuilder)
+				.tokenType(OAuth2TokenType.ACCESS_TOKEN)
+				.build();
+		// @formatter:on
+		DefaultOAuth2TokenCustomizers.jwtCustomizer().customize(tokenContext);
+		JwtClaimsSet jwtClaimsSet = this.jwtClaimsBuilder.build();
+		assertThat(jwtClaimsSet.getClaims()).containsOnly(entry(JwtClaimNames.ISS, ISSUER_1));
+	}
+
+	@Test
+	void customizeWhenTokenExchangeGrantAndResourcesThenNoClaimsAdded() {
+		OAuth2TokenExchangeAuthenticationToken tokenExchangeAuthentication = mock(
+				OAuth2TokenExchangeAuthenticationToken.class);
+		when(tokenExchangeAuthentication.getResources()).thenReturn(Set.of("resource1", "resource2"));
+		// @formatter:off
+		JwtEncodingContext tokenContext = JwtEncodingContext.with(this.jwsHeaderBuilder, this.jwtClaimsBuilder)
+				.tokenType(OAuth2TokenType.ACCESS_TOKEN)
+				.authorizationGrant(tokenExchangeAuthentication)
+				.build();
+		// @formatter:on
+		DefaultOAuth2TokenCustomizers.jwtCustomizer().customize(tokenContext);
+		JwtClaimsSet jwtClaimsSet = this.jwtClaimsBuilder.build();
+		// We do not populate claims (e.g. `aud`) based on the resource parameter
+		assertThat(jwtClaimsSet.getClaims()).containsOnly(entry(JwtClaimNames.ISS, ISSUER_1));
+	}
+
+	@Test
+	void customizeWhenTokenExchangeGrantAndAudiencesThenNoClaimsAdded() {
+		OAuth2TokenExchangeAuthenticationToken tokenExchangeAuthentication = mock(
+				OAuth2TokenExchangeAuthenticationToken.class);
+		when(tokenExchangeAuthentication.getAudiences()).thenReturn(Set.of("audience1", "audience2"));
+		// @formatter:off
+		JwtEncodingContext tokenContext = JwtEncodingContext.with(this.jwsHeaderBuilder, this.jwtClaimsBuilder)
+				.tokenType(OAuth2TokenType.ACCESS_TOKEN)
+				.authorizationGrant(tokenExchangeAuthentication)
+				.build();
+		// @formatter:on
+		DefaultOAuth2TokenCustomizers.jwtCustomizer().customize(tokenContext);
+		JwtClaimsSet jwtClaimsSet = this.jwtClaimsBuilder.build();
+		// NOTE: We do not populate claims (e.g. `aud`) based on the audience parameter
+		assertThat(jwtClaimsSet.getClaims()).containsOnly(entry(JwtClaimNames.ISS, ISSUER_1));
+	}
+
+	@Test
+	void customizeWhenTokenExchangeGrantAndDelegationThenActClaimAdded() {
+		OAuth2TokenExchangeAuthenticationToken tokenExchangeAuthentication = mock(
+				OAuth2TokenExchangeAuthenticationToken.class);
+		when(tokenExchangeAuthentication.getAudiences()).thenReturn(Collections.emptySet());
+
+		Authentication subject = new TestingAuthenticationToken("subject", null);
+		OAuth2TokenExchangeActor actor1 = new OAuth2TokenExchangeActor(Map.of(JwtClaimNames.ISS, ISSUER_1,
+				JwtClaimNames.SUB, "actor1"));
+		OAuth2TokenExchangeActor actor2 = new OAuth2TokenExchangeActor(Map.of(JwtClaimNames.ISS, ISSUER_2,
+				JwtClaimNames.SUB, "actor2"));
+		OAuth2TokenExchangeCompositeAuthenticationToken principal = new OAuth2TokenExchangeCompositeAuthenticationToken(
+				subject, List.of(actor1, actor2));
+
+		// @formatter:off
+		JwtEncodingContext tokenContext = JwtEncodingContext.with(this.jwsHeaderBuilder, this.jwtClaimsBuilder)
+				.tokenType(OAuth2TokenType.ACCESS_TOKEN)
+				.principal(principal)
+				.authorizationGrant(tokenExchangeAuthentication)
+				.build();
+		// @formatter:on
+		DefaultOAuth2TokenCustomizers.jwtCustomizer().customize(tokenContext);
+		JwtClaimsSet jwtClaimsSet = this.jwtClaimsBuilder.build();
+		assertThat(jwtClaimsSet.getClaims()).isNotEmpty();
+		assertThat(jwtClaimsSet.getClaims()).hasSize(2);
+		assertThat(jwtClaimsSet.getClaims().get("act")).isNotNull();
+		@SuppressWarnings("unchecked")
+		Map<String, Object> actClaim1 = (Map<String, Object>) jwtClaimsSet.getClaims().get("act");
+		assertThat(actClaim1.get(JwtClaimNames.ISS)).isEqualTo(ISSUER_1);
+		assertThat(actClaim1.get(JwtClaimNames.SUB)).isEqualTo("actor1");
+		@SuppressWarnings("unchecked")
+		Map<String, Object> actClaim2 = (Map<String, Object>) actClaim1.get("act");
+		assertThat(actClaim2.get(JwtClaimNames.ISS)).isEqualTo(ISSUER_2);
+		assertThat(actClaim2.get(JwtClaimNames.SUB)).isEqualTo("actor2");
+	}
+
+	@Test
+	void customizeWhenPKIX509ClientCertificateAndCertificateBoundAccessTokensThenX5tClaimAdded() {
+		// @formatter:off
+		RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
+				.clientAuthenticationMethod(ClientAuthenticationMethod.TLS_CLIENT_AUTH)
+				.clientSettings(
+						ClientSettings.builder()
+								.x509CertificateSubjectDN(TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE[0].getSubjectX500Principal().getName())
+								.build()
+				)
+				.tokenSettings(
+						TokenSettings.builder()
+								.x509CertificateBoundAccessTokens(true)
+								.build()
+				)
+				.build();
+		// @formatter:on
+		OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
+				registeredClient, ClientAuthenticationMethod.TLS_CLIENT_AUTH,
+				TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE);
+		OAuth2ClientCredentialsAuthenticationToken clientCredentialsAuthentication =
+				new OAuth2ClientCredentialsAuthenticationToken(clientPrincipal, null, null);
+		// @formatter:off
+		JwtEncodingContext tokenContext = JwtEncodingContext.with(this.jwsHeaderBuilder, this.jwtClaimsBuilder)
+				.tokenType(OAuth2TokenType.ACCESS_TOKEN)
+				.registeredClient(registeredClient)
+				.authorizationGrant(clientCredentialsAuthentication)
+				.build();
+		// @formatter:on
+		DefaultOAuth2TokenCustomizers.jwtCustomizer().customize(tokenContext);
+		JwtClaimsSet jwtClaimsSet = this.jwtClaimsBuilder.build();
+		assertThat(jwtClaimsSet.getClaims()).isNotEmpty();
+		assertThat(jwtClaimsSet.getClaims()).hasSize(2);
+		Map<String, Object> cnfClaim = jwtClaimsSet.getClaim("cnf");
+		assertThat(cnfClaim).isNotEmpty();
+		assertThat(cnfClaim.get("x5t#S256")).isNotNull();
+	}
+
+	@Test
+	void customizeWhenSelfSignedX509ClientCertificateAndCertificateBoundAccessTokensThenX5tClaimAdded() {
+		// @formatter:off
+		RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
+				.clientAuthenticationMethod(ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH)
+				.clientSettings(
+						ClientSettings.builder()
+								.jwkSetUrl("https://client.example.com/jwks")
+								.build()
+				)
+				.tokenSettings(
+						TokenSettings.builder()
+								.x509CertificateBoundAccessTokens(true)
+								.build()
+				)
+				.build();
+		// @formatter:on
+		OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
+				registeredClient, ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH,
+				TestX509Certificates.DEMO_CLIENT_SELF_SIGNED_CERTIFICATE);
+		OAuth2ClientCredentialsAuthenticationToken clientCredentialsAuthentication =
+				new OAuth2ClientCredentialsAuthenticationToken(clientPrincipal, null, null);
+		// @formatter:off
+		JwtEncodingContext tokenContext = JwtEncodingContext.with(this.jwsHeaderBuilder, this.jwtClaimsBuilder)
+				.tokenType(OAuth2TokenType.ACCESS_TOKEN)
+				.registeredClient(registeredClient)
+				.authorizationGrant(clientCredentialsAuthentication)
+				.build();
+		// @formatter:on
+		DefaultOAuth2TokenCustomizers.jwtCustomizer().customize(tokenContext);
+		JwtClaimsSet jwtClaimsSet = this.jwtClaimsBuilder.build();
+		assertThat(jwtClaimsSet.getClaims()).isNotEmpty();
+		assertThat(jwtClaimsSet.getClaims()).hasSize(2);
+		Map<String, Object> cnfClaim = jwtClaimsSet.getClaim("cnf");
+		assertThat(cnfClaim).isNotEmpty();
+		assertThat(cnfClaim.get("x5t#S256")).isNotNull();
+	}
+
+}

+ 0 - 128
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/token/DefaultOAuth2TokenClaimsConsumerTests.java

@@ -1,128 +0,0 @@
-/*
- * 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.
- * 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.token;
-
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Consumer;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import org.springframework.security.authentication.TestingAuthenticationToken;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
-import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenExchangeActor;
-import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenExchangeAuthenticationToken;
-import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenExchangeCompositeAuthenticationToken;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-/**
- * Tests for {@link DefaultOAuth2TokenClaimsConsumer}.
- *
- * @author Steve Riesenberg
- */
-public class DefaultOAuth2TokenClaimsConsumerTests {
-
-	private OAuth2TokenContext tokenContext;
-
-	private Consumer<Map<String, Object>> consumer;
-
-	@BeforeEach
-	public void setUp() {
-		this.tokenContext = mock(OAuth2TokenContext.class);
-		this.consumer = new DefaultOAuth2TokenClaimsConsumer(this.tokenContext);
-	}
-
-	@Test
-	public void acceptWhenTokenTypeIsRefreshTokenThenNoClaimsAdded() {
-		when(this.tokenContext.getTokenType()).thenReturn(OAuth2TokenType.REFRESH_TOKEN);
-		Map<String, Object> claims = new LinkedHashMap<>();
-		this.consumer.accept(claims);
-		assertThat(claims).isEmpty();
-	}
-
-	@Test
-	public void acceptWhenAuthorizationGrantIsNullThenNoClaimsAdded() {
-		when(this.tokenContext.getTokenType()).thenReturn(OAuth2TokenType.ACCESS_TOKEN);
-		when(this.tokenContext.getAuthorizationGrant()).thenReturn(null);
-		Map<String, Object> claims = new LinkedHashMap<>();
-		this.consumer.accept(claims);
-		assertThat(claims).isEmpty();
-	}
-
-	@Test
-	public void acceptWhenTokenExchangeGrantAndResourcesThenNoClaimsAdded() {
-		OAuth2TokenExchangeAuthenticationToken tokenExchangeAuthentication = mock(
-				OAuth2TokenExchangeAuthenticationToken.class);
-		when(tokenExchangeAuthentication.getResources()).thenReturn(Set.of("resource1", "resource2"));
-		when(this.tokenContext.getTokenType()).thenReturn(OAuth2TokenType.ACCESS_TOKEN);
-		when(this.tokenContext.getAuthorizationGrant()).thenReturn(tokenExchangeAuthentication);
-		Map<String, Object> claims = new LinkedHashMap<>();
-		this.consumer.accept(claims);
-		// We do not populate claims (e.g. `aud`) based on the resource parameter
-		assertThat(claims).isEmpty();
-	}
-
-	@Test
-	public void acceptWhenTokenExchangeGrantAndAudiencesThenNoClaimsAdded() {
-		OAuth2TokenExchangeAuthenticationToken tokenExchangeAuthentication = mock(
-				OAuth2TokenExchangeAuthenticationToken.class);
-		when(tokenExchangeAuthentication.getAudiences()).thenReturn(Set.of("audience1", "audience2"));
-		when(this.tokenContext.getTokenType()).thenReturn(OAuth2TokenType.ACCESS_TOKEN);
-		when(this.tokenContext.getAuthorizationGrant()).thenReturn(tokenExchangeAuthentication);
-		Map<String, Object> claims = new LinkedHashMap<>();
-		this.consumer.accept(claims);
-		// NOTE: We do not populate claims (e.g. `aud`) based on the audience parameter
-		assertThat(claims).isEmpty();
-	}
-
-	@Test
-	public void acceptWhenTokenExchangeGrantAndDelegationThenActClaimAdded() {
-		OAuth2TokenExchangeAuthenticationToken tokenExchangeAuthentication = mock(
-				OAuth2TokenExchangeAuthenticationToken.class);
-		when(tokenExchangeAuthentication.getAudiences()).thenReturn(Collections.emptySet());
-		when(this.tokenContext.getTokenType()).thenReturn(OAuth2TokenType.ACCESS_TOKEN);
-		when(this.tokenContext.getAuthorizationGrant()).thenReturn(tokenExchangeAuthentication);
-		Authentication subject = new TestingAuthenticationToken("subject", null);
-		OAuth2TokenExchangeActor actor1 = new OAuth2TokenExchangeActor(Map.of(OAuth2TokenClaimNames.ISS, "issuer1",
-				OAuth2TokenClaimNames.SUB, "actor1"));
-		OAuth2TokenExchangeActor actor2 = new OAuth2TokenExchangeActor(Map.of(OAuth2TokenClaimNames.ISS, "issuer2",
-				OAuth2TokenClaimNames.SUB, "actor2"));
-		OAuth2TokenExchangeCompositeAuthenticationToken principal = new OAuth2TokenExchangeCompositeAuthenticationToken(
-				subject, List.of(actor1, actor2));
-		when(this.tokenContext.getPrincipal()).thenReturn(principal);
-		Map<String, Object> claims = new LinkedHashMap<>();
-		this.consumer.accept(claims);
-		assertThat(claims).hasSize(1);
-		assertThat(claims.get("act")).isNotNull();
-		@SuppressWarnings("unchecked")
-		Map<String, Object> actClaim1 = (Map<String, Object>) claims.get("act");
-		assertThat(actClaim1.get(OAuth2TokenClaimNames.ISS)).isEqualTo("issuer1");
-		assertThat(actClaim1.get(OAuth2TokenClaimNames.SUB)).isEqualTo("actor1");
-		@SuppressWarnings("unchecked")
-		Map<String, Object> actClaim2 = (Map<String, Object>) actClaim1.get("act");
-		assertThat(actClaim2.get(OAuth2TokenClaimNames.ISS)).isEqualTo("issuer2");
-		assertThat(actClaim2.get(OAuth2TokenClaimNames.SUB)).isEqualTo("actor2");
-	}
-
-}

+ 3 - 31
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/token/JwtGeneratorTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2020-2024 the original author or authors.
+ * Copyright 2020-2023 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.
@@ -53,10 +53,8 @@ import org.springframework.security.oauth2.server.authorization.client.Registere
 import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients;
 import org.springframework.security.oauth2.server.authorization.context.TestAuthorizationServerContext;
 import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
-import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
 import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat;
 import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
-import org.springframework.security.oauth2.server.authorization.util.TestX509Certificates;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -130,26 +128,11 @@ public class JwtGeneratorTests {
 
 	@Test
 	public void generateWhenAccessTokenTypeThenReturnJwt() {
-		// @formatter:off
-		RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
-				.clientAuthenticationMethod(ClientAuthenticationMethod.TLS_CLIENT_AUTH)
-				.clientSettings(
-						ClientSettings.builder()
-								.x509CertificateSubjectDN(TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE[0].getSubjectX500Principal().getName())
-								.build()
-				)
-				.tokenSettings(
-						TokenSettings.builder()
-								.x509CertificateBoundAccessTokens(true)
-								.build()
-				)
-				.build();
-		// @formatter:on
+		RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
 		OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient).build();
 
 		OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
-				registeredClient, ClientAuthenticationMethod.TLS_CLIENT_AUTH,
-				TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE);
+				registeredClient, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, registeredClient.getClientSecret());
 		OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute(
 				OAuth2AuthorizationRequest.class.getName());
 		OAuth2AuthorizationCodeAuthenticationToken authentication =
@@ -342,17 +325,6 @@ public class JwtGeneratorTests {
 
 			Set<String> scopes = jwtClaimsSet.getClaim(OAuth2ParameterNames.SCOPE);
 			assertThat(scopes).isEqualTo(tokenContext.getAuthorizedScopes());
-
-			OAuth2ClientAuthenticationToken clientAuthentication = (OAuth2ClientAuthenticationToken) tokenContext.getAuthorizationGrant().getPrincipal();
-			if (ClientAuthenticationMethod.TLS_CLIENT_AUTH.equals(clientAuthentication.getClientAuthenticationMethod()) &&
-					tokenContext.getRegisteredClient().getTokenSettings().isX509CertificateBoundAccessTokens()) {
-				Map<String, Object> cnf = jwtClaimsSet.getClaim("cnf");
-				assertThat(cnf).isNotEmpty();
-				assertThat(cnf.get("x5t#S256")).isNotNull();
-			} else {
-				Map<String, Object> cnf = jwtClaimsSet.getClaim("cnf");
-				assertThat(cnf).isEmpty();
-			}
 		} else {
 			assertThat(jwtClaimsSet.<String>getClaim(IdTokenClaimNames.AZP)).isEqualTo(tokenContext.getRegisteredClient().getClientId());
 			if (tokenContext.getAuthorizationGrantType().equals(AuthorizationGrantType.AUTHORIZATION_CODE)) {

+ 2 - 16
oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/token/OAuth2AccessTokenGeneratorTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2020-2024 the original author or authors.
+ * 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.
@@ -18,7 +18,6 @@ package org.springframework.security.oauth2.server.authorization.token;
 import java.security.Principal;
 import java.time.Instant;
 import java.util.Collections;
-import java.util.Map;
 import java.util.Set;
 
 import org.junit.jupiter.api.BeforeEach;
@@ -42,10 +41,8 @@ import org.springframework.security.oauth2.server.authorization.client.TestRegis
 import org.springframework.security.oauth2.server.authorization.context.AuthorizationServerContext;
 import org.springframework.security.oauth2.server.authorization.context.TestAuthorizationServerContext;
 import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
-import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
 import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat;
 import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
-import org.springframework.security.oauth2.server.authorization.util.TestX509Certificates;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -117,16 +114,10 @@ public class OAuth2AccessTokenGeneratorTests {
 	@Test
 	public void generateWhenReferenceAccessTokenTypeThenReturnAccessToken() {
 		// @formatter:off
-		ClientSettings clientSettings = ClientSettings.builder()
-				.x509CertificateSubjectDN(TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE[0].getSubjectX500Principal().getName())
-				.build();
 		TokenSettings tokenSettings = TokenSettings.builder()
 				.accessTokenFormat(OAuth2TokenFormat.REFERENCE)
-				.x509CertificateBoundAccessTokens(true)
 				.build();
 		RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
-				.clientAuthenticationMethod(ClientAuthenticationMethod.TLS_CLIENT_AUTH)
-				.clientSettings(clientSettings)
 				.tokenSettings(tokenSettings)
 				.build();
 		// @formatter:on
@@ -134,8 +125,7 @@ public class OAuth2AccessTokenGeneratorTests {
 		Authentication principal = authorization.getAttribute(Principal.class.getName());
 
 		OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
-				registeredClient, ClientAuthenticationMethod.TLS_CLIENT_AUTH,
-				TestX509Certificates.DEMO_CLIENT_PKI_CERTIFICATE);
+				registeredClient, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, registeredClient.getClientSecret());
 		OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute(
 				OAuth2AuthorizationRequest.class.getName());
 		OAuth2AuthorizationCodeAuthenticationToken authentication =
@@ -179,10 +169,6 @@ public class OAuth2AccessTokenGeneratorTests {
 		Set<String> scopes = accessTokenClaims.getClaim(OAuth2ParameterNames.SCOPE);
 		assertThat(scopes).isEqualTo(tokenContext.getAuthorizedScopes());
 
-		Map<String, Object> cnf = accessTokenClaims.getClaim("cnf");
-		assertThat(cnf).isNotEmpty();
-		assertThat(cnf.get("x5t#S256")).isNotNull();
-
 		ArgumentCaptor<OAuth2TokenClaimsContext> tokenClaimsContextCaptor = ArgumentCaptor.forClass(OAuth2TokenClaimsContext.class);
 		verify(this.accessTokenCustomizer).customize(tokenClaimsContextCaptor.capture());