web-dev-qa-db-ja.com

Jersey Clientを使用して自己署名SSL証明書を無視する

Jerseyクライアントライブラリを使用して、jbossで実行されている残りのサービスに対してテストを実行しています。自己署名証明書を使用して、httpsをサーバー(localhostで実行)で正常にセットアップしました。

ただし、https URLを使用してテストを実行すると、次のエラーが発生します。

com.Sun.jersey.api.client.ClientHandlerException: javax.net.ssl.SSLHandshakeException: Sun.security.validator.ValidatorException: PKIX path building failed: Sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at com.Sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.Java:131)
    at com.Sun.jersey.api.client.Client.handle(Client.Java:629)
    at com.Sun.jersey.oauth.client.OAuthClientFilter.handle(OAuthClientFilter.Java:137)
    at com.Sun.jersey.api.client.WebResource.handle(WebResource.Java:601)
    at com.Sun.jersey.api.client.WebResource.access$200(WebResource.Java:74)
    at com.Sun.jersey.api.client.WebResource$Builder.get(WebResource.Java:459)
    at test.helper.Helper.sendSignedRequest(Helper.Java:174)
    ... And so on

これは、自己署名証明書がJavaキーストアにないためです。 Clientにssl証明書の有効性をチェックせず、それを単に使用する方法はありますか?

このコードはテストサーバーに対してのみ実行されるため、新しいテストサーバーをセットアップするたびに、新しい信頼できる証明書を追加する手間がかかりたくありません。

呼び出しを行っているコードは次のとおりです。

OAuthParameters params = new OAuthParameters();

// baseline OAuth parameters for access to resource
params.signatureMethod(props.getProperty("signature_method"));
params.consumerKey(props.getProperty("consumer_key"));
params.setToken(props.getProperty("token"));
params.setVersion("1.0");
params.nonce();

// OAuth secrets to access resource
OAuthSecrets secrets = new OAuthSecrets();
secrets.consumerSecret(props.getProperty("consumer_secret"));
secrets.setTokenSecret(props.getProperty("token_secret"));

// Jersey client to make REST calls to token services
Client client = Client.create();

// OAuth test server resource
WebResource resource = client.resource(props.getProperty("url"));

// if parameters and secrets remain static, filter cab be added to each web resource
OAuthClientFilter filter = new OAuthClientFilter(client.getProviders(), params, secrets);

// filter added at the web resource level
resource.addFilter(filter);
WebResource.Builder wbr = resource.getRequestBuilder().accept(props.getProperty("accept"));

return wbr.get(ClientResponse.class);

どんな助けも大歓迎です。

60
Chris Salij

古いstackoverflowの質問をいくつか検索して探した後、以前に尋ねられたSOの質問で解決策を見つけました。

これが、私が最終的に使用したコードです。

// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager(){
    public X509Certificate[] getAcceptedIssuers(){return null;}
    public void checkClientTrusted(X509Certificate[] certs, String authType){}
    public void checkServerTrusted(X509Certificate[] certs, String authType){}
}};

// Install the all-trusting trust manager
try {
    SSLContext sc = SSLContext.getInstance("TLS");
    sc.init(null, trustAllCerts, new SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
    ;
}
88
Chris Salij

Jersey 2. *(2.7でテスト済み)およびJava 8の場合:

import Java.security.cert.CertificateException; 
import Java.security.cert.X509Certificate; 
import javax.net.ssl.SSLContext; 
import javax.net.ssl.TrustManager; 
import javax.net.ssl.X509TrustManager; 

public static Client ignoreSSLClient() throws Exception {

    SSLContext sslcontext = SSLContext.getInstance("TLS");

    sslcontext.init(null, new TrustManager[]{new X509TrustManager() {
        public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
        public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
        public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
    }}, new Java.security.SecureRandom());

    return ClientBuilder.newBuilder()
                        .sslContext(sslcontext)
                        .hostnameVerifier((s1, s2) -> true)
                        .build();
}
56
eitan

私は同じ問題を抱えていて、これをグローバルに設定したくないので、上記と同じTrustManagerとSSLContextコードを使用し、特別なプロパティで作成されるようにクライアントを変更しました

 ClientConfig config = new DefaultClientConfig();
 config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties(
     new HostnameVerifier() {
         @Override
         public boolean verify( String s, SSLSession sslSession ) {
             // whatever your matching policy states
         }
     }
 ));
 Client client = Client.create(config);
11
Ransom Briggs

このコードはテストサーバーに対してのみ実行されるため、新しいテストサーバーをセットアップするたびに、新しい信頼できる証明書を追加する手間がかかりたくありません。

これは、最終的に本番環境で使用されるコードの種類です(この質問を読んでいない人は、提案された安全でない信頼マネージャーをアプリケーションにコピーアンドペーストします)。この種のコードは、問題として表示されないため、期限があるときに削除するのを忘れるのはとても簡単です。

テストサーバーがあるたびに新しい証明書を追加する必要がある場合は、独自の小さなCAを作成し、そのCAを使用してテストサーバー用のすべての証明書を発行し、このCA証明書をクライアントの信頼ストアにインポートします。 (ローカル環境でオンライン証明書失効のようなものを扱っていなくても、これは何でも通過させるトラストマネージャーを使用するよりも確かに優れています。)

これを行うのに役立つツールがあります。たとえば、 TinyCA または XCA です。

8
Bruno

私はstackoverflowの初心者であり、他の人の答えについてコメントする評判が低いため、Chris Salijが提案した解決策をいくつか修正して入れました。

            SSLContext ctx = null;
            TrustManager[] trustAllCerts = new X509TrustManager[]{new X509TrustManager(){
                public X509Certificate[] getAcceptedIssuers(){return null;}
                public void checkClientTrusted(X509Certificate[] certs, String authType){}
                public void checkServerTrusted(X509Certificate[] certs, String authType){}
            }};
            try {
                ctx = SSLContext.getInstance("SSL");
                ctx.init(null, trustAllCerts, null);
            } catch (NoSuchAlgorithmException | KeyManagementException e) {
                LOGGER.info("Error loading ssl context {}", e.getMessage());
            }

            SSLContext.setDefault(ctx);
8
Mukesh

ラムダなしのJersey 2.xのユーザーには、これを使用します。

import Java.security.cert.CertificateException;
import Java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;

public static Client getUnsecureClient() throws Exception 
{
    SSLContext sslcontext = SSLContext.getInstance("TLS");
    sslcontext.init(null, new TrustManager[]{new X509TrustManager() 
    {
            public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException{}
            public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException{}
            public X509Certificate[] getAcceptedIssuers()
            {
                return new X509Certificate[0];
            }

    }}, new Java.security.SecureRandom());


    HostnameVerifier allowAll = new HostnameVerifier() 
    {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };

    return ClientBuilder.newBuilder().sslContext(sslcontext).hostnameVerifier(allowAll).build();
}

JRE 1.7jersey-client 2.11でテスト済み。

4
masi

インポートに同じコードを追加するだけです。コンパイルに必要な未実装コードも含まれています。最初、このコードのためにインポートされたものを見つけるのに苦労しました。また、X509Certificateに適切なパッケージを追加します。試行錯誤でこれが機能するようになりました:

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.security.cert.CertificateException;
import javax.security.cert.X509Certificate;
import javax.ws.rs.core.MultivaluedMap;

 TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {

     public Java.security.cert.X509Certificate[] getAcceptedIssuers() {
         Java.security.cert.X509Certificate[] chck = null;
         ;
         return chck;
     }

     public void checkServerTrusted(X509Certificate[] arg0, String arg1)
             throws CertificateException {
         // TODO Auto-generated method stub

     }

     public void checkClientTrusted(X509Certificate[] arg0, String arg1)
             throws CertificateException {

     }

     public void checkClientTrusted(
             Java.security.cert.X509Certificate[] arg0, String arg1)
                     throws Java.security.cert.CertificateException {
         // TODO Auto-generated method stub

     }

     public void checkServerTrusted(
             Java.security.cert.X509Certificate[] arg0, String arg1)
                     throws Java.security.cert.CertificateException {
         // TODO Auto-generated method stub

     }
 } };

 // Install the all-trusting trust manager
 try {
     SSLContext sc = SSLContext.getInstance("TLS");
     sc.init(null, trustAllCerts, new SecureRandom());
     HttpsURLConnection
     .setDefaultSSLSocketFactory(sc.getSocketFactory());
 } catch (Exception e) {
     ;
 }
3

Jersey 2. *の場合:

Client client = ClientBuilder.newBuilder()
                .hostnameVerifier(new HostnameVerifier() {
                    @Override
                    public boolean verify(String hostname, SSLSession session) {
                        return true;
                    }
                }).build();

-> https://jersey.Java.net/documentation/latest/migration.html

1
Marcelo C.

Jersey 1.Xの場合

    TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {

        public void checkClientTrusted(Java.security.cert.X509Certificate[] chain, String authType) throws Java.security.cert.CertificateException {}

        public void checkServerTrusted(Java.security.cert.X509Certificate[] chain, String authType) throws Java.security.cert.CertificateException {}

        public Java.security.cert.X509Certificate[] getAcceptedIssuers() { 
            // or you can return null too
            return new Java.security.cert.X509Certificate[0];
        }
    }};


    SSLContext sc = SSLContext.getInstance("TLS");
    sc.init(null, trustAllCerts, new SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
        public boolean verify(String string, SSLSession sslSession) {
            return true;
        }
    });
0
grep

プールマネージャーでApache httpクライアント構成を使用すると、受け入れられた答えが機能しないことがわかりました。

この場合、ClientConfig.sslContextおよびClientConfig.hostnameVerifierセッターは暗黙のうちに無視されるようです。したがって、Apacheクライアントのhttpクライアント設定で接続プーリングを使用している場合、次のコードを使用してSSL検証を無視できるようにする必要があります。

  ClientConfig clientConfig = new ClientConfig();
  // ... configure your clientConfig
  SSLContext sslContext = null;
  try {
    sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null, new TrustManager[] {
        new X509TrustManager() {
          @Override
          public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {
          }

          @Override
          public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {
          }

          @Override
          public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[] {};
          }
        }
    }, null);
  } catch (NoSuchAlgorithmException e) {
    //logger.debug("Ignoring 'NoSuchAlgorithmException' while ignoring ssl certificate validation.");
  } catch (KeyManagementException e) {
    //logger.debug("Ignoring 'KeyManagementException' while ignoring ssl certificate validation.");
  }
  Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
      .register("http", PlainConnectionSocketFactory.getSocketFactory())
      .register("https", new SSLConnectionSocketFactory(sslContext, new AbstractVerifier() {
        @Override
        public void verify(String Host, String[] cns, String[] subjectAlts) {
        }
      }))
      .build();
  connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
  clientConfig.property(ApacheClientProperties.CONNECTION_MANAGER, connectionManager);
  return ClientBuilder.newClient(clientConfig);
0