简体   繁体   English

使Apache HttpClient 4.3与sslSocketFactory / HostnameVerifier一起使用

[英]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.

相关问题 apache httpclient 4.4:HostnameVerifier从4.3.x过渡 - apache httpclient 4.4: HostnameVerifier transition from 4.3.x apache httpclient 4.3没有超时 - apache httpclient 4.3 not timing out 获取Apache httpconents HttpClient 4.3.x OSGi包以解决Apache Karaf 2.3.x的问题 - Problems with getting Apache httpcomponents HttpClient 4.3.x OSGi bundle to work on Apache Karaf 2.3.x HttpsURLConnectioin的行为以及HostnameVerifier和SSLSocketFactory的默认实现 - Behavior of HttpsURLConnectioin with default implementation of HostnameVerifier and SSLSocketFactory 如何使用Apache HttpClient 4.3处理Cookie - How to handle Cookies with Apache HttpClient 4.3 忽略 Apache HttpClient 4.3 中的 SSL 证书 - Ignoring SSL certificate in Apache HttpClient 4.3 Apache HttpClient 4.3 - 设置连接空闲超时 - Apache HttpClient 4.3 - setting connection idle timeout Apache HttpClient 4.3和x509客户端证书进行身份验证 - Apache HttpClient 4.3 and x509 client certificate to authenticate Apache HttpClient 4.3 SocketConfig.getSoTimeout()与RequestConfig.getSocketTimeout() - Apache HttpClient 4.3 SocketConfig.getSoTimeout() vs RequestConfig.getSocketTimeout() 迁移Apache Commons cookiePolicy到httpClient4.3的cookieSpec - migration apache commons cookiePolicy to cookieSpec of httpClient4.3
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM