查看此问题的底部以获取更多最新信息

我试图拦截所有通过我的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的ojit_a:“HttpsURLConnection没有使用set SSLSocketFactory来创建其所有套接字”。这似乎是我的确切问题。据说此错误已在JDK7中修复。我正在使用(如前所述)8u60,这已经远远超过了修复该错误的时间。我很困惑。我找到了Java参数-Djavax.net.debug = all并进行了设置-我没有看到任何错误或任何不合适的地方,似乎HttpsUrlConnection没有使用对它设置的SSLSocketFactory。

更新3:
采纳了来自wyvern的#java @ irc.freenode.net上的建议后,我决定使用apache-connector而不是JDK HttpsUrlConnection连接器,最后经过一些欺骗和哄骗之后,我得到了:
[HandshakeCompletedNotify-Thread][ObservableSSLConnectionSocketFactory] Handshake successful!
因此,我想我已经准备就绪,然后=)。

最佳答案

在进行SSL握手之前,请确保客户端和服务在服务器(客户端和服务)上均安装了正确的证书。请参阅url:http://www.programcreek.com/java-api-examples/index.php?api=javax.net.ssl.SSLSocketFactory以获取SSLFactory实现

关于java - HttpsUrlConnection(通过Jersey客户端调用)未调用set SSLSocketFactory的createSocket,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31127321/

10-08 22:27