Keycloak X509客户端身份验证配置

时间:2020-02-14 11:28:31

标签: authentication keycloak x509certificate ambassador

我需要一些提示,以了解如何针对Keycloak使用x509证书执行客户端身份验证。

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

但这不是我们想要的。 对我们来说,需要进行客户端身份验证(React Native Mobile App),

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

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

然后... IdP如何检查和验证此客户端证书?是否需要在Keycloak上某处安装Server证书副本?

将客户端证书传递给密钥斗篷的正确格式是什么(例如带有CURL)? 是否还需要传递私钥,为什么?

2 个答案:

答案 0 :(得分:0)

请检查《 Keycloak服务器管理指南》第6节中的X.509 Client Certificate User Authentication部分,内容:

  • 如何在Wildfly和Keycloak中启用和配置客户端证书认证
  • 如何将证书字段映射到用户属性
  • 具有Keycloak / Wildfly(Keycloak容器)的客户端证书身份验证工作流。

答案 1 :(得分:0)

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

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

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

Keycloak文档是一个很好的起点,请选中“将X.509客户端证书身份验证添加到浏览器流”和“将X.509客户端证书身份验证添加到直接授权流” 如果您需要整个DN作为用户密钥,则可以在配置X509上使用此RegEx:

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

是否需要在Keycloak上某处安装Server证书副本?

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

什么是将客户端证书传递给密钥斗篷的正确格式(例如CURL)?

URL: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");
    }
}

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