Keycloak Spring UMA 被拒绝

问题描述 投票:0回答:2

我正在尝试为此用例实施授权:

  • 用户只能访问自己的资源
  • 管理员可以访问所有内容

我正在试用 Keycloak 和它的资源服务器。出于测试目的并了解这些范围和权限以及内容,我创建了测试客户端

weather-api
和一个资源
Weather
与 url
/weatherforecast
.

然后我有范围

weather:read
和策略,每个具有角色
weatherer
的用户都可以阅读该资源。

现在,当我尝试评估具有该角色的用户时,我得到

PERMIT

另一个没有这个角色的用户被拒绝。

所以我想我的政策和权限设置正确。

当我尝试从我的服务中使用它禁用用户管理访问时,我也获得了许可。

但是当我启用

user-managed-access
时,它失败了。

我在调试日志中看到它获得了权限令牌:

{
  ...
  "permissions": [
    {
      "scopes": [
        "weather:read"
      ],
      "rsid": "ae5ac493-b7dc-481e-9204-a664d1558a51"
    }
  ],
  ...
}

但是接下来的消息是

Policy enforcement result for path [http://192.168.0.9:5001/weatherforecast] is : DENIED

我尝试调试 Keycloak 库,发现了一些我不太明白的东西。

KeycloakAdapterPolicyEnforcer
这部分代码:

@Override
protected boolean isAuthorized(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, AccessToken accessToken, OIDCHttpFacade httpFacade, Map<String, List<String>> claims) {
  AccessToken original = accessToken;

  if (super.isAuthorized(pathConfig, methodConfig, accessToken, httpFacade, claims)) {
      return true;
  }

  accessToken = requestAuthorizationToken(pathConfig, methodConfig, httpFacade, claims);

  if (accessToken == null) {
      return false;
  }
  ...
}

private AccessToken requestAuthorizationToken(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, OIDCHttpFacade httpFacade, Map<String, List<String>> claims) {
  if (getEnforcerConfig().getUserManagedAccess() != null) {
      return null;
  }
  ...
}

所以当 UserManagedAccess 不为 null 时,

requestAuthorizationToken
返回 null 然后它的行为就像用户未经授权
HTTP 401
.

我在这里错过了什么?为什么它只能在没有 UMA 的情况下工作?

我看过这些(app-authz-uma-photozdevconf2019-authz)示例,但没有注意到我遗漏了什么。

除非他们实际上是从 Java 应用程序为用户创建一些资源,否则我不是。但我想如果我保护用户创建的资源或单个“预制”URL 应该无关紧要,对吧?它应该只取决于正确的权限,因为它们评估为

PERMIT
所以我不明白为什么这不起作用。

还有一个问题。在用户之间永远不会有任何共享的情况下,对于“用户可以访问他自己的,管理员可以访问所有内容”的情况,这个 UMA 事情是不是太过分了?我正在考虑一些更简单的方法,可以在不在 Keycloak 中创建用户资源的情况下工作,但我想不出任何东西,我相信我仍然需要将用户 ID 与一些资源 ID 连接起来才能工作。

authorization keycloak
2个回答
0
投票

让我们在调试或您的 Catalina 会话中检查您的 KeycloakSecurityContext,也许它将为 null 并返回 403。只需将 enforcer 配置添加到 spring boot 配置文件中,前缀为:keycloak 对于 KeycloakSecurityContext 的初始默认上下文,Spring boot 将能够加载 Enforcer从keycloak服务器配置。


0
投票

Spring 的 Keycloak 适配器已于 2022 年初弃用。不要使用它。它甚至不兼容 Spring Boot 3.

我在这个问题的答案中详细介绍了配置资源服务器的替代解决方案:Use Keycloak Spring Adapter with Spring Boot 3,但对于高级访问控制的示例,我建议您参考我关于该主题的教程

如果您绝对想使用授权服务,则必须使用

WebClient
@FeignClient
或其他方式手动调用 REST 端点。

我不喜欢Keycloak授权服务,原因如下:

  • 效率很低:资源服务器必须为它处理的每个请求发送一个请求到授权服务器(Keycloak)以获取访问决策
  • 访问控制定义的方式很难(不可能?)进行单元测试
  • 它非常遵守 Keycloak(它不是标准的,如果您被迫使用另一个身份提供者,您不太可能找到接受相同配置的完全相同的功能)
  • 很容易在环境之间获得配置差异。特定环境中的访问控制“错误”可能是发现和修复的噩梦,在我看来,这对应用程序来说是一个非常高的安全风险:如何确保在任何时候,没有人插入错误或产品中的恶意授权规则?

相反,如果您编写方法安全表达式,例如

@PreAtuhorize("hasAutority('ADMIN') or #weatherForecast.authorUsername == #auth.tokenAttributes['preferred_username']")
@GetMapping("/weatherforecast/{forecastId}")
public WeatherForecastDto getForecast(@PathVariable("forecastId") WeatherForecastEntity weatherForecast, JwtAuthenticationToken auth) {
    ...
}

然后:

  • 客户端向授权服务器查询访问令牌颁发(在很多请求中一次,如授权服务),但是您保存来自资源服务器的所有访问控制请求
  • 您可以使用模拟的
    JwtAuthenticationToken
    实例编写单元测试,以断言访问控制的行为符合您的预期
  • 授权规则是不可变的并随应用程序一起提供(没有人可以在产品中更改它)
  • 它可以移植到任何授权服务器,您可以在其上控制访问令牌私有声明(大多数允许)
© www.soinside.com 2019 - 2024. All rights reserved.