From 49d2deae8aa7b57ecf6fb692803594c1bae8e8bf Mon Sep 17 00:00:00 2001 From: dfarrelly Date: Wed, 3 Apr 2019 14:40:31 +0000 Subject: Add support for HTTPS *Add AAF certificates *Switch PM Mapper endpoints to HTTPS *Make external API calls secure if applicable Issue-ID: DCAEGEN2-1296 Change-Id: I63aef8a93cfe6d6a37dcd32496b35ed0841cec4b Signed-off-by: dfarrelly --- dpo/blueprints/k8s-pm-mapper.yaml | 64 ++-- .../org/onap/dcaegen2/services/pmmapper/App.java | 20 +- .../pmmapper/datarouter/DataRouterSubscriber.java | 2 +- .../exceptions/CreateContextException.java | 27 ++ .../pmmapper/exceptions/KeyManagerException.java | 27 ++ .../pmmapper/exceptions/LoadKeyStoreException.java | 27 ++ .../exceptions/ServerResponseException.java | 27 ++ .../pmmapper/exceptions/TrustManagerException.java | 27 ++ .../services/pmmapper/model/MapperConfig.java | 371 +++++++++++---------- .../services/pmmapper/ssl/SSLContextFactory.java | 133 ++++++++ .../services/pmmapper/utils/DataRouterUtils.java | 5 +- .../services/pmmapper/utils/RequestSender.java | 19 +- .../pmmapper/config/util/RequestSenderTests.java | 1 - .../pmmapper/ssl/SSLContextFactoryTest.java | 84 +++++ .../pmmapper/utils/DataRouterUtilsTest.java | 68 +++- src/test/resources/password | 1 + src/test/resources/testkeystore.jks.b64 | 35 ++ src/test/resources/valid_mapper_config.json | 7 +- 18 files changed, 732 insertions(+), 213 deletions(-) create mode 100644 src/main/java/org/onap/dcaegen2/services/pmmapper/exceptions/CreateContextException.java create mode 100644 src/main/java/org/onap/dcaegen2/services/pmmapper/exceptions/KeyManagerException.java create mode 100644 src/main/java/org/onap/dcaegen2/services/pmmapper/exceptions/LoadKeyStoreException.java create mode 100644 src/main/java/org/onap/dcaegen2/services/pmmapper/exceptions/ServerResponseException.java create mode 100644 src/main/java/org/onap/dcaegen2/services/pmmapper/exceptions/TrustManagerException.java create mode 100644 src/main/java/org/onap/dcaegen2/services/pmmapper/ssl/SSLContextFactory.java create mode 100644 src/test/java/org/onap/dcaegen2/services/pmmapper/ssl/SSLContextFactoryTest.java create mode 100644 src/test/resources/password create mode 100644 src/test/resources/testkeystore.jks.b64 diff --git a/dpo/blueprints/k8s-pm-mapper.yaml b/dpo/blueprints/k8s-pm-mapper.yaml index 88fb44a..0944da3 100644 --- a/dpo/blueprints/k8s-pm-mapper.yaml +++ b/dpo/blueprints/k8s-pm-mapper.yaml @@ -22,17 +22,17 @@ tosca_definitions_version: cloudify_dsl_1_3 imports: - "http://www.getcloudify.org/spec/cloudify/3.4/types.yaml" - - "https://nexus.onap.org/service/local/repositories/raw/content/org.onap.dcaegen2.platform.plugins/R3/k8splugin/1.4.4/k8splugin_types.yaml" + - "https://nexus.onap.org/service/local/repositories/raw/content/org.onap.dcaegen2.platform.plugins/R4/k8splugin/1.4.5/k8splugin_types.yaml" inputs: service_name: type: string description: Name of the serice - default: "pm-mapper" + default: "dcae-pm-mapper" tag_version: type: string description: Docker image to be used - default: "nexus3.onap.org:10001/onap/org.onap.dcaegen2.services.pm-mapper:1.0-SNAPSHOT" + default: "nexus3.onap.org:10001/onap/org.onap.dcaegen2.services.pm-mapper:latest" replicas: type: integer description: Number of instances @@ -55,11 +55,11 @@ inputs: default: "ves-pub-1" dmaap_dr_username: type: string - description: dmaap datarouter user name + description: DMAAP Data Router user name default: "username" dmaap_dr_password: type: string - description: dmaap datarouter password + description: DMAAP Data Router password default: "password" dcae_location: type: string @@ -69,42 +69,54 @@ inputs: type: string description: Subscriber id in Data Router default: "" + pm_mapper_service_protocol: + type: string + description: PM Mapper protocol + default: "https" + pm_mapper_service_port: + type: string + description: PM Mapper host port + default: "8443" dmaap_buscontroller_service_host: type: string description: DMAAP Bus Controller host address default: "dmaap-bc.onap.svc.cluster.local" dmaap_buscontroller_service_port: type: string - description: DMAAP bus Controller host port + description: DMAAP Bus Controller host port default: "8080" dmaap_dr_feed_id: type: string - description: ID of the data router feed that the PM Mapper will subscribe to + description: ID of the Data Router feed that the PM Mapper will subscribe to default: "1" dmaap_dr_service_host: type: string description: DMAAP Data Router host address - default: "dmaap-dr-node.onap.svc.cluster.local" + default: "dmaap-dr-node" dmaap_dr_service_port: type: string description: DMAAP Data Router host port default: "8443" dmaap_mr_service_host: type: string - description: DMAAP Data Router host address - default: "message-router.onap.svc.cluster.local" + description: DMAAP Message Router host address + default: "dmaap-mr" dmaap_mr_service_port: type: string - description: DMAAP Data Router host port - default: "3904" + description: DMAAP Message Router host port + default: "3905" dmaap_mr_topic_name: type: string - description: Name of MR topic events will be published to + description: Name of Message Router topic events will be published to default: "pm-mapper-ves" filter: type: string - description: PM mapper filter on measInfo, measInfoId, measType, instanceId + description: PM Mapper filter on measInfo, measInfoId, measType, instanceId default: "{ \"filters\":[]}" + enable_http: + type: boolean + description: Option to turn on HTTP connections + default: false node_templates: pm-mapper: @@ -113,18 +125,25 @@ node_templates: start: inputs: ports: - - '8080:0' + - '8443:0' + - '8081:0' properties: application_config: + enable_http: + { get_input: enable_http } + trust_store_path: "/opt/app/pm-mapper/etc/cert/trust.jks.b64" + trust_store_pass_path: "/opt/app/pm-mapper/etc/cert/trust.pass" + key_store_path: "/opt/app/pm-mapper/etc/cert/cert.jks.b64" + key_store_pass_path: "/opt/app/pm-mapper/etc/cert/cert.pass" buscontroller_feed_subscription_endpoint: { concat: ["http://", { get_input: dmaap_buscontroller_service_host }, ":", { get_input: dmaap_buscontroller_service_port}, "/webapi/dr_subs"]} dmaap_dr_feed_id: get_input: dmaap_dr_feed_id dmaap_dr_delete_endpoint: - { concat: ["http://", { get_input: dmaap_dr_service_host }, + { concat: ["https://", { get_input: dmaap_dr_service_host }, ":", { get_input: dmaap_dr_service_port}, "/delete"]} - filters: + pm-mapper-filter: get_input: filter streams_subscribes: dmaap_subscriber: @@ -140,8 +159,8 @@ node_templates: subscriber_id: get_input: subscriber_id delivery_url: - { concat: ["http://", { get_input: service_name }, ".onap.svc.cluster.local", - ":8081/delivery"]} + { concat: [{ get_input: pm_mapper_service_protocol },"://", { get_input: service_name }, ".onap.svc.cluster.local", + ":", { get_input: pm_mapper_service_port }, "/delivery"]} streams_publishes: dmaap_publisher: aaf_username: @@ -156,7 +175,7 @@ node_templates: client_id: get_input: client_id topic_url: - { concat: ["http://", { get_input: dmaap_mr_service_host }, + { concat: ["https://", { get_input: dmaap_mr_service_host }, ":", { get_input: dmaap_mr_service_port }, "/events/", { get_input: dmaap_mr_topic_name }]} location: get_input: dcae_location @@ -165,7 +184,7 @@ node_templates: endpoint: /healthcheck interval: 15s timeout: 1s - type: http + type: https image: get_input: tag_version replicas: { get_input: replicas } @@ -173,4 +192,7 @@ node_templates: dns_name: { get_input: service_name } log_info: log_directory: "/var/log/ONAP/dcaegen2/services/pm-mapper" + tls_info: + cert_directory: "/opt/app/pm-mapper/etc/cert/" + use_tls: true type: dcae.nodes.ContainerizedPlatformComponent \ No newline at end of file diff --git a/src/main/java/org/onap/dcaegen2/services/pmmapper/App.java b/src/main/java/org/onap/dcaegen2/services/pmmapper/App.java index b52a5f1..25e3918 100644 --- a/src/main/java/org/onap/dcaegen2/services/pmmapper/App.java +++ b/src/main/java/org/onap/dcaegen2/services/pmmapper/App.java @@ -42,6 +42,7 @@ import org.onap.dcaegen2.services.pmmapper.messagerouter.VESPublisher; import org.onap.dcaegen2.services.pmmapper.model.Event; import org.onap.dcaegen2.services.pmmapper.model.MapperConfig; import org.onap.dcaegen2.services.pmmapper.healthcheck.HealthCheckHandler; +import org.onap.dcaegen2.services.pmmapper.ssl.SSLContextFactory; import org.onap.dcaegen2.services.pmmapper.utils.DataRouterUtils; import org.onap.dcaegen2.services.pmmapper.utils.MeasConverter; import org.onap.dcaegen2.services.pmmapper.utils.MeasSplitter; @@ -53,6 +54,8 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.FluxSink; import reactor.core.scheduler.Schedulers; +import javax.net.ssl.SSLContext; +import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -64,7 +67,7 @@ public class App { private static Path xmlSchema = Paths.get("/opt/app/pm-mapper/etc/measCollec_plusString.xsd"); private static FluxSink fluxSink; - public static void main(String[] args) throws InterruptedException, TooManyTriesException, CBSConfigException, EnvironmentConfigException, CBSServerError, MapperConfigException { + public static void main(String[] args) throws InterruptedException, TooManyTriesException, CBSConfigException, EnvironmentConfigException, CBSServerError, MapperConfigException, IOException { Flux flux = Flux.create(eventFluxSink -> fluxSink = eventFluxSink); HealthCheckHandler healthCheckHandler = new HealthCheckHandler(); MapperConfig mapperConfig = new ConfigHandler().getMapperConfig(); @@ -89,7 +92,7 @@ public class App { .filter(events -> App.filter(filterHandler, events, mapperConfig)) .concatMap(events -> App.map(mapper, events, mapperConfig)) .concatMap(vesPublisher::publish) - .subscribe(events -> logger.unwrap().info("Event Processed")); + .subscribe(event -> App.sendEventProcessed(mapperConfig, event)); DataRouterSubscriber dataRouterSubscriber = new DataRouterSubscriber(fluxSink::next, mapperConfig); dataRouterSubscriber.start(); @@ -98,8 +101,17 @@ public class App { configurables.add(mapperConfig); DynamicConfiguration dynamicConfiguration = new DynamicConfiguration(configurables, mapperConfig); - Undertow.builder() - .addHttpListener(8081, "0.0.0.0") + Undertow.Builder builder = Undertow.builder(); + + SSLContextFactory sslContextFactory = new SSLContextFactory(mapperConfig); + SSLContext sslContext = sslContextFactory.createSSLContext(mapperConfig); + SSLContext.setDefault(sslContext); + + if(mapperConfig.getEnableHttp()) { + builder.addHttpListener(8081, "0.0.0.0"); + } + + builder.addHttpsListener(8443, "0.0.0.0", sslContext) .setHandler(Handlers.routing() .add("put", "/delivery/{filename}", dataRouterSubscriber) .add("get", "/healthcheck", healthCheckHandler) diff --git a/src/main/java/org/onap/dcaegen2/services/pmmapper/datarouter/DataRouterSubscriber.java b/src/main/java/org/onap/dcaegen2/services/pmmapper/datarouter/DataRouterSubscriber.java index 19a4750..a0a8eaf 100644 --- a/src/main/java/org/onap/dcaegen2/services/pmmapper/datarouter/DataRouterSubscriber.java +++ b/src/main/java/org/onap/dcaegen2/services/pmmapper/datarouter/DataRouterSubscriber.java @@ -85,7 +85,7 @@ public class DataRouterSubscriber implements HttpHandler, Configurable { private Random jitterGenerator; private Gson metadataBuilder; private MapperConfig config; - private String subscriberId; + public static String subscriberId; @NonNull private EventReceiver eventReceiver; diff --git a/src/main/java/org/onap/dcaegen2/services/pmmapper/exceptions/CreateContextException.java b/src/main/java/org/onap/dcaegen2/services/pmmapper/exceptions/CreateContextException.java new file mode 100644 index 0000000..a5a230c --- /dev/null +++ b/src/main/java/org/onap/dcaegen2/services/pmmapper/exceptions/CreateContextException.java @@ -0,0 +1,27 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.dcaegen2.services.pmmapper.exceptions; + +public class CreateContextException extends RuntimeException { + public CreateContextException(String message, Throwable cause) { + super(message, cause); + } +} \ No newline at end of file diff --git a/src/main/java/org/onap/dcaegen2/services/pmmapper/exceptions/KeyManagerException.java b/src/main/java/org/onap/dcaegen2/services/pmmapper/exceptions/KeyManagerException.java new file mode 100644 index 0000000..d123991 --- /dev/null +++ b/src/main/java/org/onap/dcaegen2/services/pmmapper/exceptions/KeyManagerException.java @@ -0,0 +1,27 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.dcaegen2.services.pmmapper.exceptions; + +public class KeyManagerException extends RuntimeException { + public KeyManagerException(String message, Throwable cause) { + super(message, cause); + } +} \ No newline at end of file diff --git a/src/main/java/org/onap/dcaegen2/services/pmmapper/exceptions/LoadKeyStoreException.java b/src/main/java/org/onap/dcaegen2/services/pmmapper/exceptions/LoadKeyStoreException.java new file mode 100644 index 0000000..96bfad5 --- /dev/null +++ b/src/main/java/org/onap/dcaegen2/services/pmmapper/exceptions/LoadKeyStoreException.java @@ -0,0 +1,27 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.dcaegen2.services.pmmapper.exceptions; + +public class LoadKeyStoreException extends RuntimeException { + public LoadKeyStoreException(String message, Throwable cause) { + super(message, cause); + } +} \ No newline at end of file diff --git a/src/main/java/org/onap/dcaegen2/services/pmmapper/exceptions/ServerResponseException.java b/src/main/java/org/onap/dcaegen2/services/pmmapper/exceptions/ServerResponseException.java new file mode 100644 index 0000000..b52e2d4 --- /dev/null +++ b/src/main/java/org/onap/dcaegen2/services/pmmapper/exceptions/ServerResponseException.java @@ -0,0 +1,27 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.dcaegen2.services.pmmapper.exceptions; + +public class ServerResponseException extends Exception { + public ServerResponseException(String message, Throwable cause) { + super(message, cause); + } +} \ No newline at end of file diff --git a/src/main/java/org/onap/dcaegen2/services/pmmapper/exceptions/TrustManagerException.java b/src/main/java/org/onap/dcaegen2/services/pmmapper/exceptions/TrustManagerException.java new file mode 100644 index 0000000..75ce61d --- /dev/null +++ b/src/main/java/org/onap/dcaegen2/services/pmmapper/exceptions/TrustManagerException.java @@ -0,0 +1,27 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.dcaegen2.services.pmmapper.exceptions; + +public class TrustManagerException extends RuntimeException { + public TrustManagerException(String message, Throwable cause) { + super(message, cause); + } +} \ No newline at end of file diff --git a/src/main/java/org/onap/dcaegen2/services/pmmapper/model/MapperConfig.java b/src/main/java/org/onap/dcaegen2/services/pmmapper/model/MapperConfig.java index bd4eafb..b9d58ee 100644 --- a/src/main/java/org/onap/dcaegen2/services/pmmapper/model/MapperConfig.java +++ b/src/main/java/org/onap/dcaegen2/services/pmmapper/model/MapperConfig.java @@ -1,176 +1,197 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2019 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ -package org.onap.dcaegen2.services.pmmapper.model; - -import java.net.MalformedURLException; -import java.net.URL; - -import org.onap.dcaegen2.services.pmmapper.config.Configurable; -import org.onap.dcaegen2.services.pmmapper.utils.GSONRequired; -import com.google.gson.annotations.SerializedName; -import lombok.Getter; -import lombok.AccessLevel; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -@Getter -@EqualsAndHashCode -@NoArgsConstructor -public class MapperConfig implements Configurable{ - - public static final String CLIENT_NAME = "pm-mapper"; - - @GSONRequired - @Getter(AccessLevel.PRIVATE) - @SerializedName("streams_subscribes") - private StreamsSubscribes streamsSubscribes; - - @GSONRequired - @Getter(AccessLevel.PRIVATE) - @SerializedName("streams_publishes") - private StreamsPublishes streamsPublishes; - - @GSONRequired - @SerializedName("buscontroller_feed_subscription_endpoint") - private String busControllerSubscriptionEndpoint; - - @GSONRequired - @SerializedName("dmaap_dr_feed_id") - private String dmaapDRFeedId; - - @GSONRequired - @SerializedName("dmaap_dr_delete_endpoint") - private String dmaapDRDeleteEndpoint; - - public String getBusControllerDeliveryUrl() { - return this.getStreamsSubscribes().getDmaapSubscriber().getDmaapInfo().getDeliveryUrl(); - } - - public String getDcaeLocation() { - return this.getStreamsSubscribes().getDmaapSubscriber().getDmaapInfo().getLocation(); - } - - public String getBusControllerUserName() { - return this.getStreamsSubscribes().getDmaapSubscriber().getDmaapInfo().getUsername(); - } - - public String getBusControllerPassword() { - return this.getStreamsSubscribes().getDmaapSubscriber().getDmaapInfo().getPassword(); - } - - public URL getBusControllerSubscriptionUrl() throws MalformedURLException { - return new URL(this.getBusControllerSubscriptionEndpoint()); - } - - public String getSubscriberIdentity(){ - return this.getStreamsSubscribes().getDmaapSubscriber().getDmaapInfo().getSubscriberId(); - } - - public String getSubscriberDcaeLocation() { - return this.getStreamsSubscribes().getDmaapSubscriber().getDmaapInfo().getLocation(); - } - - public String getPublisherTopicUrl() { - return this.getStreamsPublishes().getDmaapPublisher().getDmaapInfo().getTopicUrl(); - } - - public boolean dmaapInfoEquals(MapperConfig mapperConfig){ - return this - .getStreamsSubscribes() - .getDmaapSubscriber() - .getDmaapInfo() - .equals(mapperConfig.getStreamsSubscribes().getDmaapSubscriber().getDmaapInfo()); - } - - @Getter - @EqualsAndHashCode - private class StreamsSubscribes { - @GSONRequired - @SerializedName("dmaap_subscriber") - DmaapSubscriber dmaapSubscriber; - } - - @Getter - @EqualsAndHashCode - class DmaapSubscriber { - @GSONRequired - @SerializedName("dmaap_info") - DmaapInfo dmaapInfo; - } - - @Getter - @EqualsAndHashCode - private class StreamsPublishes { - @GSONRequired - @SerializedName("dmaap_publisher") - DmaapPublisher dmaapPublisher; - } - - @Getter - @EqualsAndHashCode - class DmaapPublisher { - @GSONRequired - @SerializedName("dmaap_info") - DmaapInfo dmaapInfo; - } - - @Getter - @EqualsAndHashCode - class DmaapInfo { - private String location; - private String username; - private String password; - - @SerializedName("delivery_url") - private String deliveryUrl; - - @SerializedName("subscriber_id") - private String subscriberId; - - @SerializedName("aaf_username") - private String aafUsername; - - @SerializedName("aaf_password") - private String aafPassword; - - @SerializedName("client_role") - private String clientRole; - - @SerializedName("client_id") - private String clientId; - - @SerializedName("topic_url") - private String topicUrl; - } - - @SerializedName("pm-mapper-filter") - MeasFilterConfig filterConfig; - - @Override - public void reconfigure(MapperConfig mapperConfig) { - if(!this.equals(mapperConfig)) { - this.streamsSubscribes = mapperConfig.getStreamsSubscribes(); - this.streamsPublishes = mapperConfig.getStreamsPublishes(); - this.busControllerSubscriptionEndpoint = mapperConfig.getBusControllerSubscriptionEndpoint(); - this.dmaapDRFeedId = mapperConfig.getDmaapDRFeedId(); - this.dmaapDRDeleteEndpoint = mapperConfig.getDmaapDRDeleteEndpoint(); - } - } +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.dcaegen2.services.pmmapper.model; + +import java.net.MalformedURLException; +import java.net.URL; + +import org.onap.dcaegen2.services.pmmapper.config.Configurable; +import org.onap.dcaegen2.services.pmmapper.utils.GSONRequired; +import com.google.gson.annotations.SerializedName; +import lombok.Getter; +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@Getter +@EqualsAndHashCode +@NoArgsConstructor +public class MapperConfig implements Configurable{ + + public static final String CLIENT_NAME = "pm-mapper"; + + @GSONRequired + @SerializedName("enable_http") + private Boolean enableHttp; + + @GSONRequired + @SerializedName("key_store_path") + private String keyStorePath; + + @GSONRequired + @SerializedName("key_store_pass_path") + private String keyStorePassPath; + + @GSONRequired + @SerializedName("trust_store_path") + private String trustStorePath; + + @GSONRequired + @SerializedName("trust_store_pass_path") + private String trustStorePassPath; + + @GSONRequired + @Getter(AccessLevel.PRIVATE) + @SerializedName("streams_subscribes") + private StreamsSubscribes streamsSubscribes; + + @GSONRequired + @Getter(AccessLevel.PRIVATE) + @SerializedName("streams_publishes") + private StreamsPublishes streamsPublishes; + + @GSONRequired + @SerializedName("buscontroller_feed_subscription_endpoint") + private String busControllerSubscriptionEndpoint; + + @GSONRequired + @SerializedName("dmaap_dr_feed_id") + private String dmaapDRFeedId; + + @GSONRequired + @SerializedName("dmaap_dr_delete_endpoint") + private String dmaapDRDeleteEndpoint; + + @GSONRequired + @SerializedName("pm-mapper-filter") + private MeasFilterConfig filterConfig; + + public String getBusControllerDeliveryUrl() { + return this.getStreamsSubscribes().getDmaapSubscriber().getDmaapInfo().getDeliveryUrl(); + } + + public String getDcaeLocation() { + return this.getStreamsSubscribes().getDmaapSubscriber().getDmaapInfo().getLocation(); + } + + public String getBusControllerUserName() { + return this.getStreamsSubscribes().getDmaapSubscriber().getDmaapInfo().getUsername(); + } + + public String getBusControllerPassword() { + return this.getStreamsSubscribes().getDmaapSubscriber().getDmaapInfo().getPassword(); + } + + public URL getBusControllerSubscriptionUrl() throws MalformedURLException { + return new URL(this.getBusControllerSubscriptionEndpoint()); + } + + public String getSubscriberIdentity(){ + return this.getStreamsSubscribes().getDmaapSubscriber().getDmaapInfo().getSubscriberId(); + } + + public String getSubscriberDcaeLocation() { + return this.getStreamsSubscribes().getDmaapSubscriber().getDmaapInfo().getLocation(); + } + + public String getPublisherTopicUrl() { + return this.getStreamsPublishes().getDmaapPublisher().getDmaapInfo().getTopicUrl(); + } + + public boolean dmaapInfoEquals(MapperConfig mapperConfig){ + return this + .getStreamsSubscribes() + .getDmaapSubscriber() + .getDmaapInfo() + .equals(mapperConfig.getStreamsSubscribes().getDmaapSubscriber().getDmaapInfo()); + } + + @Getter + @EqualsAndHashCode + private class StreamsSubscribes { + @GSONRequired + @SerializedName("dmaap_subscriber") + DmaapSubscriber dmaapSubscriber; + } + + @Getter + @EqualsAndHashCode + class DmaapSubscriber { + @GSONRequired + @SerializedName("dmaap_info") + DmaapInfo dmaapInfo; + } + + @Getter + @EqualsAndHashCode + private class StreamsPublishes { + @GSONRequired + @SerializedName("dmaap_publisher") + DmaapPublisher dmaapPublisher; + } + + @Getter + @EqualsAndHashCode + class DmaapPublisher { + @GSONRequired + @SerializedName("dmaap_info") + DmaapInfo dmaapInfo; + } + + @Getter + @EqualsAndHashCode + class DmaapInfo { + private String location; + private String username; + private String password; + + @SerializedName("delivery_url") + private String deliveryUrl; + + @SerializedName("subscriber_id") + private String subscriberId; + + @SerializedName("aaf_username") + private String aafUsername; + + @SerializedName("aaf_password") + private String aafPassword; + + @SerializedName("client_role") + private String clientRole; + + @SerializedName("client_id") + private String clientId; + + @SerializedName("topic_url") + private String topicUrl; + } + + @Override + public void reconfigure(MapperConfig mapperConfig) { + if(!this.equals(mapperConfig)) { + this.streamsSubscribes = mapperConfig.getStreamsSubscribes(); + this.streamsPublishes = mapperConfig.getStreamsPublishes(); + this.busControllerSubscriptionEndpoint = mapperConfig.getBusControllerSubscriptionEndpoint(); + this.dmaapDRFeedId = mapperConfig.getDmaapDRFeedId(); + this.dmaapDRDeleteEndpoint = mapperConfig.getDmaapDRDeleteEndpoint(); + } + } } \ No newline at end of file diff --git a/src/main/java/org/onap/dcaegen2/services/pmmapper/ssl/SSLContextFactory.java b/src/main/java/org/onap/dcaegen2/services/pmmapper/ssl/SSLContextFactory.java new file mode 100644 index 0000000..68e63f5 --- /dev/null +++ b/src/main/java/org/onap/dcaegen2/services/pmmapper/ssl/SSLContextFactory.java @@ -0,0 +1,133 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.dcaegen2.services.pmmapper.ssl; + +import org.onap.dcaegen2.services.pmmapper.exceptions.CreateContextException; +import org.onap.dcaegen2.services.pmmapper.exceptions.KeyManagerException; +import org.onap.dcaegen2.services.pmmapper.exceptions.LoadKeyStoreException; +import org.onap.dcaegen2.services.pmmapper.exceptions.TrustManagerException; +import org.onap.dcaegen2.services.pmmapper.model.MapperConfig; +import org.onap.logging.ref.slf4j.ONAPLogAdapter; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Paths; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.util.Base64; + +import static java.nio.file.Files.readAllBytes; + +public class SSLContextFactory { + private static final ONAPLogAdapter logger = new ONAPLogAdapter(LoggerFactory.getLogger(SSLContextFactory.class)); + private static MapperConfig mapperConfig; + + public SSLContextFactory(MapperConfig config) { + mapperConfig = config; + } + + public SSLContext createSSLContext(MapperConfig mapperConfig) throws IOException { + SSLContext sslContext = null; + + try { + KeyStore keyStore = loadKeyStore(mapperConfig.getKeyStorePath(), mapperConfig.getKeyStorePassPath()); + KeyManager[] keyManagers = createKeyManager(keyStore); + + KeyStore trustStore = loadKeyStore(mapperConfig.getTrustStorePath(), mapperConfig.getTrustStorePassPath()); + TrustManager[] trustManagers = createTrustManager(trustStore); + + sslContext = SSLContext.getInstance("TLSv1.2"); + sslContext.init(keyManagers, trustManagers, null); + } catch(KeyManagementException | NoSuchAlgorithmException e) { + logger.unwrap().error("Failed to create SSL Context.", e); + throw new CreateContextException("Failed to create SSL Context", e); + } + return sslContext; + } + + private KeyManager[] createKeyManager(KeyStore keyStore) throws NoSuchAlgorithmException, IOException { + KeyManager[] keyManager; + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + + try { + keyManagerFactory.init(keyStore, getPassword(mapperConfig.getKeyStorePassPath()).toCharArray()); + } catch (KeyStoreException | UnrecoverableKeyException e) { + logger.unwrap().error("Failed to initialize keystore.", e); + throw new KeyManagerException("Failed to create KeyManager from Keystore", e); + } + keyManager = keyManagerFactory.getKeyManagers(); + + return keyManager; + } + + private TrustManager[] createTrustManager(KeyStore trustStore) throws NoSuchAlgorithmException { + TrustManager[] trustManagers; + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + try { + trustManagerFactory.init(trustStore); + } catch (KeyStoreException e) { + throw new TrustManagerException("Failed to create TrustManager from Truststore", e); + } + trustManagers = trustManagerFactory.getTrustManagers(); + + return trustManagers; + } + + private KeyStore loadKeyStore(String path, String passwordPath) throws IOException, NoSuchAlgorithmException { + String type = "JKS"; + String encodedKeystore = new String(readAllBytes(Paths.get(path))); + String password = getPassword(passwordPath); + + KeyStore keyStore = null; + + try { + keyStore = KeyStore.getInstance(type); + byte[] decodedKeystore = Base64.getMimeDecoder().decode(encodedKeystore); + InputStream stream = new ByteArrayInputStream(decodedKeystore); + keyStore.load(stream, password.toCharArray()); + } catch(KeyStoreException | CertificateException e) { + logger.unwrap().error("Failed to load Keystore from given configuration.", e); + throw new LoadKeyStoreException("Failed to load Keystore from given configuration", e); + } + return keyStore; + } + + private String getPassword(String passwordPath) throws IOException { + try { + String password = new String(readAllBytes(Paths.get(passwordPath))); + password = password.replace("\n", "").replace("\r", ""); + return password; + } catch (IOException e) { + logger.unwrap().error("Could not read password from: {}.", passwordPath, e); + throw new IOException("Password not found"); + } + } +} diff --git a/src/main/java/org/onap/dcaegen2/services/pmmapper/utils/DataRouterUtils.java b/src/main/java/org/onap/dcaegen2/services/pmmapper/utils/DataRouterUtils.java index f30fb96..5147863 100644 --- a/src/main/java/org/onap/dcaegen2/services/pmmapper/utils/DataRouterUtils.java +++ b/src/main/java/org/onap/dcaegen2/services/pmmapper/utils/DataRouterUtils.java @@ -20,6 +20,7 @@ package org.onap.dcaegen2.services.pmmapper.utils; +import org.onap.dcaegen2.services.pmmapper.datarouter.DataRouterSubscriber; import org.onap.dcaegen2.services.pmmapper.exceptions.ProcessEventException; import org.onap.dcaegen2.services.pmmapper.model.Event; import org.onap.dcaegen2.services.pmmapper.model.MapperConfig; @@ -41,7 +42,7 @@ public class DataRouterUtils { public static String processEvent(MapperConfig config, Event event){ logger.unwrap().info("Sending processed to DataRouter"); String baseDelete = config.getDmaapDRDeleteEndpoint(); - String subscriberIdentity = config.getSubscriberIdentity(); + String subscriberIdentity = DataRouterSubscriber.subscriberId; String delete = String.format("%s/%s/%s", baseDelete, subscriberIdentity, event.getPublishIdentity()); try { return new RequestSender().send("DELETE", delete); @@ -50,4 +51,4 @@ public class DataRouterUtils { throw new ProcessEventException("Process event failure", exception); } } -} +} \ No newline at end of file diff --git a/src/main/java/org/onap/dcaegen2/services/pmmapper/utils/RequestSender.java b/src/main/java/org/onap/dcaegen2/services/pmmapper/utils/RequestSender.java index 658f820..fdbae59 100644 --- a/src/main/java/org/onap/dcaegen2/services/pmmapper/utils/RequestSender.java +++ b/src/main/java/org/onap/dcaegen2/services/pmmapper/utils/RequestSender.java @@ -30,11 +30,15 @@ import java.nio.charset.StandardCharsets; import java.util.UUID; import java.util.stream.Collectors; +import org.onap.dcaegen2.services.pmmapper.exceptions.ServerResponseException; import org.onap.dcaegen2.services.pmmapper.model.MapperConfig; import org.onap.logging.ref.slf4j.ONAPLogAdapter; import org.onap.logging.ref.slf4j.ONAPLogConstants; import org.slf4j.LoggerFactory; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; + public class RequestSender { private static final int MAX_RETRIES = 5; private static final int RETRY_INTERVAL = 1000; @@ -79,9 +83,16 @@ public class RequestSender { for (int i = 1; i <= MAX_RETRIES; i++) { final URL url = new URL(urlString); final HttpURLConnection connection = getHttpURLConnection(method, url, invocationID, requestID); + + + if("https".equalsIgnoreCase(url.getProtocol())) { + HttpsURLConnection.setDefaultSSLSocketFactory(SSLContext.getDefault().getSocketFactory()); + } + if(!body.isEmpty()) { setMessageBody(connection, body); } + logger.unwrap().info("Sending {} request to {}.", method, urlString); try (InputStream is = connection.getInputStream(); @@ -90,13 +101,13 @@ public class RequestSender { .collect(Collectors.joining("\n")); int responseCode = connection.getResponseCode(); if (!(isWithinErrorRange(responseCode))) { - logger.unwrap().info("Server Response Received:\n{}", result); + logger.unwrap().info("Response code: {}, Server Response Received:\n{}",responseCode, result); break; } } catch (Exception e) { if (retryLimitReached(i)) { - logger.unwrap().error("Execution error: "+connection.getResponseMessage(), e); - throw new Exception(SERVER_ERROR_MESSAGE + ": " + connection.getResponseMessage(), e); + logger.unwrap().error("Execution error: {}", connection.getResponseMessage(), e); + throw new ServerResponseException(SERVER_ERROR_MESSAGE + ": " + connection.getResponseMessage(), e); } } @@ -105,7 +116,7 @@ public class RequestSender { return result; } - private HttpURLConnection getHttpURLConnection(String method, URL url, UUID invocationID, UUID requestID) throws Exception { + private HttpURLConnection getHttpURLConnection(String method, URL url, UUID invocationID, UUID requestID) throws IOException { HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setReadTimeout(DEFAULT_READ_TIMEOUT); connection.setRequestProperty(ONAPLogConstants.Headers.REQUEST_ID, requestID.toString()); diff --git a/src/test/java/org/onap/dcaegen2/pmmapper/config/util/RequestSenderTests.java b/src/test/java/org/onap/dcaegen2/pmmapper/config/util/RequestSenderTests.java index 770ae43..b349b80 100644 --- a/src/test/java/org/onap/dcaegen2/pmmapper/config/util/RequestSenderTests.java +++ b/src/test/java/org/onap/dcaegen2/pmmapper/config/util/RequestSenderTests.java @@ -26,7 +26,6 @@ import static org.mockserver.integration.ClientAndServer.startClientAndServer; import static org.mockserver.model.HttpRequest.request; import static org.mockserver.model.HttpResponse.response; -import java.io.IOException; import java.net.URL; import java.net.UnknownHostException; diff --git a/src/test/java/org/onap/dcaegen2/services/pmmapper/ssl/SSLContextFactoryTest.java b/src/test/java/org/onap/dcaegen2/services/pmmapper/ssl/SSLContextFactoryTest.java new file mode 100644 index 0000000..6f5cee9 --- /dev/null +++ b/src/test/java/org/onap/dcaegen2/services/pmmapper/ssl/SSLContextFactoryTest.java @@ -0,0 +1,84 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.dcaegen2.services.pmmapper.ssl; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.junit.Rule; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.rules.ExpectedException; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.mockito.junit.jupiter.MockitoExtension; +import org.onap.dcaegen2.services.pmmapper.model.MapperConfig; + +import javax.net.ssl.*; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static org.junit.Assert.assertNotNull; + +@ExtendWith(MockitoExtension.class) + +public class SSLContextFactoryTest { + + @Rule + public ExpectedException exception = ExpectedException.none(); + + private static String validConfigFileContents; + private static MapperConfig validConfig; + private static MapperConfig inValidConfig; + + + private static final Path validConfigPath = Paths.get("src/test/resources/valid_mapper_config.json"); + + private SSLContextFactory objUnderTest; + + @BeforeEach + void setUp() throws Exception { + validConfigFileContents = new String(Files.readAllBytes(validConfigPath)); + JsonObject configObject = new JsonParser().parse(validConfigFileContents).getAsJsonObject(); + validConfig = new Gson().fromJson(configObject, MapperConfig.class); + + objUnderTest = new SSLContextFactory(validConfig); + } + + @Test + void testCreateSSLContext() throws IOException { + SSLContext sslContext = objUnderTest.createSSLContext(validConfig); + + assertNotNull(sslContext); + } + + @Test + void testCreateSSLContextInvalidPassword() { + JsonObject configObject = new JsonParser().parse(validConfigFileContents).getAsJsonObject(); + configObject.addProperty("key_store_pass_path", "src/test/resources/nopassword"); + inValidConfig = new Gson().fromJson(configObject, MapperConfig.class); + + assertThrows(IOException.class, () -> objUnderTest.createSSLContext(inValidConfig)); + } +} \ No newline at end of file diff --git a/src/test/java/org/onap/dcaegen2/services/pmmapper/utils/DataRouterUtilsTest.java b/src/test/java/org/onap/dcaegen2/services/pmmapper/utils/DataRouterUtilsTest.java index 73967c2..9975849 100644 --- a/src/test/java/org/onap/dcaegen2/services/pmmapper/utils/DataRouterUtilsTest.java +++ b/src/test/java/org/onap/dcaegen2/services/pmmapper/utils/DataRouterUtilsTest.java @@ -31,25 +31,74 @@ import static org.mockito.Mockito.when; import java.io.ByteArrayInputStream; import java.net.HttpURLConnection; import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import org.junit.Test; import org.junit.runner.RunWith; +import org.onap.dcaegen2.services.pmmapper.datarouter.DataRouterSubscriber; import org.onap.dcaegen2.services.pmmapper.exceptions.ProcessEventException; import org.onap.dcaegen2.services.pmmapper.model.Event; import org.onap.dcaegen2.services.pmmapper.model.EventMetadata; import org.onap.dcaegen2.services.pmmapper.model.MapperConfig; +import org.onap.dcaegen2.services.pmmapper.ssl.SSLContextFactory; import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import org.powermock.reflect.Whitebox; import utils.EventUtils; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +@PowerMockIgnore({"org.apache.http.conn.ssl.*", "javax.net.ssl.*" , "javax.crypto.*"}) +@PrepareForTest({RequestSender.class,DataRouterSubscriber.class}) @RunWith(PowerMockRunner.class) -@PrepareForTest(RequestSender.class) public class DataRouterUtilsTest { + private static String validConfigFileContents; + private static MapperConfig validConfig; + private SSLContextFactory sslContextFactory; + private static final Path validConfigPath = Paths.get("src/test/resources/valid_mapper_config.json"); + @Test public void processEventSuccessful() throws Exception { + validConfigFileContents = new String(Files.readAllBytes(validConfigPath)); + JsonObject configObject = new JsonParser().parse(validConfigFileContents).getAsJsonObject(); + validConfig = new Gson().fromJson(configObject, MapperConfig.class); + sslContextFactory = new SSLContextFactory(validConfig); + + SSLContext sslContext = sslContextFactory.createSSLContext(validConfig); + SSLContext.setDefault(sslContext); + + String serviceResponse = "I'm a service response ;)"; + String publishIdentity = "12"; + PowerMockito.mockStatic(Thread.class); + MapperConfig mockMapperConfig = mock(MapperConfig.class); + URL mockURL = mock(URL.class); + HttpsURLConnection mockConnection = mock(HttpsURLConnection.class, RETURNS_DEEP_STUBS); + when(mockConnection.getResponseCode()).thenReturn(200); + when(mockConnection.getInputStream()).thenReturn(new ByteArrayInputStream(serviceResponse.getBytes())); + + when(mockURL.openConnection()).thenReturn(mockConnection); + when(mockURL.getProtocol()).thenReturn("https"); + when(mockMapperConfig.getDmaapDRDeleteEndpoint()).thenReturn("https://dmaap-dr-node/delete/"); + when(mockMapperConfig.getSubscriberIdentity()).thenReturn("12"); + + PowerMockito.whenNew(URL.class).withAnyArguments().thenReturn(mockURL); + + Event testEvent = EventUtils.makeMockEvent("", mock(EventMetadata.class), publishIdentity); + assertEquals(serviceResponse, DataRouterUtils.processEvent(mockMapperConfig, testEvent)); + verify(mockConnection, times(1)).setRequestMethod(RequestSender.DELETE); + } + + @Test + public void processEventSuccessfulHttp() throws Exception { String serviceResponse = "I'm a service response ;)"; String publishIdentity = "12"; PowerMockito.mockStatic(Thread.class); @@ -60,7 +109,8 @@ public class DataRouterUtilsTest { when(mockConnection.getInputStream()).thenReturn(new ByteArrayInputStream(serviceResponse.getBytes())); when(mockURL.openConnection()).thenReturn(mockConnection); - when(mockMapperConfig.getDmaapDRDeleteEndpoint()).thenReturn("dmaap-dr-node/delete/"); + when(mockURL.getProtocol()).thenReturn("http"); + when(mockMapperConfig.getDmaapDRDeleteEndpoint()).thenReturn("http://dmaap-dr-node/delete/"); when(mockMapperConfig.getSubscriberIdentity()).thenReturn("12"); PowerMockito.whenNew(URL.class).withAnyArguments().thenReturn(mockURL); @@ -72,17 +122,26 @@ public class DataRouterUtilsTest { @Test public void testNegativeResponse() throws Exception { + validConfigFileContents = new String(Files.readAllBytes(validConfigPath)); + JsonObject configObject = new JsonParser().parse(validConfigFileContents).getAsJsonObject(); + validConfig = new Gson().fromJson(configObject, MapperConfig.class); + sslContextFactory = new SSLContextFactory(validConfig); + + SSLContext sslContext = sslContextFactory.createSSLContext(validConfig); + SSLContext.setDefault(sslContext); + String serviceResponse = "I'm a negative service response ;)"; String publishIdentity = "12"; PowerMockito.mockStatic(Thread.class); MapperConfig mockMapperConfig = mock(MapperConfig.class); URL mockURL = mock(URL.class); - HttpURLConnection mockConnection = mock(HttpURLConnection.class, RETURNS_DEEP_STUBS); + HttpsURLConnection mockConnection = mock(HttpsURLConnection.class, RETURNS_DEEP_STUBS); when(mockConnection.getResponseCode()).thenReturn(503); when(mockConnection.getInputStream()) .thenAnswer(invocationOnMock -> new ByteArrayInputStream(serviceResponse.getBytes())); when(mockURL.openConnection()).thenReturn(mockConnection); + when(mockURL.getProtocol()).thenReturn("https"); when(mockMapperConfig.getDmaapDRDeleteEndpoint()).thenReturn("dmaap-dr-node/delete/"); when(mockMapperConfig.getSubscriberIdentity()).thenReturn("12"); @@ -102,10 +161,11 @@ public class DataRouterUtilsTest { PowerMockito.mockStatic(Thread.class); MapperConfig mockMapperConfig = mock(MapperConfig.class); URL mockURL = mock(URL.class); - HttpURLConnection mockConnection = mock(HttpURLConnection.class, RETURNS_DEEP_STUBS); + HttpsURLConnection mockConnection = mock(HttpsURLConnection.class, RETURNS_DEEP_STUBS); when(mockConnection.getResponseCode()).thenReturn(503); when(mockURL.openConnection()).thenReturn(mockConnection); + when(mockURL.getProtocol()).thenReturn("https"); when(mockMapperConfig.getDmaapDRDeleteEndpoint()).thenReturn("dmaap-dr-node/delete/"); when(mockMapperConfig.getSubscriberIdentity()).thenReturn("12"); diff --git a/src/test/resources/password b/src/test/resources/password new file mode 100644 index 0000000..547d6c7 --- /dev/null +++ b/src/test/resources/password @@ -0,0 +1 @@ +pmmapper \ No newline at end of file diff --git a/src/test/resources/testkeystore.jks.b64 b/src/test/resources/testkeystore.jks.b64 new file mode 100644 index 0000000..f466fce --- /dev/null +++ b/src/test/resources/testkeystore.jks.b64 @@ -0,0 +1,35 @@ +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 diff --git a/src/test/resources/valid_mapper_config.json b/src/test/resources/valid_mapper_config.json index 040406f..e37b77e 100644 --- a/src/test/resources/valid_mapper_config.json +++ b/src/test/resources/valid_mapper_config.json @@ -30,5 +30,10 @@ "dmaap_dr_feed_id": "2", "buscontroller_feed_subscription_endpoint": "http://dmaap-bc.onap.svc.cluster.local:8080/webapi/dr_subs", "dmaap_dr_delete_endpoint": "http://dmaap-dr-node.onap.svc.cluster.local:8443/delete", - "services_calls": {} + "services_calls": {}, + "key_store_path": "src/test/resources/testkeystore.jks.b64", + "key_store_pass_path": "src/test/resources/password", + "trust_store_path": "src/test/resources/testkeystore.jks.b64", + "trust_store_pass_path": "src/test/resources/password", + "enable_http": false } \ No newline at end of file -- cgit 1.2.3-korg