[英]Making Apache HttpClient 4.3 work with sslSocketFactory/HostnameVerifier
I'm working on a Java program that will send POST requests to a website for my company to use. 我正在开发一个Java程序,该程序会将POST请求发送到网站供我的公司使用。 We do not own this website, they are separate from us. 我们不拥有此网站,它们与我们分开。 I've been fighting with various ways to actually pass it the very picky parameters it wants in order for me to do work on it from a program (as opposed to doing it manually). 我一直在努力通过各种方式来实际传递它想要的非常挑剔的参数,以便我可以从程序中进行处理(而不是手动进行处理)。
I've found that the Apache HttpClient 4.3 seems to be my best route for actually trying to access it, anything results in a angry response from the website telling me my username and password and not valid/authorized. 我发现Apache HttpClient 4.3似乎是我实际尝试访问它的最佳途径,任何事情都会导致网站愤怒地告诉我我的用户名和密码,并且无效/未授权。
But then I got an error because the site certificate doesn't match, I contacted their support and they reportedly share an infrastructure with another site so the certificate mismatch is expected. 但是随后我得到了一个错误,因为站点证书不匹配,我联系了他们的支持人员,据说他们与另一个站点共享一个基础结构,因此可能会出现证书不匹配的情况。
So I went commandline and generated a keystore, passed that to the program and then got the error "java.security.cert.CertificateException: No subject alternative DNS name matching". 因此,我进入命令行并生成了一个密钥库,将该密钥库传递给程序,然后得到错误“ java.security.cert.CertificateException:没有主题备用DNS名称匹配”。
Some hunting lead me to utilize a verifier, which removed errors. 一些狩猎使我使用了验证程序,从而消除了错误。
Then I realized that I can't make URLConnection/HttpsURLConnection and HttpClient/HttpPost work together. 然后我意识到我无法使URLConnection / HttpsURLConnection和HttpClient / HttpPost一起工作。 That's where I'm stuck. 那就是我被困住的地方。 I'm not sure how to make the code that handles my keystore, TrustManager, SSLSocketFactory, etc connect to the part where I actually have to connect and POST. 我不确定如何使处理我的密钥库,TrustManager,SSLSocketFactory等的代码连接到我实际必须连接和POST的部分。
Code that handles the certificates and verification: 处理证书和验证的代码:
InputStream in = new FileInputStream(new File("C:\\Program Files (x86)\\Java\\jre7\\bin\\my.keystore"));
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(in, "blahblah".toCharArray());
in.close(); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
X509TrustManager defaultTrustManager = (X509TrustManager)tmf.getTrustManagers()[0];
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new TrustManager[] {defaultTrustManager}, null);
javax.net.ssl.SSLSocketFactory sslSocketFactory = context.getSocketFactory();
URL url = new URL("https://emailer.driveclick.com/dbadmin/xml_post.pl");
URLConnection con = url.openConnection();
((HttpsURLConnection) con).setSSLSocketFactory(sslSocketFactory);
((HttpsURLConnection) con).setHostnameVerifier(new Verifier());
con.connect();
in = con.getInputStream();
Code that should be connecting me to the website: 应该将我连接到网站的代码:
try {
//log into the website
String url2 = "https://emailer.driveclick.com/dbadmin/xml_post.pl";
HttpClient client = HttpClientBuilder.create().build();
HttpPost post = new HttpPost(url2);
post.setHeader("User-Agent", USER_AGENT);
List<BasicNameValuePair> urlParameters = new ArrayList<>();
urlParameters.add(new BasicNameValuePair("username", "namefoo"));
urlParameters.add(new BasicNameValuePair("api_password", "passfoo"));
post.setEntity(new UrlEncodedFormEntity(urlParameters));
org.apache.http.HttpResponse response = client.execute(post);
System.out.println("\nSending 'POST' request to URL : " + url2);
System.out.println("Post parameters : " + post.getEntity());
System.out.println("Response Code : " + response.getStatusLine().getStatusCode());
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer result = new StringBuffer();
String line = "";
while ((line = rd.readLine()) != null)
{
result.append(line);
}
System.out.println(result.toString());
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(LastFileMove.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(LastFileMove.class.getName()).log(Level.SEVERE, null, ex);
}
EDIT: I forgot to include the little class I made for the Verifier that I referenced. 编辑:我忘了包括我为我参考的验证程序制作的小类。
public class Verifier implements HostnameVerifier
{
public boolean verify(String arg0, SSLSession arg1) {
return true; // mark everything as verified
}
}
Update 5/8/2014 SSLConext and Verifier are now set up like this: 更新5/8/2014 SSLConext和Verifier的设置如下:
SSLContext sslContext = SSLContexts.custom()
.useTLS()
.loadTrustMaterial(ks)
.build();
X509HostnameVerifier verifier = new AbstractVerifier()
{
@Override
public void verify(final String host, final String[]
cns, final String[] subjectAlts) throws SSLException
{
verify(host, cns, subjectAlts, true);
}
};
And I've gone ahead and changed my HttpClient to a closeable one here: 我继续将HttpClient更改为此处的可关闭地址:
CloseableHttpClient client = HttpClients.custom()
sslSocketFactory)
.setHostnameVerifier(verifier)
.setSslcontext(sslContext)
.build();
And I'm back to having "javax.net.ssl.SSLException: hostname in certificate didn't match" errors. 我又回到了“ javax.net.ssl.SSLException:证书中的主机名不匹配”的错误。 Suggestions? 有什么建议吗?
I have no idea how Verifier
is implemented but this code snippet demonstrates how one can create a custom hostname verifier none of those shipped with HttpClient fits their needs 我不知道如何实现Verifier
,但是此代码段演示了如何创建自定义主机名验证程序,而HttpClient附带的这些验证程序都不符合他们的需求
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream in = new FileInputStream(new File("C:\\Program Files (x86)\\Java\\jre7\\bin\\my.keystore"));
try {
ks.load(in, "blahblah".toCharArray());
} finally {
in.close();
}
SSLContext sslContext = SSLContexts.custom()
.useTLS()
.loadTrustMaterial(ks)
.build();
X509HostnameVerifier verifier = new AbstractVerifier() {
@Override
public void verify(final String host, final String[] cns, final String[] subjectAlts) throws SSLException {
verify(host, cns, subjectAlts, true);
}
};
CloseableHttpClient hc = HttpClients.custom()
.setSslcontext(sslContext)
.setHostnameVerifier(verifier)
.build();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.