使用 SAAJ 从密钥库中选择特定的客户端证书
Selecting specific client certificate from keystore using SAAJ
我在 SAAJ 中编写了一个 Java 客户端,它在通过 HTTP 发送 SOAP 消息时成功运行,但是当我尝试通过 HTTPS 将任何 SOAP 消息发送到需要客户端证书的 Web 服务时,它不起作用。
在页面底部 link - SAAJ Security - 它声明如下:
从 SAAJ 端,您需要做的就是使用 URLs 和 HTTPS 作为协议。这仅在证书成功导入 /jre/lib/security/cacerts 时有效;否则 JSSE 将不允许连接
我按照上面的说明将客户端证书连同相关的根证书导入到我的 Java cacerts 和 运行 程序中,但是我收到以下错误:
java.net.SocketException: Connection reset
我 运行 对流量进行了 wireshark 跟踪,发现 Java 代码在服务器要求时没有提供客户端证书,因此我有以下问题:
1) 仅将 HTTPS URL 传递给 soapConnection.call() 方法并将证书导入我的 cacerts 文件,这是否足以进行身份验证,即 SAAJ 是否自动处理此问题?还是需要更多上述 link 中未描述的步骤?
2) 通过将证书导入我的 JAVA_HOME 中的 cacerts 文件,Java SAAJ 客户端在调用 soapConnection.call() 时是否自动知道要查看此处?或者我是否需要明确告诉我的代码要使用什么 cacerts 文件?
3) 如果 Java SAAJ 客户端自动使用我 JAVA_HOME 下的 cacerts 文件,那么它如何知道要使用哪个客户端证书?同样,我不需要明确编码还是 SAAJ 会自动处理它?
提前致谢
我设法解决了这个问题。我使用了以下代码:
static public void doTrustToCertificates() throws Exception
{
// Set truststore that contains root / intermediary certs
System.setProperty("javax.net.ssl.trustStore", "C:\cert\trusted.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
// Set keystore that contains private key
File pKeyFile = new File("C:\cert\privatekey.pfx");
String pKeyPassword = "Password01";
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
KeyStore keyStore = KeyStore.getInstance("PKCS12");
InputStream keyInput = new FileInputStream(pKeyFile);
keyStore.load(keyInput, pKeyPassword.toCharArray());
keyInput.close();
keyManagerFactory.init(keyStore, pKeyPassword.toCharArray());
// Set ssl context with private key and truststore details
SSLContext sc = SSLContext.getInstance("TLSv1");
sc.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());
SSLSocketFactory sockFact = sc.getSocketFactory();
// Add ssl context to https connection
HttpsURLConnection.setDefaultSSLSocketFactory(sockFact);
}
然后在 SAAJ 的 soapConnection.call() 方法之前调用 doTrustToCertificates() 方法,它的工作原理如下:
doTrustToCertificates();
SOAPMessage soapResponse = soapConnection.call(soapMsgXml, ENDPOINT_URL);
你没听懂。说明有误导性,但只适用于服务器证书自签名的情况,根本不适用于客户端需要证书的情况。
在这种情况下,您需要在客户端的 keystore 中创建客户端证书。您要么创建一个 CSR 并对其进行签名,然后使用与生成密钥对和 CSR 时使用的别名相同的别名将其导入回同一个密钥库,要么您需要生成一个自签名证书(糟糕)并将其导出并将其导入 服务器的 信任库。
您不需要编写任何代码。您需要做的就是设置系统属性 javax.net.ssl.keyStore
和朋友告诉 JSSE 关于您的客户端密钥库。
我在 SAAJ 中编写了一个 Java 客户端,它在通过 HTTP 发送 SOAP 消息时成功运行,但是当我尝试通过 HTTPS 将任何 SOAP 消息发送到需要客户端证书的 Web 服务时,它不起作用。
在页面底部 link - SAAJ Security - 它声明如下:
从 SAAJ 端,您需要做的就是使用 URLs 和 HTTPS 作为协议。这仅在证书成功导入 /jre/lib/security/cacerts 时有效;否则 JSSE 将不允许连接
我按照上面的说明将客户端证书连同相关的根证书导入到我的 Java cacerts 和 运行 程序中,但是我收到以下错误:
java.net.SocketException: Connection reset
我 运行 对流量进行了 wireshark 跟踪,发现 Java 代码在服务器要求时没有提供客户端证书,因此我有以下问题:
1) 仅将 HTTPS URL 传递给 soapConnection.call() 方法并将证书导入我的 cacerts 文件,这是否足以进行身份验证,即 SAAJ 是否自动处理此问题?还是需要更多上述 link 中未描述的步骤?
2) 通过将证书导入我的 JAVA_HOME 中的 cacerts 文件,Java SAAJ 客户端在调用 soapConnection.call() 时是否自动知道要查看此处?或者我是否需要明确告诉我的代码要使用什么 cacerts 文件?
3) 如果 Java SAAJ 客户端自动使用我 JAVA_HOME 下的 cacerts 文件,那么它如何知道要使用哪个客户端证书?同样,我不需要明确编码还是 SAAJ 会自动处理它?
提前致谢
我设法解决了这个问题。我使用了以下代码:
static public void doTrustToCertificates() throws Exception
{
// Set truststore that contains root / intermediary certs
System.setProperty("javax.net.ssl.trustStore", "C:\cert\trusted.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
// Set keystore that contains private key
File pKeyFile = new File("C:\cert\privatekey.pfx");
String pKeyPassword = "Password01";
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
KeyStore keyStore = KeyStore.getInstance("PKCS12");
InputStream keyInput = new FileInputStream(pKeyFile);
keyStore.load(keyInput, pKeyPassword.toCharArray());
keyInput.close();
keyManagerFactory.init(keyStore, pKeyPassword.toCharArray());
// Set ssl context with private key and truststore details
SSLContext sc = SSLContext.getInstance("TLSv1");
sc.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());
SSLSocketFactory sockFact = sc.getSocketFactory();
// Add ssl context to https connection
HttpsURLConnection.setDefaultSSLSocketFactory(sockFact);
}
然后在 SAAJ 的 soapConnection.call() 方法之前调用 doTrustToCertificates() 方法,它的工作原理如下:
doTrustToCertificates();
SOAPMessage soapResponse = soapConnection.call(soapMsgXml, ENDPOINT_URL);
你没听懂。说明有误导性,但只适用于服务器证书自签名的情况,根本不适用于客户端需要证书的情况。
在这种情况下,您需要在客户端的 keystore 中创建客户端证书。您要么创建一个 CSR 并对其进行签名,然后使用与生成密钥对和 CSR 时使用的别名相同的别名将其导入回同一个密钥库,要么您需要生成一个自签名证书(糟糕)并将其导出并将其导入 服务器的 信任库。
您不需要编写任何代码。您需要做的就是设置系统属性 javax.net.ssl.keyStore
和朋友告诉 JSSE 关于您的客户端密钥库。