Polish gh-17080
This commit is contained in:
+12
-20
@@ -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
@@ -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 {
|
||||||
|
|||||||
+2
-3
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user