我尝试在java 6u45上使用URLConnection进行客户端证书身份验证,它返回400个HTTP代码,但是当我使用java 7u25构建它时,它工作正常并返回OK 200。
当我尝试Apache HttpPost时,它为6u45和7u25都提供400错误。
C:\java\test>"C:\Program Files (x86)\Java\jdk1.6.0_45\bin\javac" Test.java -cp ".;lib/*"
C:\java\test>"C:\Program Files (x86)\Java\jdk1.6.0_45\bin\java" -cp ".;lib/*" Test
Response Code 1: 400
Response Code 2: 400
C:\java\test>"C:\Program Files (x86)\Java\jdk1.7.0_25\bin\javac" Test.java -cp ".;lib/*"
C:\java\test>"C:\Program Files (x86)\Java\jdk1.7.0_25\bin\java" -cp ".;lib/*" Test
Response Code 1: 200
Response Code 2: 400
我相信至少使用Apache HttpPost很容易让它在java 6上运行,但是我做错了。
我的测试代码如下:
import java.io.*;
import java.net.*;
import java.security.*;
import javax.net.ssl.*;
import org.apache.http.*;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.scheme.*;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.BasicClientConnectionManager;
import org.apache.http.params.*;
import org.apache.http.entity.StringEntity;
public class Test {
public static void main(String[] args) {
String keyStorePath = "C:\\java\\keys\\client_certificate.p12";
String keyStorePass = "someKeyStorePass";
String trustStorePath = "C:\\java\\keys\\truststore.jks";
String trustStorePass = "someTrustStorePath";
String postData = "<request></request>";
String url = "https://api.some-url.com/v2";
SSLContext sslContext = GetSSLContext(keyStorePath, keyStorePass, trustStorePath, trustStorePass);
PostData1(postData, url, sslContext);
SchemeRegistry schemeRegistry = GetSchemeRegistry(keyStorePath, keyStorePass, trustStorePath, trustStorePass);
PostData2(postData, url, schemeRegistry);
}
public static void PostData1(String dataToPost, String serviceUrl, SSLContext sslContext) {
try {
URL url = new URL(serviceUrl);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
HttpsURLConnection urlConn = (HttpsURLConnection)url.openConnection();
urlConn.setDoOutput(true);
urlConn.setDoInput(true);
urlConn.setUseCaches(false);
urlConn.setRequestMethod("POST");
urlConn.setRequestProperty("Content-Type", "application/xml");
urlConn.connect();
PrintWriter out = new PrintWriter(urlConn.getOutputStream());
out.println(dataToPost);
out.close();
System.out.println("Response Code 1: " + urlConn.getResponseCode());
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void PostData2(String dataToPost, String serviceUrl, SchemeRegistry schemeRegistry) {
try {
HttpParams httpParams = new BasicHttpParams();
DefaultHttpClient httpClient = new DefaultHttpClient(new BasicClientConnectionManager(schemeRegistry), httpParams);
HttpPost httpPost = new HttpPost(serviceUrl);
HttpEntity lEntity = new StringEntity(dataToPost, "UTF-8");
httpPost.setEntity(lEntity);
HttpResponse response = httpClient.execute(httpPost);
try {
System.out.println("Response Code 2: " + response.getStatusLine().getStatusCode());
} finally {
httpPost.releaseConnection();
}
httpClient.getConnectionManager().shutdown();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static SSLContext GetSSLContext(String clientStorePath, String clientStorePass, String trustStorePath, String trustStorePass) {
SSLContext sslContext = null;
try {
KeyStore clientStore = KeyStore.getInstance("PKCS12");
clientStore.load(new FileInputStream(clientStorePath), clientStorePass.toCharArray());
KeyManagerFactory kmf =KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(clientStore, clientStorePass.toCharArray());
KeyManager[] kms = kmf.getKeyManagers();
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(new FileInputStream(trustStorePath), trustStorePass.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
TrustManager[] tms = tmf.getTrustManagers();
sslContext = SSLContext.getInstance("TLS");
sslContext.init(kms, tms, new SecureRandom());
} catch (Exception ex) {
ex.printStackTrace();
}
return sslContext;
}
public static SchemeRegistry GetSchemeRegistry(String clientStorePath, String clientStorePass, String trustStorePath, String trustStorePass) {
final SchemeRegistry schemeRegistry = new SchemeRegistry();
try {
KeyStore clientStore = KeyStore.getInstance("PKCS12");
clientStore.load(new FileInputStream(clientStorePath), clientStorePass.toCharArray());
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(new FileInputStream(trustStorePath), trustStorePass.toCharArray());
schemeRegistry.register(new Scheme("https", 443, new SSLSocketFactory(clientStore, clientStorePass, trustStore)));
} catch (Exception ex) {
ex.printStackTrace();
}
return schemeRegistry;
}
}
答案 0 :(得分:1)
在对HTTPS协议流量进行深入调查后,我发现Java 6不支持SNI,并且此功能仅在Java 7中添加。
我的Nginx服务器在同一个IP上有几个HTTPS VirtualHosts,因为Java 6没有传递确切的主机名,所以返回了默认主机。
要解决此问题,您只需将具有客户端身份验证的VirtualHost标记为默认值:
listen xxx.xxx.xxx.xxx:443 default;