mirror of
https://github.com/spring-projects/spring-authorization-server.git
synced 2026-05-02 19:29:14 +01:00
Fix DPoP jkt claim validation during refresh_token grant for public clients
Closes gh-2008
This commit is contained in:
+4
-17
@@ -15,16 +15,12 @@
|
||||
*/
|
||||
package org.springframework.security.oauth2.server.authorization.authentication;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.Principal;
|
||||
import java.security.PublicKey;
|
||||
import java.util.Base64;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.nimbusds.jose.jwk.AsymmetricJWK;
|
||||
import com.nimbusds.jose.jwk.JWK;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -292,18 +288,15 @@ public final class OAuth2RefreshTokenAuthenticationProvider implements Authentic
|
||||
}
|
||||
|
||||
private static void verifyDPoPProofPublicKey(Jwt dPoPProof, ClaimAccessor accessTokenClaims) {
|
||||
PublicKey publicKey = null;
|
||||
JWK jwk = null;
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> jwkJson = (Map<String, Object>) dPoPProof.getHeaders().get("jwk");
|
||||
try {
|
||||
JWK jwk = JWK.parse(jwkJson);
|
||||
if (jwk instanceof AsymmetricJWK) {
|
||||
publicKey = ((AsymmetricJWK) jwk).toPublicKey();
|
||||
}
|
||||
jwk = JWK.parse(jwkJson);
|
||||
}
|
||||
catch (Exception ignored) {
|
||||
}
|
||||
if (publicKey == null) {
|
||||
if (jwk == null) {
|
||||
OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.INVALID_DPOP_PROOF,
|
||||
"jwk header is missing or invalid.", null);
|
||||
throw new OAuth2AuthenticationException(error);
|
||||
@@ -311,7 +304,7 @@ public final class OAuth2RefreshTokenAuthenticationProvider implements Authentic
|
||||
|
||||
String jwkThumbprint;
|
||||
try {
|
||||
jwkThumbprint = computeSHA256(publicKey);
|
||||
jwkThumbprint = jwk.computeThumbprint().toString();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.INVALID_DPOP_PROOF,
|
||||
@@ -335,10 +328,4 @@ public final class OAuth2RefreshTokenAuthenticationProvider implements Authentic
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-2
@@ -295,9 +295,8 @@ public class OAuth2RefreshTokenGrantTests {
|
||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.DPOP,
|
||||
"dpop-bound-access-token", Instant.now(), Instant.now().plusSeconds(300));
|
||||
Map<String, Object> accessTokenClaims = new HashMap<>();
|
||||
PublicKey publicKey = TestJwks.DEFAULT_EC_JWK.toPublicKey();
|
||||
Map<String, Object> cnfClaim = new HashMap<>();
|
||||
cnfClaim.put("jkt", computeSHA256(publicKey));
|
||||
cnfClaim.put("jkt", TestJwks.DEFAULT_EC_JWK.toPublicJWK().computeThumbprint().toString());
|
||||
accessTokenClaims.put("cnf", cnfClaim);
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations
|
||||
.authorization(registeredClient, accessToken, accessTokenClaims)
|
||||
|
||||
Reference in New Issue
Block a user