Keycloak 21.0.0:未找到用于使用外部 JWK API 进行签名验证的公钥

问题描述 投票:0回答:1

在 Keycloak 21.0.0 中,使用提供 JSON Web 密钥 (JWK) 的外部 API 时,在签名验证过程中会出现问题。系统无法找到预期的公钥,记录以下警告和错误消息:

警告 [org.keycloak.keys.infinispan.InfinispanPublicKeyStorageProvider] 在存储中找不到 PublicKey。要求的孩子: 'sig-2024-10-07-DB'。可用的孩子:“[]”警告[org.keycloak.services] KC-SERVICES0097:无效请求:java.lang.RuntimeException:失败 验证“请求”对象上的签名

@Override
public void authenticate(AuthenticationFlowContext context) {
    JWKSet euroInfoJwkSet = fetchJWKSet();
    boolean isValid = verifySignature(decryptedJwt, euroInfoJwkSet);
    if (!isValid) {
        context.failure(GENERIC_AUTHENTICATION_ERROR);
        return;
    }
}

private JWKSet fetchJWKSet() throws Exception {
    URL url = new URL("https://request/jwk_request.cgi?client_id=5g4h4r8r");
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setRequestMethod("GET");
    conn.setRequestProperty("Accept", "application/json");
    
    if (conn.getResponseCode() != 200) {
        throw new RuntimeException("Failed to fetch JWKs: HTTP error code " + conn.getResponseCode());
    }

    BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    StringBuilder response = new StringBuilder();
    String inputLine;

    while ((inputLine = in.readLine()) != null) {
        response.append(inputLine);
    }
    in.close();
    
    Gson gson = new Gson();
    return JWKSet.parse(response.toString());
}

private boolean verifySignature(String jwt, JWKSet euroInfoJwkSet) throws Exception {
    String[] jwtParts = jwt.split("\\.");
    if (jwtParts.length != 3) {
        throw new IllegalArgumentException("Invalid JWT format");
    }

    byte[] signatureBytes = Base64.getUrlDecoder().decode(jwtParts[2]);

    JWK jwk = euroInfoJwkSet.getKeyByKeyId(jwtParts[0]);

    PublicKey publicKey = ((RSAKey) jwk).toPublicKey();

    Signature sig = Signature.getInstance("SHA256withRSA");
    sig.initVerify(publicKey);
    sig.update((jwtParts[0] + "." + jwtParts[1]).getBytes());
    return sig.verify(signatureBytes);
}
java spring-boot encryption keycloak jwk
1个回答
0
投票

我通过调整Keycloak中的客户端身份验证流程解决了这个问题。具体来说,我将客户端更改为机密模式。设置完成后,客户端配置下会出现一个新选项卡,我可以在其中输入 JWK URL。

Keycloak 在使用 /auth 路径时处理整个身份验证过程。它会自动从提供的 URL 检索 JWK,验证签名,解密消息,并将结果存储在会话中,解决公钥验证问题。

© www.soinside.com 2019 - 2024. All rights reserved.