KEYCLOAK-12500 Avoid NPE when parsing JWKS and keys without the use parameter

This commit is contained in:
Johannes Knutsen 2021-06-21 14:54:04 +02:00 committed by Marek Posolda
parent b102c892fa
commit ba8d27121c
2 changed files with 19 additions and 3 deletions

View file

@ -17,6 +17,7 @@
package org.keycloak.util; package org.keycloak.util;
import org.jboss.logging.Logger;
import org.keycloak.crypto.KeyUse; import org.keycloak.crypto.KeyUse;
import org.keycloak.crypto.KeyWrapper; import org.keycloak.crypto.KeyWrapper;
import org.keycloak.jose.jwk.JSONWebKeySet; import org.keycloak.jose.jwk.JSONWebKeySet;
@ -32,12 +33,16 @@ import java.util.Map;
*/ */
public class JWKSUtils { public class JWKSUtils {
private static final Logger logger = Logger.getLogger(JWKSUtils.class);
public static Map<String, PublicKey> getKeysForUse(JSONWebKeySet keySet, JWK.Use requestedUse) { public static Map<String, PublicKey> getKeysForUse(JSONWebKeySet keySet, JWK.Use requestedUse) {
Map<String, PublicKey> result = new HashMap<>(); Map<String, PublicKey> result = new HashMap<>();
for (JWK jwk : keySet.getKeys()) { for (JWK jwk : keySet.getKeys()) {
JWKParser parser = JWKParser.create(jwk); JWKParser parser = JWKParser.create(jwk);
if (jwk.getPublicKeyUse().equals(requestedUse.asString()) && parser.isKeyTypeSupported(jwk.getKeyType())) { if (jwk.getPublicKeyUse() == null) {
logger.debugf("Ignoring JWK key '%s'. Missing required field 'use'.", jwk.getKeyId());
} else if (requestedUse.asString().equals(jwk.getPublicKeyUse()) && parser.isKeyTypeSupported(jwk.getKeyType())) {
result.put(jwk.getKeyId(), parser.toPublicKey()); result.put(jwk.getKeyId(), parser.toPublicKey());
} }
} }
@ -49,7 +54,9 @@ public class JWKSUtils {
Map<String, KeyWrapper> result = new HashMap<>(); Map<String, KeyWrapper> result = new HashMap<>();
for (JWK jwk : keySet.getKeys()) { for (JWK jwk : keySet.getKeys()) {
JWKParser parser = JWKParser.create(jwk); JWKParser parser = JWKParser.create(jwk);
if (jwk.getPublicKeyUse().equals(requestedUse.asString()) && parser.isKeyTypeSupported(jwk.getKeyType())) { if (jwk.getPublicKeyUse() == null) {
logger.debugf("Ignoring JWK key '%s'. Missing required field 'use'.", jwk.getKeyId());
} else if (requestedUse.asString().equals(jwk.getPublicKeyUse()) && parser.isKeyTypeSupported(jwk.getKeyType())) {
KeyWrapper keyWrapper = new KeyWrapper(); KeyWrapper keyWrapper = new KeyWrapper();
keyWrapper.setKid(jwk.getKeyId()); keyWrapper.setKid(jwk.getKeyId());
if (jwk.getAlgorithm() != null) { if (jwk.getAlgorithm() != null) {
@ -82,7 +89,9 @@ public class JWKSUtils {
public static JWK getKeyForUse(JSONWebKeySet keySet, JWK.Use requestedUse) { public static JWK getKeyForUse(JSONWebKeySet keySet, JWK.Use requestedUse) {
for (JWK jwk : keySet.getKeys()) { for (JWK jwk : keySet.getKeys()) {
JWKParser parser = JWKParser.create(jwk); JWKParser parser = JWKParser.create(jwk);
if (parser.getJwk().getPublicKeyUse().equals(requestedUse.asString()) && parser.isKeyTypeSupported(jwk.getKeyType())) { if (jwk.getPublicKeyUse() == null) {
logger.debugf("Ignoring JWK key '%s'. Missing required field 'use'.", jwk.getKeyId());
} else if (requestedUse.asString().equals(parser.getJwk().getPublicKeyUse()) && parser.isKeyTypeSupported(jwk.getKeyType())) {
return jwk; return jwk;
} }
} }

View file

@ -44,6 +44,7 @@ public class JWKSUtilsTest {
String kidRsa1 = "key1"; String kidRsa1 = "key1";
String kidRsa2 = "key2"; String kidRsa2 = "key2";
String kidInvalidKey = "ignored";
String kidEC1 = "key3"; String kidEC1 = "key3";
String kidEC2 = "key4"; String kidEC2 = "key4";
String jwksJson = "{" + String jwksJson = "{" +
@ -64,6 +65,12 @@ public class JWKSUtilsTest {
" \"e\": \"AQAB\"" + " \"e\": \"AQAB\"" +
" }," + " }," +
" {" + " {" +
" \"kty\": \"RSA\"," +
" \"kid\": \"" + kidInvalidKey + "\"," +
" \"n\": \"soFDjoZ5mQ8XAA7reQAFg90inKAHk0DXMTizo4JuOsgzUbhcplIeZ7ks83hsEjm8mP8lUVaHMPMAHEIp3gu6Xxsg-s73ofx1dtt_Fo7aj8j383MFQGl8-FvixTVobNeGeC0XBBQjN8lEl-lIwOa4ZoERNAShplTej0ntDp7TQm0=\"," +
" \"e\": \"AQAB\"" +
" }," +
" {" +
" \"kty\": \"EC\"," + " \"kty\": \"EC\"," +
" \"use\": \"sig\"," + " \"use\": \"sig\"," +
" \"crv\": \"P-384\"," + " \"crv\": \"P-384\"," +