Spring

Keycloak을 통해 Spring Boot에서 개별 리소스 보호

기록만이살길 2021. 3. 24. 09:05
반응형

Keycloak을 통해 Spring Boot에서 개별 리소스 보호

1. 질문(문제점):

/repositories및에 리소스가있는 매우 간단한 Spring Boot 애플리케이션이 있습니다 /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

사용자 zemircooneKeycloak이 있으며 둘 다 user역할이 있습니다. 그것은 모두 매우 잘 작동하며 경로 /persons는 보호되지만 /repositories모두에게 열려 있습니다.

여기 내 문제가 있습니다! 개별 리소스를 보호하고 싶습니다 /person/1. 나는 그것을 작동시킬 수 없습니다 :( 나는 지금 며칠 동안 노력했지만 운이 없습니다. 여기 내 열쇠 망토 설정이 있습니다.

여기 내 정책이 있습니다.

수단

여기에 리소스가 있습니다.

자원

여기에 허가가 있습니다.

허가

Keycloak에서 평가하는 동안 모두 작동합니다. 그러나 Spring Boot 애플리케이션에서 직접 작동하지 않습니다. 난 여전히 액세스 할 수 있습니다 /person/1zemirco사용자가 있지만 one에만 액세스 할 수 있어야합니다.

나는 지금 조금 길을 잃었다. 아이디어가 있습니까?

대단히 감사합니다!


2021 년 1 월 10 일 수정

답변 해주셔서 감사합니다.하지만 제 쪽 (응용 프로그램 쪽)에서 많은 추가 노력 없이도 가능하다고 생각합니다. 특히 정책 집행자 https://www.keycloak.org/docs/latest/authorization_services/#_enforcer_overview를 찾고 있습니다 .

PEP는 보호 된 리소스와 관련된 정책을 평가하여 이러한 결정을 내리는 Keycloak 서버에서 액세스 결정을 시행 할 책임이 있습니다. 이러한 결정에 의해 부여 된 권한을 기반으로 보호 된 리소스에 대한 특정 요청을 수행 할 수 있는지 여부를 확인하기 위해 애플리케이션에서 필터 또는 인터셉터 역할을합니다.

이것은 내가하려는 것과 똑같이 들립니다. 불행히도 나는 그것을 작동시킬 수 없습니다. 내 구성이 잘못되었거나 불완전하다고 생각합니다. 질문에 현상금을 추가하겠습니다.

2. 해결방안:

드디어 작동합니다 :) 행복합니다!

내가 한 일은 다음과 같습니다.

우선 keycloak.jsonKeycloak 클라이언트 설치 파일을 사용했습니다 . 처음에는 모든 구성을 내 application.yaml. keycloak.json파일에 위치해야합니다 src/main/webapp/WEB-INF/keycloak.json. YAML 파일 대신 JSON 파일을 사용하는 경우 SecurityConfig.

public KeycloakConfigResolver keycloakConfigResolver() {
  return new KeycloakSpringBootConfigResolver();
}

It's actually quite nice. You can simply copy&paste the content from Keycloak into the file and you can be sure that everything is right. Another problem I saw is that the config in keycloak.json is called policy-enforcer compared to policy-enforcer-config in application.yaml. That's quite annoying because I didn't realize it at the beginning. Here is 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": {}
}

The "policy-enforcer": {} is the most important part. Here we enable the default settings and simply say that Keycloak should authorize all requests to our resources.

Then everything seemed to work. I was able to gain access to a protected resource only with the right user. However after I logged out and tried to access the resource again I was still able to do it. Here I learned that my ant matchers were wrong. This is the right configuration.

  @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"));
  }

Now everything works and my resources/policies/permissions from Keycloak are automatically applied in my Spring Boot application.

65628832
반응형