From cef5a0b50f07e4e658ff9d2e058d6aa6eb8cb780 Mon Sep 17 00:00:00 2001 From: PatrikBuhr Date: Fri, 6 Nov 2020 12:07:28 +0100 Subject: Added support for using HTTP proxy A HTTP proxy may be used to access NearRT-RICs For other HTTP acces; Consul; DMAAP, local, and R-APP callbacks no proxy is used. Change-Id: Ibc3ed8bada76cafb23323bf03b28a9876bed60eb Issue-ID: CCSDK-2502 Signed-off-by: PatrikBuhr --- .../clients/AsyncRestClient.java | 49 ++++++++++------------ .../clients/AsyncRestClientFactory.java | 19 ++++++++- .../clients/CcsdkA1AdapterClient.java | 10 +++-- .../configuration/ApplicationConfig.java | 13 ++++++ .../configuration/WebClientConfig.java | 9 ++++ .../controllers/ServiceCallbacks.java | 2 +- .../controllers/v2/PolicyController.java | 3 +- .../dmaap/DmaapMessageConsumer.java | 6 +-- 8 files changed, 73 insertions(+), 38 deletions(-) (limited to 'a1-policy-management/src/main/java/org') diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClient.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClient.java index 7f453a27..cba1c7cc 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClient.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClient.java @@ -28,6 +28,7 @@ import io.netty.handler.timeout.WriteTimeoutHandler; import java.lang.invoke.MethodHandles; import java.util.concurrent.atomic.AtomicInteger; +import org.onap.ccsdk.oran.a1policymanagementservice.configuration.WebClientConfig.HttpProxyConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.MediaType; @@ -42,6 +43,7 @@ import org.springframework.web.reactive.function.client.WebClientResponseExcepti import reactor.core.publisher.Mono; import reactor.netty.http.client.HttpClient; import reactor.netty.resources.ConnectionProvider; +import reactor.netty.tcp.ProxyProvider.Proxy; import reactor.netty.tcp.TcpClient; /** @@ -54,19 +56,12 @@ public class AsyncRestClient { private final String baseUrl; private static final AtomicInteger sequenceNumber = new AtomicInteger(); private final SslContext sslContext; + private final HttpProxyConfig httpProxyConfig; - /** - * Note that only http (not https) will work when this constructor is used. - * - * @param baseUrl - */ - public AsyncRestClient(String baseUrl) { - this(baseUrl, null); - } - - public AsyncRestClient(String baseUrl, SslContext sslContext) { + public AsyncRestClient(String baseUrl, @Nullable SslContext sslContext, @Nullable HttpProxyConfig httpProxyConfig) { this.baseUrl = baseUrl; this.sslContext = sslContext; + this.httpProxyConfig = httpProxyConfig; } public Mono> postForEntity(String uri, @Nullable String body) { @@ -200,27 +195,32 @@ public class AsyncRestClient { } } - private TcpClient createTcpClientSecure(SslContext sslContext) { - return TcpClient.create(ConnectionProvider.newConnection()) // - .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10_000) // - .secure(c -> c.sslContext(sslContext)) // - .doOnConnected(connection -> { - connection.addHandlerLast(new ReadTimeoutHandler(30)); - connection.addHandlerLast(new WriteTimeoutHandler(30)); - }); + private boolean isHttpProxyConfigured() { + return httpProxyConfig != null && httpProxyConfig.httpProxyPort() > 0 + && !httpProxyConfig.httpProxyHost().isEmpty(); } - private TcpClient createTcpClientInsecure() { - return TcpClient.create(ConnectionProvider.newConnection()) // + private TcpClient createTcpClient() { + TcpClient client = TcpClient.create(ConnectionProvider.newConnection()) // .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10_000) // .doOnConnected(connection -> { connection.addHandlerLast(new ReadTimeoutHandler(30)); connection.addHandlerLast(new WriteTimeoutHandler(30)); }); + if (this.sslContext != null) { + client = client.secure(c -> c.sslContext(sslContext)); + } + if (isHttpProxyConfigured()) { + client = client.proxy(proxy -> { + proxy.type(Proxy.HTTP).host(httpProxyConfig.httpProxyHost()).port(httpProxyConfig.httpProxyPort()); + }); + } + return client; } private WebClient createWebClient(String baseUrl, TcpClient tcpClient) { HttpClient httpClient = HttpClient.from(tcpClient); + ReactorClientHttpConnector connector = new ReactorClientHttpConnector(httpClient); ExchangeStrategies exchangeStrategies = ExchangeStrategies.builder() // .codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(-1)) // @@ -235,13 +235,8 @@ public class AsyncRestClient { private Mono getWebClient() { if (this.webClient == null) { try { - if (this.sslContext != null) { - TcpClient tcpClient = createTcpClientSecure(sslContext); - this.webClient = createWebClient(this.baseUrl, tcpClient); - } else { - TcpClient tcpClient = createTcpClientInsecure(); - this.webClient = createWebClient(this.baseUrl, tcpClient); - } + TcpClient tcpClient = createTcpClient(); + this.webClient = createWebClient(this.baseUrl, tcpClient); } catch (Exception e) { logger.error("Could not create WebClient {}", e.getMessage()); return Mono.error(e); diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClientFactory.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClientFactory.java index 5b88fce4..b5590cc2 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClientFactory.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClientFactory.java @@ -42,6 +42,7 @@ import java.util.stream.Collectors; import javax.net.ssl.KeyManagerFactory; import org.onap.ccsdk.oran.a1policymanagementservice.configuration.WebClientConfig; +import org.onap.ccsdk.oran.a1policymanagementservice.configuration.WebClientConfig.HttpProxyConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.ResourceUtils; @@ -49,29 +50,43 @@ import org.springframework.util.ResourceUtils; /** * Factory for a generic reactive REST client. */ +@SuppressWarnings("squid:S2629") // Invoke method(s) only conditionally public class AsyncRestClientFactory { private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); private final SslContextFactory sslContextFactory; + private final HttpProxyConfig httpProxyConfig; public AsyncRestClientFactory(WebClientConfig clientConfig) { if (clientConfig != null) { this.sslContextFactory = new CachingSslContextFactory(clientConfig); + this.httpProxyConfig = clientConfig.httpProxyConfig(); } else { + logger.warn("HTTPS will not work"); this.sslContextFactory = null; + this.httpProxyConfig = null; } } + public AsyncRestClient createRestClientNoHttpProxy(String baseUrl) { + return createRestClient(baseUrl, false); + } + public AsyncRestClient createRestClient(String baseUrl) { + return createRestClient(baseUrl, true); + } + + private AsyncRestClient createRestClient(String baseUrl, boolean useHttpProxy) { if (this.sslContextFactory != null) { try { - return new AsyncRestClient(baseUrl, this.sslContextFactory.createSslContext()); + return new AsyncRestClient(baseUrl, this.sslContextFactory.createSslContext(), + useHttpProxy ? httpProxyConfig : null); } catch (Exception e) { String exceptionString = e.toString(); logger.error("Could not init SSL context, reason: {}", exceptionString); } } - return new AsyncRestClient(baseUrl); + return new AsyncRestClient(baseUrl, null, httpProxyConfig); } private class SslContextFactory { diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/CcsdkA1AdapterClient.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/CcsdkA1AdapterClient.java index 3b581b63..448b7b61 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/CcsdkA1AdapterClient.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/CcsdkA1AdapterClient.java @@ -81,7 +81,8 @@ public class CcsdkA1AdapterClient implements A1Client { * Constructor that creates the REST client to use. * * @param protocolType the southbound protocol of the controller. Supported - * protocols are CCSDK_A1_ADAPTER_STD_V1_1, CCSDK_A1_ADAPTER_OSC_V1 and + * protocols are CCSDK_A1_ADAPTER_STD_V1_1, + * CCSDK_A1_ADAPTER_OSC_V1 and * CCSDK_A1_ADAPTER_STD_V2_0_0 with * @param ricConfig the configuration of the Near-RT RIC to communicate * with @@ -92,14 +93,15 @@ public class CcsdkA1AdapterClient implements A1Client { public CcsdkA1AdapterClient(A1ProtocolType protocolType, RicConfig ricConfig, ControllerConfig controllerConfig, AsyncRestClientFactory restClientFactory) { this(protocolType, ricConfig, controllerConfig, - restClientFactory.createRestClient(controllerConfig.baseUrl() + "/restconf/operations")); + restClientFactory.createRestClientNoHttpProxy(controllerConfig.baseUrl() + "/restconf/operations")); } /** * Constructor where the REST client to use is provided. * * @param protocolType the southbound protocol of the controller. Supported - * protocols are CCSDK_A1_ADAPTER_STD_V1_1, CCSDK_A1_ADAPTER_OSC_V1 and + * protocols are CCSDK_A1_ADAPTER_STD_V1_1, + * CCSDK_A1_ADAPTER_OSC_V1 and * CCSDK_A1_ADAPTER_STD_V2_0_0 with * @param ricConfig the configuration of the Near-RT RIC to communicate * with @@ -108,7 +110,7 @@ public class CcsdkA1AdapterClient implements A1Client { * * @throws IllegalArgumentException when the protocolType is illegal. */ - public CcsdkA1AdapterClient(A1ProtocolType protocolType, RicConfig ricConfig, ControllerConfig controllerConfig, + CcsdkA1AdapterClient(A1ProtocolType protocolType, RicConfig ricConfig, ControllerConfig controllerConfig, AsyncRestClient restClient) { if (A1ProtocolType.CCSDK_A1_ADAPTER_STD_V1_1.equals(protocolType) // || A1ProtocolType.CCSDK_A1_ADAPTER_OSC_V1.equals(protocolType) // diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfig.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfig.java index 65c6daa3..d6dc3975 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfig.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfig.java @@ -29,6 +29,7 @@ import javax.validation.constraints.NotEmpty; import lombok.Getter; +import org.onap.ccsdk.oran.a1policymanagementservice.configuration.WebClientConfig.HttpProxyConfig; import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -64,6 +65,12 @@ public class ApplicationConfig { @Value("${app.webclient.trust-store}") private String sslTrustStore = ""; + @Value("${app.webclient.http.proxy-host}") + private String httpProxyHost = ""; + + @Value("${app.webclient.http.proxy-port}") + private int httpProxyPort = 0; + private Map ricConfigs = new HashMap<>(); @Getter @@ -79,6 +86,11 @@ public class ApplicationConfig { } public WebClientConfig getWebClientConfig() { + HttpProxyConfig httpProxyConfig = ImmutableHttpProxyConfig.builder() // + .httpProxyHost(this.httpProxyHost) // + .httpProxyPort(this.httpProxyPort) // + .build(); + return ImmutableWebClientConfig.builder() // .keyStoreType(this.sslKeyStoreType) // .keyStorePassword(this.sslKeyStorePassword) // @@ -87,6 +99,7 @@ public class ApplicationConfig { .isTrustStoreUsed(this.sslTrustStoreUsed) // .trustStore(this.sslTrustStore) // .trustStorePassword(this.sslTrustStorePassword) // + .httpProxyConfig(httpProxyConfig) // .build(); } diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/WebClientConfig.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/WebClientConfig.java index ef7bd87c..beb6e51f 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/WebClientConfig.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/WebClientConfig.java @@ -42,4 +42,13 @@ public interface WebClientConfig { public String trustStore(); + @Value.Immutable + public interface HttpProxyConfig { + public String httpProxyHost(); + + public int httpProxyPort(); + } + + public HttpProxyConfig httpProxyConfig(); + } diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/ServiceCallbacks.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/ServiceCallbacks.java index d6286eed..f9e446e4 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/ServiceCallbacks.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/ServiceCallbacks.java @@ -48,7 +48,7 @@ public class ServiceCallbacks { private final AsyncRestClient restClient; public ServiceCallbacks(AsyncRestClientFactory restClientFactory) { - this.restClient = restClientFactory.createRestClient(""); + this.restClient = restClientFactory.createRestClientNoHttpProxy(""); } public void notifyServicesRicSynchronized(Ric ric, Services services) { diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyController.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyController.java index 8dd2df61..ec776042 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyController.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyController.java @@ -97,7 +97,8 @@ public class PolicyController { private static Gson gson = new GsonBuilder() // .create(); // - @GetMapping(path = "/v2/policy-types/{policytype_id:.+}", produces = MediaType.APPLICATION_JSON_VALUE) + @GetMapping(path = Consts.V2_API_ROOT + "/policy-types/{policytype_id:.+}", + produces = MediaType.APPLICATION_JSON_VALUE) @ApiOperation(value = "Returns a policy type definition") @ApiResponses(value = { // @ApiResponse(code = 200, message = "Policy type", response = PolicyTypeInfo.class), // diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/dmaap/DmaapMessageConsumer.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/dmaap/DmaapMessageConsumer.java index f948e5f5..3a06e71f 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/dmaap/DmaapMessageConsumer.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/dmaap/DmaapMessageConsumer.java @@ -182,7 +182,7 @@ public class DmaapMessageConsumer { protected Mono getFromMessageRouter(String topicUrl) { logger.trace("getFromMessageRouter {}", topicUrl); - AsyncRestClient c = restClientFactory.createRestClient(""); + AsyncRestClient c = restClientFactory.createRestClientNoHttpProxy(""); return c.get(topicUrl); } @@ -229,9 +229,9 @@ public class DmaapMessageConsumer { private DmaapMessageHandler getDmaapMessageHandler() { if (this.dmaapMessageHandler == null) { String pmsBaseUrl = "http://localhost:" + this.localServerHttpPort; - AsyncRestClient pmsClient = restClientFactory.createRestClient(pmsBaseUrl); + AsyncRestClient pmsClient = restClientFactory.createRestClientNoHttpProxy(pmsBaseUrl); AsyncRestClient producer = - restClientFactory.createRestClient(this.applicationConfig.getDmaapProducerTopicUrl()); + restClientFactory.createRestClientNoHttpProxy(this.applicationConfig.getDmaapProducerTopicUrl()); this.dmaapMessageHandler = new DmaapMessageHandler(producer, pmsClient); } return this.dmaapMessageHandler; -- cgit 1.2.3-korg