60

私は、ブラウザクライアントを持ち、サードパーティとのサーバー間通信にも参加する分散アプリケーションのサーバーで作業しています。私のサーバーには、クライアントが HTTP/S および XMPP(セキュア) を使用した TLS (SSL) 通信を使用して接続できるようにするための CA 署名付き証明書があります。それはすべてうまくいっています。

ここで、HTTPS/SSL 経由で JAX-WS を使用してサードパーティ サーバーに安全に接続する必要があります。このコミュニケーションでは、私のサーバーは JAX-WS 相互作用のクライアントとして機能し、サードパーティによって署名されたクライアント証明書を持っています。

標準のシステム構成 ( ) を使用して新しいキーストアを追加しようとしました-Djavax.net.ssl.keyStore=xyzが、他のコンポーネントが明らかに影響を受けています。私の他のコンポーネントは SSL 構成 ( ) に専用のパラメーターを使用していますがmy.xmpp.keystore=xxx, my.xmpp.truststore=xxy, ...、最終的にはグローバル を使用しているようですSSLContext。(構成の名前空間my.xmpp.は分離を示しているように見えましたが、そうではありません)

また、クライアント証明書を元のキーストアに追加しようとしましたが、他のコンポーネントも気に入らないようです。

私に残された唯一の選択肢は、プログラムで JAX-WS HTTPS 構成にフックして、クライアント JAX-WS 対話用のキーストアとトラストストアをセットアップすることだと思います。

これを行う方法に関するアイデア/ポインタはありますか? 私が見つけたすべての情報は、javax.net.ssl.keyStoreメソッドを使用しているか、グローバルSSLContextを設定しており、-おそらく-同じコンフィルクになります。私が何か役に立つものに最も近かったのは、必要な機能を要求するこの古いバグレポートでした: SSLContext を JAX-WS クライアントランタイムに渡すためのサポートを追加します。

テイクはありますか?

4

10 に答える 10

55

これはクラックするのが難しいものだったので、記録のために:

これを解決するには、カスタムKeyManagerと、SSLSocketFactoryこのカスタムKeyManagerを使用して分離された にアクセスする が必要でしたKeyStoreKeyStoreこれとSSLFactoryこの優れたブログ エントリ のベース コードを見つけました: how-to-dynamically-select-a-certificate-alias-when-invoking-web-services

次に、特殊SSLSocketFactory化されたニーズを WebService コンテキストに挿入する必要があります。

service = getWebServicePort(getWSDLLocation());
BindingProvider bindingProvider = (BindingProvider) service; 
bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", getCustomSocketFactory()); 

は、上記のメソッドを使用して作成されたをgetCustomSocketFactory()返します。SSLSocketFactoryこれは、JDK に組み込まれた Sun-Oracle impl からの JAX-WS RI に対してのみ機能しますSSLSocketFactory。プロパティを示す文字列がこの実装専用であるためです。

この段階では、JAX-WS サービス通信は SSL によって保護されますが、同じ安全なサーバー () から WSDL をロードしている場合、WSDL を収集するための HTTPS 要求が使用されないため、ブートストラップの問題が発生します。 Web サービスと同じ資格情報。WSDL をローカルで使用できるようにし (file:///... ) 、Web サービス エンドポイントを動的に変更することで、この問題を回避しました。

bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, webServiceLocation); 

これで、WebService がブートストラップされ、名前付き (エイリアス) クライアント証明書と相互認証を使用して、SSL 経由でサーバーの相手と通信できるようになります。∎</p>

于 2012-06-14T11:50:57.807 に答える
22

これは、この投稿に基づいていくつかの微調整を加えて解決した方法です。このソリューションでは、追加のクラスを作成する必要はありません。

SSLContext sc = SSLContext.getInstance("SSLv3");

KeyManagerFactory kmf =
    KeyManagerFactory.getInstance( KeyManagerFactory.getDefaultAlgorithm() );

KeyStore ks = KeyStore.getInstance( KeyStore.getDefaultType() );
ks.load(new FileInputStream( certPath ), certPasswd.toCharArray() );

kmf.init( ks, certPasswd.toCharArray() );

sc.init( kmf.getKeyManagers(), null, null );

((BindingProvider) webservicePort).getRequestContext()
    .put(
        "com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory",
        sc.getSocketFactory() );
于 2012-09-17T17:32:35.300 に答える
21

以下を試してみましたが、私の環境ではうまくいきませんでした。

bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", getCustomSocketFactory());

しかし、別のプロパティが魅力のように機能しました:

bindingProvider.getRequestContext().put(JAXWSProperties.SSL_SOCKET_FACTORY, getCustomSocketFactory());

コードの残りの部分は、最初の返信から取得されました。

于 2012-10-30T13:30:04.830 に答える
5

Radek と l0co の回答を組み合わせることで、https の背後にある WSDL にアクセスできます。

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

KeyManagerFactory kmf = KeyManagerFactory
        .getInstance(KeyManagerFactory.getDefaultAlgorithm());

KeyStore ks = KeyStore.getInstance("JKS");
ks.load(getClass().getResourceAsStream(keystore),
        password.toCharArray());

kmf.init(ks, password.toCharArray());

sc.init(kmf.getKeyManagers(), null, null);

HttpsURLConnection
        .setDefaultSSLSocketFactory(sc.getSocketFactory());

yourService = new YourService(url); //Handshake should succeed
于 2015-07-23T21:01:10.937 に答える
0

システム統合間のキーストアの競合により、この問題に直面したため、次のコードを使用しました。

private PerSecurityWS prepareConnectionPort()  {
      final String HOST_BUNDLE_SYMBOLIC_NAME = "wpp.ibm.dailyexchangerates";
      final String PATH_TO_SLL = "ssl/<your p.12 certificate>";
      final File ksFile = getFile(HOST_BUNDLE_SYMBOLIC_NAME, PATH_TO_SLL);
      final String serverURI = "you url";


      final KeyStore keyStore = KeyStore.getInstance("pkcs12");
      keyStore.load(new FileInputStream(ksFile.getAbsolutePath()), keyStorePassword.toCharArray());
      final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
      kmf.init(keyStore, keyStorePassword.toCharArray());

      final HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
        @Override
        public boolean verify(final String hostname, final SSLSession session) {
          return false;
        }
      };

      final SSLContext ctx = SSLContext.getInstance("TLS");
      ctx.init(kmf.getKeyManagers(), null, null);
      final SSLSocketFactory sslSocketFactory = ctx.getSocketFactory();

      final PerSecurityWS port = new PerSecurityWS_Service().getPerSecurityWSPort();

      final BindingProvider bindingProvider = (BindingProvider) port;
      bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory",sslSocketFactory);
      bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, serverURI);
      bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.hostname.verifier",DO_NOT_VERIFY);
      return port;
    }
于 2021-10-30T11:44:42.157 に答える