Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ssl/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何使用相同的HttpClient实例选择客户端证书?_Java_Ssl_Ssl Certificate_Apache Httpclient 4.x_Truststore - Fatal编程技术网

Java 如何使用相同的HttpClient实例选择客户端证书?

Java 如何使用相同的HttpClient实例选择客户端证书?,java,ssl,ssl-certificate,apache-httpclient-4.x,truststore,Java,Ssl,Ssl Certificate,Apache Httpclient 4.x,Truststore,我有一个由多个客户端使用的应用程序(其中一个客户端具有客户端证书)。该应用程序应该通过HTTPS与web服务通信(使用HttpClient)。要在此web服务中进行身份验证,必须提供客户端证书。如前所述,每个客户端都有不同的客户端证书,我需要使用当前客户端的证书。我有下面的代码正在执行所描述的操作 X509TrustManager trustManager = new X509TrustManager() { public void checkClientTrusted(X509Cer

我有一个由多个客户端使用的应用程序(其中一个客户端具有客户端证书)。该应用程序应该通过HTTPS与web服务通信(使用HttpClient)。要在此web服务中进行身份验证,必须提供客户端证书。如前所述,每个客户端都有不同的客户端证书,我需要使用当前客户端的证书。我有下面的代码正在执行所描述的操作

X509TrustManager trustManager = new X509TrustManager() {

    public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
    }

    public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
    }

    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }
};
SSLContext sslcontext = SSLContext.getInstance("TLS");
KeyManager[] managers = /* Code that get the current client's KeyManager[] */;

sslcontext.init(managers, trustManager, null);
SSLSocketFactory socketFactory = new SSLSocketFactory(sslcontext);
socketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

HttpParams params = new BasicHttpParams();
params.setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, true);
HttpClient client = new DefaultHttpClient(params);
Scheme sch = new Scheme("https", socketFactory, 443);

client.getConnectionManager().getSchemeRegistry().register(sch);
HttpPost post = /* Code that get the POST */ 

HttpResponse response = client.execute(post, new BasicHttpContext());
好的,它起作用了。但是有很多线程向这个服务发送请求。有时它会给我带来一些问题。因此,我发现很多人都在说,最好每个应用程序只有一个HttpClient,而且可以这样做:

SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
schemeRegistry.register(new Scheme("https", 443, SSLSocketFactory.getSocketFactory()));

PoolingClientConnectionManager cm = new PoolingClientConnectionManager(schemeRegistry);
// Increase max total connection to 200
cm.setMaxTotal(200);
// Increase default max connection per route to 20
cm.setDefaultMaxPerRoute(20);
// Increase max connections for localhost:80 to 50
HttpHost localhost = new HttpHost("localhost", 80);
cm.setMaxPerRoute(new HttpRoute(localhost), 50);

httpClient = new DefaultHttpClient(cm, params);
这样我就有了一个带有连接池的HttpClient。但是如何使用这种方法并为特定请求选择客户端证书呢?提前谢谢

编辑:

我想解释一下我为什么要这么做。我们有时会遇到问题。服务器停止与web服务器的通信,过了一段时间,它又开始工作。需要注意的是,在调用webservice之前,有很多处理工作要做。因此,有一个池执行器,它创建线程来执行所有处理。作业完成后,该线程将创建另一个与Web服务通信的线程。因此,第一个线程通过超时(thread.join(timeout))连接第二个线程。当第一个线程唤醒时,如果还没有完成,它会中断尝试与Web服务通信的线程。我不是实现这个的人,但它应该给完成请求一个超时时间。 在我的开发机器中,我创建了一个JMeter测试,它模拟了许多使用此服务的客户机,并连接了JConsole以查看发生了什么。在完成300个任务(其中一些任务失败)后,由执行器池创建的线程死亡。但是很多线程仍然活着,10分钟后就死了。当我查看stacktrace时,我看到它与HttpClient相关。然后,我开始搜索,发现有人说最好对整个应用程序只使用一个HttpClient,使它能够汇集连接。 我认为HttpClient在搜索要连接的端口时被锁定,并且被第一个线程中断。然后,不知何故,它锁定了很长一段时间

编辑:

这就是我在JConsole中看到的。这次,我只启动了100个任务,有15个线程处于这种状态:

Name: Thread-228
State: RUNNABLE
Total blocked: 0  Total waited: 0

Stack trace: 
 java.net.SocketInputStream.socketRead0(Native Method)
java.net.SocketInputStream.read(SocketInputStream.java:129)
com.sun.net.ssl.internal.ssl.InputRecord.readFully(InputRecord.java:293)
com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:331)
com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:798)
   - locked java.lang.Object@7c1975
com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138)
   - locked java.lang.Object@16b53a6
com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1165)
com.sun.net.ssl.internal.ssl.SSLSocketImpl.getSession(SSLSocketImpl.java:1916)
org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:91)
org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:572)
org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:692)
org.apache.http.conn.scheme.SchemeSocketFactoryAdaptor.connectSocket(SchemeSocketFactoryAdaptor.java:65)
org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:294)
org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:640)
org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479)
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
sun.reflect.GeneratedMethodAccessor3671.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
java.lang.reflect.Method.invoke(Method.java:597)
org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoCachedMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:229)
org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:52)
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:128)
br.com.fibonacci.webservice.InvocacaoDeServico$_monteChamada_closure8.doCall(InvocacaoDeServico.groovy:441)
sun.reflect.GeneratedMethodAccessor3667.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
java.lang.reflect.Method.invoke(Method.java:597)
org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:266)
org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:51)
org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:150)
br.com.fibonacci.webservice.InvocacaoDeServico$_monteChamada_closure8.call(InvocacaoDeServico.groovy)
sun.reflect.GeneratedMethodAccessor3662.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
java.lang.reflect.Method.invoke(Method.java:597)
org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:266)
org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMetaMethodSite.java:63)
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
br.com.fibonacci.ChamadaComTimeout$_execute_closure1.doCall(ChamadaComTimeout.groovy:19)
sun.reflect.GeneratedMethodAccessor3657.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
java.lang.reflect.Method.invoke(Method.java:597)
org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:266)
org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:51)
org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:150)
br.com.fibonacci.ChamadaComTimeout$_execute_closure1.doCall(ChamadaComTimeout.groovy)
sun.reflect.GeneratedMethodAccessor3655.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
java.lang.reflect.Method.invoke(Method.java:597)
org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:234)
groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1061)
groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:910)
groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:892)
groovy.lang.Closure.call(Closure.java:279)
groovy.lang.Closure.call(Closure.java:274)
groovy.lang.Closure.run(Closure.java:355)
java.lang.Thread.run(Thread.java:662)

我认为这是不可能的,因为在我看来这毫无意义。
对纯文本重复使用连接是有意义的,但对经验证的加密连接来说,重复使用连接是没有意义的。

每个连接都属于一个用户,应该根据SSL参数终止,而不是在用户之间重复使用这些参数。

我找到了这篇解释我的问题的博文。它与HttpClient没有真正的联系。问题在于超时实现。

该代码容易受到MITM攻击。不要使用不执行类似操作的信任管理器(此外,
getAcceptedIssuers
应至少返回
new X509Certificate[0]
,而不是
null
)。不要使用允许任何内容通过的主机名进行验证。谢谢您的建议。我正在维护这个软件,它已经在做了。我没有SSL方面的经验。让一个客户端同时访问多个用户的凭据也没有什么意义。(我想这对于使用委托认证机制的服务器来说是有意义的。)谢谢你的回答,但是我在打开许多HttpClients时遇到了麻烦。我用JConsole验证了一些线程在HttpClient内部发生了一些异常,并且它们保持活动状态大约10分钟,直到服务器杀死它们。我发现这个问题建议只使用一个HttpClient。没有更好的多线程解决方案吗?