【问题标题】:@Configuration not applied depending on names of classes@Configuration 不应用取决于类的名称
【发布时间】:2021-06-25 16:20:01
【问题描述】:

请阅读底部的“更新”。控制器的名称似乎有问题。根据名称,不应用 SSL 配置。


我的 spring 应用程序的UserService 连接到在开发中使用自签名证书的外部服务器。我将自签名且有效的证书添加到 java 密钥库 ./dev-truststore.jks 并使用此 @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")
  }
}

这是减少的UserServiceImpl,仍然显示错误:

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)
    }
  }
}

这是创建用户的途径:

@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)
  }
}

这是 Keycloak 的 bean 创建:


@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()
  }
}

这很好用。

现在,我正在开发一个新的不相关功能(控制器/服务/存储库),突然 create-user 路由停止工作,因为它无法再连接到 keycloak 服务,因为它无法执行 SSL 握手。请注意,create-user 操作与新服务/功能中的任何内容都无关,也没有被修改。

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

完整的堆栈跟踪是:

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

我通过从新服务中删除所有方法来跟踪问题(因此它是一个空接口 + @Service 注释类中的实现):

interface TaskService {}

@Service
class TaskServiceImpl(
  // next line implies the error.
  private val userService: UserService,
) : TaskService {}

当我从 TaskServiceImpl 中删除 private val userService: UserService 依赖项时,userService 能够连接到 keycloak 并且 create-user 路由不会失败,但如果我再次添加它,上述 SSL 握手创建用户路由发生错误。

也依赖于UserService 的其他服务并不意味着同样的错误。新服务完全是空的,所以我很困惑为什么其他服务没有暗示同样的错误?

例如,该服务也使用UserService,它确实暗示用户创建路线失败:

@Service
class FeedServiceImpl(
  private val userService: UserService,
  // other dependencies
) : FeedService {
   /// ...
}

TaskService 在两个控制器中使用,我已删除所有路由和所有其他依赖项:

@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,
) {
}

当我从两者中删除taskService 依赖项时,错误不会发生。当我只将它添加到ActionsController 时,错误确实会发生 - 但如果我只将它添加到TaskReviewController,那么错误确实不会发生。

我不知道如何进一步追踪它。我认为这可能表示一个依赖循环,但没有循环,因为UserService 不依赖于任何新的TaskService,并且在添加新的TaskService 时没有被修改。而且UserService 也不依赖于任何控制器。

有什么想法吗?

--

  • spring-boot 2.5.0
  • org.keycloak:keycloak-admin-client:13.0.1

PS:我还验证了configureSSL 仍在执行,并且我正在运行正确的development 配置文件。

更新

我发现错误取决于控制器的包和名称。如果使用TaskService 的所有控制器在SSLConfigDev 配置之后按字母顺序排列,则不会发生错误:

因此,与“SSLConfigDev”在同一个包中的这个控制器意味着错误:

@RestController
class SSLConfigDeuController(
  private val taskService: TaskReviewService,
) {
}

但这很好:

@RestController
class SSLConfigDewController(
  private val taskService: TaskReviewService,
) {
}

【问题讨论】:

  • 可能您的 UserService 依赖于使用默认 SSL 上下文的 HTTP 客户端(Spring RestTemplate 或 Apache HttpClient)。您应该配置两个具有单独 SSL 上下文的 http 客户端,并将非 SSL http 客户端注入 UserService
  • 是的,它使用 RestEasy 客户端连接到 keycloak,但为什么在那之前会起作用?为什么其他服务@AutowireUserService不会出现这个问题?已经有大约 20 种其他服务。
  • 您是否尝试添加-Djavax.net.debug=all 以获得详细信息?你可以添加相关的依赖项来提问吗?您的新服务是使用 HTTPClient 而不是 RESTEasy 吗?
  • @user7294900 新的服务接口和它的实现是完全空的,所以它没有使用任何http客户端。 UserService 接口及其实现相当复杂。我将添加它的最小版本,稍后当我有更多时间时仍然会显示错误。但是我仍然很困惑,为什么当其他服务将UserService添加为依赖项时不会出现此问题,并想到可能由新服务的名称和类路径上的排序引起的依赖项问题...... ?
  • 听起来像循环依赖,你有特定方面的代码吗?

标签: spring spring-boot kotlin


【解决方案1】:

经过进一步调查,我想我明白了这个问题。

根据控制器的名称,用户服务在SSLConfigDev 配置之前或之后实例化。

UserService 依赖于KeycloakKeycloak 类在构造函数中创建了一个 resteasy 客户端:

该库的相关代码为:

Keycloak(String serverUrl, String realm, String username, String password, String clientId, String clientSecret, String grantType, Client resteasyClient, String authtoken) {
        config = new Config(serverUrl, realm, username, password, clientId, clientSecret, grantType);
        client = resteasyClient != null ? resteasyClient : newRestEasyClient(null, null, false);
        authToken = authtoken;
        tokenManager = authtoken == null ? new TokenManager(config, client) : null;

        target = (ResteasyWebTarget) client.target(config.getServerUrl());
        target.register(newAuthFilter());
    }

此代码在 UserService 被实例化时运行,因为它会触发创建 Keycloak bean。

取决于这是否发生在 SSLConfigDev 运行之前或之后,系统属性是否已经设置。

与难以发现的错误一样,解决问题很容易: 我们只需要确保在设置系统属性后创建Keycloak bean。并且因为正确的配置不应该依赖于 bean 创建的顺序,实现应该绑定到具体的 bean。

例如,我们可以删除SSLConfigDev,而是创建Keycloak.init() 方法的dev-profile 版本,该方法在创建bean 实例之前设置系统属性。或者我们可以在创建 bean 时检查环境如下:

@Configuration
@ConfigurationProperties("keycloak")
class KeycloakConfig(
  private val env: Environment,
){
  lateinit var serverUrl: String
  lateinit var realm: String
  lateinit var clientId: String
  lateinit var clientSecret: String
  lateinit var frontEndClientId: String

  @Bean
  fun init(): Keycloak {
    if (env.activeProfiles.contains("development")) {
      System.setProperty("javax.net.ssl.trustStore", "./dev-truststore.jks")
      System.setProperty("javax.net.ssl.trustStorePassword", "keycloak")
    }
    return KeycloakBuilder.builder()
      .serverUrl(serverUrl)
      .grantType(OAuth2Constants.CLIENT_CREDENTIALS)
      .realm(realm)
      .clientId(clientId)
      .clientSecret(clientSecret)
      .resteasyClient(
        ResteasyClientBuilder().connectionPoolSize(10).build()
      )
      .build()
  }
}

【讨论】:

    猜你喜欢
    • 2016-03-05
    • 1970-01-01
    • 2014-10-21
    • 1970-01-01
    • 2010-10-08
    • 1970-01-01
    • 2022-01-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多