1

Apache HttpComponents ライブラリを使用して JBoss サーバーへの HTTP GET 呼び出しを行おうとしています。http URL でこれを行うと問題なく動作しますが、https URL を使用すると動作しません。ここに私が持っているコードがあります:

public static String HttpGET(String requestURL, Cookie cookie)
        throws HttpException {

    DefaultHttpClient httpClient = new DefaultHttpClient();

    if (cookie != null) {
        CookieStore store = new BasicCookieStore();
        store.addCookie(cookie);
        ((AbstractHttpClient) httpClient).setCookieStore(store);
    }

    HttpGet httpGet = new HttpGet(requestURL);

    HttpResponse response = null;
    HttpEntity responseEntity = null;
    String responseBody = null;
    try {
        response = httpClient.execute(httpGet);
        // Do some more stuff...

    } catch (SSLPeerUnverifiedException ex) {
        // Message "peer not authenticated" means the server presented
        // a certificate that was not found in the local truststore.
        throw new HttpException("HTTP GET request failed; possible"
                + " missing or invalid certificate: " + ex.getMessage());
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        // When HttpClient instance is no longer needed,
        // shut down the connection manager to ensure
        // immediate deallocation of all system resources
        httpClient.getConnectionManager().shutdown();
    }

    return responseBody;
}

私は私のGET呼び出しSSLPeerUnverifiedExceptionを取得しています。execute()エラーメッセージは次のとおりです。

javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated

大規模なグーグル検索と StackOverflow の質問の検索を行った後、この提案が表示され続けたので、次のように DefaultHttpClient の周りにこのラッパーを追加しました。

private static HttpClient wrapClient(HttpClient httpClient) {       
    try {
        SSLContext ctx = SSLContext.getInstance("TLS");
        X509TrustManager tm = new X509TrustManager() {

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

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

            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        X509HostnameVerifier verifier = new X509HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return false;
            }

            @Override
            public void verify(String arg0, SSLSocket arg1)
                    throws IOException { }

            @Override
            public void verify(String arg0, X509Certificate arg1)
                    throws SSLException { }

            @Override
            public void verify(String arg0, String[] arg1, String[] arg2)
                    throws SSLException { }

        };

        ctx.init(null, new TrustManager[] { tm }, null);

        SSLSocketFactory socketFactory = new SSLSocketFactory(ctx);
        socketFactory.setHostnameVerifier(verifier);
        Scheme sch = new Scheme("https", 443, socketFactory);
        httpClient.getConnectionManager().getSchemeRegistry().register(sch);
        return httpClient;

    } catch (Exception ex) {
        ex.printStackTrace();
        return null;
    }
}

ただし、これは別のエラーを生成します。

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

このサーバーへの接続を確立するために Jersey ライブラリを使用して作成された他のコードは正常に接続できるため、証明書が正しく設定されていると思います。ただし、Apache HttpComponents で間違っていることはわかりません。何か案は?明らかな間違いを犯している場合は申し訳ありません。私は SSL に不慣れで、自分が何をしているのかまだ完全には理解していません。助けてくれてありがとう!

4

1 に答える 1

0

これは、サーバーが Server Name Indication を要求していることが原因である可能性があります。

Apache HTTP クライアント 4.2.2 は SNI をサポートしていないように見えるため ( server_nameJava 7 を使用している場合でも拡張機能を送信しない)、SNI を使用する他のライブラリで取得する証明書とは異なる証明書を取得する可能性があります。

Apache HTTP Client 4.3 で SNI をサポートする方法があるようです (ただし、少なくとも Java 7 は必要です)。

于 2013-09-17T20:04:48.447 に答える