Truststore for LDAPS breaks Identity Providers

Hi,
I am having trouble getting both LDAPS for user federation and external Identity Providers working. I am running the following:

KeyCloak - Running in Docker using jboss/keycloak image
Directory - Windows Server 2019 Active Directory (LDAPS enabled with internal CA signed cert)
Identity Providers - Google & Microsoft

I had both Identity Providers working and Flows configured as desired (First, Keycloak attempts to matching federated user by ‘mail’ attribute; if not found, then the user is presented with a login form to bind the identity)

I initially started using simple LDAP for User Federation but needed to be able to reset credentials via Keycloak, so I needed LDAPS. After a lot of headache, I finally got that working. I found several methods using ENV to point to the truststore but I could not get that working. Ultimately, I got LDAPS working the following way:

  1. Copy current standalone-ha.xml from container to host under ./data/standalone-ha.xml
  2. Add the following to standalone-ha.xml
            <spi name="truststore">
                <provider name="file" enabled="true">
                    <properties>
                        <property name="file" value="/opt/jboss/keycloak/standalone/configuration/keystores/truststore.jks"/>
                        <property name="password" value="somepassword"/>
                        <property name="hostname-verification-policy" value="WILDCARD"/>
                        <property name="disabled" value="false"/>
                    </properties>
                </provider>
            </spi>
  1. Mount the following volumes in docker-compose.yml
    volumes:
      - ./data/certs:/opt/jboss/keycloak/standalone/configuration/keystores
      - ./data/standalone-ha.xml:/opt/jboss/keycloak/standalone/configuration/standalone-ha.xml
  1. Restart the container
  2. Copy both the AD Server and CA certs (base64 format) into ./data/certs
  3. Inside the container, import both certs into the truststore.jks using the following:
keytool -import -alias domain.com -file ca.domain.cer -keystore truststore.jks
keytool -import -alias ds.domain.com -file ds.domain.cer -keystore truststore.jks
  1. Restart the container

After completing those steps, LDAPS is not working and users can manage credentials via Keycloak, however now Identity Providers are broken. When I try to login using Google as the Identity provider, I am properly redirected to the Google login screen, but once I successfully authenticate with Google, I am taken back to Keycloak with an error saying “Unexpected error when authenticating with identity provider”

In the logs, I see a similar error to what I was previously seeing when LDAPS was not working:

ERROR [org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider] (default task-3) Failed to make identity provider oauth callback: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

If I remove the mount for standalone-ha.xml (thus removing the keystore spi entries), identity providers work again, but fails at LDAPS with a similar complaint about the certificate.

My assumption is that without providing a truststore, keycloak is trusting certs signed by well-known CAs (as provided by the Google and Microsoft identity providers) but once I provide the truststore (in order to trust my internal PKI certs as provided by LDAPS) that serves as the ONLY certificates keycloak trusts. I must be doing something wrong here but cannot figure out what.

EDIT: As an additional note; I do hot have HTTPS enabled on keycloak. I am using Traefik to reverse proxy and handle HTTPS and TLS certs

Looks like I might have somewhat confirmed my assumption. As a test I used a letsencrypt signed certificate for my AD Server and backed out my truststore. Now both federation over LDAPS and Identity Providers work.

I would still like to use my internal PKI cert for LDAPS though. Is there anyway I can add a custom truststore for my PKI certs AND trust well-known certs?

This is not Keycloak related, but about how Java handles the certificates with a truststore.

If you don’t provide a custom truststore, Java uses the default, “built-in” truststore with all the trusted public CAs.

If you provide a custom truststore with only your custom certs, Java will use this truststore - with only your custom certs/CAs.

If you want to have both, you have to create your own custom truststore and import the default truststore into your custom truststore. Now your custom truststore contains all the desired certs/CAs.

1 Like

Awesome, thank you for that :slight_smile:

Looks like I was at least headed in the right direction. I did not know you could import an existing truststore into a custom truststore. I was afraid I’d have to gather well-knowns and import each.

Also in poking around a bit more I found I could actually just import my CA into the default truststore using

keytool -import -cacerts -alias ca.domain.com -file ca.domain.cer

Are there any implications in doing that that I’m not considering?

Well, it’s the default truststore, I personally, I don’t like to modify defaults which are being shipped with the JDK. IMHO it’s the better approach to built up a custom store and import everything you need there and then use this one. This way, you won’t destroy the default store, in any case.

1 Like

The keytool has everything you need, really, but I suppose a better approach if you’re not familiar with truststore formats and whatnot is to use KeyStore Explorer (https://keystore-explorer.org/).

It supports a lot of formats and you can just make a copy of the JDK default cacerts file, import your files into it and save it as PCKS 12 file with a password.