Apache HttpClient может обмениваться данными через HTTPS, когда DIRECT, но не через ошибку PROXY: javax.net.ssl.SSLPeerUnverifiedException: узел не аутентифицирован - PullRequest
2 голосов
/ 20 декабря 2011

Я прочитал много разных примеров, но в настоящее время у меня возникают трудности при попытке установить связь через прокси-сервер с использованием HTTPS. У меня есть оболочка для создания Apache HttpClient, как видно из кода ниже.

В настоящее время, если я позвоню без настройки прокси-сервера, он будет использовать мое хранилище доверенных сертификатов из SSLSocketFactory и правильно разрешит связь через SSL. Единственный требуемый сертификат - это сертификат сервера Verisign, который не требует аутентификации.

Когда я настраиваю прокси, я получаю сообщение об ошибке:

javax.net.ssl.SSLPeerUnverifiedException: одноранговый узел не аутентифицирован

Мне кажется, что мне не хватает какого-то типа настройки прокси, которая заставляет соединение прокси использовать тот же SSLSocketFactory?

Я протестировал с -Djavax.net.debug = ssl, и я могу видеть намного больше активности SSL при переходе прямо. Когда я использую Direct, я вижу все ключи, загруженные и отправленные с запросом, когда я использую прокси, я вижу только:

httpConnector.receiver.3, setSoTimeout(30000) called
%% No cached client session
*** ClientHello, TLSv1
RandomCookie:  GMT: 1307565311 bytes = { 184, 216, 5, 151, 154, 212, 232, 96, 69, 73, 240, 54, 236, 26, 8, 45, 109, 9, 192,
227, 193, 58, 129, 212, 57, 249, 205, 56 }
Session ID:  {}
Cipher Suites: [SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_C
BC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH
_3DES_EDE_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH
_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA
]
Compression Methods:  { 0 }
***
httpConnector.receiver.3, WRITE: TLSv1 Handshake, length = 73
httpConnector.receiver.3, WRITE: SSLv2 client hello message, length = 98
httpConnector.receiver.3, handling exception: javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
httpConnector.receiver.3, SEND TLSv1 ALERT:  fatal, description = unexpected_message
httpConnector.receiver.3, WRITE: TLSv1 Alert, length = 2
httpConnector.receiver.3, called closeSocket()
httpConnector.receiver.3, IOException in getSession():  javax.net.ssl.SSLException: Unrecognized SSL message, plaintext conn
ection?
httpConnector.receiver.3, called close()
httpConnector.receiver.3, called closeInternal(true)
httpConnector.receiver.3, called close()
httpConnector.receiver.3, called closeInternal(true)
2011-12-20 11:11:59,401 [httpConnector.receiver.3] INFO - The JavaScript method AddEvent threw an exception of type class co
m.alarmpoint.integrationagent.soap.exception.SOAPRequestException with message "javax.net.ssl.SSLPeerUnverifiedException: pe
er not authenticated".  The exception will be propogated up the call stack.

Может кто-нибудь помочь, пожалуйста. Вот мой код для настройки прокси и SSLSocketFactory.

var client = httpClientWrapper.getHttpClient();
var proxy = new HttpHost(PROXY_HOST, PROXY_PORT, "https"); 
client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy); 

var authpref = new ArrayList();
authpref.add(AuthPolicy.BASIC);

client.getParams().setParameter(AuthPNames.PROXY_AUTH_PREF, authpref);

ServiceAPI.getLogger().debug("KeyStore.getDefaultType() " + KeyStore.getDefaultType());


var trustStore  = KeyStore.getInstance(KeyStore.getDefaultType());        
var instream = new FileInputStream(new File("conf/my.truststore")); 
try {
ServiceAPI.getLogger().debug("getting trustore");
trustStore.load(instream, "changeit".split(''));
} finally {
instream.close();
}


var socketFactory = new SSLSocketFactory(trustStore);
var sch = new Scheme("https", socketFactory, 443);

client.getConnectionManager().getSchemeRegistry().register(sch);

Трассировка стека:

Caused by: javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
at com.sun.net.ssl.internal.ssl.SSLSessionImpl.getPeerCertificates(Unknown Source)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:390)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:488)
at org.apache.http.conn.scheme.SchemeSocketFactoryAdaptor.connectSocket(SchemeSocketFactoryAdaptor.java:62)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:148)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:149)
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:121)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:561)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:415)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:732)

Ответы [ 3 ]

3 голосов
/ 12 октября 2012

Вот вариант решения Аарона в Java (против Groovy). Это решение также позволяет избежать использования класса HttpClientWrapper (откуда это?) И напрямую загружает сертификат прокси. Он написан против HttpClient 4.2 (но я думаю, что он должен работать с 4.0). В качестве дополнительного бонуса он включает пример проверки подлинности прокси-сервера для Windows-прокси, такого как Microsoft ForeFront TMG.

Мне потребовалось достаточно много времени, чтобы собрать это воедино, и я решил поделиться этим:

    HttpParams params = new BasicHttpParams();
    DefaultHttpClient.setDefaultHttpParams( params );   // Add the default parameters to the parameter set we're building
    DefaultHttpClient client = new DefaultHttpClient( params );

    KeyStore trustStore = KeyStore.getInstance( KeyStore.getDefaultType() );
    trustStore.load( null );

    InputStream certStream = new FileInputStream( "cert-file" );
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    X509Certificate cert = (X509Certificate)cf.generateCertificate(certStream);
    certStream.close();
    trustStore.setCertificateEntry( "proxy-cert", cert );

    SSLSocketFactory socketFactory = new SSLSocketFactory(trustStore);
    client.getConnectionManager().getSchemeRegistry().register( new Scheme( "https", 443, socketFactory ));

    client.getParams().setParameter( ConnRoutePNames.DEFAULT_PROXY, 
                           new HttpHost( "my-proxy", 8080 ));

    // These 3 lines are only needed if your proxy is Windows based & requires authentication
    AuthScope scope = new AuthScope( "myproxy", 8080, null, AuthPolicy.NTLM );
    Credentials credentials = new NTCredentials( "username", "changeit", "WORKSTATION", "MY-DOMAIN" );
    client.getCredentialsProvider().setCredentials( scope, credentials );

    HttpGet get = new HttpGet( "https://mysite.com/resource" );
    String result = client.execute( get, new BasicResponseHandler() );

    System.out.println( result );
1 голос
/ 21 декабря 2011

Я решил это.Проблема, которую я обнаружил после отладки в коде HttpClients, заключалась в том, как был настроен мой прокси-сервер и доступна схема.

HttpRoute[{tls}->https://someproxy->https://some_endpoint:443]

Проблема заключалась в том, что прокси-сервер был настроен для схемы https, но фактически он работал на http.Это стало проблемой, когда оболочка не настроила схему http.В конце я создал SSLSocketFactory для своего склада доверенных сертификатов и схему http по умолчанию и правильно настроил свой прокси.

// Setup the Keystore and Schemes for the HttpClient and Proxy
var trustStore  = KeyStore.getInstance(KeyStore.getDefaultType());        
var instream = new FileInputStream(new File("conf/my.truststore")); 
try {
    trustStore.load(instream, "changeit".split(''));
} finally {
    instream.close();
}

var socketFactory = new SSLSocketFactory(trustStore);
var schHttp = new Scheme("http", PROXY_PORT, PlainSocketFactory.getSocketFactory());

// Create the HttpClient wrapper which will have the truststore SSLSocketFactory and a default http scheme and proxy setup 
httpClientWrapper = new HttpClientWrapper("some_endpoint", 443, "/", socketFactory);
var client = httpClientWrapper.getHttpClient();
var proxy = new HttpHost(PROXY_HOST, PROXY_PORT, "http"); 
client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);

client.getConnectionManager().getSchemeRegistry().register(schHttp);
0 голосов
/ 20 декабря 2011

Вы пытались использовать глобальный -Dhttp.proxyHost = proxy.host.com -Dhttp.proxyPort = 8080 при запуске процесса Java, чтобы убедиться, что SSLSocketFactory не возвращается к связи без прокси.

...