+
+ private static Object createTraceTag() {
+ return sequenceNumber.incrementAndGet();
+ }
+
+ private void onHttpError(Object traceTag, Throwable t) {
+ if (t instanceof WebClientResponseException) {
+ WebClientResponseException exception = (WebClientResponseException) t;
+ logger.debug("{} HTTP error status = '{}', body '{}'", traceTag, exception.getStatusCode(),
+ exception.getResponseBodyAsString());
+ } else {
+ logger.debug("{} HTTP error: {}", traceTag, t.getMessage());
+ }
+ }
+
+ private Mono<String> toBody(ResponseEntity<String> entity) {
+ if (entity.getBody() == null) {
+ return Mono.just("");
+ } else {
+ return Mono.just(entity.getBody());
+ }
+ }
+
+ private boolean isCertificateEntry(KeyStore trustStore, String alias) {
+ try {
+ return trustStore.isCertificateEntry(alias);
+ } catch (KeyStoreException e) {
+ logger.error("Error reading truststore {}", e.getMessage());
+ return false;
+ }
+ }
+
+ private Certificate getCertificate(KeyStore trustStore, String alias) {
+ try {
+ return trustStore.getCertificate(alias);
+ } catch (KeyStoreException e) {
+ logger.error("Error reading truststore {}", e.getMessage());
+ return null;
+ }
+ }
+
+ private static synchronized KeyStore getTrustStore(String trustStorePath, String trustStorePass)
+ throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException {
+ if (clientTrustStore == null) {
+ KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType());
+ store.load(new FileInputStream(ResourceUtils.getFile(trustStorePath)), trustStorePass.toCharArray());
+ clientTrustStore = store;
+ }
+ return clientTrustStore;
+ }
+
+ private SslContext createSslContextRejectingUntrustedPeers(String trustStorePath, String trustStorePass)
+ throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException {
+
+ final KeyStore trustStore = getTrustStore(trustStorePath, trustStorePass);
+ List<Certificate> certificateList = Collections.list(trustStore.aliases()).stream() //
+ .filter(alias -> isCertificateEntry(trustStore, alias)) //
+ .map(alias -> getCertificate(trustStore, alias)) //
+ .collect(Collectors.toList());
+ final X509Certificate[] certificates = certificateList.toArray(new X509Certificate[certificateList.size()]);
+
+ return SslContextBuilder.forClient() //
+ .trustManager(certificates) //
+ .build();
+ }
+
+ private SslContext createSslContext()
+ throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
+ if (this.clientConfig.isTrustStoreUsed()) {
+ return createSslContextRejectingUntrustedPeers(this.clientConfig.trustStore(),
+ this.clientConfig.trustStorePassword());
+ } else {
+ // Trust anyone
+ return SslContextBuilder.forClient() //
+ .trustManager(InsecureTrustManagerFactory.INSTANCE) //
+ .build();
+ }
+ }
+
+ private WebClient createWebClient(String baseUrl, SslContext sslContext) {
+ TcpClient tcpClient = TcpClient.create() //
+ .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10_000) //
+ .secure(c -> c.sslContext(sslContext)) //
+ .doOnConnected(connection -> {
+ connection.addHandlerLast(new ReadTimeoutHandler(30));
+ connection.addHandlerLast(new WriteTimeoutHandler(30));
+ });
+ HttpClient httpClient = HttpClient.from(tcpClient);
+ ReactorClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);
+
+ return WebClient.builder() //
+ .clientConnector(connector) //
+ .baseUrl(baseUrl) //
+ .build();
+ }
+
+ private Mono<WebClient> getWebClient() {
+ if (this.webClient == null) {
+ try {
+ SslContext sslContext = createSslContext();
+ this.webClient = createWebClient(this.baseUrl, sslContext);
+ } catch (Exception e) {
+ logger.error("Could not create WebClient {}", e.getMessage());
+ return Mono.error(e);
+ }
+ }
+ return Mono.just(this.webClient);
+ }
+