web-dev-qa-db-ja.com

SSLを使用したSpring 5 WebClient

WebClientの使用例を探しています。私の目標は、Spring 5 WebClientを使用して、httpsと自己署名証明書を使用してRESTサービスを照会することです

どんな例?

11
Seb

使用例を参照してください insecure TrustManagerFactory 検証なしですべてのX.509証明書(自己署名を含む)を信頼します。ドキュメントからの重要なメモ:

このTrustManagerFactoryを実稼働環境で使用しないでください。これは純粋にテスト目的のためであり、したがって非常に安全ではありません。

@Bean
public WebClient createWebClient() throws SSLException {
    SslContext sslContext = SslContextBuilder
            .forClient()
            .trustManager(InsecureTrustManagerFactory.INSTANCE)
            .build();
    ClientHttpConnector httpConnector = HttpClient.create().secure { t -> t.sslContext(sslContext) }
    return WebClient.builder().clientConnector(httpConnector).build();
}
14
Venelin

Spring 5.1.1(Spring boot 2.1.0)はHttpClientOptionsからReactorClientHttpConnectorを削除したように見えるため、ReactorClientHttpConnectorのインスタンスの作成中にオプションを構成することはできません。

現在機能するオプションの1つは次のとおりです。

val sslContext = SslContextBuilder
            .forClient()
            .trustManager(InsecureTrustManagerFactory.INSTANCE)
            .build()
val httpClient = HttpClient.create().secure { t -> t.sslContext(sslContext) }
val webClient = WebClient.builder().clientConnector(ReactorClientHttpConnector(httpClient)).build()

基本的にHttpClientの作成中に、insecuresslContextを構成し、使用するためにこのhttpClientを渡しますReactorClientHttpConnectorでグローバルに。

他のオプションは、以下に示すように、安全でないsslContextでTcpClientを設定し、それを使用してHttpClientインスタンスを作成することです。

val sslContext = SslContextBuilder
            .forClient()
            .trustManager(InsecureTrustManagerFactory.INSTANCE)
            .build()
val tcpClient = TcpClient.create().secure { sslProviderBuilder -> sslProviderBuilder.sslContext(sslContext) }
val httpClient = HttpClient.from(tcpClient)
val webClient =  WebClient.builder().clientConnector(ReactorClientHttpConnector(httpClient)).build()

詳細については:

10
Munish Chandel

これを編集し、spring-boot 2.0-> 2.1の変更に対応する必要がありました。

別の方法として、プロダクションコードをプログラムする場合は、トラストストアとキーストアがあるスプリングブートサーバーの設定を使用して、注入されたWebクライアントを変更するようなスプリングBeanを作成します。クライアントでは、2-way-sslを使用している場合にのみキーストアを指定する必要があります。確かに、本当にクールなスプリングブートサーバーの設定と同様に、ssl-stuffが事前に設定されておらず、簡単に注入できないのはなぜですか。

import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
.
.
.

  @Bean
  WebClientCustomizer configureWebclient(@Value("${server.ssl.trust-store}") String trustStorePath, @Value("${server.ssl.trust-store-password}") String trustStorePass,
      @Value("${server.ssl.key-store}") String keyStorePath, @Value("${server.ssl.key-store-password}") String keyStorePass, @Value("${server.ssl.key-alias}") String keyAlias) {

      return (WebClient.Builder webClientBuilder) -> {
          SslContext sslContext;
          final PrivateKey privateKey;
          final X509Certificate[] certificates;
          try {
            final KeyStore trustStore;
            final KeyStore keyStore;
            trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            trustStore.load(new FileInputStream(ResourceUtils.getFile(trustStorePath)), trustStorePass.toCharArray());
            keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(new FileInputStream(ResourceUtils.getFile(keyStorePath)), keyStorePass.toCharArray());
            List<Certificate> certificateList = Collections.list(trustStore.aliases())
                .stream()
                .filter(t -> {
                  try {
                    return trustStore.isCertificateEntry(t);
                  } catch (KeyStoreException e1) {
                    throw new RuntimeException("Error reading truststore", e1);
                  }
                })
                .map(t -> {
                  try {
                    return trustStore.getCertificate(t);
                  } catch (KeyStoreException e2) {
                    throw new RuntimeException("Error reading truststore", e2);
                  }
                })
                .collect(Collectors.toList());
            certificates = certificateList.toArray(new X509Certificate[certificateList.size()]);
            privateKey = (PrivateKey) keyStore.getKey(keyAlias, keyStorePass.toCharArray());
            Certificate[] certChain = keyStore.getCertificateChain(keyAlias);
            X509Certificate[] x509CertificateChain = Arrays.stream(certChain)
                .map(certificate -> (X509Certificate) certificate)
                .collect(Collectors.toList())
                .toArray(new X509Certificate[certChain.length]);
            sslContext = SslContextBuilder.forClient()
                .keyManager(privateKey, keyStorePass, x509CertificateChain)
                .trustManager(certificates)
                .build();

            HttpClient httpClient = HttpClient.create()
                .secure(sslContextSpec -> sslContextSpec.sslContext(sslContext));
            ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);
            webClientBuilder.clientConnector(connector);
          } catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException | UnrecoverableKeyException e) {
            throw new RuntimeException(e);
          }
        };
  }

ここで、Webclientを使用する部分:import org.springframework.web.reactive.function.client.WebClient;

@Component
public class ClientComponent {

  public ClientComponent(WebClient.Builder webClientBuilder, @Value("${url}") String url) {
    this.client = webClientBuilder.baseUrl(solrUrl).build();
  }
}
6
Frischling