使用Java URL类,我可以连接到外部HTTPS
服务器(例如我们的生产站点),但是使用本地URL我会得到以下异常。
"SunCertPathBuilderException: unable to find valid certification path to requested target".
如何获得有效的认证路径?
编辑:我没有使用此网址直接创建连接,我将网址传递给itext
PDFReader
,然后发生连接问题。
答案 0 :(得分:13)
这是我的解决方案,它结合了这个主题中的一些想法,并与来自网络的代码一起调整。 所有我都调用此函数,它为HttpsURLConnection设置默认的Trust Manager和HostName Verifier。这对某些人来说可能是不受欢迎的,因为它会影响所有HttpsURLConnections,但我只是编写一个简单的代理,因此它对我有用。
private void setTrustAllCerts() throws Exception
{
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted( java.security.cert.X509Certificate[] certs, String authType ) { }
public void checkServerTrusted( java.security.cert.X509Certificate[] certs, String authType ) { }
}
};
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance( "SSL" );
sc.init( null, trustAllCerts, new java.security.SecureRandom() );
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(
new HostnameVerifier() {
public boolean verify(String urlHostName, SSLSession session) {
return true;
}
});
}
catch ( Exception e ) {
//We can not recover from this exception.
e.printStackTrace();
}
}
答案 1 :(得分:3)
您可能需要设置HostnameVerifier
。在连接之前,您需要将其添加到连接对象
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
// check hostname/session
return true;
}
});
conn.connect();
// read/write...
如果你需要的话,肯定有一些实现。您可能也想查看HttpClient项目。
答案 2 :(得分:3)
要看的另一件事是你正在使用的TrustManager
。该错误消息表明服务器提供的证书未由受信任的根签名。由于您无法直接控制所创建的SSL套接字,因此我认为您最好的选择是initialize您自己的SSLContext
TrustManager
已setup with the root CA服务器的证书链。然后将此上下文设置为default。
这假设您使用的是Java 6.在Java 5中,API更受限制。您可以获得默认的SSLSocketFactory
,但没有标准的方法来设置它。
答案 3 :(得分:0)
它抱怨的问题是,当您创建SSL连接时,服务器必须向客户端提供有效的证书。你可以用Java编写一个合适的端点(我认为HTTPServerSocket会这样做)但是需要一些黑客来设置它。使用正确处理SSL的任何东西(Apache,lighttp等)设置本地Web服务器可能更容易 - 并使用openssl工具创建自签名证书。
更新这是Java Almanac的一个例子。 http://www.exampledepot.com/egs/javax.net.ssl/Server.html
SSL服务器套接字需要将发送给客户端进行身份验证的证书。证书必须包含在必须明确指定其位置的密钥库中(没有默认值)。在该示例之后,我们描述了如何为要使用的SSL服务器套接字创建和指定密钥库。
try {
int port = 443;
ServerSocketFactory ssocketFactory = SSLServerSocketFactory.getDefault();
ServerSocket ssocket = ssocketFactory.createServerSocket(port);
// Listen for connections
Socket socket = ssocket.accept();
// Create streams to securely send and receive data to the client
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
// Read from in and write to out...
// Close the socket
in.close();
out.close();
} catch(IOException e) {
}
使用javax.net.ssl.keyStore系统属性指定证书的密钥库:
> java -Djavax.net.ssl.keyStore=mySrvKeystore -Djavax.net.ssl.keyStorePassword=123456 MyServer
答案 4 :(得分:0)
它还可以帮助您将本地主机服务器正在使用的证书(我假设它是自签名的)添加到JVM的keystore,using the "keytool" utility。这应该会告诉JVM“你可以信任这个证书”。
答案 5 :(得分:0)
我最终运行了一个静态方法(仅在dev上),它安装了一个非常信任的TrustManager(接受所有内容),并且还添加了一个始终返回true的hostnameVerifier(感谢sblundy)。