间歇性 - SunCertPathBuilderException:无法找到请求目标的有效证书路径

Intermittent - SunCertPathBuilderException: unable to find valid certification path to requested target

我写了一个 java 客户端来通过 ssl 连接到 Ldap。 我将 CA 证书导入到我的 java 密钥库,我能够通过 ssl 连接 Ldap 并提取信息。问题是它并不总是有效。通常它 throws:CommunicationException:sun.security.validator.ValidatorException: PKIX 路径构建失败。如果我再次 运行(不做任何更改),它会起作用。

这个问题困扰了我好几天,作为解决方法,我正在捕获此异常并重试。但我正在寻找永久修复。任何帮助将不胜感激。

下面是我获取上下文的代码:

Hashtable<String, String> env = new Hashtable<String, String>();
        env.put(Context.INITIAL_CONTEXT_FACTORY,
                "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, securityPrincipal);
        env.put(Context.PROVIDER_URL, url);
env.put(Context.SECURITY_CREDENTIALS, securityCredential);
        env.put("java.naming.provider.url", url);
        return new InitialLdapContext(env, null);

跟踪轨迹:

javax.naming.CommunicationException: simple bind failed: adapps.nms.comm:636 [Root exception is 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 com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:215)
        at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2685)
        at com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:306)
        at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:193)
        at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:211)
        at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:154)
        at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:84)
        at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:684)
        at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:305)
        at javax.naming.InitialContext.init(InitialContext.java:240)
        at javax.naming.ldap.InitialLdapContext.<init>(InitialLdapContext.java:151)
        at NMSLdapServiceDAOImpl.getLdapContext(NMSLdapServiceDAOImpl.java:149)
        at NMSLdapServiceDAOImpl.getUserByNTID(NMSLdapServiceDAOImpl.java:97)
        at NMSLdapServiceDAOImpl.main(NMSLdapServiceDAOImpl.java:287)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:616)
        at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
Caused 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:1682)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:257)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:251)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1168)
        at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:153)
        at sun.security.ssl.Handshaker.processLoop(Handshaker.java:609)
        at sun.security.ssl.Handshaker.process_record(Handshaker.java:545)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:930)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1175)
        at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:805)
        at sun.security.ssl.AppInputStream.read(AppInputStream.java:94)
        at java.io.BufferedInputStream.fill(BufferedInputStream.java:235)
        at java.io.BufferedInputStream.read1(BufferedInputStream.java:275)
        at java.io.BufferedInputStream.read(BufferedInputStream.java:334)
        at com.sun.jndi.ldap.Connection.run(Connection.java:820)
        at java.lang.Thread.run(Thread.java:679)
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 sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:324)
        at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:224)
        at sun.security.validator.Validator.validate(Validator.java:235)
        at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:147)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:230)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:270)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1147)
        ... 12 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:197)
        at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:255)
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:319)
        ... 18 more
CommunicationException:sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
javax.naming.CommunicationException: simple bind failed: adapps.nms.com:636 [Root exception is 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 com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:215)
        at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2685)
        at com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:306)
        at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:193)
        at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:211)
        at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:154)
        at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:84)
        at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:684)
        at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:305)
        at javax.naming.InitialContext.init(InitialContext.java:240)
        at javax.naming.ldap.InitialLdapContext.<init>(InitialLdapContext.java:151)
        at NMSLdapServiceDAOImpl.getLdapContext(NMSLdapServiceDAOImpl.java:149)
        at NMSLdapServiceDAOImpl.getUserByNTID(NMSLdapServiceDAOImpl.java:97)
        at NMSLdapServiceDAOImpl.getUserByNTID(NMSLdapServiceDAOImpl.java:109)
        at NMSLdapServiceDAOImpl.main(NMSLdapServiceDAOImpl.java:287)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:616)
        at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
Caused 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:1682)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:257)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:251)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1168)
        at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:153)
        at sun.security.ssl.Handshaker.processLoop(Handshaker.java:609)
        at sun.security.ssl.Handshaker.process_record(Handshaker.java:545)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:930)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1175)
        at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:657)
        at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:108)
        at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
        at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
        at com.sun.jndi.ldap.Connection.writeRequest(Connection.java:409)
        at com.sun.jndi.ldap.LdapClient.ldapBind(LdapClient.java:352)
        at com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:210)
        ... 19 more
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 sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:324)
        at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:224)
        at sun.security.validator.Validator.validate(Validator.java:235)
        at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:147)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:230)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:270)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1147)
        ... 31 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:197)
        at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:255)
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:319)
        ... 37 more
CommunicationException:sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
javax.naming.CommunicationException: simple bind failed: adapps.nms.com:636 [Root exception is 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 com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:215)
        at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2685)
        at com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:306)
        at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:193)
        at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:211)
        at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:154)
        at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:84)
        at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:684)
        at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:305)
        at javax.naming.InitialContext.init(InitialContext.java:240)
        at javax.naming.ldap.InitialLdapContext.<init>(InitialLdapContext.java:151)
        at NMSLdapServiceDAOImpl.getLdapContext(NMSLdapServiceDAOImpl.java:149)
        at NMSLdapServiceDAOImpl.getUserByNTID(NMSLdapServiceDAOImpl.java:97)
        at NMSLdapServiceDAOImpl.getUserByNTID(NMSLdapServiceDAOImpl.java:109)
        at NMSLdapServiceDAOImpl.getUserByNTID(NMSLdapServiceDAOImpl.java:109)
        at NMSLdapServiceDAOImpl.main(NMSLdapServiceDAOImpl.java:287)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:616)
        at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
Caused 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:1682)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:257)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:251)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1168)
        at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:153)
        at sun.security.ssl.Handshaker.processLoop(Handshaker.java:609)
        at sun.security.ssl.Handshaker.process_record(Handshaker.java:545)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:930)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1175)
        at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:657)
        at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:108)
        at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
        at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
        at com.sun.jndi.ldap.Connection.writeRequest(Connection.java:409)
        at com.sun.jndi.ldap.LdapClient.ldapBind(LdapClient.java:352)
        at com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:210)
        ... 20 more
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 sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:324)
        at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:224)
        at sun.security.validator.Validator.validate(Validator.java:235)
        at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:147)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:230)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:270)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1147)
        ... 32 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:197)
        at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:255)
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:319)
        ... 38 more
  • 您应该将 server:port 的证书导入到 java JRE 密钥库,例如以下服务器和端口:

    serverAddress: myserver.mydomain.com
    serverPort: 443
    keystore password is default: changeit
    
  • 首先,在继续之前检查 $JAVA_HOME 和 java 可执行文件,你应该确定选择正确的 JAVA_HOME 进行导入,如果你有不同的:

    $ ~/bin$ echo $JAVA_HOME
    /opt/jdk
    $ ~/bin$ which java
    /usr/bin/java
    $ ~/bin$ ls -l /usr/bin/java
    lrwxrwxrwx 1 root root 22 May 10  2014 /usr/bin/java -> /etc/alternatives/java
    $ ~/bin$ ls -l /etc/alternatives/java
    lrwxrwxrwx 1 root root 17 Jun  6  2014 /etc/alternatives/java -> /opt/jdk/bin/java
    $ ~/bin$ java -version
    java version "1.8.0_05"
    Java(TM) SE Runtime Environment (build 1.8.0_05-b13)
    Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode)
    $ ~/bin$ `which java` -version
    java version "1.8.0_05"
    Java(TM) SE Runtime Environment (build 1.8.0_05-b13)
    Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode)
    $ ~/bin$   $JAVA_HOME/bin/java -version
    java version "1.8.0_05"
    Java(TM) SE Runtime Environment (build 1.8.0_05-b13)
    Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode)
    
  • 正在从服务器提取证书:

    $ openssl s_client -connect <serverAddress:serverPort> 2>&1 < "/" | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > /tmp/myserver.crt
    

    对于此示例,<serverAddress:serverPort> 应替换为 myserver.mydomain.com:443

  • 提取的文件应该如下所示:

    $ cat /tmp/myserver.crt
    -----BEGIN CERTIFICATE-----
    blahblahblahaC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCd
    ME22AKpyBPIRbTwTBedJz/KFtwCAxO2jXIcIob99LXv8W4KMOJgazn2UUBm/azZ1
    z+9qhq3UeIy8Z58WK2N5l/SI7s3+bkii/dnpW3Akw8OyXABnN1EyfwnL607POqXm
    blahblahblah
      ...Certificate Data is variable for each server address...
    blahblahblah
    blahblahblahT9p1jar2vxoHv3/dSwKoeLL8XpkmVx9oVUZ3XuICPvEmu8eBfOEm
    ZXNlYXJjaC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCd4I7L
    ME22AKpyBPIRbTwTBedJz/KFtwCAxO2jXIcIob99LXv8W4KMOJgazn2UUBm/azZ1
    -----END CERTIFICATE-----
    
  • 您需要将提取的证书导入 JRE 密钥库:

    $ keytool -import -alias myserverCert -file  /tmp/myserver.crt -keystore $JAVA_HOME/jre/lib/security/cacerts
    
  • 您可以在导入后检查 java JRE 密钥库中是否存在证书:

     $ keytool -list -keystore $JAVA_HOME/jre/lib/security/cacerts
    
  • java JRE 密钥库的默认密码是

    改变

  • 要应用更改,您需要重新启动 java JVM。

  • 完成后,如果您在非临时位置创建了临时文件,则可以将其删除:

    $ rm /tmp/myserver.crt