Troubleshooting SSO Integration Issues in DataHub

Original Slack Thread

<@U06TM7M40RK> Caught exception while attempting to redirect to SSO identity provider! It’s likely that SSO integration is mis-configured , getting this when i click on Sign in with SSO in DataHub

The error message “Caught exception while attempting to redirect to SSO identity provider! It’s likely that SSO integration is mis-configured” typically indicates a misconfiguration in the Single Sign-On (SSO) setup. Here are some potential causes and solutions based on the provided data sources:

  1. Incorrect Client ID or Secret: Ensure that the client ID and client secret are correctly configured in your DataHub setup. These should match the values provided by your Identity Provider (IdP).

  2. Discovery URI Accessibility: Verify that the AUTH_OIDC_DISCOVERY_URI is accessible from the DataHub frontend container. This URI is crucial for the OpenID Connect (OIDC) flow to function correctly. You can test this by issuing a CURL command to the URI or visiting it in a browser to ensure it is reachable.

  3. User Profile Attributes: Check that the IdP is configured to include the necessary claims, such as the email claim, in the ID token. This claim is often used by DataHub to uniquely identify users. You can decode the ID token using a tool like https://jwt.io|jwt.io to inspect its contents.

  4. Configuration of Environment Variables: Ensure that the environment variables related to OIDC are correctly set. For example, the AUTH_OIDC_USER_NAME_CLAIM should be set to the attribute that uniquely identifies users, such as email or preferred_username.

  5. Network Configuration: If you are using a load balancer or proxy, ensure that it is correctly configured to handle HTTPS requests and that there are no issues with SSL termination.

  6. Logs for More Details: Check the logs of the datahub-frontend container for more detailed error messages that might provide additional context on the misconfiguration.

For more detailed troubleshooting steps, you can refer to the <https://github.com/datahub-project/datahub/blob/master/docs/authentication/guides/sso/configure-oidc-react.md|DataHub SSO configuration guide> and the <OIDC Authentication | DataHub section>.

Would you like more detailed steps or further assistance on any of these points?

Sources:

how to verify Verify that the AUTH_OIDC_DISCOVERY_URI is accessible from the DataHub frontend container. This URI is crucial for the OpenID Connect (OIDC) flow to function correctly. You can test this by issuing a CURL command to the URI or visiting it in a browser to ensure it is reachable.
<@U06TM7M40RK>

how to verify Verify that the AUTH_OIDC_DISCOVERY_URI is accessible from the DataHub frontend container. This URI is crucial for the OpenID Connect (OIDC) flow to function correctly. You can test this by issuing a CURL command to the URI or visiting it in a browser to ensure it is reachable.
<@U06TM7M40RK> (edited)

To verify that the AUTH_OIDC_DISCOVERY_URI is accessible from the DataHub frontend container, you can use the curl command from within the container. Here are the steps to do this:

  1. Access the datahub-frontend Pod: First, you need to get a shell into the datahub-frontend pod. You can do this using the kubectl exec command if you are running DataHub on Kubernetes.

  2. Run a curl Command: Once you have a shell in the pod, you can use curl to test the connectivity to the AUTH_OIDC_DISCOVERY_URI.

Step-by-Step Instructions

  1. Get the Name of the datahub-frontend Pod:

    kubectl get pods -n <namespace> -l app=datahub-frontend
    
  2. Access the datahub-frontend Pod:

    kubectl exec -it <datahub-frontend-pod-name> -n <namespace> -- /bin/sh
    
  3. Run the curl Command:

    curl -v https://<your-idp-domain>/.well-known/openid-configuration
    

Example

Assuming your datahub-frontend pod name is datahub-frontend-12345 and it is in the default namespace, and your AUTH_OIDC_DISCOVERY_URI is https://idp.example.com/.well-known/openid-configuration, the commands would be:

  1. Get the Name of the datahub-frontend Pod:

    kubectl get pods -n default -l app=datahub-frontend
    
  2. Access the datahub-frontend Pod:

    kubectl exec -it datahub-frontend-12345 -n default -- /bin/sh
    
  3. Run the curl Command:

    curl -v https://idp.example.com/.well-known/openid-configuration
    

Expected Output

If the connectivity is working, you should see a JSON response similar to the following:

{
  "issuer": "https://idp.example.com",
  "authorization_endpoint": "https://idp.example.com/auth",
  "token_endpoint": "https://idp.example.com/token",
  ...
}

If there is an issue with connectivity, you might see an error message indicating that the URL is not reachable.

Would you like more detailed guidance on any of these steps?

Sources:

<@U06TM7M40RK> / $ curl -v https://keycloak.o2.platform.hbkworld.com/auth/realms/datahub/.well-known/openid-configuration

  • Host http://keycloak.o2.platform.hbkworld.com:443|keycloak.o2.platform.hbkworld.com:443 was resolved.
  • IPv6: (none)
  • IPv4: 10.88.0.37
  • Trying 10.88.0.37:443…
  • ALPN: curl offers h2,http/1.1
  • TLSv1.3 (OUT), TLS handshake, Client hello (1):
  • CAfile: /etc/ssl/certs/ca-certificates.crt
  • CApath: /etc/ssl/certs
  • TLSv1.3 (IN), TLS handshake, Server hello (2):
  • TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
  • TLSv1.3 (IN), TLS handshake, Certificate (11):
  • TLSv1.3 (OUT), TLS alert, certificate expired (557):
  • closing connection #0
    curl: (60) SSL peer certificate or SSH remote key was not OK
    More details here: https://curl.se/docs/sslcerts.html

The error message you’re encountering, “SSL peer certificate or SSH remote key was not OK,” indicates that the SSL certificate for the URL you are trying to access has expired. This is a common issue when the server’s SSL certificate is not up-to-date or is not trusted by the client.

Here are some steps you can take to resolve this issue:

  1. Check Certificate Expiry: Verify the expiration date of the SSL certificate for the domain keycloak.o2.platform.hbkworld.com. You can do this by visiting the URL in a web browser and checking the certificate details.

  2. Update the Certificate: If the certificate is indeed expired, you will need to update it. This typically involves obtaining a new certificate from a Certificate Authority (CA) and installing it on the server.

  3. Trust the Certificate: If you are using a self-signed certificate or a certificate from a private CA, ensure that the CA certificate is added to the trusted CA store on the client machine. This can be done by updating the CA certificates on the system where the curl command is being run.

  4. Bypass SSL Verification (Not Recommended for Production): As a temporary workaround, you can bypass SSL verification by using the -k or --insecure option with curl. However, this is not recommended for production environments as it makes the connection insecure.

    curl -v -k https://keycloak.o2.platform.hbkworld.com/auth/realms/datahub/.well-known/openid-configuration
    
  5. Check System Time: Ensure that the system time on the client machine is correct. An incorrect system time can sometimes cause SSL verification issues.

Would you like more detailed guidance on any of these steps?

Sources:

The output from your curl command indicates that you were able to successfully connect to the OpenID Connect (OIDC) discovery endpoint, despite the SSL certificate verification issue. Here’s a breakdown of what happened and what you can do next:

  1. SSL Certificate Verification: The curl command was executed with the -k (or --insecure) option, which bypasses SSL certificate verification. This is why you were able to connect and receive a response even though there was an issue with the SSL certificate.

  2. Successful Connection: The HTTP response code 200 indicates that the request was successful, and you received the OIDC configuration in JSON format. This means that the AUTH_OIDC_DISCOVERY_URI is accessible from the environment where you ran the curl command.

  3. SSL Certificate Issue: The message “SSL certificate verify result: unable to get local issuer certificate (20)” suggests that the SSL certificate chain is incomplete or the certificate is not trusted by the client. This could be due to a missing intermediate certificate or a self-signed certificate.

Recommendations:

  • Update SSL Certificates: Ensure that the SSL certificate chain is complete and includes all necessary intermediate certificates. If you are using a self-signed certificate, consider adding the certificate to the trusted CA store on the client machine.

  • Avoid Using -k in Production: While the -k option is useful for testing, it is not recommended for production environments as it makes the connection insecure. Ensure that SSL certificates are properly configured and trusted to avoid using this option.

  • Check Certificate Validity: Verify that the SSL certificate is valid and not expired. You can do this by checking the certificate details in a web browser or using tools like openssl.

Would you like more detailed guidance on resolving the SSL certificate issue?

Sources:

<@U06TM7M40RK> 2025-01-03 09:17:01,196 [application-akka.actor.default-dispatcher-9] ERROR c.AuthenticationController - Caught exception while attempting to redirect to SSO identity provider! It’s likely that SSO integration is mis-configured
java.lang.NullPointerException: null
at java.base/java.util.Objects.requireNonNull(Objects.java:209)
at auth.sso.oidc.custom.CustomOidcAuthenticator.loadWithRetry(CustomOidcAuthenticator.java:220)
at auth.sso.oidc.custom.CustomOidcAuthenticator.<init>(CustomOidcAuthenticator.java:60)
at auth.sso.oidc.custom.CustomOidcClient.internalInit(CustomOidcClient.java:32)
at org.pac4j.core.util.InitializableObject.init(InitializableObject.java:61)
at org.pac4j.core.util.InitializableObject.init(InitializableObject.java:38)
at org.pac4j.core.client.IndirectClient.getRedirectionAction(IndirectClient.java:115)
at controllers.AuthenticationController.redirectToIdentityProvider(AuthenticationController.java:312)
at controllers.AuthenticationController.sso(AuthenticationController.java:147)
at router.Routes$$anonfun$routes$1.$anonfun$applyOrElse$14(Routes.scala:698)
at play.core.routing.HandlerInvokerFactory$$anon$8.resultCall(HandlerInvoker.scala:150)
at play.core.routing.HandlerInvokerFactory$$anon$8.resultCall(HandlerInvoker.scala:149)
at play.core.routing.HandlerInvokerFactory$JavaActionInvokerFactory$$anon$3$$anon$4$$anon$5.invocation(HandlerInvoker.scala:115)
at play.core.j.JavaAction$$anon$1.call(JavaAction.scala:119)
at play.http.DefaultActionCreator$1.call(DefaultActionCreator.java:31)
at play.core.j.JavaAction.$anonfun$apply$8(JavaAction.scala:175)
at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:687)
at scala.concurrent.impl.Promise$Transformation.run(Promise.scala:467)
at play.core.j.HttpExecutionContext.$anonfun$execute$1(HttpExecutionContext.scala:64)
at play.api.libs.streams.Execution$trampoline$.execute(Execution.scala:70)
at play.core.j.HttpExecutionContext.execute(HttpExecutionContext.scala:59)
at scala.concurrent.impl.Promise$Transformation.submitWithValue(Promise.scala:429)
at scala.concurrent.impl.Promise$DefaultPromise.submitWithValue(Promise.scala:338)
at scala.concurrent.impl.Promise$DefaultPromise.dispatchOrAddCallbacks(Promise.scala:312)
at scala.concurrent.impl.Promise$DefaultPromise.map(Promise.scala:182)
at scala.concurrent.Future$.apply(Future.scala:687)
at play.core.j.JavaAction.apply(JavaAction.scala:176)
at play.api.mvc.Action.$anonfun$apply$4(Action.scala:82)
at play.api.libs.streams.StrictAccumulator.$anonfun$mapFuture$4(Accumulator.scala:168)
at scala.util.Try$.apply(Try.scala:217)
at play.api.libs.streams.StrictAccumulator.$anonfun$mapFuture$3(Accumulator.scala:168)
at scala.Function1.$anonfun$andThen$1(Function1.scala:87)
at scala.Function1.$anonfun$andThen$1(Function1.scala:87)
at play.api.libs.streams.StrictAccumulator.run(Accumulator.scala:199)
at play.core.server.AkkaHttpServer.$anonfun$runAction$4(AkkaHttpServer.scala:428)
at akka.http.scaladsl.util.FastFuture$.strictTransform$1(FastFuture.scala:40)
at akka.http.scaladsl.util.FastFuture$.transformWith$extension(FastFuture.scala:54)
at akka.http.scaladsl.util.FastFuture$.flatMap$extension(FastFuture.scala:25)
at play.core.server.AkkaHttpServer.runAction(AkkaHttpServer.scala:426)
at play.core.server.AkkaHttpServer.executeHandler(AkkaHttpServer.scala:368)
at play.core.server.AkkaHttpServer.handleRequest(AkkaHttpServer.scala:331)
at play.core.server.AkkaHttpServer.$anonfun$createServerBinding$1(AkkaHttpServer.scala:227)
at akka.stream.impl.fusing.MapAsyncUnordered$$anon$31.onPush(Ops.scala:1430)
at akka.stream.impl.fusing.GraphInterpreter.processPush(GraphInterpreter.scala:542)
at akka.stream.impl.fusing.GraphInterpreter.processEvent(GraphInterpreter.scala:496)
at akka.stream.impl.fusing.GraphInterpreter.execute(GraphInterpreter.scala:390)
at akka.stream.impl.fusing.GraphInterpreterShell.runBatch(ActorGraphInterpreter.scala:650)
at akka.stream.impl.fusing.GraphInterpreterShell$AsyncInput.execute(ActorGraphInterpreter.scala:521)
at akka.stream.impl.fusing.GraphInterpreterShell.processEvent(ActorGraphInterpreter.scala:625)
at akka.stream.impl.fusing.ActorGraphInterpreter.akka$stream$impl$fusing$ActorGraphInterpreter$$processEvent(ActorGraphInterpreter.scala:800)
at akka.stream.impl.fusing.ActorGraphInterpreter$$anonfun$receive$1.applyOrElse(ActorGraphInterpreter.scala:818)
at akka.actor.Actor.aroundReceive(Actor.scala:537)
at akka.actor.Actor.aroundReceive$(Actor.scala:535)
at akka.stream.impl.fusing.ActorGraphInterpreter.aroundReceive(ActorGraphInterpreter.scala:716)
at akka.actor.ActorCell.receiveMessage(ActorCell.scala:579)
at akka.actor.ActorCell.invoke(ActorCell.scala:547)
at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:270)
at akka.dispatch.Mailbox.run(Mailbox.scala:231)
at akka.dispatch.Mailbox.exec(Mailbox.scala:243)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)