Please read the "Update" at the bottom. It seems to be a problem with the name of the controllers. Depending on the name the SSL-configuration is not applied.
The UserService of my spring application connects to an external server that uses a self-signed cert in development. I added the self-signed and valid cert to a java key store ./dev-truststore.jks and use this @Configuration:
@Profile("development") @Configuration class SSLConfigDev { @Suppress("unused") @PostConstruct private fun configureSSL() { System.setProperty("javax.net.ssl.trustStore", "./dev-truststore.jks") System.setProperty("javax.net.ssl.trustStorePassword", "secret") } } This is the reduced UserServiceImpl that still shows the error:
import org.keycloak.admin.client.Keycloak // ... @Service class UserServiceFeatureImpl( private val userRepository: UserRepository, private val kc: Keycloak, ) : UserService { override suspend fun createUser(email: String, pw: String) { try { val realmResources = kc.realm("myRealm") val usersResource = realmResources.users() // The next line works fine until I define the new TaskService as // described below. Then it fails with the SSL exception shown below. val existingUsers = usersResource.search(email, 0, 1) // ... } catch (e: Exception) { throw CreateAccountException("Could not create account", e) } } } And this is the route for creating users:
@RestController class UserController( private val userService: UserService, ) { @PostMapping("/users/new") @ResponseStatus(HttpStatus.CREATED) suspend fun create(@RequestBody @Valid dto: CredentialsDTO) { userService.createUser(dto.email, dto.password) } } This is the bean creation for Keycloak:
@Configuration @ConfigurationProperties("keycloak") class KeycloakConfig{ lateinit var serverUrl: String lateinit var realm: String lateinit var clientId: String lateinit var clientSecret: String lateinit var frontEndClientId: String @Bean fun init(): Keycloak { return KeycloakBuilder.builder() .serverUrl(serverUrl) .grantType(OAuth2Constants.CLIENT_CREDENTIALS) .realm(realm) .clientId(clientId) .clientSecret(clientSecret) .resteasyClient( ResteasyClientBuilder().connectionPoolSize(10).build() ) .build() } } This works fine.
Now, I was developing a new unrelated feature (controller/service/repository) and suddenly the create-user route stops working, because it cannot connect to the keycloak service anymore because it fails to perform the SSL handshake. Note that the create-user action is not related to anything in the new service/feature and has not been modified.
javax.ws.rs.ProcessingException: RESTEASY004655: Unable to invoke request: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target The full stack trace is:
2021-06-25 18:04:19.050 ERROR 7821 --- [or-http-epoll-3] a.w.r.e.AbstractErrorWebExceptionHandler : [755b0875-1] 500 Server Error for HTTP POST "/users/new" com.example.backend.user.CreateAccountException: Could not create account at com.example.backend.user.UserServiceFeatureImpl.createUser$suspendImpl(UserServiceFeatureImpl.kt:278) ~[main/:na] Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: Error has been observed at the following site(s): |_ checkpoint ⇢ Handler com.example.backend.user.UserController#create(CredentialsDTO, Continuation) [DispatcherHandler] |_ checkpoint ⇢ com.example.backend.core.ReactorContextLocaleWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.security.web.server.authorization.AuthorizationWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.security.web.server.authorization.ExceptionTranslationWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.security.web.server.authentication.logout.LogoutWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.security.web.server.savedrequest.ServerRequestCacheWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.security.web.server.context.SecurityContextServerWebExchangeWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.security.web.server.authentication.AuthenticationWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.security.web.server.context.ReactorContextWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.security.web.server.header.HttpHeaderWriterWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.security.config.web.server.ServerHttpSecurity$ServerWebExchangeReactorContextWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.security.web.server.WebFilterChainProxy [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ HTTP POST "/users/new" [ExceptionHandlingWebHandler] Stack trace: at com.example.backend.user.UserServiceFeatureImpl.createUser$suspendImpl(UserServiceFeatureImpl.kt:278) ~[main/:na] at com.example.backend.user.UserServiceFeatureImpl.createUser(UserServiceFeatureImpl.kt) ~[main/:na] at com.example.backend.user.UserServiceFeatureImpl$$FastClassBySpringCGLIB$$ed9e17ac.invoke(<generated>) ~[main/:na] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.7.jar:5.3.7] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.3.7.jar:5.3.7] at com.example.backend.user.UserServiceFeatureImpl$$EnhancerBySpringCGLIB$$2ccf6d25.createUser(<generated>) ~[main/:na] at com.example.backend.user.UserServicePermissionsImpl.createUser$suspendImpl(UserServicePermissionsImpl.kt:47) ~[main/:na] at com.example.backend.user.UserServicePermissionsImpl.createUser(UserServicePermissionsImpl.kt) ~[main/:na] at com.example.backend.user.UserServicePermissionsImpl$$FastClassBySpringCGLIB$$d7f96f3a.invoke(<generated>) ~[main/:na] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.7.jar:5.3.7] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.3.7.jar:5.3.7] at com.example.backend.user.UserServicePermissionsImpl$$EnhancerBySpringCGLIB$$fb5d3241.createUser(<generated>) ~[main/:na] at com.example.backend.user.UserController.create$suspendImpl(UserController.kt:116) ~[main/:na] at com.example.backend.user.UserController.create(UserController.kt) ~[main/:na] at com.example.backend.user.UserController$$FastClassBySpringCGLIB$$d1552207.invoke(<generated>) ~[main/:na] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.7.jar:5.3.7] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.3.7.jar:5.3.7] at com.example.backend.user.UserController$$EnhancerBySpringCGLIB$$f0dbf2c8.create(<generated>) ~[main/: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:564) ~[na:na] at kotlin.reflect.jvm.internal.calls.CallerImpl$Method.callMethod(CallerImpl.kt:97) ~[kotlin-reflect-1.5.0.jar:1.5.0-release-749 (1.5.0)] at kotlin.reflect.jvm.internal.calls.CallerImpl$Method$Instance.call(CallerImpl.kt:113) ~[kotlin-reflect-1.5.0.jar:1.5.0-release-749 (1.5.0)] at kotlin.reflect.jvm.internal.KCallableImpl.call(KCallableImpl.kt:108) ~[kotlin-reflect-1.5.0.jar:1.5.0-release-749 (1.5.0)] at kotlin.reflect.full.KCallables.callSuspend(KCallables.kt:55) ~[kotlin-reflect-1.5.0.jar:1.5.0-release-749 (1.5.0)] at org.springframework.core.CoroutinesUtils$invokeSuspendingFunction$mono$1.invokeSuspend(CoroutinesUtils.kt:64) ~[spring-core-5.3.7.jar:5.3.7] at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) ~[kotlin-stdlib-1.5.0.jar:1.5.0-release-749 (1.5.0)] at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:377) ~[kotlinx-coroutines-core-jvm-1.5.0.jar:na] at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:30) ~[kotlinx-coroutines-core-jvm-1.5.0.jar:na] at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:25) ~[kotlinx-coroutines-core-jvm-1.5.0.jar:na] at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:110) ~[kotlinx-coroutines-core-jvm-1.5.0.jar:na] at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126) ~[kotlinx-coroutines-core-jvm-1.5.0.jar:na] at kotlinx.coroutines.reactor.MonoKt.monoInternal$lambda-2(Mono.kt:90) ~[kotlinx-coroutines-reactor-1.5.0.jar:na] at reactor.core.publisher.MonoCreate.subscribe(MonoCreate.java:57) ~[reactor-core-3.4.6.jar:3.4.6] // ... at reactor.netty.channel.FluxReceive.terminateReceiver(FluxReceive.java:469) ~[reactor-netty-core-1.0.7.jar:1.0.7] at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:261) ~[reactor-netty-core-1.0.7.jar:1.0.7] at reactor.netty.channel.FluxReceive.request(FluxReceive.java:130) ~[reactor-netty-core-1.0.7.jar:1.0.7] at reactor.core.publisher.FluxMap$MapSubscriber.request(FluxMap.java:162) ~[reactor-core-3.4.6.jar:3.4.6] at reactor.core.publisher.FluxPeek$PeekSubscriber.request(FluxPeek.java:137) ~[reactor-core-3.4.6.jar:3.4.6] at reactor.core.publisher.FluxMap$MapSubscriber.request(FluxMap.java:162) ~[reactor-core-3.4.6.jar:3.4.6] at reactor.core.publisher.MonoCollect$CollectSubscriber.onSubscribe(MonoCollect.java:103) ~[reactor-core-3.4.6.jar:3.4.6] at reactor.core.publisher.FluxMap$MapSubscriber.onSubscribe(FluxMap.java:92) ~[reactor-core-3.4.6.jar:3.4.6] at reactor.core.publisher.FluxPeek$PeekSubscriber.onSubscribe(FluxPeek.java:170) ~[reactor-core-3.4.6.jar:3.4.6] at reactor.core.publisher.FluxMap$MapSubscriber.onSubscribe(FluxMap.java:92) ~[reactor-core-3.4.6.jar:3.4.6] at reactor.netty.channel.FluxReceive.startReceiver(FluxReceive.java:168) ~[reactor-netty-core-1.0.7.jar:1.0.7] at reactor.netty.channel.FluxReceive.lambda$subscribe$2(FluxReceive.java:147) ~[reactor-netty-core-1.0.7.jar:1.0.7] at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164) ~[netty-common-4.1.65.Final.jar:4.1.65.Final] at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472) ~[netty-common-4.1.65.Final.jar:4.1.65.Final] at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:384) ~[netty-transport-native-epoll-4.1.65.Final-linux-x86_64.jar:4.1.65.Final] at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989) ~[netty-common-4.1.65.Final.jar:4.1.65.Final] at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.65.Final.jar:4.1.65.Final] at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.65.Final.jar:4.1.65.Final] at java.base/java.lang.Thread.run(Thread.java:832) ~[na:na] Caused by: javax.ws.rs.ProcessingException: RESTEASY004655: Unable to invoke request: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine.invoke(ApacheHttpClient4Engine.java:328) ~[resteasy-client-3.13.2.Final.jar:3.13.2.Final] at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.invoke(ClientInvocation.java:443) ~[resteasy-client-3.13.2.Final.jar:3.13.2.Final] at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invokeSync(ClientInvoker.java:149) ~[resteasy-client-3.13.2.Final.jar:3.13.2.Final] at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invoke(ClientInvoker.java:112) ~[resteasy-client-3.13.2.Final.jar:3.13.2.Final] at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientProxy.invoke(ClientProxy.java:76) ~[resteasy-client-3.13.2.Final.jar:3.13.2.Final] at com.sun.proxy.$Proxy131.grantToken(Unknown Source) ~[na:na] at org.keycloak.admin.client.token.TokenManager.grantToken(TokenManager.java:90) ~[keycloak-admin-client-13.0.1.jar:13.0.1] at org.keycloak.admin.client.token.TokenManager.getAccessToken(TokenManager.java:70) ~[keycloak-admin-client-13.0.1.jar:13.0.1] at org.keycloak.admin.client.token.TokenManager.getAccessTokenString(TokenManager.java:65) ~[keycloak-admin-client-13.0.1.jar:13.0.1] at org.keycloak.admin.client.resource.BearerAuthFilter.filter(BearerAuthFilter.java:52) ~[keycloak-admin-client-13.0.1.jar:13.0.1] at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.filterRequest(ClientInvocation.java:579) ~[resteasy-client-3.13.2.Final.jar:3.13.2.Final] at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.invoke(ClientInvocation.java:440) ~[resteasy-client-3.13.2.Final.jar:3.13.2.Final] at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invokeSync(ClientInvoker.java:149) ~[resteasy-client-3.13.2.Final.jar:3.13.2.Final] at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invoke(ClientInvoker.java:112) ~[resteasy-client-3.13.2.Final.jar:3.13.2.Final] at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientProxy.invoke(ClientProxy.java:76) ~[resteasy-client-3.13.2.Final.jar:3.13.2.Final] at com.sun.proxy.$Proxy173.search(Unknown Source) ~[na:na] at com.example.backend.user.UserServiceFeatureImpl.createUser$suspendImpl(UserServiceFeatureImpl.kt:247) ~[main/:na] at com.example.backend.user.UserServiceFeatureImpl.createUser(UserServiceFeatureImpl.kt) ~[main/:na] at com.example.backend.user.UserServiceFeatureImpl$$FastClassBySpringCGLIB$$ed9e17ac.invoke(<generated>) ~[main/:na] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.7.jar:5.3.7] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.3.7.jar:5.3.7] at com.example.backend.user.UserServiceFeatureImpl$$EnhancerBySpringCGLIB$$2ccf6d25.createUser(<generated>) ~[main/:na] at com.example.backend.user.UserServicePermissionsImpl.createUser$suspendImpl(UserServicePermissionsImpl.kt:47) ~[main/:na] at com.example.backend.user.UserServicePermissionsImpl.createUser(UserServicePermissionsImpl.kt) ~[main/:na] at com.example.backend.user.UserServicePermissionsImpl$$FastClassBySpringCGLIB$$d7f96f3a.invoke(<generated>) ~[main/:na] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.7.jar:5.3.7] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.3.7.jar:5.3.7] at com.example.backend.user.UserServicePermissionsImpl$$EnhancerBySpringCGLIB$$fb5d3241.createUser(<generated>) ~[main/:na] at com.example.backend.user.UserController.create$suspendImpl(UserController.kt:116) ~[main/:na] at com.example.backend.user.UserController.create(UserController.kt) ~[main/:na] at com.example.backend.user.UserController$$FastClassBySpringCGLIB$$d1552207.invoke(<generated>) ~[main/:na] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.7.jar:5.3.7] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.3.7.jar:5.3.7] at com.example.backend.user.UserController$$EnhancerBySpringCGLIB$$f0dbf2c8.create(<generated>) ~[main/: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:564) ~[na:na] at kotlin.reflect.jvm.internal.calls.CallerImpl$Method.callMethod(CallerImpl.kt:97) ~[kotlin-reflect-1.5.0.jar:1.5.0-release-749 (1.5.0)] at kotlin.reflect.jvm.internal.calls.CallerImpl$Method$Instance.call(CallerImpl.kt:113) ~[kotlin-reflect-1.5.0.jar:1.5.0-release-749 (1.5.0)] at kotlin.reflect.jvm.internal.KCallableImpl.call(KCallableImpl.kt:108) ~[kotlin-reflect-1.5.0.jar:1.5.0-release-749 (1.5.0)] at kotlin.reflect.full.KCallables.callSuspend(KCallables.kt:55) ~[kotlin-reflect-1.5.0.jar:1.5.0-release-749 (1.5.0)] at org.springframework.core.CoroutinesUtils$invokeSuspendingFunction$mono$1.invokeSuspend(CoroutinesUtils.kt:64) ~[spring-core-5.3.7.jar:5.3.7] at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) ~[kotlin-stdlib-1.5.0.jar:1.5.0-release-749 (1.5.0)] at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:377) ~[kotlinx-coroutines-core-jvm-1.5.0.jar:na] at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:30) ~[kotlinx-coroutines-core-jvm-1.5.0.jar:na] at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:25) ~[kotlinx-coroutines-core-jvm-1.5.0.jar:na] at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:110) ~[kotlinx-coroutines-core-jvm-1.5.0.jar:na] at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126) ~[kotlinx-coroutines-core-jvm-1.5.0.jar:na] at kotlinx.coroutines.reactor.MonoKt.monoInternal$lambda-2(Mono.kt:90) ~[kotlinx-coroutines-reactor-1.5.0.jar:na] // ... at reactor.core.publisher.FluxMap$MapSubscriber.onSubscribe(FluxMap.java:92) ~[reactor-core-3.4.6.jar:3.4.6] at reactor.netty.channel.FluxReceive.startReceiver(FluxReceive.java:168) ~[reactor-netty-core-1.0.7.jar:1.0.7] at reactor.netty.channel.FluxReceive.lambda$subscribe$2(FluxReceive.java:147) ~[reactor-netty-core-1.0.7.jar:1.0.7] at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164) ~[netty-common-4.1.65.Final.jar:4.1.65.Final] at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472) ~[netty-common-4.1.65.Final.jar:4.1.65.Final] at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:384) ~[netty-transport-native-epoll-4.1.65.Final-linux-x86_64.jar:4.1.65.Final] at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989) ~[netty-common-4.1.65.Final.jar:4.1.65.Final] at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.65.Final.jar:4.1.65.Final] at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.65.Final.jar:4.1.65.Final] at java.base/java.lang.Thread.run(Thread.java:832) ~[na:na] 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:325) ~[na:na] at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:268) ~[na:na] at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:263) ~[na:na] at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1340) ~[na:na] at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.onConsumeCertificate(CertificateMessage.java:1215) ~[na:na] at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.consume(CertificateMessage.java:1158) ~[na:na] at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:396) ~[na:na] at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:445) ~[na:na] at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:423) ~[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:171) ~[na:na] at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1475) ~[na:na] at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1381) ~[na:na] at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:441) ~[na:na] at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:412) ~[na:na] at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:436) ~[httpclient-4.5.13.jar:4.5.13] at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:384) ~[httpclient-4.5.13.jar:4.5.13] at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142) ~[httpclient-4.5.13.jar:4.5.13] at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:376) ~[httpclient-4.5.13.jar:4.5.13] at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:393) ~[httpclient-4.5.13.jar:4.5.13] at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236) ~[httpclient-4.5.13.jar:4.5.13] at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186) ~[httpclient-4.5.13.jar:4.5.13] at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89) ~[httpclient-4.5.13.jar:4.5.13] at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) ~[httpclient-4.5.13.jar:4.5.13] at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185) ~[httpclient-4.5.13.jar:4.5.13] at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83) ~[httpclient-4.5.13.jar:4.5.13] at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56) ~[httpclient-4.5.13.jar:4.5.13] at org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine.invoke(ApacheHttpClient4Engine.java:323) ~[resteasy-client-3.13.2.Final.jar:3.13.2.Final] ... 98 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.checkTrusted(X509TrustManagerImpl.java:231) ~[na:na] at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:132) ~[na:na] at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1324) ~[na:na] ... 122 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] ... 127 common frames omitted 2021-06-25 18:04:19.072 INFO 7821 --- [or-http-epoll-3] reactor.netty.http.server.AccessLog : 127.0.0.1:59138 - - [25/Jun/2021:18:04:18 +0200] "POST /users/new HTTP/1.1" 500 23140 306 ms I tracked the issue down by removing all methods from the new service (so it is an empty interface + the implementation in a @Service annotated class):
interface TaskService {} and
@Service class TaskServiceImpl( // next line implies the error. private val userService: UserService, ) : TaskService {} When I remove the private val userService: UserService dependency from the TaskServiceImpl the userService is able to connect to keycloak and the create-user route does not fail, but if I add it again, the said SSL handshake error occurs on the create-user route.
Other services, that also depend on the UserService as well, do not imply the same error. The new service is completely empty, so I am very confused why the other services do not imply the same error?
For example, this service also uses the UserService and it does not imply the user creation route to fail:
@Service class FeedServiceImpl( private val userService: UserService, // other dependencies ) : FeedService { /// ... } The TaskService is used in two controllers, I have removed all routes and all other dependencies:
@RestController class TaskReviewController( // adding or removing this dependency does not change anything private val taskService: TaskService, ) { } @RestController class ActionsController( // adding or removing this dependency implies the error private val taskService: TaskService, ) { } When I remove the taskService dependency from both, the error does not occur. When I only add it to the ActionsController the error does occur - but if I only add it to the TaskReviewController the error does not occur.
I am lost how I can track it further down. I thought that this might indicate a dependency cycle but there isn't a cycle, as UserService does not depend on anything of the new TaskService and has not been modified when adding the new TaskService. And the UserService also has no dependency on any of the controllers.
Any ideas?
--
- spring-boot 2.5.0
- org.keycloak:keycloak-admin-client:13.0.1
PS: I also verified that configureSSL is still executed and I am running the right development profile.
UPDATE
I found out that the error depends on the package and name of the controller. If all controllers that use the TaskService are alphabetically ordered after the SSLConfigDev configuration than the error does not occur:
So this controller in the same package as the 'SSLConfigDev` implies the error:
@RestController class SSLConfigDeuController( private val taskService: TaskReviewService, ) { } but this is fine:
@RestController class SSLConfigDewController( private val taskService: TaskReviewService, ) { }
@AutowiretheUserService? There are ~20 other services already.-Djavax.net.debug=allfor verbose details? can you add relevant dependencies to question? Is your new service using HTTPClient and not RESTEasy ?UserServiceinterface and its implementation is quite complex. I will add a minimal version of it that still shows the error later when I have more time. But I am still very confused, why this problem would not occur when other services add theUserServiceas dependency and thought of a dependency issue that might result from the name of the new service and the ordering on the classpath or so...?