2

我需要一些技巧来了解如何使用 x509 证书对 Keycloak 执行客户端身份验证。

我们有一个简单的 Spring Boot Web App (API REST) 到 Kubernetes 集群中。此 Web 应用程序通过 API 网关(大使)公开,目前通过浏览器重定向到 Keycloak 登录页面进行保护,用户可以在其中输入其用户名和密码。

然而这不是我们想要的。我们需要的是客户端身份验证(React Native Mobile App),其中:

  • 移动应用程序尝试调用我们的服务器 API REST 端点
  • 大使检查有效的访问令牌并(如果没有)以 403 http 状态响应(无浏览器重定向)
  • 移动应用程序然后重定向到 Keycloak 以执行身份验证
  • Keycloak 不显示用户名/密码登录页面,而是移动应用程序通过其浏览器传递 x509 用户证书。

不幸的是,我无法理解如何使用用户数据(信息、角色 ecc)生成有效且受信任的 x509 证书,以便从 IdP 获取访问令牌。

并且...... IdP 如何检查和验证此客户端证书?是否有必要在 Keycloak 上的某个地方安装服务器证书副本?

将客户端证书传递给 keycloak 的正确形式是什么(例如 CURL)?是否也需要传递私钥,为什么?

4

2 回答 2

1

请查看Keycloak 服务器管理指南第 6 节中的X.509 客户端证书用户身份验证部分,其中描述:

  • 如何在 Wildfly 和 Keycloak 中启用和配置客户端证书身份验证
  • 如何将证书字段映射到用户属性
  • 使用 Keycloak/Wildfly(Keycloak 容器)的客户端证书身份验证工作流程。
于 2020-02-18T00:16:41.333 回答
1

不幸的是,我无法理解如何使用用户数据(信息、角色 ecc)生成有效且受信任的 x509 证书,以便从 IdP 获取访问令牌。

看看这篇文章来生成证书How to create a self-signed certificate with OpenSSL

IdP 如何检查和验证此客户端证书?

Keycloak 文档是一个很好的起点,如果您需要用户密钥的整个 DN,请检查“将 X.509 客户端证书身份验证添加到浏览器流”和“将 X.509 客户端证书身份验证添加到直接授予流”,您可以使用配置 X509 上的这个正则表达式:

  • 设置“提取用户身份的正则表达式”:(.*)
  • 例如,添加一个名为“usercertificate”的用户属性并在其中复制 DN。

是否有必要在 Keycloak 上的某个地方安装服务器证书副本?

不是所有的证书,您可以只在名为“usercertificate”的用户用户属性中添加 DN。

将客户端证书传递给 keycloak 的正确形式是什么(例如 CURL)?

网址:https://localhost:9445/auth/realms//protocol/openid-connect/token

打开 Keycloak TLS 会话的代码示例:

public String openSession(
        File p12File, 
        String passphrase,
        String clientId) 
throws IOException, GeneralSecurityException {

    try (FileInputStream fis = new FileInputStream(p12File);) {
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        keyStore.load(new FileInputStream(p12File), passphrase.toCharArray());
        
        HttpClient httpClient = HttpClients
                .custom()
                .setSSLContext(new SSLContextBuilder()
                        .loadTrustMaterial(null, TrustAllStrategy.INSTANCE)
                        .loadKeyMaterial(keyStore, passphrase.toCharArray())
                        .build())
                .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                .build();
        
        HttpPost httpPost = new HttpPost(tokenEndpoint);
        httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");

        String data = "grant_type=password" + "&client_id="+ clientId;
        StringEntity input = new StringEntity(data);
        httpPost.setEntity(input);

        HttpResponse response = httpClient.execute(httpPost);
        return IOUtils.toString(response.getEntity().getContent(), "UTF-8");
    }
}

是否也需要传递私钥,为什么?

于 2020-08-18T09:50:47.700 回答