keycloak

Error PKIX path building failed When Connecting to Keycloak with a Self Signed Certificate

For this scenario im using Keycloak version 17, which are being installed by using below command.

docker pull quay.io/keycloak/keycloak:17.0.0

And being run by using below command,

docker run -p 8443:8443 -e KC_HOSTNAME=localhost:8443 \ 
	-e KC_HOSTNAME_URL=https://localhost:8443 -e KC_DB=mysql \ 
	-e KC_DB_USERNAME=keycloak -e KC_DB_PASSWORD=password \ 
	-e KC_DB_URL=jdbc:mysql://192.168.56.1:3306/keycloak_db \
	quay.io/keycloak/keycloak:17.0.0 start

As for the Spring Boot sourcecode, we are utilizing the same code that are being used in below article,

https://github.com/edwin/spring-boot-and-rhsso

So lets start by setting up our application.properties to pointing to Keycloak’s HTTPS port

keycloak.auth-server-url=https://localhost:8443/
keycloak.realm=external
keycloak.resource=client
keycloak.public-client=false
keycloak.bearer-only=false
keycloak.principal-attribute=preferred_username
keycloak.credentials.secret=xxxxxx

But when HTTPS is created by using a self signed certificate, it will display below error from the Java application console.

o.k.adapters.KeycloakDeployment - Failed to load URLs from https://localhost:8443/realms/external/.well-known/openid-configuration
javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
	at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:349)
	at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:292)
	at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:287)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:439)
	at java.base/sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:306)
	at java.base/sun.security.validator.Validator.validate(Validator.java:264)
	at java.base/sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:313)
	at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:222)
	at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:129)
	at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1340)
	... 86 common frames omitted
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at java.base/sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
	at java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
	at java.base/java.security.cert.CertPathBuilder.build(CertPathBuilder.java:297)
	at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:434)
	... 92 common frames omitted

Thats why we need to include Keycloak’s custom SSL certificate into our Spring Boot application so that Spring Boot able to recognize a self sign certificate.

We can start by using OpenSSL to capture Keycloak’s SSL Certificate

echo "" | openssl s_client -connect localhost:8443  -showcerts 2>/dev/null | openssl x509 -out certfile.cert

It will generate a certificate which is belongs to Keycloak, next step is to create a truststore to contain the corresponding certificate. Below command will create a keystore with the name of “customcacerts” and its password which is “changeit”

keytool -import -alias ca -file certfile.cert \
         -keystore customcacerts  -storepass changeit

And we can run our Spring Boot application with below command, using the created truststore and its password as parameter.

java -Djavax.net.ssl.trustStore=customcacerts \
         -Djavax.net.ssl.trustStorePassword=changeit -jar spring-boot.jar

How to Generate User Statistics Queries using Keycloak

Sometimes we want to see how many users has registered to our Keycloak, how many login per-hours, how many failed logins, and other statistical data for multiple purposes.

We can a use sample queries below for generating those reports. But first we need to enable events for that corresponding realm,

Once we turn Keycloak events on, we can run below queries to populate the required results

## get total number of successful login
select count(1) from EVENT_ENTITY where TYPE='LOGIN';

## get total number of failed login
select count(1) from EVENT_ENTITY where TYPE='LOGIN_ERROR';

## get user's all activity
select USER_ENTITY.USERNAME, EVENT_ENTITY.* 
from USER_ENTITY, EVENT_ENTITY where EVENT_ENTITY.USER_ID = USER_ENTITY.ID
order by USER_ENTITY.USERNAME, EVENT_TIME;

Pretty simple right 🙂

Keycloak redirect_uri is Not HTTPS when Spring Boot is Behind Reverse Proxy

Recently i have a regular Keycloak deployment with the high level concept like below image,

But during implementation, i had this weird condition when Keycloak, behind a reverse proxy for SSL offloader, is redirecting to my Spring Boot application. But Keycloak is not detecting my Spring Boot application as https.

https://keycloak/auth/realms/realm/protocol/openid-connect/auth?
response_type=code&client_id=client-id&redirect_uri=http%3A%2F%2Fspring-boot-app%2Fsso&state=123&
login=true&scope=openid

As we can see, redirect_uri is having http as its protocol, instead of https. Despite my Spring Boot application is being deployed behind a reverse proxy with an SSL offloader.

The workaround is actually quite simple, first thing is that we need to forward request from users into downstream apps, which is Keycloak and Spring Boot. This is primarily being done on reverse proxy or Load Balancer such as F5 or Nginx

X-Forwarded-For: 10.20.81.131
X-Forwarded-Proto: https
X-Forwarded-Host: my.apps.com

But sometimes even after above headers being forwarded, Spring Boot still unaware that it is being accessed as HTTPS. Therefore we need to add one more configuration line in our Spring Boot’s application.properties configuration.

server.forward-headers-strategy=NATIVE

This should be sufficient enough.

Error user_session_not_found when Using Keycloak’s UserInfo API

Had this error on Keycloak console,

09:49:35,417 WARN  [org.keycloak.events] (default task-145) type=USER_INFO_REQUEST_ERROR, 
realmId=internal, clientId=my-client-id, userId=null, ipAddress=10.20.24.35, 
error=user_session_not_found, auth_method=validate_access_token

Basically it happens when a specific user hitting a UserInfo API request bringing their active JWT token. JWT token is generated after a user successfully login to Keycloak, either via Login page or Rest API, and to be used in their internal application.

Also the error seems happening, generated JWT token seems to be invalid after 30minutes despite we update access token lifespan into 1 hour.

Finally i realized that this error keeps happening because i was updating the wrong configuration. It is supposed to be the “SSO Session Idle” configuration, in the “Tokens” tab in “Realm Settings” that need to be updated.

After change it into 1 Hour, i can see that my JWT token is successfully validated using UserInfo API for at most 1 hour after being created.