i have a Problem Running Spring Boot and Keycloak both in docker containers.
I started with Keycloak with mysql as db running in docker.
services: mysql: image: mysql:5.7 container_name: mysql volumes: - mysql_data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: keycloak MYSQL_USER: keycloak MYSQL_PASSWORD: password networks: - testNetwork keycloak: image: jboss/keycloak container_name: keycloak restart: on-failure volumes: - ./config:/config/ environment: DB_VENDOR: MYSQL DB_ADDR: mysql DB_DATABASE: keycloak DB_USER: keycloak DB_PASSWORD: password KEYCLOAK_USER: xxx KEYCLOAK_PASSWORD: yyy KEYCLOAK_IMPORT_REALM: /keycloak/import/realm-import.json ports: - 8180:8080 depends_on: - mysql networks: - testNetwork
Then i added my realm (SpringBootKeycloak), my client (testclient), and a user with role ‘user’. After that i added spring-security to my Spring-boot-application. And edited my application.yml
spring: main: banner-mode: 'off' application: name: testclient version: @project.version@ jpa: hibernate: ddl-auto: create datasource: url: jdbc:h2:mem:testclient;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE username: xxx password: xxx keycloak: auth-server-url: http://localhost:8180/auth realm: SpringBootKeycloak resource: testclient public-client: true principal-attribute: preferred_username security-constraints: - authRoles: - user securityCollections: - patterns: - /* server: port: ${port:8090} rest: path: testclient
accoring to that i added my SecurityConfig:
/** * Secure appropriate endpoints */ @Override protected void configure(HttpSecurity http) throws Exception { super.configure(http); http.authorizeRequests() .antMatchers("/*").hasRole("user") // only user with role user are allowed to access .anyRequest().permitAll(); }
Running my SpringBoot-Application locally is working fine. I have to login with keycloak and get redirected to localhost:8090. But when i add my SpringBoot-Application to my docker-compose and start it in a container i get still to keycloak for login, but when i should redirect i get a 403.
testclient: image: testclient container_name: testclient environment: JAVA_OPTS: "-agentlib:jdwp=transport=dt_socket,address=5005,server=y,suspend=n" build: context: testclient-application ports: - 8090:8090 - 5006:5005 networks: - testNetwork
with following container log:
{"@timestamp":"2018-08-16T11:50:11.530+00:00","@version":"1","message":"failed to turn code into token","logger_name":"org.keycloak.adapters.OAuthRequestAuthenticator","thread_name":"http-nio-8090-exec-6","level":"ERROR","level_value":40000,"stack_trace":"java.net.ConnectException: Connection refused (Connection refused)ntat java.net.PlainSocketImpl.socketConnect(Native Method)ntat java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)ntat java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)ntat java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)ntat java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)ntat java.net.Socket.connect(Socket.java:589)ntat org.apache.http.conn.scheme.PlainSocketFactory.connectSocket(PlainSocketFactory.java:121)ntat org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)ntat org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:144)ntat org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:134)ntat org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:610)ntat org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:445)ntat org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:835)ntat org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)ntat org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)ntat org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56)ntat org.keycloak.adapters.ServerRequest.invokeAccessCodeToToken(ServerRequest.java:111)ntat org.keycloak.adapters.OAuthRequestAuthenticator.resolveCode(OAuthRequestAuthenticator.java:336)ntat org.keycloak.adapters.OAuthRequestAuthenticator.authenticate(OAuthRequestAuthenticator.java:281)ntat org.keycloak.adapters.RequestAuthenticator.authenticate(RequestAuthenticator.java:139)ntat org.keycloak.adapters.tomcat.AbstractKeycloakAuthenticatorValve.authenticateInternal(AbstractKeycloakAuthenticatorValve.java:203)ntat org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve.authenticate(KeycloakAuthenticatorValve.java:50)ntat org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve.doAuthenticate(KeycloakAuthenticatorValve.java:57)ntat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:575)ntat org.keycloak.adapters.tomcat.AbstractKeycloakAuthenticatorValve.invoke(AbstractKeycloakAuthenticatorValve.java:181)ntat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)ntat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)ntat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)ntat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)ntat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800)ntat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)ntat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:800)ntat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1471)ntat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)ntat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)ntat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)ntat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)ntat java.lang.Thread.run(Thread.java:748)n","app":"testclient","version":"1.0.0-SNAPSHOT"}
I can’t figure out how to solve this…
EDIT 1: One more information: I’m running docker on Windows.
EDIT 2: A SOLUTION
My Working solution contains following:
- Step, add keycloak as hosts
To make things work, you’ll need to make sure to add the following to your hosts file (/etc/hosts on Mac/Linux, c:WindowsSystem32Driversetchosts on Windows).
127.0.0.1 keycloak
This is because you will access your application with a browser on your machine (which name is localhost, or 127.0.0.1), but inside Docker it will run in its own container, which name is keycloak.
- Step
Inner Docker port and published port needs to be same:
services: mysql: image: mysql:5.7 container_name: mysql volumes: - mysql_data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: keycloak MYSQL_USER: keycloak MYSQL_PASSWORD: password networks: - testNetwork keycloak: image: jboss/keycloak container_name: keycloak restart: on-failure volumes: - ./config:/config/ environment: DB_VENDOR: MYSQL DB_ADDR: mysql DB_DATABASE: keycloak DB_USER: keycloak DB_PASSWORD: password KEYCLOAK_USER: xxx KEYCLOAK_PASSWORD: yyy KEYCLOAK_IMPORT_REALM: /keycloak/import/realm-import.json ports: - 8080:8080 <--- edited depends_on: - mysql networks: - testNetwork
Step 3: keycloak definition in application.yml for Spring boot edited auth-server-url:
keycloak: realm: SpringBootKeycloak auth-server-url: http://keycloak:8080/auth <--- edited resource: testclient public-client: true security-constraints: - authRoles: - user securityCollections: - patterns: - /* ssl-required: external confidential-port: 0
The ugly thing coming with this solution: You cant map your Docker Port onto another port to access from url. ports: – 8080:8080 i spend a lot of time testing other combinations, with the result that the access url port has to be the same as inner docker port (8080 in my case).
EDIT 4:
Same thing is working with Thorntail.
To change the port for Keycloak add…
environment: JAVA_OPTS: "-Djboss.socket.binding.port-offset=10 -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true"
… for keycloak in docker-compose. -Djboss.socket.binding.port-offset=10 sets default port (8080) + offset (10) The rest are default values for keycloak. Don’t forget to edit “ports” and “auth-server-url”
Advertisement
Answer
I think your problem is auth-server-url: http://localhost:8180/auth
. That localhost
effectively has a different meaning when your app is running inside a docker container.
Inside the container it needs to be the name of the container i.e. keycloak
. This is a bit awkward as when you connect to keycloak from your host machine you’d want to use localhost
but the token issuer url needs to match to the url on which the token was requested (otherwise the token is rejected) so you end up having to put keycloak
into your etc/hosts file.
You are in good company with this problem – I’ve encountered this working with Activiti. And you can find the JHipster project dealing with it in the same way – they say:
To make things work, you’ll need to make sure to add the following to your hosts file (
/etc/hosts
on Mac/Linux,c:WindowsSystem32Driversetchosts
on Windows).
127.0.0.1 keycloak
This is because you will access your application with a browser on your machine (which name is
localhost
, or127.0.0.1
), but inside Docker it will run in its own container, which name iskeycloak
.