3

I have to deploy a Java application which uses Spring Boot and Spring Security. This application acts as a resource server to issue JWT.

Here is an extract of the local configuration application.yaml:

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: http://localhost:8090/auth/realms/myrealm

It is working fine when the authorization server (keycloak) is running on localhost. However, when keycloak is deployed on a DNS name with a self-signed certificate, the application fails to start with the following error:

2022-01-28 09:17:40.438  INFO 1 --- [           main] i.k.k.front.MyApplication                : Starting MyApplication using Java 11.0.12 on myapp-c8c7c5554-czpsd with PID 1 (/myapp/sbapp.jar started by spring in /myapp)                                                                                                                                                                                                                                                     
2022-01-28 09:17:40.495  INFO 1 --- [           main] i.k.k.front.MyApplication                : No active profile set, falling back to default profiles: default
2022-01-28 09:18:11.465  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8000 (http)
2022-01-28 09:18:11.664  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2022-01-28 09:18:11.670  INFO 1 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.53]
2022-01-28 09:18:12.968  INFO 1 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2022-01-28 09:18:12.972  INFO 1 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 31543 ms     
2022-01-28 09:18:53.802  WARN 1 --- [           main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bea
n with name 'jwtDecoderByIssuerUri' defined in class path resource [org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwtConfiguration$JwtDecoderConfiguration.class]: Bean instantiation via factory method failed;
 nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.security.oauth2.jwt.JwtDecoder]: Factory method 'jwtDecoderByIssuerUri' threw exception; nested exception is java.lang.IllegalArgumentEx
ception: Unable to resolve the Configuration with the provided Issuer of "https://myhost/auth/realms/myrealm"
2022-01-28 09:18:53.897  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Stopping service [Tomcat]
2022-01-28 09:18:54.189  INFO 1 --- [           main] ConditionEvaluationReportLoggingListener :                        
                                                                                                                                                                                                                                                             
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2022-01-28 09:18:54.583 ERROR 1 --- [           main] o.s.boot.SpringApplication               : Application run failed                                                                                                                                      
                                                                                       
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jwtDecoderByIssuerUri' defined in class path resource [org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwtConfiguration$Jw
tDecoderConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.security.oauth2.jwt.JwtDecoder]: Factory method 'jwtDecoderBy
IssuerUri' threw exception; nested exception is java.lang.IllegalArgumentException: Unable to resolve the Configuration with the provided Issuer of "https://myhost/auth/realms/myrealm"
        at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:658) ~[spring-beans-5.3.10.jar!/:5.3.10]                                                                                                       
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:486) ~[spring-beans-5.3.10.jar!/:5.3.10]                                                                                     
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352) ~[spring-beans-5.3.10.jar!/:5.3.10]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195) ~[spring-beans-5.3.10.jar!/:5.3.10]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) ~[spring-beans-5.3.10.jar!/:5.3.10]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.10.jar!/:5.3.10]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.10.jar!/:5.3.10]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.10.jar!/:5.3.10]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.10.jar!/:5.3.10]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.10.jar!/:5.3.10]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944) ~[spring-beans-5.3.10.jar!/:5.3.10]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.10.jar!/:5.3.10]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.10.jar!/:5.3.10]
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.5.5.jar!/:2.5.5]                                                                             
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-2.5.5.jar!/:2.5.5]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434) ~[spring-boot-2.5.5.jar!/:2.5.5]                                                                                                                            
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:338) ~[spring-boot-2.5.5.jar!/:2.5.5]                                                                                                                                       
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) ~[spring-boot-2.5.5.jar!/:2.5.5]                                                                                                                                      
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1332) ~[spring-boot-2.5.5.jar!/:2.5.5]  
        at io.myapp.MyApplication            .main(MyApplication            .java:10) ~[classes!/:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]                                                                                                                                                           
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
        at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]             
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[sbapp.jar:na]  
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[sbapp.jar:na]                  
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[sbapp.jar:na]                         
        at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88) ~[sbapp.jar:na]                                                                                                                                                             
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.security.oauth2.jwt.JwtDecoder]: Factory method 'jwtDecoderByIssuerUri' threw exception; nested exception is java.lang.IllegalArgumentException: U
nable to resolve the Configuration with the provided Issuer of "https://myhost/auth/realms/myrealm"                                                                                                                                              
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.3.10.jar!/:5.3.10]
        at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ~[spring-beans-5.3.10.jar!/:5.3.10]
        ... 27 common frames omitted                                                            
Caused by: java.lang.IllegalArgumentException: Unable to resolve the Configuration with the provided Issuer of "https://myhost/auth/realms/myrealm"
        at org.springframework.security.oauth2.jwt.JwtDecoderProviderConfigurationUtils.getConfiguration(JwtDecoderProviderConfigurationUtils.java:143) ~[spring-security-oauth2-jose-5.5.2.jar!/:5.5.2]
        at org.springframework.security.oauth2.jwt.JwtDecoderProviderConfigurationUtils.getConfigurationForIssuerLocation(JwtDecoderProviderConfigurationUtils.java:76) ~[spring-security-oauth2-jose-5.5.2.jar!/:5.5.2]
        at org.springframework.security.oauth2.jwt.JwtDecoders.fromIssuerLocation(JwtDecoders.java:101) ~[spring-security-oauth2-jose-5.5.2.jar!/:5.5.2]
        at org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerJwtConfiguration$JwtDecoderConfiguration.jwtDecoderByIssuerUri(OAuth2ResourceServerJwtConfiguration.java:95) ~[spring-boot-autoconfigure-2.5.5.jar!/:2.
5.5]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
        at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.3.10.jar!/:5.3.10]                                                                                       
        ... 28 common frames omitted
Caused by: org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://myhost/auth/realms/myrealm/.well-known/openid-configuration": PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:785) ~[spring-web-5.3.10.jar!/:5.3.10]
        at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:670) ~[spring-web-5.3.10.jar!/:5.3.10]
        at org.springframework.security.oauth2.jwt.JwtDecoderProviderConfigurationUtils.getConfiguration(JwtDecoderProviderConfigurationUtils.java:132) ~[spring-security-oauth2-jose-5.5.2.jar!/:5.5.2]                                                     
        ... 36 common frames omitted
Caused by: 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) ~[na:na]
        at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:349) ~[na:na]
        at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:292) ~[na:na]
        at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:287) ~[na:na]
        at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1357) ~[na:na]                                                                                                                      
        at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.onConsumeCertificate(CertificateMessage.java:1232) ~[na:na]                                                                                                                  
        at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.consume(CertificateMessage.java:1175) ~[na:na]
        at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392) ~[na:na]
        at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:443) ~[na:na]
        at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:421) ~[na:na]
        at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:182) ~[na:na]
        at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:172) ~[na:na]
        at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1426) ~[na:na]
        at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1336) ~[na:na]
        at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:450) ~[na:na]
        at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:421) ~[na:na]
        at java.base/sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:572) ~[na:na]
        at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:197) ~[na:na]                                                                                                             
        at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:168) ~[na:na]
        at org.springframework.http.client.SimpleBufferingClientHttpRequest.executeInternal(SimpleBufferingClientHttpRequest.java:76) ~[spring-web-5.3.10.jar!/:5.3.10]                                                                                      
        at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48) ~[spring-web-5.3.10.jar!/:5.3.10]                                                                                  
        at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:66) ~[spring-web-5.3.10.jar!/:5.3.10]                                                                                                            
        at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:776) ~[spring-web-5.3.10.jar!/:5.3.10]
        ... 38 common frames omitted
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) ~[na:na]
        at java.base/sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:306) ~[na:na]
        at java.base/sun.security.validator.Validator.validate(Validator.java:264) ~[na:na]
        at java.base/sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:313) ~[na:na]
        at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:222) ~[na:na]
        at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:129) ~[na:na]
        at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1341) ~[na:na]                                                                                                                      
        ... 56 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) ~[na:na]
        at java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) ~[na:na]
        at java.base/java.security.cert.CertPathBuilder.build(CertPathBuilder.java:297) ~[na:na]
        at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:434) ~[na:na]
        ... 62 common frames omitted

Here are the things I tried so far (which didn’t work):

  • use keycloak in plain HTTP
  • provide keycloak TLS certificate public key to application through spring.security.oauth2.resourceserver.jwt.public-key-location
  • provide keycloak TLS certificate + public key to application through spring.security.oauth2.resourceserver.jwt.public-key-location
  • provide a JKS trustore containing keycloak TLS certificate to application through spring.security.oauth2.resourceserver.jwt.public-key-location
  • provide a JKS trustore containing keycloak TLS certificate to application through javax.net.ssl.trustStore (along with javax.net.ssl.trustStorePassword and javax.net.ssl.trustStoreType=jks)
  • create a nginx proxy redirecting to deployed keycloak in order to provide a plain HTTP localhost value to spring.security.oauth2.resourceserver.jwt.issuer-uri

I might add that I’m not a Java developer, therefore I don’t have any way to alter the app code. I can only act on app configuration through command line arguments or application.yaml.

As a side note, the keycloak server is working fine when deployed. I can access in my browser the URLs that Spring is complaining about, as long as I accept « the risk » of self-signed certificates.:

  • https://myhost/auth/realms/myrealm
  • https://myhost/auth/realms/myrealm/.well-known/openid-configuration
Nicolas Goudry
  • 367
  • 2
  • 6
  • 16
  • The issue in the certificate indeed. Hope this thread helps https://stackoverflow.com/questions/9210514/unable-to-find-valid-certification-path-to-requested-target-error-even-after-c. Especially answers from **Deb** and **leonaugust**. – geobreze Jan 28 '22 at 11:50
  • Thanks for the insight @geobreze but this is what I did and it doesn’t work. I tried again following answers you pointed me to (which was how I did it, but we never know if I did something wrong), without success. – Nicolas Goudry Jan 31 '22 at 09:42
  • I've tried to reproduce this locally. When using a self-signed certificate I get different errors: 1. Just HTTPS request without importing the certificate into keystore I get `SunCertPathBuilderException: unable to find valid certification path to requested target` (same as yours). 2. HTTPS request when certificate is added to keystore (`keytool -v -import -file tls.crt -alias kk-test -keystore test` + params `-Djavax.net.ssl.trustStore=/path/to-keystore -Djavax.net.ssl.trustStorePassword=pass`) I get an error `CertificateException: No name matching myhost found`. – geobreze Jan 31 '22 at 23:14
  • To fix an error from the second option you have to generate a certificate with CA (Common Name) matching your host. At least it worked for me. Alternatively, you can implement your own host validation as advised here http://java.globinch.com/enterprise-java/security/fix-java-security-certificate-exception-no-matching-localhost-found/ (which I don't recommend doing). – geobreze Jan 31 '22 at 23:17

0 Answers0