Keycloak x509 client authentication configuration
我需要一些技巧来了解如何使用 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)?
是否还需要传递私钥?为什么?
请查看 Keycloak 服务器管理指南第 6 节中的 X.509 客户端证书用户身份验证部分,其中描述:
- 如何在 Wildfly 和 Keycloak 中启用和配置客户端证书身份验证
- 如何将证书字段映射到用户属性
- 使用 Keycloak/Wildfly(Keycloak 容器)的客户端证书身份验证工作流程。
很遗憾,我不明白如何使用用户数据(信息、角色等)生成有效且受信任的 x509 证书,以便从 IdP 获取访问令牌。
看看这篇文章来生成证书如何使用 OpenSSL 创建自签名证书
IdP 如何检查和验证此客户端证书?
Keycloak 文档是一个很好的起点,请查看"将 X.509 客户端证书身份验证添加到浏览器流程"和"将 X.509 客户端证书身份验证添加到直接授权流程"
如果您需要用户密钥的整个 DN,您可以在配置 X509 上使用此 RegEx:
- 设置"提取用户身份的正则表达式":(.*)
- 例如,添加一个名为 "usercertificate" 的用户属性并在其中复制 DN。
是否有必要在 Keycloak 的某个地方安装一个服务器证书副本?
不是所有的证书,您只能在名为 "usercertificate" 的用户用户属性中添加 DN。
将客户端证书传递给 keycloak 的正确形式是什么(例如 CURL)?
网址:https://localhost:9445/auth/realms//protocol/openid-connect/token
打开 Keycloak TLS 会话的代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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"); } } |
是否还需要传递私钥?为什么?
没有