0

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

设置细节
Nuxeo 平台版本:10.10(在tomcat 9 上运行)
Keycloak 版本: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 插件。

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

客户端配置中提供的客户端详细信息

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

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

错误场景
为了从邮递员调用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版本的兼容性问题吗?

4

1 回答 1

0

迟到的答案,但对新读者来说可能会派上用场。几个月前我遇到了完全相同的问题。这似乎是由于 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 和承载身份验证。

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

于 2019-08-23T10:27:21.480 回答