与 Keycloak 身份验证插件集成时,无法从 rest 客户端调用 nuxeo rest api

Posted

技术标签:

【中文标题】与 Keycloak 身份验证插件集成时,无法从 rest 客户端调用 nuxeo rest api【英文标题】:Unable to call nuxeo rest api from rest client when integrated with Keycloak authentication plugin 【发布时间】:2019-10-27 16:17:17 【问题描述】:

我想将 keycloak 集成为在我的本地机器上运行的 nuxeo 平台的身份验证插件

设置详情 Nuxeo 平台版本:10.10(在 tomcat 9 上运行) 密钥斗篷版本:6.0.1 keycloak tomcat 适配器分发:keycloak-tomcat8-adapter-dist

我按照链接https://github.com/nuxeo/nuxeo/tree/master/nuxeo-services/login/nuxeo-platform-login-keycloak中提到的步骤进行操作。 在这里,我为 keycloak 6.0.1 版本构建了 nuxeo-platform-login-keycloak 插件。

在钥匙斗篷上, 我在新创建的领域“演示”下设置了一个身份验证客户端

客户详情可在 client configuration

我将角色创建为“成员”并为其添加了管理员角色 我创建了一个用户“keycloakuser”并添加到“成员”中。

当从浏览器点击 nuxeo ui 时,身份验证流程工作正常。它会将我重定向到 keycloak 的登录页面,在有效凭据上,它会将我重定向到 nuxeo ui。 与分配给它的“成员”组一起创建的用户。

错误场景 为了从 postman 调用 rest api,我配置了 Oauth2 进行身份验证。 授权网址:http://localhost:8080/auth/realms/demo/protocol/openid-connect/auth 令牌网址:http://localhost:8080/auth/realms/demo/protocol/openid-connect/token 客户端:testclient 客户端密码:***** 范围:openid

我使用通过Oauth2流程获得的access_token,以http://localhost:8190/nuxeo/api/v1/id/document_id进行API调用。它失败了

java.lang.ClassCastException: class org.apache.catalina.core.ApplicationHttpRequest cannot be cast to class org.apache.catalina.connector.RequestFacade (org.apache.catalina.core.ApplicationHttpRequest and org.apache.catalina.connector.RequestFacade are in unnamed module of loader java.net.URLClassLoader @39aeed2f)
    at org.nuxeo.ecm.platform.ui.web.keycloak.DeploymentResult.invokeOn(DeploymentResult.java:79) [nuxeo-platform-login-keycloak-10.10.jar:?]
    at org.nuxeo.ecm.platform.ui.web.keycloak.KeycloakAuthenticatorProvider.provide(KeycloakAuthenticatorProvider.java:56) [nuxeo-platform-login-keycloak-10.10.jar:?]
    at org.nuxeo.ecm.platform.ui.web.keycloak.KeycloakAuthenticationPlugin.handleRetrieveIdentity(KeycloakAuthenticationPlugin.java:113) [nuxeo-platform-login-keycloak-10.10.jar:?]
    at org.nuxeo.ecm.platform.ui.web.auth.NuxeoAuthenticationFilter.handleRetrieveIdentity(NuxeoAuthenticationFilter.java:1137) [nuxeo-platform-web-common-10.10.jar:?]
    at org.nuxeo.ecm.platform.ui.web.auth.NuxeoAuthenticationFilter.doFilterInternal(NuxeoAuthenticationFilter.java:548) [nuxeo-platform-web-common-10.10.jar:?]

观察: 1. API 请求调用未命中 keycloak 端点 2.我尝试在两种情况下都打印reqqest类型(实际上是请求包装器类型)。 对于浏览器请求,它是 org.apache.catalina.connector.RequestFacade,对于 api 请求,它是 org.apache.catalina.core.ApplicationHttpRequest,它没有扩展 org.apache.catalina.connector.RequestFacade

问题: 1. 上述行为(第 2 点提及)在 tomcat 9 之前的 tomcat 版本中是否有所不同? 2. 是不是tomcat版本和keycloak adapters jar版本的兼容性问题?

【问题讨论】:

交叉发表于Nuxeo forum 【参考方案1】:

答案较晚,但对新读者来说可能会派上用场。几个月前我遇到了完全相同的问题。这似乎是由于 nuxeo-platform-login-keycloak 插件中的错误。

我结束对org.nuxeo.ecm.platform.ui.web.keycloak.DeploymentResult 进行以下更改:

public class DeploymentResult 
    final static Logger LOGGER = LoggerFactory.getLogger(DeploymentResult.class);

    private boolean isOk;

    private static KeycloakDeployment keycloakDeployment;

    private HttpServletRequest httpServletRequest;
    private HttpServletResponse httpServletResponse;
    private Request request;
    private CatalinaHttpFacade facade;

    public DeploymentResult(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) 
        this.httpServletRequest = httpServletRequest;
        this.httpServletResponse = httpServletResponse;
    

    boolean isOk() 
        return isOk;
    

    public static KeycloakDeployment getKeycloakDeployment() 
        return keycloakDeployment;
    

    public Request getRequest() 
        return request;
    

    public CatalinaHttpFacade getFacade() 
        return facade;
    

    public DeploymentResult invokeOn(AdapterDeploymentContext deploymentContext) 

        // In Tomcat, a HttpServletRequest and a HttpServletResponse are wrapped in a Facades
        if (httpServletRequest instanceof RequestFacade) 
            // Received upon logout.
            request = unwrapRequest(httpServletRequest);
         else 
            request = unwrapRequest(((ServletRequestWrapper) httpServletRequest).getRequest());
        
        facade = new CatalinaHttpFacade(httpServletResponse, request);

        if (keycloakDeployment == null) 
            keycloakDeployment = deploymentContext.resolveDeployment(facade);
        
        if (keycloakDeployment.isConfigured()) 
            isOk = true;
            return this;
        
        isOk = false;
        return this;
    

    /**
     * Get the wrapper @link Request hidden in a @link ServletRequest object
     *
     * @param servletRequest, the main ServletRequest object
     * @return the wrapper @link Request in @link ServletRequest
     */
    private Request unwrapRequest(final ServletRequest servletRequest) 
        try 
            final Field f = servletRequest.getClass().getDeclaredField("request");
            f.setAccessible(true); // grant access to (protected) field
            return (Request) f.get(servletRequest);
         catch (final NoSuchFieldException | IllegalAccessException e) 
            LOGGER.error("Couldn't unwrap request", e);
            throw new RuntimeException(e);
         catch (final Exception e) 
            LOGGER.error("Couldn't unwrap request", e);
            throw e;
        
    

在使用这些更改构建和部署插件后,我被允许使用通过 Keycloak 获得的访问令牌调用 Nuxeo 的 REST API 和承载身份验证。

免责声明:我专注于让它发挥作用,而不是让它变得干净......

【讨论】:

以上是关于与 Keycloak 身份验证插件集成时,无法从 rest 客户端调用 nuxeo rest api的主要内容,如果未能解决你的问题,请参考以下文章

将Flutter应用程序的Facebook身份验证与Keycloak服务集成在一起

Spring Boot 我无法切换 keycloak 和基本身份验证

如何在 React 应用程序中集成 keycloak 身份验证?

如何在没有登录页面的情况下将 Keycloak 与 Spring Boot(API) 集成

无法使用 keycloak 构建基于 spring 的项目进行身份验证

KeyCloak 与 Azure ADB2C 集成 - 缺少状态参数