Проблема с Spring Boot с Keycloak в Docker Compose - PullRequest
1 голос
/ 18 июня 2020

Мне не удается заставить Keycloak работать в docker Compose. У меня есть базовый c Spring Boot REST API, который использует новый стек OAuth от Spring Security для работы в качестве сервера ресурсов. Я настроил сервер аутентификации Keycloak для импорта области при первом запуске. Я пытаюсь использовать поток учетных данных клиента. Он отлично работает, когда API запускается локально, но когда я запускаю его в docker -compose, он терпит неудачу с 401 Unauthorized еще до того, как достигнет конечной точки. Из того, что я читал, это потенциально ошибка cors, поскольку предварительный запрос запускает 401, но ни одна из конфигураций, с которыми я играл, не сработала. Когда я пытаюсь получить доступ с помощью curl, ответ указывает, что это недопустимый токен. Я тоже рассмотрел некоторые распространенные проблемы, такие как смещение часового пояса и многое другое, но также, похоже, не является виновником. Я обновил свой файл etc/hosts, поэтому я могу изменить утверждение iss на keycloak:8081, но это тоже не помогает. Для ясности, я могу войти в систему без проблем, и если я выключу .authorizeRequests().anyRequest().authenticated().and().oauth2ResourceServer().jwt(), он также будет работать.

version: "3.8"

services:
  mariadb:
    image: mariadb:10.5.3
    environment:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_DATABASE: keycloak
      MYSQL_USER: some_user
      MYSQL_PASSWORD: password
    container_name: mariadb-10.5.3
    networks:
      - app
    volumes:
      - "auth:/var/lib/mysql"

  auth:
    build:
      context: ./auth/
      args:
        - JAVA_VERSION=14
    image: auth:1.0.0.1
    container_name: auth-1.0.0.1
    ports:
      - "8081:8081"
    environment:
      KEYCLOAK_DB_PROTOCOL: mysql
      KEYCLOAK_DB_HOST: mariadb
      KEYCLOAK_DB_PORT: 3306
      KEYCLOAK_DB_NAME: keycloak
      KEYCLOAK_DB_USERNAME: some_user
      KEYCLOAK_DB_PASSWORD: password
      KEYCLOAK_DB_DRIVER: org.mariadb.jdbc.Driver
      KEYCLOAK_CONTEXT_PATH: /auth
    depends_on:
      - mariadb
    entrypoint:
      ["./wait-for-it.sh", "mariadb:3306", "--", "java", "-jar", "/app.jar"]
    networks:
      - app

  api:
    build:
      context: ./api/
      args:
        - JAVA_VERSION=14
    image: api:1.0.0.1
    container_name: api-1.0.0.1
    ports:
      - "8080:8080"
    environment:
      KEYCLOAK_HOST: keycloak
      KEYCLOAK_PORT: 8081
      KEYCLOAK_CONTEXT_PATH: /auth
      KEYCLOAK_REALM: api
      ELASTICSEARCH_HOST: elasticsearch
      ELASTICSEARCH_PORT: 9200
    depends_on:
      - elasticsearch
      - auth
    entrypoint:
      [
        "./wait-for-it.sh",
        "elasticsearch:9200",
        "--",
        "java",
        "-jar",
        "/app.jar",
      ]
    networks:
      - app

  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch-oss:7.7.1
    container_name: elasticsearch-7.7.1
    environment:
      discovery.type: single-node
    ports:
      - "9200:9200"
      - "9300:9300"
    networks:
      - app
      - elk

  kibana:
    image: docker.elastic.co/kibana/kibana-oss:7.7.1
    container_name: kibana-7.7.1
    depends_on:
      - elasticsearch
    ports:
      - "5601:5601"
    networks:
      - elk

  logstash:
    build:
      context: ./elk/logstash/
    image: logstash:7.7.1
    container_name: logstash-7.7.1
    depends_on:
      - elasticsearch
    environment:
      PIPELINE_WORKERS: 1
    networks:
      - elk

networks:
  elk:
    name: elk
  app:
    name: app

volumes:
  auth:
    name: auth
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)  // enables PreAuthorize annotation
public class SecurityConfig extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.cors().and()
          .authorizeRequests()
            .anyRequest()
              .authenticated()
        .and()
          .oauth2ResourceServer()
            .jwt();
  }
}

api - application.properties

spring.security.oauth2.resourceserver.jwt.issuer-uri=http://\${KEYCLOAK_HOST:localhost}:\${KEYCLOAK_PORT}/\${KEYCLOAK_CONTEXT_PATH:auth}/realms/\${KEYCLOAK_REALM}
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://\${KEYCLOAK_HOST:localhost}:\${KEYCLOAK_PORT}/\${KEYCLOAK_CONTEXT_PATH:auth}/realms/\${KEYCLOAK_REALM}/protocol/openid-connect/certs

keycloak - application.yaml

keycloak:
  cors: true
  server:
    contextPath: ${KEYCLOAK_CONTEXT_PATH:/auth}
    adminUser:
      username: admin
      password: admin
    realmImportFile:
      - api-realm.json

controller

@RestController
@RequestMapping("/")
public class Controller {
  @Autowired
  IDocumentRepository documentRepository;

  @GetMapping("/{id}")
  @PreAuthorize("@authorizationService.checkClientIDMatchesID(#token, #id)")
  public Iterable<Documents> getAll(@AuthenticationPrincipal Jwt token, @PathVariable("id") String id) {
    return documentRepository.findById(id);
  }
}

пользовательский метод авторизации

@Service
public class AuthorizationService {
  private static final Logger logger = LoggerFactory.getLogger(AuthorizationService.class);

  public boolean checkClientIDMatchesID(Jwt token, String id)
  {
    if (id == null || token == null || token.getClaimAsBoolean("clientId") == null) return false;
    return ((String)token.getClaim("clientId")).equalsIgnoreCase(id);
  }
}

Вот логи для API: enter image description here

And for Keycloak: enter image description here

curl response: введите описание изображения здесь

Я поигрался с его декодированием на jwt.io, и он говорит, что подпись не проверена, ключ publi c не делает ее действительной.

...