请查看此问题的底部以获取更多最新信息
我试图通过我的Jersey客户端拦截所有SSL握手(以便我可以获取有关它们的信息以及向用户呈现视觉信息,就像浏览器中的绿色锁定一样)。不幸的是,看起来Jersey似乎没有使用我的SSLSocketFactory实现,因为没有调用任何createSocket方法。没有错误发生,只是没有任何记录。代码应该清楚:
调用+实例化:
this.httpClient = getHttpsClient(new DefaultSSLContextProvider());
Invocation.Builder invBuilder = httpClient.target(API_URL_PRIVATE + API_VERSION_2 + "markets").request(MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN, MediaType.TEXT_HTML);
invBuilder.header("Content-Type", "application/x-www-form-urlencoded");
invBuilder.header("User-Agent", USER_AGENT);
Response response = invBuilder.get();
logger.debug("response: " + response);
的HttpClient:
public Client getHttpsClient(SSLContextProvider sslContextProvider) throws KeyStoreException
{
ClientConfig config = new ClientConfig().connectorProvider(new HttpUrlConnectorProvider().connectionFactory(
url ->
{
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setSSLSocketFactory(sslContextProvider.getSSLSocketFactory());
return connection;
}));
return ClientBuilder.newBuilder()
.sslContext(sslContextProvider.getSSLContext())
.withConfig(config)
.build();
}
DefaultSSLContextProvider:
public class DefaultSSLContextProvider implements SSLContextProvider
{
private SSLContext sslContext;
private ObservableSSLSocketFactory observableSSLSocketFactory;
private static final Logger logger = LoggerFactory.getLogger(DefaultSSLContextProvider.class);
public DefaultSSLContextProvider()
{
try
{
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");
sslContext = SSLContext.getInstance("SSL");
KeyStore keyStore = getKeyStore();
trustManagerFactory.init(keyStore);
sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
observableSSLSocketFactory = new ObservableSSLSocketFactory(sslContext);
HttpsURLConnection.setDefaultSSLSocketFactory(observableSSLSocketFactory);
SSLContext.setDefault(sslContext);
}
catch (NoSuchAlgorithmException e)
{
throw new RuntimeException(e);
}
catch (KeyManagementException | KeyStoreException e)
{
logger.error("could not create DefaultSSLContextProvider", e);
throw new IllegalStateException(e);
}
}
@Override
public SSLContext getSSLContext()
{
return sslContext;
}
@Override
public SSLSocketFactory getSSLSocketFactory()
{
return observableSSLSocketFactory;
}
@Override
public KeyStore getKeyStore()
{
// snip
}
}
ObservableSSLSocketFactory:
/**
* Based heavily on:
* http://stackoverflow.com/a/23365536/3634630
*/
public class ObservableSSLSocketFactory extends SSLSocketFactory
{
private final SSLContext sslContext;
private final String[] preferredCipherSuites;
private final String[] preferredProtocols;
private static final Logger logger = LoggerFactory.getLogger(ObservableSSLSocketFactory.class);
protected ObservableSSLSocketFactory(SSLContext sslContext)
{
logger.debug("CREATING OBSERVABLE SOCKET FACTORY!");
this.sslContext = sslContext;
preferredCipherSuites = getCiphers();
preferredProtocols = getProtocols();
logger.debug("Observable socket factory created");
logger.debug("preferredCipherSuites: " + preferredCipherSuites);
logger.debug("preferredProcotols: " + preferredProtocols);
}
@Override
public String[] getDefaultCipherSuites()
{
return preferredCipherSuites;
}
@Override
public String[] getSupportedCipherSuites()
{
return preferredCipherSuites;
}
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException
{
logger.debug("creating ssl socket");
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(s, host, port, autoClose);
sslSocket.addHandshakeCompletedListener(new HandshakeListener());
sslSocket.setEnabledProtocols(preferredProtocols);
sslSocket.setEnabledCipherSuites(preferredCipherSuites);
return sslSocket;
}
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException
{
logger.debug("creating ssl socket");
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(address, port, localAddress, localPort);
sslSocket.addHandshakeCompletedListener(new HandshakeListener());
sslSocket.setEnabledProtocols(preferredProtocols);
sslSocket.setEnabledCipherSuites(preferredCipherSuites);
return sslSocket;
}
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException
{
logger.debug("creating ssl socket");
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
SSLSocket sslSocket = (SSLSocket)sslSocketFactory.createSocket(host, port, localHost, localPort);
sslSocket.addHandshakeCompletedListener(new HandshakeListener());
sslSocket.setEnabledProtocols(preferredProtocols);
sslSocket.setEnabledCipherSuites(preferredCipherSuites);
return sslSocket;
}
public Socket createSocket(InetAddress host, int port) throws IOException
{
logger.debug("creating ssl socket");
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
SSLSocket sslSocket = (SSLSocket)sslSocketFactory.createSocket(host, port);
sslSocket.addHandshakeCompletedListener(new HandshakeListener());
sslSocket.setEnabledProtocols(preferredProtocols);
sslSocket.setEnabledCipherSuites(preferredCipherSuites);
return sslSocket;
}
public Socket createSocket(String host, int port) throws IOException
{
logger.debug("creating ssl socket");
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
SSLSocket sslSocket = (SSLSocket)sslSocketFactory.createSocket(host, port);
sslSocket.addHandshakeCompletedListener(new HandshakeListener());
sslSocket.setEnabledProtocols(preferredProtocols);
sslSocket.setEnabledCipherSuites(preferredCipherSuites);
return sslSocket;
}
private String[] getProtocols()
{
// snip
}
private String[] getCiphers()
{
// snip
}
class HandshakeListener implements HandshakeCompletedListener
{
public HandshakeListener()
{
logger.debug("Created new HandshakeListener");
}
public void handshakeCompleted(HandshakeCompletedEvent e)
{
logger.debug("Handshake successful!");
logger.debug("using cipher suite: " + e.getCipherSuite());
}
}
}
正如我所说,没有异常或错误发生(事实上原始请求没有问题(HTTP 200),但是记录的唯一内容是:
00:01:37.867 DEBUG [ObservableSSLSocketFactory] CREATING OBSERVABLE SOCKET FACTORY!
00:01:38.072 DEBUG [ObservableSSLSocketFactory] Observable socket factory created
00:01:38.073 DEBUG [ObservableSSLSocketFactory] preferredCipherSuites: [TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
00:01:38.073 DEBUG [ObservableSSLSocketFactory] preferredProcotols: [TLSv1, TLSv1.1, TLSv1.2]
00:01:39.435 DEBUG [Exchange] response: InboundJaxrsResponse{context=ClientResponse{method=GET, uri=https://www.bitstamp.net/api/order_book/, status=200, reason=OK}}
来自createSocket()
的任何内容或HandshakeCompletedListener。
非常感谢任何帮助。
更新1: 我添加了一些额外的日志声明,情况确实很奇怪。 Jersey客户端实际上正在调用HttpUrlConnectorProvider实现,实际上在连接上设置了ObservableSSLSocketFactory的实例,看来当在HttpsURLConnection上调用connect方法时,它不会使用套接字工厂。
更新2: 我发现了old bug标题为:" HttpsURLConnection没有使用set SSLSocketFactory来创建它的所有套接字"。这似乎是我的确切问题。据说这个bug在JDK7中有所修复。我正在使用(如上所述)8u60,这已经超出了这个bug被修复的时间。我很困惑。我发现java参数-Djavax.net.debug = all并设置它 - 我没有看到任何错误或任何不合适的地方,似乎HttpsUrlConnection没有使用它上面的SSLSocketFactory设置。
更新3: 在#java @ irc.freenode.net上接受了wyvern的建议,我决定使用apache-connector而不是JDK HttpsUrlConnection连接器,最后经过一些涂抹和哄骗后,我看到了:
[HandshakeCompletedNotify-Thread][ObservableSSLConnectionSocketFactory] Handshake successful!
所以,我想我已经准备好了然后=)。
答案 0 :(得分:-1)
在进行SSL握手之前,请确保客户端和服务在服务器(客户端和服务)上都安装了正确的证书。有关SSLFactory实现的信息,请参阅网址:http://www.programcreek.com/java-api-examples/index.php?api=javax.net.ssl.SSLSocketFactory