Spring 启动 - Keycloak:"failed to turn code into token" SSL

Spring Boot - Keycloak: "failed to turn code into token" SSL

我 spring 在 kuberntes 集群上使用 keycloak 集成启动。在生产中,我为 "example.com" 等域信任的 SSL 证书。我将我的 spring 启动 Web 应用程序和 keycloak 配置为在具有入口的同一域路由下,并提供 SSL 以便为两个服务器重用我的证书。

https://example.com -> Spring 启动 https://example.com/auth -> 钥匙斗篷

这工作正常,但是当我尝试通过 keycloak spring 适配器从我的 Web 应用程序获取令牌时,我在日志中收到以下错误:

message:  "failed to turn code into token"   
  stack_trace:  "s.s.p.c.SunCertPathBuilderException: unable to find valid certification path to requested target
    at s.s.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
    at s.s.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392)
    ... 95 common frames omitted
Wrapped by: s.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:397)
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302)
    at sun.security.validator.Validator.validate(Validator.java:262)
    at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:330)
    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:237)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:132)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1621)
    ... 89 common frames omitted
Wrapped by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1946)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:316)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:310)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1639)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:223)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1037)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:965)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1064)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379)
    at o.apache.http.conn.ssl.SSLSocketFactory.createLayeredSocket(SSLSocketFactory.java:570)
    at o.keycloak.adapters.SniSSLSocketFactory.createLayeredSocket(SniSSLSocketFactory.java:114)
    at o.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:554)
    at o.keycloak.adapters.SniSSLSocketFactory.connectSocket(SniSSLSocketFactory.java:109)
    at o.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:415)
    at o.a.h.i.c.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
    at o.a.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:144)
    at o.a.h.i.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:134)
    at o.a.h.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:605)
    at o.a.h.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:440)
    at o.a.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:835)
    at o.a.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
    at o.a.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
    at o.a.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56)
    at org.keycloak.adapters.ServerRequest.invokeAccessCodeToToken(ServerRequest.java:111)
    at o.k.adapters.OAuthRequestAuthenticator.resolveCode(OAuthRequestAuthenticator.java:335)
    at o.k.adapters.OAuthRequestAuthenticator.authenticate(OAuthRequestAuthenticator.java:280)
    at o.keycloak.adapters.RequestAuthenticator.authenticate(RequestAuthenticator.java:139)
    at o.k.a.s.f.KeycloakAuthenticationProcessingFilter.attemptAuthentication(KeycloakAuthenticationProcessingFilter.java:150)
    at o.s.s.w.a.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
    at o.s.s.w.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at o.s.s.w.a.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
    at o.s.s.w.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at o.k.a.s.f.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:86)
    at o.s.s.w.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at o.s.s.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74)
    at o.s.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118)
    at o.s.s.w.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at o.s.s.w.c.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
    at o.s.s.w.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at o.s.s.w.c.r.a.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
    at o.s.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118)
    at o.s.s.w.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at o.s.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
    at o.s.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
    at o.s.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357)
    at o.s.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)
    at o.a.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at o.a.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at o.s.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
    at o.s.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118)
    at o.a.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at o.a.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at o.s.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)
    at o.s.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118)
    at o.a.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at o.a.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at o.s.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
    ... 34 frames truncated
"   

Requests

此错误是因为用于验证 jvm 中的 TLS 连接的 trustore 不信任您用于 keycloak 服务器的证书。因此,将代码转换为令牌的请求永远不会完成。

你需要add the CA certificate in your jvm trustore

由于您处于 kubernetes 环境中,更简单的方法可能是使用 keycloak 适配器 (https://www.keycloak.org/docs/latest/securing_apps/index.html#_java_adapter_config) 提供的功能:

  • trustore:使用特定的 trustore 连接到 keycloak
  • disable-trust-manager: 禁用证书验证(仅用于测试)