Search code examples
dockerspring-securitydocker-composeoauth-2.0keycloak

Spring Security 5 OAuth2 App with Keycloack 17 gets "Connection Refused" when run in Docker container with docker-compose


I have a super simple Spring Boot app with Spring Security 5 that authenticates over OAuth2 with a Keycloak 17 instance running in Docker.

Everything works fine when I start the app locally from Intellij.

But when I run the app from a Docker container with docker-compose I get:

[invalid_token_response] An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: I/O error on POST request for "http://localhost:80/realms/Demo/protocol/openid-connect/token": Connection refused (Connection refused); nested exception is java.net.ConnectException: Connection refused (Connection refused)

when I input the credentials on the keycloak login page. But there is a session created for that user in keycloak.

System:

  • MacBook with Monteray 12.0.1
  • Docker Desktop 4.5 with Kubernetes 1.22.5

docker-compose.yml

version: '3.9'

networks:
  network_keycloak_postgres_app:
    driver: bridge
    driver_opts:
      com.docker.network.enable_ipv6: "false"

volumes:
  keycloak_postgres_data:
    driver: local

services:
  postgres:
    container_name: postgres
    image: postgres
    volumes:
      - keycloak_postgres_data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: keycloak
      POSTGRES_USER: keycloak_db_admin
      POSTGRES_PASSWORD: keycloak_db_password
    ports:
      - "5432:5432"
    networks:
      - network_keycloak_postgres_app

  keycloak:
    container_name: keycloak
    hostname: keycloak
    image: quay.io/keycloak/keycloak:17.0.0
    command: ["start-dev", "--log-level=debug"]
    environment:
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: change_me
      KC_DB: postgres
      KC_DB_USERNAME: keycloak_db_admin
      KC_CACHE: local
      KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
      KC_DB_PASSWORD: keycloak_db_password
    ports:
      - "80:8080"
      - "443:8443"
    depends_on:
      - postgres
    networks:
      - network_keycloak_postgres_app

  demo_app:
    container_name: demo_app
    hostname: demoapp
    build:
      context: ../
      dockerfile: Dockerfile
    environment:
      SPRING_PROFILES_ACTIVE: default
    ports:
      - "4242:4242"
    depends_on:
      - keycloak
    networks:
      - network_keycloak_postgres_app

Dockerfile (made sure to run 'mvn clean package' before build)

FROM openjdk:11.0.11-jre-slim
COPY ./target/demo-0.0.1-SNAPSHOT.jar /usr/local/lib/demo.jar
EXPOSE 4242
ENTRYPOINT ["java","-jar","/usr/local/lib/demo.jar"]

application.yml

server:
  port: 4242

logging:
  level:
    root: DEBUG
    org.springframework.web: DEBUG
    org.springframework.security: DEBUG
    # org.springframework.boot.autoconfigure: DEBUG

spring:
  thymeleaf:
    cache: false
  security:
    oauth2:
      client:
        registration:
          keycloak:
            client-id: demo-app
            client-secret: 5cuxTUgiLJATP4pMpw7j8HZieekdOBsM
            client-name: Keycloak
            authorization-grant-type: authorization_code
            redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}'
            scope:
              - openid
              - profile
              - email
        provider:
          keycloak:
            authorization-uri: http://localhost:80/realms/Demo/protocol/openid-connect/auth
            token-uri: http://localhost:80/realms/Demo/protocol/openid-connect/token
            user-info-uri: http://localhost:80/realms/Demo/protocol/openid-connect/userinfo
            jwk-set-uri: http://localhost:80/realms/Demo/protocol/openid-connect/certs
            user-name-attribute: preferred_username

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>de.kressing</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>demo</name>
    <description>Spring Security 5 OAuth2 Client and Keycloak sample</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.3</version>
        <relativePath/>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webflux</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-jose</artifactId>
        </dependency>


        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        </dependency>

        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>net.sourceforge.htmlunit</groupId>
            <artifactId>htmlunit</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

What I have already tried:

  • giving the app and keycloak container hostnames
  • running the app container in another docker-compose
  • using "http://${DOCKER_GATEWAY_HOST:-host.docker.internal}:8080" instead of localhost
  • using other openjdk image to build from

Thanks in advance for any hints and help!


Solution

  • It's working now. I added a reverse-proxy and changed the ports of the provider urls to the internal docker port.