【发布时间】:2017-08-13 07:58:00
【问题描述】:
我有一个 java webapp,它使用此类通过基本身份验证和证书连接到服务器。它单独工作正常(无需创建其他 url 连接):
public void connectCert(String jsonParams) {
try {
KeyStore clientStore = KeyStore.getInstance("PKCS12");
clientStore.load(new FileInputStream("d:\\certs\\api\\xx.p12"), "W*53as_G".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(clientStore, "W*53as_G".toCharArray());
KeyManager[] kms = kmf.getKeyManagers();
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(new FileInputStream("c:\\jdk1.8.0_51\\jre\\lib\\security\\cacerts"), "changeit".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
TrustManager[] tms = tmf.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(kms, tms, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
URL url = new URL("https://apis2s.ee/test");
HttpsURLConnection urlConn = (HttpsURLConnection) url.openConnection();
urlConn.setRequestProperty("Authorization", "Basic " + Base64.encode("andrey:pass_1".getBytes()));
urlConn.setUseCaches(false);
urlConn.setAllowUserInteraction(true);
urlConn.setRequestProperty("Pragma", "no-cache");
urlConn.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
urlConn.setRequestProperty("Content-length", Integer.toString(jsonParams.length()));
urlConn.setDoOutput(true);
urlConn.setRequestProperty("Content-Length", Integer.toString(jsonParams.length()));
PrintStream out = new PrintStream(urlConn.getOutputStream());
out.print(jsonParams);
out.flush();
out.close();
StringBuilder builder = new StringBuilder();
int responseCode = urlConn.getResponseCode();
builder.append(responseCode).append(" ").append(urlConn.getResponseMessage()).append("\n");
InputStream inputStream = null;
if (responseCode == 200) inputStream = urlConn.getInputStream();
else inputStream = urlConn.getErrorStream();//this returns 400
Scanner in = new Scanner(inputStream);
String responseStr = "";
while (in.hasNextLine()) {
String str = in.nextLine();
responseStr += str;
}
System.out.println(builder);
System.out.println("responseStr: " + responseStr);
} catch (Exception e) {
}
}
我还需要在我的 webapp 中使用基本身份验证(无证书)创建与另一台服务器的连接:
private InputStream connectHTTPS(String loginData, String url, String params) {
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) {
}
public boolean isClientTrusted(java.security.cert.X509Certificate[] certs) {
return true;
}
public boolean isServerTrusted(java.security.cert.X509Certificate[] certs) {
return true;
}
}};
HostnameVerifier verifier = new HostnameVerifier() {
public boolean verify(String string, SSLSession sSLSession) {
return true;
}
public boolean verify(String string, String string2) {
return true;
}
};
SSLContext sc = null;
try{
sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(verifier);
}catch(Exception e){
e.printStackTrace();
}
javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(verifier);
URL serverURL = null;
try{
serverURL = new URL(null,url,new sun.net.www.protocol.https.Handler());
}catch (Exception e){
e.printStackTrace();
}
javax.net.ssl.HttpsURLConnection urlConn = null;
try{
urlConn = (javax.net.ssl.HttpsURLConnection)serverURL.openConnection();
urlConn.setSSLSocketFactory(sc.getSocketFactory());
urlConn.setRequestMethod("POST");
}catch(Exception i){
i.printStackTrace();
}
InputStream res = null;
urlConn.setDoOutput(true);
if(useLogin)
urlConn.setRequestProperty("Authorization", "Basic " + loginData);
urlConn.setUseCaches(false);
urlConn.setAllowUserInteraction(true);
urlConn.setRequestProperty("Pragma", "no-cache");
urlConn.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
urlConn.setRequestProperty("Content-length", Integer.toString(params.length()));
try{
PrintStream out = new PrintStream(urlConn.getOutputStream());
out.print(params);
out.flush();
out.close();
res = urlConn.getInputStream();
}catch(Exception o){
o.printStackTrace();
}
return res;
}
如果 在 connectCert() 之前调用了 connectHTTPS() 那么我得到
<html><head><title>400 No required SSL certificate was sent</title></head><body
bgcolor="white"><center><h1>400 Bad Request</h1></center><center>No required SSL certificate was sent</center><hr><center>nginx</center></body></html>
如何解决一个 web 应用中的两个连接的证书问题?
【问题讨论】:
-
什么方法导致显示的错误,connectHTTPS 或 connectCert?
-
connectCert() 导致此块中显示的错误(我稍微编辑了代码) if (responseCode == 200) inputStream = urlConn.getInputStream(); else inputStream = urlConn.getErrorStream();//这个返回400
-
似乎connectHttps的某些配置干扰了connectCert。我建议删除所有静态配置。例如,在 connectCert 中将
HttpsURLConnection.setDefaultHostnameVerifier更改为 urlConn.setHostnameVerifier. CallurlConn.setSSLSocketFactory 。同时添加-Djavax.net.debug = all调试SSL连接
标签: java authentication certificate httpurlconnection basic-authentication