【问题标题】:Apache Http Client 4.0.1 SSL ProxyApache Http 客户端 4.0.1 SSL 代理
【发布时间】:2014-03-12 05:58:17
【问题描述】:

我正在使用 Apache Http 客户端 4.0.1 与服务器通信。我已经有一个可以正常工作的安全/非安全客户端代码。

最近新增的功能是为这段代码添加代理,所以我添加了以下代码来做到这一点(目前是非安全代理),

 HttpHost proxy = new HttpHost("localhost", 5555);
 httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);

对于非安全请求,这可以正常工作。但是,我在使用相同代码的安全 (https) 请求时遇到问题。

获取以下异常(它会在失败前尝试几次),

Mar 12, 2014 11:14:27 AM org.apache.http.impl.client.DefaultRequestDirector tryConnect
INFO: I/O exception (org.apache.http.NoHttpResponseException) caught when connecting to the target host: The target server failed to respond
Mar 12, 2014 11:14:27 AM org.apache.http.impl.client.DefaultRequestDirector tryConnect
INFO: Retrying connect
org.apache.http.NoHttpResponseException: The target server failed to respond
    at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:95)
    at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:62)
    at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:254)
    at org.apache.http.impl.AbstractHttpClientConnection.receiveResponseHeader(AbstractHttpClientConnection.java:289)
    at org.apache.http.impl.conn.DefaultClientConnection.receiveResponseHeader(DefaultClientConnection.java:252)
    at org.apache.http.impl.conn.ManagedClientConnectionImpl.receiveResponseHeader(ManagedClientConnectionImpl.java:191)
    at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:300)
    at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:127)
    at org.apache.http.impl.client.DefaultRequestDirector.createTunnelToTarget(DefaultRequestDirector.java:899)
    at org.apache.http.impl.client.DefaultRequestDirector.establishRoute(DefaultRequestDirector.java:818)
    at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:644)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:784)
    at com.poc.test.SSLTest.main(SSLTest.java:88)

尝试了以下事情,

  1. 对于 https 请求,我将“http”和“https”都添加到架构注册表中,使用与“https”相同的 SSLFactory。
  2. 将代理更改为, HttpHost 代理 = new HttpHost("localhost", 5555, "https");

但是在这两种情况下它都失败了,

javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
    at sun.security.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:397)
    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
    at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:572)
    at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
    at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:294)
    at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:640)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:784)
    at com.poc.test.SSLTest.main(SSLTest.java:89)

注意 - 我正在通过 tcpmon 在本地主机上运行非安全代理。

编辑:这是我用于 SSL 代理通信的代码,

DefaultHttpClient httpClient = new DefaultHttpClient();

try {
    SSLContext ctx = SSLContext.getInstance("TLSv1.1");
    TrustManager[] trustManagers = getTrustManagers("jks", new FileInputStream(new File("C:\\SSLKeyStore.ks")), "changeit");
    ctx.init(null, trustManagers, new SecureRandom());

    HttpGet httpget = new HttpGet("https://localhost:8844/Channels/HTTP/getData");
    System.out.println("executing request" + httpget.getRequestLine());

    SSLSocketFactory factory = new SSLSocketFactory(ctx);
    factory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

    ClientConnectionManager manager = httpClient.getConnectionManager();
    manager.getSchemeRegistry().register(new Scheme("https", 443, factory));
    manager.getSchemeRegistry().register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));

    HttpHost proxy = new HttpHost("localhost", 5555, "http");
    httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);

    HttpResponse response = httpClient.execute(httpget);
    HttpEntity entity = response.getEntity();

    System.out.println("----------------------------------------");
    System.out.println(response.getStatusLine());
    if (entity != null) {
        System.out.println("Response content length: " + entity.getContentLength());
    }
    EntityUtils.consume(entity);
} catch (Exception exception) {
    exception.printStackTrace();
} finally {
    httpClient.getConnectionManager().shutdown();
}

关于正在发生的事情的任何想法,我在 https 和代理方面缺少什么。

最新编辑 - 甚至按原样尝试了他们的示例代码 (ClientExecuteProxy.java),但代理也失败了。此功能是否损坏?

HttpHost proxy = new HttpHost("127.0.0.1", 8080, "http");

    DefaultHttpClient httpclient = new DefaultHttpClient();
    try {
        httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);

        HttpHost target = new HttpHost("issues.apache.org", 443, "https");
        HttpGet req = new HttpGet("/");

        System.out.println("executing request to " + target + " via " + proxy);
        HttpResponse rsp = httpclient.execute(target, req);
        HttpEntity entity = rsp.getEntity();

        System.out.println("----------------------------------------");
        System.out.println(rsp.getStatusLine());
        Header[] headers = rsp.getAllHeaders();
        for (int i = 0; i<headers.length; i++) {
            System.out.println(headers[i]);
        }
        System.out.println("----------------------------------------");

        if (entity != null) {
            System.out.println(EntityUtils.toString(entity));
        }

    } finally {
        // When HttpClient instance is no longer needed,
        // shut down the connection manager to ensure
        // immediate deallocation of all system resources
        httpclient.getConnectionManager().shutdown();
    }
}

谢谢, 维姬

【问题讨论】:

  • 伙计们,没有人使用/工作过这个?我也会在 Apache 论坛上发布这个。让我们希望有人可以提供一些指示。

标签: java apache ssl httpclient apache-httpclient-4.x


【解决方案1】:

我突然想说您正在处理证书信任问题。

虽然没有看到您具体是如何设置连接的,但我不能肯定地说。

“未通过身份验证的对等方”意味着在某处无法验证由一个或多个服务器提供的证书的验证。

编辑 由于代理在您的控制之下,您此时拥有很大的灵活性。

请参阅this SO article,它可能适合您的需求。

【讨论】:

  • 是的,我有一个通过 tcpmon 运行的不安全代理,所以那里不需要真正的安全检查。如果我删除代理片,呼叫成功。
  • 检查过之前的帖子,但找不到我的代码和link中提到的代码之间的区别
  • 好的,您发布的编辑内容 - 如果您正在代理 https-over-http,我看不到 tcpmon 将如何确定请求的内容。您已将目标主机设为 localhost/5555/http - 您将通过它发送加密数据。除非您已将 tcpmon 的代理配置为终止并退出 SSL 连接,否则它将无法查看内容。
  • 您能说明一下您使用的是哪个 TCPmon 吗? Apache 页面表明它不再受支持或正在积极开发中。我发现的替代方案可能是 Membrane membrane-soa.org/soap-monitor,它看起来支持 SSL。
  • 我正在使用 Apache TcpMon 的旧版本 (1.0) 之一。我知道它不再处于积极的开发或支持中。但是这个旧版本可以运行一个基本的非安全代理。我不需要这个代理来做任何类型的安全检查等。这个代理是否仍然需要确定我的请求内容,我的理解是它只会将它传递给最终目标服务器,即 https。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-30
相关资源
最近更新 更多