From 44303d2c80d01eef30ea4219296ed4cd09ec52e7 Mon Sep 17 00:00:00 2001 From: Joe Grandja <10884212+jgrandja@users.noreply.github.com> Date: Tue, 13 May 2025 08:15:00 -0400 Subject: [PATCH] Polish gh-17080 --- .../DPoPAuthenticationConfigurerTests.java | 32 +++++++------------ .../DPoPAuthenticationProvider.java | 8 ----- .../DPoPAuthenticationProviderTests.java | 5 ++- 3 files changed, 14 insertions(+), 31 deletions(-) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java index d908607a1f..6ffab052e9 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java @@ -18,7 +18,6 @@ package org.springframework.security.config.annotation.web.configurers.oauth2.se import java.nio.charset.StandardCharsets; import java.security.MessageDigest; -import java.security.PublicKey; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAPrivateKey; @@ -33,6 +32,7 @@ import java.util.Set; import java.util.UUID; import com.nimbusds.jose.jwk.ECKey; +import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.RSAKey; import com.nimbusds.jose.jwk.source.JWKSource; @@ -89,6 +89,8 @@ public class DPoPAuthenticationConfigurerTests { private static final ECPrivateKey CLIENT_EC_PRIVATE_KEY = (ECPrivateKey) TestKeys.DEFAULT_EC_KEY_PAIR.getPrivate(); + private static final ECKey CLIENT_EC_KEY = TestJwks.jwk(CLIENT_EC_PUBLIC_KEY, CLIENT_EC_PRIVATE_KEY).build(); + private static NimbusJwtEncoder providerJwtEncoder; private static NimbusJwtEncoder clientJwtEncoder; @@ -104,9 +106,8 @@ public class DPoPAuthenticationConfigurerTests { JWKSource providerJwkSource = (jwkSelector, securityContext) -> jwkSelector .select(new JWKSet(providerRsaKey)); providerJwtEncoder = new NimbusJwtEncoder(providerJwkSource); - ECKey clientEcKey = TestJwks.jwk(CLIENT_EC_PUBLIC_KEY, CLIENT_EC_PRIVATE_KEY).build(); JWKSource clientJwkSource = (jwkSelector, securityContext) -> jwkSelector - .select(new JWKSet(clientEcKey)); + .select(new JWKSet(CLIENT_EC_KEY)); clientJwtEncoder = new NimbusJwtEncoder(clientJwkSource); } @@ -114,7 +115,7 @@ public class DPoPAuthenticationConfigurerTests { public void requestWhenDPoPAndBearerAuthenticationThenUnauthorized() throws Exception { this.spring.register(SecurityConfig.class, ResourceEndpoints.class).autowire(); Set scope = Collections.singleton("resource1.read"); - String accessToken = generateAccessToken(scope, CLIENT_EC_PUBLIC_KEY); + String accessToken = generateAccessToken(scope, CLIENT_EC_KEY); String dPoPProof = generateDPoPProof(HttpMethod.GET.name(), "http://localhost/resource1", accessToken); // @formatter:off this.mvc.perform(get("/resource1") @@ -131,7 +132,7 @@ public class DPoPAuthenticationConfigurerTests { public void requestWhenDPoPAccessTokenMalformedThenUnauthorized() throws Exception { this.spring.register(SecurityConfig.class, ResourceEndpoints.class).autowire(); Set scope = Collections.singleton("resource1.read"); - String accessToken = generateAccessToken(scope, CLIENT_EC_PUBLIC_KEY); + String accessToken = generateAccessToken(scope, CLIENT_EC_KEY); String dPoPProof = generateDPoPProof(HttpMethod.GET.name(), "http://localhost/resource1", accessToken); // @formatter:off this.mvc.perform(get("/resource1") @@ -147,7 +148,7 @@ public class DPoPAuthenticationConfigurerTests { public void requestWhenMultipleDPoPProofsThenUnauthorized() throws Exception { this.spring.register(SecurityConfig.class, ResourceEndpoints.class).autowire(); Set scope = Collections.singleton("resource1.read"); - String accessToken = generateAccessToken(scope, CLIENT_EC_PUBLIC_KEY); + String accessToken = generateAccessToken(scope, CLIENT_EC_KEY); String dPoPProof = generateDPoPProof(HttpMethod.GET.name(), "http://localhost/resource1", accessToken); // @formatter:off this.mvc.perform(get("/resource1") @@ -164,7 +165,7 @@ public class DPoPAuthenticationConfigurerTests { public void requestWhenDPoPAuthenticationValidThenAccessed() throws Exception { this.spring.register(SecurityConfig.class, ResourceEndpoints.class).autowire(); Set scope = Collections.singleton("resource1.read"); - String accessToken = generateAccessToken(scope, CLIENT_EC_PUBLIC_KEY); + String accessToken = generateAccessToken(scope, CLIENT_EC_KEY); String dPoPProof = generateDPoPProof(HttpMethod.GET.name(), "http://localhost/resource1", accessToken); // @formatter:off this.mvc.perform(get("/resource1") @@ -175,11 +176,11 @@ public class DPoPAuthenticationConfigurerTests { // @formatter:on } - private static String generateAccessToken(Set scope, PublicKey clientPublicKey) { + private static String generateAccessToken(Set scope, JWK jwk) { Map jktClaim = null; - if (clientPublicKey != null) { + if (jwk != null) { try { - String sha256Thumbprint = computeSHA256(clientPublicKey); + String sha256Thumbprint = jwk.toPublicJWK().computeThumbprint().toString(); jktClaim = new HashMap<>(); jktClaim.put("jkt", sha256Thumbprint); } @@ -207,10 +208,7 @@ public class DPoPAuthenticationConfigurerTests { private static String generateDPoPProof(String method, String resourceUri, String accessToken) throws Exception { // @formatter:off - Map publicJwk = TestJwks.jwk(CLIENT_EC_PUBLIC_KEY, CLIENT_EC_PRIVATE_KEY) - .build() - .toPublicJWK() - .toJSONObject(); + Map publicJwk = CLIENT_EC_KEY.toPublicJWK().toJSONObject(); JwsHeader jwsHeader = JwsHeader.with(SignatureAlgorithm.ES256) .type("dpop+jwt") .jwk(publicJwk) @@ -233,12 +231,6 @@ public class DPoPAuthenticationConfigurerTests { return Base64.getUrlEncoder().withoutPadding().encodeToString(digest); } - private static String computeSHA256(PublicKey publicKey) throws Exception { - MessageDigest md = MessageDigest.getInstance("SHA-256"); - byte[] digest = md.digest(publicKey.getEncoded()); - return Base64.getUrlEncoder().withoutPadding().encodeToString(digest); - } - @Configuration @EnableWebSecurity @EnableWebMvc diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java index aa98e6c2f5..0b904254f8 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java @@ -18,13 +18,11 @@ package org.springframework.security.oauth2.server.resource.authentication; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; -import java.security.PublicKey; import java.time.Instant; import java.util.Base64; import java.util.Map; import java.util.function.Function; -import com.nimbusds.jose.jwk.AsymmetricJWK; import com.nimbusds.jose.jwk.JWK; import org.springframework.security.authentication.AuthenticationManager; @@ -243,12 +241,6 @@ public final class DPoPAuthenticationProvider implements AuthenticationProvider return new OAuth2Error(OAuth2ErrorCodes.INVALID_DPOP_PROOF, reason, null); } - private static String computeSHA256(PublicKey publicKey) throws Exception { - MessageDigest md = MessageDigest.getInstance("SHA-256"); - byte[] digest = md.digest(publicKey.getEncoded()); - return Base64.getUrlEncoder().withoutPadding().encodeToString(digest); - } - } private static final class OAuth2AccessTokenClaims implements OAuth2Token, ClaimAccessor { diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProviderTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProviderTests.java index bc2d83101e..faa84d8cb4 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProviderTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProviderTests.java @@ -18,7 +18,6 @@ package org.springframework.security.oauth2.server.resource.authentication; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; -import java.security.PublicKey; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Base64; @@ -37,7 +36,6 @@ import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.OAuth2ErrorCodes; import org.springframework.security.oauth2.jose.TestJwks; -import org.springframework.security.oauth2.jose.TestKeys; import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; import org.springframework.security.oauth2.jwt.JwsHeader; import org.springframework.security.oauth2.jwt.Jwt; @@ -293,7 +291,7 @@ public class DPoPAuthenticationProviderTests { Map jktClaim = null; if (clientJwk != null) { try { - String sha256Thumbprint = clientJwk.computeThumbprint().toString(); + String sha256Thumbprint = clientJwk.toPublicJWK().computeThumbprint().toString(); jktClaim = new HashMap<>(); jktClaim.put("jkt", sha256Thumbprint); } @@ -322,4 +320,5 @@ public class DPoPAuthenticationProviderTests { byte[] digest = md.digest(value.getBytes(StandardCharsets.UTF_8)); return Base64.getUrlEncoder().withoutPadding().encodeToString(digest); } + }