Browse Source

Polish gh-17080

pull/17100/head
Joe Grandja 11 months ago
parent
commit
44303d2c80
  1. 32
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/DPoPAuthenticationConfigurerTests.java
  2. 8
      oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java
  3. 5
      oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProviderTests.java

32
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.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.PublicKey;
import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey; import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPrivateKey;
@ -33,6 +32,7 @@ import java.util.Set;
import java.util.UUID; import java.util.UUID;
import com.nimbusds.jose.jwk.ECKey; import com.nimbusds.jose.jwk.ECKey;
import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey; import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.JWKSource; 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 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 providerJwtEncoder;
private static NimbusJwtEncoder clientJwtEncoder; private static NimbusJwtEncoder clientJwtEncoder;
@ -104,9 +106,8 @@ public class DPoPAuthenticationConfigurerTests {
JWKSource<SecurityContext> providerJwkSource = (jwkSelector, securityContext) -> jwkSelector JWKSource<SecurityContext> providerJwkSource = (jwkSelector, securityContext) -> jwkSelector
.select(new JWKSet(providerRsaKey)); .select(new JWKSet(providerRsaKey));
providerJwtEncoder = new NimbusJwtEncoder(providerJwkSource); providerJwtEncoder = new NimbusJwtEncoder(providerJwkSource);
ECKey clientEcKey = TestJwks.jwk(CLIENT_EC_PUBLIC_KEY, CLIENT_EC_PRIVATE_KEY).build();
JWKSource<SecurityContext> clientJwkSource = (jwkSelector, securityContext) -> jwkSelector JWKSource<SecurityContext> clientJwkSource = (jwkSelector, securityContext) -> jwkSelector
.select(new JWKSet(clientEcKey)); .select(new JWKSet(CLIENT_EC_KEY));
clientJwtEncoder = new NimbusJwtEncoder(clientJwkSource); clientJwtEncoder = new NimbusJwtEncoder(clientJwkSource);
} }
@ -114,7 +115,7 @@ public class DPoPAuthenticationConfigurerTests {
public void requestWhenDPoPAndBearerAuthenticationThenUnauthorized() throws Exception { public void requestWhenDPoPAndBearerAuthenticationThenUnauthorized() throws Exception {
this.spring.register(SecurityConfig.class, ResourceEndpoints.class).autowire(); this.spring.register(SecurityConfig.class, ResourceEndpoints.class).autowire();
Set<String> scope = Collections.singleton("resource1.read"); Set<String> 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); String dPoPProof = generateDPoPProof(HttpMethod.GET.name(), "http://localhost/resource1", accessToken);
// @formatter:off // @formatter:off
this.mvc.perform(get("/resource1") this.mvc.perform(get("/resource1")
@ -131,7 +132,7 @@ public class DPoPAuthenticationConfigurerTests {
public void requestWhenDPoPAccessTokenMalformedThenUnauthorized() throws Exception { public void requestWhenDPoPAccessTokenMalformedThenUnauthorized() throws Exception {
this.spring.register(SecurityConfig.class, ResourceEndpoints.class).autowire(); this.spring.register(SecurityConfig.class, ResourceEndpoints.class).autowire();
Set<String> scope = Collections.singleton("resource1.read"); Set<String> 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); String dPoPProof = generateDPoPProof(HttpMethod.GET.name(), "http://localhost/resource1", accessToken);
// @formatter:off // @formatter:off
this.mvc.perform(get("/resource1") this.mvc.perform(get("/resource1")
@ -147,7 +148,7 @@ public class DPoPAuthenticationConfigurerTests {
public void requestWhenMultipleDPoPProofsThenUnauthorized() throws Exception { public void requestWhenMultipleDPoPProofsThenUnauthorized() throws Exception {
this.spring.register(SecurityConfig.class, ResourceEndpoints.class).autowire(); this.spring.register(SecurityConfig.class, ResourceEndpoints.class).autowire();
Set<String> scope = Collections.singleton("resource1.read"); Set<String> 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); String dPoPProof = generateDPoPProof(HttpMethod.GET.name(), "http://localhost/resource1", accessToken);
// @formatter:off // @formatter:off
this.mvc.perform(get("/resource1") this.mvc.perform(get("/resource1")
@ -164,7 +165,7 @@ public class DPoPAuthenticationConfigurerTests {
public void requestWhenDPoPAuthenticationValidThenAccessed() throws Exception { public void requestWhenDPoPAuthenticationValidThenAccessed() throws Exception {
this.spring.register(SecurityConfig.class, ResourceEndpoints.class).autowire(); this.spring.register(SecurityConfig.class, ResourceEndpoints.class).autowire();
Set<String> scope = Collections.singleton("resource1.read"); Set<String> 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); String dPoPProof = generateDPoPProof(HttpMethod.GET.name(), "http://localhost/resource1", accessToken);
// @formatter:off // @formatter:off
this.mvc.perform(get("/resource1") this.mvc.perform(get("/resource1")
@ -175,11 +176,11 @@ public class DPoPAuthenticationConfigurerTests {
// @formatter:on // @formatter:on
} }
private static String generateAccessToken(Set<String> scope, PublicKey clientPublicKey) { private static String generateAccessToken(Set<String> scope, JWK jwk) {
Map<String, Object> jktClaim = null; Map<String, Object> jktClaim = null;
if (clientPublicKey != null) { if (jwk != null) {
try { try {
String sha256Thumbprint = computeSHA256(clientPublicKey); String sha256Thumbprint = jwk.toPublicJWK().computeThumbprint().toString();
jktClaim = new HashMap<>(); jktClaim = new HashMap<>();
jktClaim.put("jkt", sha256Thumbprint); jktClaim.put("jkt", sha256Thumbprint);
} }
@ -207,10 +208,7 @@ public class DPoPAuthenticationConfigurerTests {
private static String generateDPoPProof(String method, String resourceUri, String accessToken) throws Exception { private static String generateDPoPProof(String method, String resourceUri, String accessToken) throws Exception {
// @formatter:off // @formatter:off
Map<String, Object> publicJwk = TestJwks.jwk(CLIENT_EC_PUBLIC_KEY, CLIENT_EC_PRIVATE_KEY) Map<String, Object> publicJwk = CLIENT_EC_KEY.toPublicJWK().toJSONObject();
.build()
.toPublicJWK()
.toJSONObject();
JwsHeader jwsHeader = JwsHeader.with(SignatureAlgorithm.ES256) JwsHeader jwsHeader = JwsHeader.with(SignatureAlgorithm.ES256)
.type("dpop+jwt") .type("dpop+jwt")
.jwk(publicJwk) .jwk(publicJwk)
@ -233,12 +231,6 @@ public class DPoPAuthenticationConfigurerTests {
return Base64.getUrlEncoder().withoutPadding().encodeToString(digest); 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 @Configuration
@EnableWebSecurity @EnableWebSecurity
@EnableWebMvc @EnableWebMvc

8
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.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.PublicKey;
import java.time.Instant; import java.time.Instant;
import java.util.Base64; import java.util.Base64;
import java.util.Map; import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import com.nimbusds.jose.jwk.AsymmetricJWK;
import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.JWK;
import org.springframework.security.authentication.AuthenticationManager; 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); 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 { private static final class OAuth2AccessTokenClaims implements OAuth2Token, ClaimAccessor {

5
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.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.PublicKey;
import java.time.Instant; import java.time.Instant;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.Base64; 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.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2ErrorCodes; import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
import org.springframework.security.oauth2.jose.TestJwks; 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.jose.jws.SignatureAlgorithm;
import org.springframework.security.oauth2.jwt.JwsHeader; import org.springframework.security.oauth2.jwt.JwsHeader;
import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.Jwt;
@ -293,7 +291,7 @@ public class DPoPAuthenticationProviderTests {
Map<String, Object> jktClaim = null; Map<String, Object> jktClaim = null;
if (clientJwk != null) { if (clientJwk != null) {
try { try {
String sha256Thumbprint = clientJwk.computeThumbprint().toString(); String sha256Thumbprint = clientJwk.toPublicJWK().computeThumbprint().toString();
jktClaim = new HashMap<>(); jktClaim = new HashMap<>();
jktClaim.put("jkt", sha256Thumbprint); jktClaim.put("jkt", sha256Thumbprint);
} }
@ -322,4 +320,5 @@ public class DPoPAuthenticationProviderTests {
byte[] digest = md.digest(value.getBytes(StandardCharsets.UTF_8)); byte[] digest = md.digest(value.getBytes(StandardCharsets.UTF_8));
return Base64.getUrlEncoder().withoutPadding().encodeToString(digest); return Base64.getUrlEncoder().withoutPadding().encodeToString(digest);
} }
} }

Loading…
Cancel
Save