【问题标题】:Using Keycloak for defining subjects in policies in Eclispe Ditto使用 Keycloak 在 Eclispe Ditto 中定义策略中的主题
【发布时间】:2020-10-31 17:56:36
【问题描述】:

我当前的用例是:我有一个用户通过 Keycloak 登录的前端应用程序。我想在这个前端 (https://www.eclipse.org/ditto/http-api-doc.html) 中实现 Ditto HTTP API 的某些部分。

例如,我想为授权创建策略 (https://www.eclipse.org/ditto/basic-policy.html)。我在文档中读到可以使用符合 OpenID Connect 的提供程序,格式为:(https://www.eclipse.org/ditto/basic-policy.html#who-can-be-addressed)。

页面底部有基本的auth示例,在这种情况下似乎使用了用户名。

{
    "policyId": "my.namespace:policy-a",
    "entries": {
      "owner": {
        "subjects": {
          "nginx:ditto": {
            "type": "nginx basic auth user"
          }
        },
        
    ...
}

我的问题是:如果我想使用 Keycloak,子声明到底是什么?它也是我要授予权限的用户的用户名吗?以及如何在我想要指定之后将其发送到 Ditto 的策略的前端中获取此信息?


更新 1:

我尝试在 Ditto 中启用 keycloak 身份验证,如下所示,如下所述:https://www.eclipse.org/ditto/installation-operating.html#openid-connect

因为我使用 Docker Compose 运行 Ditto,所以我在第 136 行的 ditto/deployment/docker/docker-compose.yml 中添加了以下行作为环境变量:- Dditto.gateway.authentication.oauth.openid-connect-issuers.keycloak=http://localhost:8090/auth/realms/twin 此 URL 与我从 keycloak 收到的令牌的颁发者声明中的相同。

现在,如果我尝试使用 Postman 向 {{basePath}}/things 发出发布请求,我会收到以下错误:

<html>

<head>
    <title>401 Authorization Required</title>
</head>

<body bgcolor="white">
    <center>
        <h1>401 Authorization Required</h1>
    </center>
    <hr>
    <center>nginx/1.13.12</center>
</body>

</html>

我在 Postman 中选择了 Bearer Token 作为 Auth 并粘贴了一个新的令牌。使用默认同上用户的基本身份验证仍在工作。

我之前必须在同上指定新的主题/我的用户吗?


更新 2:

我设法通过在 nginx.conf 中注释掉“auth_basic”和“auth_basic_user_file”来关闭 nginx 中的基本身份验证!

它现在似乎被转发到同上,因为现在我收到 Postman 的以下错误:

{ 
   "status": 401, 
   "error": "gateway:jwt.issuer.notsupported", 
   "message": "The JWT issuer 'localhost:8090/auth/realms/twin' is not supported.", 
   "description": "Check if your JWT is correct." 
}

更新 3:

我在 gateway.conf 中的配置现在看起来像这样:

oauth {
        protocol = "http"
        openid-connect-issuers = {
          keycloak = "localhost:8090/auth/realms/twin"
        }
      }

我也尝试在 docker-compose.yml 中添加这两行:

- Dditto.gateway.authentication.oauth.protocol=http
- Dditto.gateway.authentication.oauth.openid-connect-issuers.keycloak=localhost:8090/auth/realms/twin

不幸的是,我仍然没有运气,与上述相同的错误:/ 似乎用户之前遇到过类似的 keycloak 问题 (https://gitter.im/eclipse/ditto?at=5de3ff186a85195b9edcb1a6),但遗憾的是他没有提到任何解决方案。

编辑:原来我以错误的方式指定了这些变量,正确的解决方案是将它们添加为command: java ... 的一部分更多信息here


更新 4:

我尝试在本地构建 Ditto 而不是使用最新的 docker 映像,我想我现在可能更进一步,我的 oauth 配置似乎正在运行。我现在明白了:

{
    "status": 503,
    "error": "gateway:publickey.provider.unavailable",
    "message": "The public key provider is not available.",
    "description": "If after retry it is still unavailable, please contact the service team."
}

日志中的错误信息是:

gateway_1        | 2020-11-05 15:33:18,669 WARN  [] o.e.d.s.g.s.a.j.DittoPublicKeyProvider  - Got Exception from discovery endpoint <http://localhost:8090/auth/realms/twin/.well-known/openid-configuration>.
gateway_1        | akka.stream.StreamTcpException: Tcp command [Connect(localhost:8090,None,List(),Some(10 seconds),true)] failed because of java.net.ConnectException: Connection refused
gateway_1        | Caused by: java.net.ConnectException: Connection refused
...
gateway_1        | java.util.concurrent.CompletionException: org.eclipse.ditto.services.gateway.security.authentication.jwt.PublicKeyProviderUnavailableException [message='The public key provider is not available.', errorCode=gateway:publickey.provider.unavailable, statusCode=SERVICE_UNAVAILABLE, description='If after retry it is still unavailable, please contact the service team.', href=null, dittoHeaders=ImmutableDittoHeaders [{}]]
...
gateway_1        | Caused by: org.eclipse.ditto.services.gateway.security.authentication.jwt.PublicKeyProviderUnavailableException [message='The public key provider is not available.', errorCode=gateway:publickey.provider.unavailable, statusCode=SERVICE_UNAVAILABLE, description='If after retry it is still unavailable, please contact the service team.', href=null, dittoHeaders=ImmutableDittoHeaders [{}]]
...
gateway_1        | Caused by: akka.stream.StreamTcpException: Tcp command [Connect(localhost:8090,None,List(),Some(10 seconds),true)] failed because of java.net.ConnectException: Connection refused
gateway_1        | Caused by: java.net.ConnectException: Connection refused

我的 keyloak 肯定在运行,我可以获得令牌。如果我打开第一条错误消息中的http://localhost:8090/auth/realms/twin/.well-known/openid-configuration,我可以从 keycloak 配置中看到我的 openid 配置。 编辑:似乎我的网关容器无法访问我的 keycloak 容器,将尝试解决这个问题。


最终更新:

网关 docker 容器无法访问 keycloak docker 容器是问题所在。我现在正在使用 traefik:

  1. Keycloak 容器具有以下别名:keycloak.localhost
  2. 网关中的 Oauth 配置如下所示:
oauth {
        protocol = "http"
        openid-connect-issuers = {
          keycloak = "keycloak.localhost/auth/realms/twin"
        }
      }
  1. 现在网关可以通过别名找到 keycloak 容器,我仍然可以使用本地主机中的 keycloak 管理 ui:http://keycloak.localhost:8090/auth/admin/

其他信息:Traefic Blog

【问题讨论】:

  • 401好像是nginx发出的。你还在nginx里配置基本的auth吗?如果是这种情况,请求永远不会到达同上。
  • docker-compose.yml 中的 ENABLE_DUMMY_AUTH=true 仍然打开。这是你的意思吗?我把它关掉了,所以默认的同上用户不再使用基本身份验证。另外我设置了 ENABLE_PRE_AUTHENTICATION=false。但是当我切换到 Bearer 时,它仍然是和以前一样的错误消息。我不知道如何正确禁用基本身份验证,您能否再给我一个提示?我必须调整文件 nginx.conf 吗?
  • 我更新了 openid-connect-issuer 的配置部分。似乎该方案不能成为发行人配置的一部分,但需要在 oauth 级别进行配置(适用于所有发行人)。我不建议在这里使用http。
  • 我解决了并更新了解决方案!再次感谢您!
  • 我很乐意提供帮助!但我仍然想知道为什么我不能让它与预先构建的 docker 图像一起使用。似乎我的环境变量根本不起作用,因此它说仍然不受支持的 jwt 发行者,因为配置列表为空..

标签: keycloak eclipse-ditto


【解决方案1】:

如果我想使用 Keycloak,子声明到底是什么?

Keycloak 为您提供 JWT。

JWT 是一种加密的 JSON,其中包含多个称为“声明”的字段。您可以通过访问 https://jwt.io 并将您的令牌粘贴到那里来检查您的令牌的外观。其中一个字段称为sub。这是sub claim。

要在 eclipse ditto 中启用 keycloak 身份验证,您需要将颁发者添加到 ditto 配置中。

可以在here 找到一个例子。 该地址必须与您的 JWT 令牌的 issuer claim 中的 URL 匹配。

ditto.gateway.authentication {
    oauth {
      protocol = "http"
      openid-connect-issuers = {
        some-name = "localhost:8090/auth/realms/twin"
      }
    }
}

这也是我要授予权限的用户的用户名吗?

在 Eclipse 中,实际上并没有“用户名”的概念。 Eclipse 同上身份验证基于授权主题。对于您提供的基本身份验证示例,在同上生成的授权主题是nginx:ditto。

对于 JWT 身份验证,授权主题是作为您配置的开放 id 连接颁发者的名称(在我的情况下为 some-name)和 sub 声明的值的组合生成的。授权主题可能如下所示:some-name:8d078113-3ee5-4dbf-8db1-eb1a6cf0fe81。

我如何在我的前端中得到这个,我想指定之后将其发送到 Ditto 的策略?

我不确定我是否正确理解了这个问题。如果您的意思是如何对 Eclipse 同上的前端 HTTP 请求进行身份验证,则需要通过以下形式将 JWT 添加到您的 HTTP 请求的授权标头中,从而将 JWT 提供给 eclipse 同上:

authorization: Bearer yourJWT

如果您的意思是如何知道 JWT 的子声明,则需要将 parse the JWT 发送到 JSON 对象,然后从有效负载部分中读取子声明。

【讨论】:

  • 感谢 Yannic 的详细解答!我对最后一个问题的意思以及我仍然不明白的意思是:假设我想授予策略中的另一个主体(不是我)的权利,例如您上面提到的授权主体(“某个名称”)。我无权访问另一个用户的 JWT,以获取他的特定子声明以将其写入策略。我该怎么做?也许我完全走错了路。
  • 我的意思是基本的身份验证示例很清楚,我可以只写“主题”:{“nginx:another-user”:{}},但是在使用 OpenID 时如何与其他用户一起执行此操作连接 Keycloak 等合规提供商?
  • 或者我可以这样从 keycloak 中获得其他用户的用户名吗?
  • 您可以考虑将“sub”声明等同于用户名。因此,如果您请求某人授予对资源的访问权限,他或她需要向您提供他或她的令牌的子声明的价值。
  • 再次感谢您的澄清!因为我使用 docker compose 运行 Ditto,所以我添加了“-Dditto.gateway.authentication.oauth.openid-connect-issuers.keycloak=localhost:8090/auth/realms/twin”(来自我对令牌的颁发者声明)作为网关的环境变量撰写文件中的服务。使用邮递员和我的不记名令牌,我仍然得到“需要 401 授权”,并且只有基本身份验证在工作。我试图发布一个新东西:“{{basePath}}/things”。你会推荐我什么来找出我的错误?
猜你喜欢
  • 2022-01-14
  • 2022-01-09
  • 2018-12-03
  • 2018-08-30
  • 2019-09-15
  • 2020-06-19
  • 2021-05-01
  • 2021-08-07
  • 2017-03-06
相关资源
最近更新 更多