通过 Keycloak 保护单个资源免受 Spring Boot 的影响

Posted

技术标签:

【中文标题】通过 Keycloak 保护单个资源免受 Spring Boot 的影响【英文标题】:Protect individual resources from Spring Boot via Keycloak 【发布时间】:2021-04-14 03:37:31 【问题描述】:

我有一个非常简单的 Spring Boot 应用程序,其资源位于 /repositories/persons

这是我的build.gradle 文件。

plugins 
    id 'org.springframework.boot' version '2.4.0'
    id 'io.spring.dependency-management' version '1.0.10.RELEASE'
    id 'java'


// use java 11 until keycloak is fixed
sourceCompatibility = '11'

repositories 
    mavenCentral()


dependencyManagement 
    imports 
        mavenBom "org.keycloak.bom:keycloak-adapter-bom:12.0.1"
    


dependencies 
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.keycloak:keycloak-spring-boot-starter'

    implementation 'org.flywaydb:flyway-core'
    runtime 'org.postgresql:postgresql'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'


...
...

这是我的SecurityConfig.java 文件。

@KeycloakConfiguration
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter 

  @Autowired
  public void configureGlobal(AuthenticationManagerBuilder auth) 
    var keycloakAuthenticationProvider = keycloakAuthenticationProvider();
    keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
    auth.authenticationProvider(keycloakAuthenticationProvider);
  

  @Bean
  @Override
  protected SessionAuthenticationStrategy sessionAuthenticationStrategy() 
    return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
  

  @Override
  protected void configure(HttpSecurity http) throws Exception 
    super.configure(http);
    http.authorizeRequests()
        .antMatchers("/persons*")
        .hasRole("user")
        .anyRequest()
        .permitAll();
  

  @Bean
  public KeycloakConfigResolver keycloakConfigResolver() 
    return new KeycloakSpringBootConfigResolver();
  

这是我的application.yaml 文件。

spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/postgres
    username: john
    password: john

keycloak:
  auth-server-url: http://localhost:8081/auth/
  realm: myrealm
  resource: myclient
  credentials:
    secret: 45d43bd6-5ab9-476c-83c8-67bd203a78ee

这一切都在我的本地机器上,Keycloak 和 Postgres 是通过 docker compose 启动的。


version: "3.1"

volumes:
  postgres_data:
      driver: local

services:
  db:
    image: "postgres:13.1"
    ports:
      - "5432:5432"
    environment:
      POSTGRES_DB: postgres
      POSTGRES_USER: john
      POSTGRES_PASSWORD: john
  postgres:
    image: "postgres:13.1"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: keycloak
      POSTGRES_USER: keycloak
      POSTGRES_PASSWORD: password
  keycloak:
    image: quay.io/keycloak/keycloak:12.0.1
    environment:
      DB_VENDOR: POSTGRES
      DB_ADDR: postgres
      DB_DATABASE: keycloak
      DB_USER: keycloak
      DB_SCHEMA: public
      DB_PASSWORD: password
      KEYCLOAK_USER: admin
      KEYCLOAK_PASSWORD: Pa55w0rd
    ports:
      - 8081:8080
    depends_on:
      - postgres

我在 Keycloak 中有用户 zemircoone,他们都有 user 角色。这一切都运行得很好,/persons 的路线受到保护,而/repositories 对所有人开放。

这是我的问题!我想保护个人资源,例如/person/1。我无法让它工作:(我已经尝试了好几天但没有运气。这是我的 keycloak 设置。

这是我的政策。

这里是资源。

这里是许可。

这一切都在 Keycloak 的评估期间有效。但是它不能直接在我的 Spring Boot 应用程序中工作。我仍然可以以zemirco 的身份访问/person/1,尽管用户one 应该只有访问权限。

我现在有点迷茫。你有什么想法吗?

非常感谢!


2021 年 1 月 10 日编辑

感谢大家的回答,但我仍然认为无需我(应用程序方面)付出很多额外的努力,这是可行的。我特别关注政策执行者https://www.keycloak.org/docs/latest/authorization_services/#_enforcer_overview。

PEP 负责执行来自 Keycloak 服务器的访问决策,这些决策是通过评估与受保护资源相关的策略来做出的。它在您的应用程序中充当过滤器或拦截器,以便根据这些决定授予的权限检查是否可以满足对受保护资源的特定请求。

这听起来和我想要做的完全一样。不幸的是我不能让它工作。我只是认为我的配置是错误的或者可能不完整。我会为这个问题添加一个赏金。

【问题讨论】:

【参考方案1】:

终于成功了 :) 我很高兴!

这就是我所做的。

首先,我使用了 Keycloak 客户端安装中的 keycloak.json 文件。一开始我尝试将所有配置放入我的application.yamlkeycloak.json 文件必须位于 src/main/webapp/WEB-INF/keycloak.json。当您使用 JSON 文件而不是 YAML 文件时,您可以从 SecurityConfig 中删除以下内容。

public KeycloakConfigResolver keycloakConfigResolver() 
  return new KeycloakSpringBootConfigResolver();

其实挺好看的。您只需将 Keycloak 中的内容复制并粘贴到文件中,就可以确保一切正常。我看到的另一个问题是keycloak.json 中的配置被称为policy-enforcerapplication.yaml 中的policy-enforcer-config 相比。这很烦人,因为我一开始并没有意识到这一点。这是配置。


  "realm": "myrealm",
  "auth-server-url": "http://localhost:8081/auth/",
  "ssl-required": "external",
  "resource": "myclient",
  "verify-token-audience": true,
  "credentials": 
    "secret": "45d43bd6-5ab9-476c-83c8-67bd203a78ee"
  ,
  "confidential-port": 0,
  "policy-enforcer": 

"policy-enforcer": 是最重要的部分。这里我们启用默认设置,并简单地说 Keycloak 应该授权对我们资源的所有请求。

然后一切似乎都奏效了。只有正确的用户才能访问受保护的资源。但是,在我注销并尝试再次访问该资源后,我仍然能够做到这一点。在这里,我了解到我的蚂蚁匹配器是错误的。这是正确的配置。

  @Override
  protected void configure(HttpSecurity http) throws Exception 
    super.configure(http);
    http.authorizeRequests()
        .antMatchers("/persons/**") // changed from .antMatchers("/persons*")
        .hasRole("user")
        .anyRequest()
        .permitAll()
        .and()
        // this is just to have a convenient GET /logout method. DO NOT USE IN PRODUCTION
        .logout()
        .logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
  

现在一切正常,我从 Keycloak 获得的资源/策略/权限会自动应用到我的 Spring Boot 应用程序中。

【讨论】:

我很高兴知道您能够找到仅基于 Keycloak 安全性的解决方案。尽管我仍然认为 Spring Security 本身提供了一种更简单的方法来控制细粒度的权限,但它看起来确实很有趣。我会仔细审查它。 +1【参考方案2】:

Keycloak 中的 AuthZ 是 PITA,恕我直言,不应使用它。有更好的解决方案(例如OPA)。只是遵循原则:“不做傻事!”

其次,不要混淆 AuthN 和 AuthZ。 仅仅因为在 Keycloak 中配置了一些 AuthZ 策略,这并不意味着它们被“自动和神奇地”使用。 如果您使用任何适配器(无论是 Spring Security 还是某些 KC 自己的适配器)进行身份验证,他们正在做“只是 OIDC”,而 OIDC 是关于 AuthN,而不是 AuthZ。

如果您想在应用程序中调整或使用您的 AuthZ 策略和规则,则必须将它们与身份验证分开查询。 Keycloak 为此提供了keycloak-authz-client,记录在此:https://www.keycloak.org/docs/latest/authorization_services/#_service_client_api

【讨论】:

【参考方案3】:

Keycloak 以在访问管理解决方案中拥有最糟糕的策略/访问工具而闻名,但是,您描述的问题似乎有点奇怪。

Keycloak 是一个访问管理工具,从策略的角度来看,它提供决策,但不会强制执行它们,因此由于策略评估按预期工作,您需要做的就是对评估进行 api 调用来自您的 spring 应用程序的 enpoints,如果它是 200,那么用户将访问,如果不是,则不显示页面。

另一种解决方案是使用预制的策略执行点,apache/nginx spring 都有自己的自定义策略执行点。

一些有用的链接:

how-to-use-keycloak-policy-enforcer-with-spring-boot-application

keycloak-enforcement-filter

【讨论】:

以上是关于通过 Keycloak 保护单个资源免受 Spring Boot 的影响的主要内容,如果未能解决你的问题,请参考以下文章

带有 keycloak 的 ABAC - 在策略中使用资源属性

如何保护企业免受网络钓鱼

签名以保护 JAR 免受逆向工程

保护Exchange OWA免受暴力***

如何使用从公共客户端发出的令牌查询 keycloak 资源权限

保护用户免受扩展程序加密劫持