java - Keycloak 桌面 Java 适配器删除 KEYCLOAK_IDENTITY cookie

标签 java cookies single-sign-on keycloak adapter

我的 Keycloak java 适配器有问题。我尝试将桌面应用程序与 Keycloak 集成,并在其他一些 Web 应用程序之间启用 SSO。问题是,当我尝试登录 Keycloak 时,一切都运行完美且顺利,我获得有关正确身份验证的信息,获取 token ,甚至可以毫无问题地解析它,但在 WebBrowser 中没有创建 session (没有 session ,没有 cookie) 。这意味着我无法将刚刚创建的 session 与同一 Keycloak 领域中的其他应用程序一起使用,即使 Keycloak 中的 session 已正确创建。

此外,在我的桌面适配器“成功”登录尝试后,其他应用程序之前创建和存储的 cookie 也会被删除(作为 cookie,我指的是 KEYCLOAK_IDENTITY 和 KEYCLOAK_INDENTITY_LEGACY)。当我检查浏览器 cookie 时,有一些警告声明说 cookie 由于过期而被拒绝。

我使用的是KeycloakInstalled适配器(最新的15.0.2版本)。我使用页面上的说明配置了它: https://www.keycloak.org/docs/latest/securing_apps/

我认为本例中最重要的代码是:

            KeycloakInstalled keycloak = new KeycloakInstalled();
            AdapterConfig config = new AdapterConfig();
            Map<String, Object> credentials = new HashMap<String, Object>();
            credentials.put("secret", secret);
            config.setAuthServerUrl(url);

            keycloak.getDeployment().setRealm(realm);
            keycloak.getDeployment().setAuthServerBaseUrl(config);
            keycloak.getDeployment().setResourceName(resource);
            keycloak.getDeployment().setResourceCredentials(credentials);
            keycloak.getDeployment().setClientAuthenticator(ClientCredentialsProviderUtils.bootstrapClientAuthenticator(keycloak.getDeployment()));

            keycloak.loginDesktop();

在这种情况下,一些 Keycloak 属性在 keycloak.json 文件中静态设置,而另一些则在 Java 中动态设置(上面的示例)。在 keycloak.json 文件中,一些属性,例如 realmauth-server-urlresource Secret 中充满了垃圾数据,因为它们是稍后动态设置的。

{
  "realm": "<realm>",
  "auth-server-url": "<url>",
  "ssl-required": "external",
  "resource": "<keycloak-client>",
  "use-resource-role-mappings": true,
  "credentials" : {
    "secret" : "abc"
  },
  "truststore" : "<file>.jks",
  "truststore-password" : "<password>"
}

Keycloak 的客户端配置我设置如下:

Keycloak_configuration

如何避免使用桌面适配器删除 session cookie?

最佳答案

我已经解决了我的问题。问题全都与适配器身份验证机制有关。它的工作原理如下:

  1. 适配器连接到 keycloak 以验证用户身份。
  2. 然后,从标记为 redirect_url 的第一个网址重定向到参数中的地址,以告诉适配器身份验证是肯定的。 请注意,此时每个 cookie 均已正确设置。
  3. 然后还有一个到/deleerated端点的重定向,这使得所有 session cookie都过期了。这一切都归功于 Keycloak 存储库中的这段代码:
    @Path("delegated")
    public Response kcinitBrowserLoginComplete(@QueryParam("error") boolean error) {
        AuthenticationManager.expireIdentityCookie(realm, session.getContext().getUri(), clientConnection);
        AuthenticationManager.expireRememberMeCookie(realm, session.getContext().getUri(), clientConnection);
        ...
    }

来源:https://github.com/keycloak/keycloak/blob/d29d945cc4f5674ecff58cf5bf6bb65933f65cad/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java#L295

我所做的是创建自己的CustomKeycloakInstalled类,扩展原始的KeycloakInstalled,其中我复制了关键方法loginDesktop()和其他一些方法让 loginDesktop() 正常工作的必要方法,而且 - 最重要的是,用我自己的方法重写返回最后一个重定向 URL (/deleated) 的函数:

        private String getRedirectUrl() {
            String redirectUrl = CustomKeycloakInstalled.this.getDeployment().getTokenUrl()
                    .replace("/protocol/openid-connect/token", "/my-endpoint");
            if (this.error != null) {
                redirectUrl = redirectUrl + "?error=true";
            }

            return redirectUrl;
        }

现在每个 cookie 都已正确设置,并且 SSO 工作完美,但 Keycloak 服务器中没有 /my-endpoint,因此最后一步是实现和部署它。我在下面使用了 KeycloakResourceProvider 示例: https://github.com/keycloak/keycloak/tree/master/examples/providers/rest

这真的很简单,所以我所做的就是用 Keycloak 的端点委托(delegate)的实现替换 get() 方法,但不会使 cookies 片段过期:

    @GET
    @Produces("text/plain; charset=utf-8")
    public Response get(@QueryParam("error") boolean error) {
        if (error) {
            LoginFormsProvider forms = session.getProvider(LoginFormsProvider.class);
            return forms
                    .setAttribute("messageHeader", forms.getMessage(Messages.DELEGATION_FAILED_HEADER))
                    .setAttribute(Constants.SKIP_LINK, true).setError(Messages.DELEGATION_FAILED).createInfoPage();

        } else {
            LoginFormsProvider forms = session.getProvider(LoginFormsProvider.class);
            return forms
                    .setAttribute("messageHeader", forms.getMessage(Messages.DELEGATION_COMPLETE_HEADER))
                    .setAttribute(Constants.SKIP_LINK, true)
                    .setSuccess(Messages.DELEGATION_COMPLETE).createInfoPage();
        }
    }

然后编译并部署到Keycloak中。

关于java - Keycloak 桌面 Java 适配器删除 KEYCLOAK_IDENTITY cookie,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69001263/

相关文章:

java - 如何测试和模拟mapstruct转换器?

java - RESTEasy java 中的用户登录认证

ios - 为什么在从 Gmail iOS 应用程序打开链接时无法读取 SameSite Lax cookie 的内容?

.net-core - 具有期望 SAML 和 JWT 的服务的 SSO 和 IdentityServer

java - Spring Boot 和 Google SSO

Linux 上 Path 变量中的 Java

java - 滚动条不滚动

go - Cookie 创建后删除?

php - PostGreSQL 和 PHP 的登录脚本不起作用

Azure AD Multi-Tenancy + 身份验证过滤最佳实践