【问题标题】:CAS SunCertPathBuilderException:unable to find valid certification path to requested targetCAS SunCertPathBuilderException:无法找到请求目标的有效证书路径
【发布时间】:2017-12-27 13:06:53
【问题描述】:

我已在我的计算机中配置了 CAS 以在特定域(例如 a.com)上工作,它工作正常。在那里,我有一对 .crt 和 .key 文件以及代码。现在需要更改域,所以我所做的是,相应地更改源代码中的域(例如b.com)并导入我收到的 .crt 和 .key 文件。现在,当我访问 CAS 登录页面时,我可以访问它。但是当我提供登录凭据并单击登录按钮时,它会失败并出现以下异常。

sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
    sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
    java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
    sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
    sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
    sun.security.validator.Validator.validate(Validator.java:260)
    sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
    sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
    sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
    sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1496)
    sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
    sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026)
    sun.security.ssl.Handshaker.process_record(Handshaker.java:961)
    sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
    sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
    sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
    sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
    sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
    sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
    sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1546)
    sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1474)
    sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
    org.jasig.cas.client.util.CommonUtils.getResponseFromServer(CommonUtils.java:429)
    org.jasig.cas.client.validation.AbstractCasProtocolUrlBasedTicketValidator.retrieveResponseFromServer(AbstractCasProtocolUrlBasedTicketValidator.java:41)
    org.jasig.cas.client.validation.AbstractUrlBasedTicketValidator.validate(AbstractUrlBasedTicketValidator.java:193)
    org.springframework.security.cas.authentication.CasAuthenticationProvider.authenticateNow(CasAuthenticationProvider.java:158)
    org.springframework.security.cas.authentication.CasAuthenticationProvider.authenticate(CasAuthenticationProvider.java:143)
    org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174)
    org.springframework.security.cas.web.CasAuthenticationFilter.attemptAuthentication(CasAuthenticationFilter.java:270)
    org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    org.jasig.cas.client.session.SingleSignOutFilter.doFilter(SingleSignOutFilter.java:97)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:121)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:121)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
    org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
    org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)

谁能告诉我这里到底发生了什么?我见过很多类似的问题,但似乎没有一个能解决我的情况。

【问题讨论】:

    标签: java tomcat ssl ssl-certificate cas


    【解决方案1】:

    原来是我的 Tomcat 配置有问题。即使我已将密钥导入密钥库,但 tomcat 未访问密钥库,导致读取证书失败。

    这似乎适用于那些下载和提取 tomcat 发行版的二进制文件而不是使用包管理器(例如 apt-get)的人。

    目前有两种可能的选择(可能还有更多)。

    1. 修改 catalina.sh 以添加属性 -Djavax.net.ssl.trustStore 以包含所需的信任存储文件。基本上,属性和值都附加到上述脚本中的JAVA_OPTS 变量中。例如。 JAVA_OPTS="$JAVA_OPTS -Djavax.net.ssl.trustStore=$JAVA_HOME/jre/lib/security/cacerts".However 这只是一个快速修复。我认为这不是一个好的解决方案,因为信任库正在全球范围内添加。
    2. 将密钥库位置添加到server.xml 配置文件中的连接器属性。可以在here 找到示例。

    我现在意识到这是一个非常简单的基本问题。但是为了支持学习者,我想留下问题和答案。请进一步改进此答案。

    【讨论】:

      【解决方案2】:

      来自CAS docs

      PKIX 路径构建错误是最常见的 SSL 错误。这里的问题是 CAS 客户端不信任 CAS 服务器提供的证书;大多数情况下,这是因为在 CAS 服务器上使用了自签名证书。要解决此错误,请将 CAS 服务器证书导入 CAS 客户端的系统信任库。如果证书是您自己的 PKI 颁发的,最好将您的 PKI 的根证书导入 CAS 客户端信任库。

      默认情况下,Java 系统信任库位于 $JAVA_HOME/jre/lib/security/cacerts。要导入的证书必须是 DER 编码的文件。

      所以,如果你有密钥库文件,比如store.jks,首先,导出服务器的证书:

      keytool -exportcert -keystore store.jks -alias server -file server.crt
      

      [请注意,您的密钥库中的别名可能不同]。接下来,移动$JAVA_HOME/jre/lib/security/cacerts目录中的证书,并将其导入客户端的信任库(这里,客户端是你的JVM):

      keytool -import -keystore cacerts -file server.crt -alias server -storepass changeit
      

      [最后一个命令必须以管理员权限调用!]

      注意,如果你在 localhost 上运行,证书的 CN 必须是“localhost”。

      就是这样,现在启动服务器并享受。

      【讨论】:

        最近更新 更多