diff options
author | wsliwka <wojciech.sliwka@nokia.com> | 2019-11-21 10:07:37 +0100 |
---|---|---|
committer | Morgan Richomme <morgan.richomme@orange.com> | 2020-01-27 15:05:10 +0000 |
commit | 6073f407aeeea1225241b4e873903deb7719da6e (patch) | |
tree | 535b737545b870f54947f923597001323ae488fa /test | |
parent | 86e0740ff36b97ba98f1ed02f34bfb23d1b96262 (diff) |
Added mTLS support in pnf simulator
Issue-ID: INT-1372
Signed-off-by: wsliwka <wojciech.sliwka@nokia.com>
Change-Id: I3bb0f3fe3849da0a72377fde5c974f4b30abd199
Diffstat (limited to 'test')
22 files changed, 262 insertions, 45 deletions
diff --git a/test/mocks/pnfsimulator/pnfsimulator/Dockerfile b/test/mocks/pnfsimulator/pnfsimulator/Dockerfile index 62d131a5a..aafea0e45 100644 --- a/test/mocks/pnfsimulator/pnfsimulator/Dockerfile +++ b/test/mocks/pnfsimulator/pnfsimulator/Dockerfile @@ -5,4 +5,4 @@ CMD apk update CMD apk add ca-certificates ADD certificates /usr/local/share/ca-certificates/ RUN update-ca-certificates -CMD java -cp /app/libs/*:/app/pnf-simulator.jar org.onap.pnfsimulator.Main +CMD java -Dspring.config.location=file:/app/application.properties -cp /app/libs/*:/app/pnf-simulator.jar org.onap.pnfsimulator.Main diff --git a/test/mocks/pnfsimulator/pnfsimulator/README.md b/test/mocks/pnfsimulator/pnfsimulator/README.md index fadb2d4a3..6caa64410 100644 --- a/test/mocks/pnfsimulator/pnfsimulator/README.md +++ b/test/mocks/pnfsimulator/pnfsimulator/README.md @@ -297,3 +297,37 @@ To test your local changes before running integration tests please build project then go to 'integration' folder and run: 'mvn test' + +### Client certificate authentication +Simulator can cooperate with VES server in different security types in particular ```auth.method=certBasicAuth``` which means that it needs to authenticate using client private certificate. + +Warning: according to VES implementation which uses certificate with Common Name set to DCAELOCAL we decided not to use strict hostname verification, so at least this parameter is skipped during checking of the client certificate. + +#### How to generate client correct keystore for pnf-simulator + The Root CA cert is available in certs folder in VES repository. The password for rootCA.key is collector. + + The procedure of generating client's certificate: + 1. Generate a private key for the SSL client: ```openssl genrsa -out client.key 2048``` + 2. Use the client’s private key to generate a cert request: ```openssl req -new -key client.key -out client.csr``` + 3. Issue the client certificate using the cert request and the CA cert/key: ```openssl x509 -req -in client.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out client.crt -days 500 -sha256``` + 4. Convert the client certificate and private key to pkcs#12 format: openssl pkcs12 -export -inkey client.key -in client.cer -out client.p12 + 5. Copy pkcs file into pnf simulators folder: ```/app/store/``` + +#### How to generate correct truststore for pnf-simulator + Create truststore with rootCA.crt: + 1. ```keytool -import -file rootCA.crt -alias firstCA -keystore trustStore``` + 2. Copy truststore to ```/app/store/``` + +#### How to refresh configuration of app +Depends your needs, you are able to change client certificate, replace trustStore to accept new server certificate change keystore and truststore passwords or completely disable client cert authentication. + +For this purpose: +1. Go to the pnf simulator container into the /app folder. +2. If you want to replace keystore or truststore put them into the /app/store folder. +3. Edit /app/application.properties file as follow: +- ssl.clientCertificateEnabled=true (to disable/enable client authentication) +- ssl.clientCertificateDir=/app/store/client.p12 (to replace keystore file) +- ssl.clientCertificatePassword=collector (to replace password for keystore) +- ssl.trustStoreDir=/app/store/trustStore (to replace truststore file) +- ssl.trustStorePassword=collector (to replace password for truststore) +4. Refresh configuration sending simple POST request to correct actuator endpoint at: ```curl http://localhost:5001/refresh -H 'Content-type: application/json' -X POST --data '{}'``` diff --git a/test/mocks/pnfsimulator/pnfsimulator/docker-compose.yml b/test/mocks/pnfsimulator/pnfsimulator/docker-compose.yml index e69d371ed..3ec8931a4 100644 --- a/test/mocks/pnfsimulator/pnfsimulator/docker-compose.yml +++ b/test/mocks/pnfsimulator/pnfsimulator/docker-compose.yml @@ -30,6 +30,7 @@ services: volumes: - ./logs:/var/log - ./templates:/app/templates + - ./store:/app/store restart: on-failure depends_on: - mongo diff --git a/test/mocks/pnfsimulator/pnfsimulator/pom.xml b/test/mocks/pnfsimulator/pnfsimulator/pom.xml index 30f1c507f..43ec50571 100644 --- a/test/mocks/pnfsimulator/pnfsimulator/pom.xml +++ b/test/mocks/pnfsimulator/pnfsimulator/pom.xml @@ -45,7 +45,7 @@ <docker.image.tag>latest</docker.image.tag> <junit.jupiter.version>5.1.0</junit.jupiter.version> <junit.vintage.version>5.1.0</junit.vintage.version> - <spring.boot.version>2.1.6.RELEASE</spring.boot.version> + <spring.boot.version>2.1.0.RELEASE</spring.boot.version> <docker.image.name>onap/${project.artifactId}</docker.image.name> <dependency.directory.name>libs</dependency.directory.name> @@ -79,6 +79,16 @@ <version>${spring.boot.version}</version> </dependency> <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-actuator</artifactId> + <version>${spring.boot.version}</version> + </dependency> + <dependency> + <groupId>org.springframework.cloud</groupId> + <artifactId>spring-cloud-config-client</artifactId> + <version>2.1.4.RELEASE</version> + </dependency> + <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/SwaggerConfig.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/SwaggerConfig.java index 90a5ecb03..6e0e18eb5 100644 --- a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/SwaggerConfig.java +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/SwaggerConfig.java @@ -20,6 +20,8 @@ package org.onap.pnfsimulator; +import org.onap.pnfsimulator.simulator.client.utils.ssl.SSLAuthenticationHelper; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.PathSelectors; @@ -29,6 +31,7 @@ import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; @Configuration +@EnableConfigurationProperties(SSLAuthenticationHelper.class) @EnableSwagger2 public class SwaggerConfig { diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/SimulatorController.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/SimulatorController.java index 88648f91d..0e4bd56ad 100644 --- a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/SimulatorController.java +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/SimulatorController.java @@ -53,6 +53,7 @@ import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; import java.io.IOException; import java.net.MalformedURLException; +import java.security.GeneralSecurityException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.List; @@ -117,7 +118,13 @@ public class SimulatorController { return buildResponse(BAD_REQUEST, ImmutableMap.of(MESSAGE, String .format(INCORRECT_TEMPLATE_MESSAGE, triggerEventRequest.getTemplateName(), e.getMessage()))); - } catch (IOException e) { + } catch (GeneralSecurityException e ){ + MDC.put(RESPONSE_CODE, INTERNAL_SERVER_ERROR.toString() ); + LOGGER.error("Client certificate validation failed: {}", e.getMessage()); + return buildResponse(INTERNAL_SERVER_ERROR, + ImmutableMap.of(MESSAGE, "Invalid or misconfigured client certificate")); + } + catch (IOException e) { MDC.put(RESPONSE_CODE, BAD_REQUEST.toString()); LOGGER.warn("Json validation failed: {}", e.getMessage()); return buildResponse(BAD_REQUEST, @@ -171,7 +178,8 @@ public class SimulatorController { } @PostMapping("event") - public ResponseEntity sendEventDirectly(@RequestHeader HttpHeaders headers, @Valid @RequestBody FullEvent event) throws MalformedURLException { + public ResponseEntity sendEventDirectly(@RequestHeader HttpHeaders headers, @Valid @RequestBody FullEvent event) + throws IOException, GeneralSecurityException{ logContextHeaders(headers, "/simulator/event"); LOGGER.info(ENTRY, "Trying to send one-time event directly to VES Collector"); simulatorService.triggerOneTimeEvent(event); @@ -179,7 +187,7 @@ public class SimulatorController { } private ResponseEntity processRequest(SimulatorRequest triggerEventRequest) - throws IOException, SchedulerException { + throws IOException, SchedulerException, GeneralSecurityException { String jobName = simulatorService.triggerEvent(triggerEventRequest); MDC.put(RESPONSE_CODE, OK.toString()); diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/SimulatorService.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/SimulatorService.java index 704905584..155c0ff91 100644 --- a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/SimulatorService.java +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/SimulatorService.java @@ -24,6 +24,7 @@ import com.google.common.base.Strings; import com.google.gson.JsonObject; import java.io.IOException; import java.net.MalformedURLException; +import java.security.GeneralSecurityException; import java.util.Optional; import org.onap.pnfsimulator.event.EventData; import org.onap.pnfsimulator.event.EventDataService; @@ -32,6 +33,7 @@ import org.onap.pnfsimulator.rest.model.SimulatorParams; import org.onap.pnfsimulator.rest.model.SimulatorRequest; import org.onap.pnfsimulator.simulator.client.HttpClientAdapter; import org.onap.pnfsimulator.simulator.client.HttpClientAdapterImpl; +import org.onap.pnfsimulator.simulator.client.utils.ssl.SSLAuthenticationHelper; import org.onap.pnfsimulator.simulator.scheduler.EventScheduler; import org.onap.pnfsimulator.simulatorconfig.SimulatorConfig; import org.onap.pnfsimulator.simulatorconfig.SimulatorConfigService; @@ -46,21 +48,23 @@ public class SimulatorService { private final TemplateReader templateReader; private final EventDataService eventDataService; private final EventScheduler eventScheduler; + private final SSLAuthenticationHelper sslAuthenticationHelper; private SimulatorConfigService simulatorConfigService; private static final JsonObject EMPTY_JSON_OBJECT = new JsonObject(); @Autowired public SimulatorService(TemplatePatcher templatePatcher, TemplateReader templateReader, EventScheduler eventScheduler, EventDataService eventDataService, - SimulatorConfigService simulatorConfigService) { + SimulatorConfigService simulatorConfigService, SSLAuthenticationHelper sslAuthenticationHelper) { this.templatePatcher = templatePatcher; this.templateReader = templateReader; this.eventDataService = eventDataService; this.eventScheduler = eventScheduler; this.simulatorConfigService = simulatorConfigService; + this.sslAuthenticationHelper = sslAuthenticationHelper; } - public String triggerEvent(SimulatorRequest simulatorRequest) throws IOException, SchedulerException { + public String triggerEvent(SimulatorRequest simulatorRequest) throws IOException, SchedulerException, GeneralSecurityException { String templateName = simulatorRequest.getTemplateName(); SimulatorParams simulatorParams = simulatorRequest.getSimulatorParams(); JsonObject template = templateReader.readTemplate(templateName); @@ -79,7 +83,7 @@ public class SimulatorService { patchedJson); } - public void triggerOneTimeEvent(FullEvent event) throws MalformedURLException { + public void triggerOneTimeEvent(FullEvent event) throws IOException, GeneralSecurityException { KeywordsHandler keywordsHandler = new KeywordsHandler(new KeywordsExtractor(), id -> 1); JsonObject withKeywordsSubstituted = keywordsHandler.substituteKeywords(event.getEvent(), "").getAsJsonObject(); @@ -105,9 +109,9 @@ public class SimulatorService { return eventScheduler.cancelEvent(jobName); } - HttpClientAdapter createHttpClientAdapter(String vesServerUrl) throws MalformedURLException { + HttpClientAdapter createHttpClientAdapter(String vesServerUrl) throws IOException, GeneralSecurityException { String targetVesUrl = getDefaultUrlIfNotProvided(vesServerUrl); - return new HttpClientAdapterImpl(targetVesUrl); + return new HttpClientAdapterImpl(targetVesUrl, sslAuthenticationHelper); } private String getDefaultUrlIfNotProvided(String vesUrlSimulatorParam) { diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImpl.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImpl.java index 6b0761975..6ea115712 100644 --- a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImpl.java +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImpl.java @@ -26,7 +26,7 @@ import static org.onap.pnfsimulator.logging.MDCVariables.X_ONAP_REQUEST_ID; import java.io.IOException; import java.io.UnsupportedEncodingException; -import java.net.MalformedURLException; +import java.security.GeneralSecurityException; import java.util.UUID; import org.apache.http.HttpResponse; @@ -35,6 +35,7 @@ import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.util.EntityUtils; +import org.onap.pnfsimulator.simulator.client.utils.ssl.SSLAuthenticationHelper; import org.onap.pnfsimulator.simulator.client.utils.ssl.SslSupportLevel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,7 +45,7 @@ import org.slf4j.MarkerFactory; public class HttpClientAdapterImpl implements HttpClientAdapter { - public static final int CONNECTION_TIMEOUT = 1000; + private static final int CONNECTION_TIMEOUT = 1000; private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientAdapterImpl.class); private static final String CONTENT_TYPE = "Content-Type"; private static final String APPLICATION_JSON = "application/json"; @@ -54,11 +55,15 @@ public class HttpClientAdapterImpl implements HttpClientAdapter { .setSocketTimeout(CONNECTION_TIMEOUT) .build(); private static final Marker INVOKE = MarkerFactory.getMarker("INVOKE"); + private SslSupportLevel sslSupportLevel; private HttpClient client; private final String targetUrl; - public HttpClientAdapterImpl(String targetUrl) throws MalformedURLException { - this.client = SslSupportLevel.getSupportLevelBasedOnProtocol(targetUrl).getClient(CONFIG); + public HttpClientAdapterImpl(String targetUrl, SSLAuthenticationHelper sslAuthenticationHelper) + throws IOException, GeneralSecurityException { + this.sslSupportLevel = sslAuthenticationHelper.isClientCertificateEnabled() ? + SslSupportLevel.CLIENT_CERT_AUTH : SslSupportLevel.getSupportLevelBasedOnProtocol(targetUrl); + this.client = sslSupportLevel.getClient(CONFIG, sslAuthenticationHelper); this.targetUrl = targetUrl; } @@ -81,6 +86,10 @@ public class HttpClientAdapterImpl implements HttpClientAdapter { } } + public SslSupportLevel getSslSupportLevel(){ + return sslSupportLevel; + } + private HttpPost createRequest(String content) throws UnsupportedEncodingException { HttpPost request = new HttpPost(this.targetUrl); StringEntity stringEntity = new StringEntity(content); diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SSLAuthenticationHelper.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SSLAuthenticationHelper.java new file mode 100644 index 000000000..40b8ab30b --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SSLAuthenticationHelper.java @@ -0,0 +1,77 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.pnfsimulator.simulator.client.utils.ssl; + +import java.io.Serializable; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "ssl") +@RefreshScope +public class SSLAuthenticationHelper implements Serializable { + + private boolean clientCertificateEnabled; + private String clientCertificateDir; + private String clientCertificatePassword; + private String trustStoreDir; + private String trustStorePassword; + + public boolean isClientCertificateEnabled() { + return clientCertificateEnabled; + } + + public void setClientCertificateEnabled(boolean clientCertificateEnabled) { + this.clientCertificateEnabled = clientCertificateEnabled; + } + + public String getClientCertificateDir() { + return clientCertificateDir; + } + + public void setClientCertificateDir(String clientCertificateDir) { + this.clientCertificateDir = clientCertificateDir; + } + + public String getClientCertificatePassword() { + return clientCertificatePassword; + } + + public void setClientCertificatePassword(String clientCertificatePassword) { + this.clientCertificatePassword = clientCertificatePassword; + } + + public String getTrustStoreDir() { + return trustStoreDir; + } + + public void setTrustStoreDir(String trustStoreDir) { + this.trustStoreDir = trustStoreDir; + } + + public String getTrustStorePassword() { + return trustStorePassword; + } + + public void setTrustStorePassword(String trustStorePassword) { + this.trustStorePassword = trustStorePassword; + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SslSupportLevel.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SslSupportLevel.java index 29416341d..264a7d1a9 100644 --- a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SslSupportLevel.java +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SslSupportLevel.java @@ -24,24 +24,32 @@ import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.TrustAllStrategy; +import org.apache.http.conn.ssl.TrustSelfSignedStrategy; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContextBuilder; +import org.apache.http.ssl.SSLContexts; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.net.ssl.SSLContext; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; +import java.security.GeneralSecurityException; import java.security.KeyManagementException; +import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; +import java.util.Optional; public enum SslSupportLevel { NONE { - public HttpClient getClient(RequestConfig requestConfig) { + public HttpClient getClient(RequestConfig requestConfig, SSLAuthenticationHelper sslAuthenticationHelper) { LOGGER.info("<!-----IN SslSupportLevel.NONE, Creating BasicHttpClient for http protocol----!>"); return HttpClientBuilder .create() @@ -50,7 +58,8 @@ public enum SslSupportLevel { } }, ALWAYS_TRUST { - public HttpClient getClient(RequestConfig requestConfig) { + public HttpClient getClient(RequestConfig requestConfig, SSLAuthenticationHelper sslAuthenticationHelper) + throws GeneralSecurityException, IOException { LoggerFactory.getLogger(SslSupportLevel.class).info("<!-----IN SslSupportLevel.ALWAYS_TRUST, Creating client with SSL support for https protocol----!>"); HttpClient client; try { @@ -61,21 +70,51 @@ public enum SslSupportLevel { .setDefaultRequestConfig(requestConfig) .build(); - } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) { + } catch (GeneralSecurityException e) { LOGGER.error("Could not initialize client due to SSL exception: {}. Default client without SSL support will be used instead.\nCause: {}", e.getMessage(), e.getCause()); - client = NONE.getClient(requestConfig); + client = NONE.getClient(requestConfig, sslAuthenticationHelper); } return client; } + }, + CLIENT_CERT_AUTH { + @Override + public HttpClient getClient(RequestConfig requestConfig, SSLAuthenticationHelper sslAuthenticationHelper) + throws GeneralSecurityException, IOException { + + SSLContext sslContext = SSLContexts.custom() + .loadKeyMaterial(readCertificate(sslAuthenticationHelper.getClientCertificateDir(), sslAuthenticationHelper.getClientCertificatePassword(), "PKCS12"), getPasswordAsCharArray(sslAuthenticationHelper.getClientCertificatePassword())) + .loadTrustMaterial(readCertificate(sslAuthenticationHelper.getTrustStoreDir(), sslAuthenticationHelper.getTrustStorePassword(), "JKS"), new TrustSelfSignedStrategy()) + .build(); + + return HttpClients.custom() + .setSSLContext(sslContext) + .setSSLHostnameVerifier(new NoopHostnameVerifier()) + .setDefaultRequestConfig(requestConfig) + .build(); + } + + private KeyStore readCertificate(String certificate, String password, String type) throws GeneralSecurityException, IOException { + try (InputStream keyStoreStream = new FileInputStream(certificate)) { + KeyStore keyStore = KeyStore.getInstance(type); + keyStore.load(keyStoreStream, getPasswordAsCharArray(password)); + return keyStore; + } + } + + private char[] getPasswordAsCharArray(String clientCertificatePassword) { + return Optional.ofNullable(clientCertificatePassword).map(String::toCharArray).orElse(null); + } }; private static final Logger LOGGER = LoggerFactory.getLogger(SslSupportLevel.class); private static final TrustStrategy TRUST_STRATEGY_ALWAYS = new TrustAllStrategy(); public static SslSupportLevel getSupportLevelBasedOnProtocol(String url) throws MalformedURLException { - return "https".equals(new URL(url).getProtocol()) ? SslSupportLevel.ALWAYS_TRUST : SslSupportLevel.NONE; + return "https".equals(new URL(url).getProtocol()) ? SslSupportLevel.ALWAYS_TRUST : SslSupportLevel.NONE; } - public abstract HttpClient getClient(RequestConfig requestConfig); + public abstract HttpClient getClient(RequestConfig config, SSLAuthenticationHelper sslAuthenticationHelper) + throws GeneralSecurityException, IOException; } diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventJob.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventJob.java index 52d076fad..c4b40fcd0 100644 --- a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventJob.java +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventJob.java @@ -25,13 +25,16 @@ import com.google.gson.JsonObject; import org.onap.pnfsimulator.simulator.KeywordsHandler; import org.onap.pnfsimulator.simulator.client.HttpClientAdapter; import org.onap.pnfsimulator.simulator.client.HttpClientAdapterImpl; +import org.onap.pnfsimulator.simulator.client.utils.ssl.SSLAuthenticationHelper; import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobExecutionContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; import java.net.MalformedURLException; +import java.security.GeneralSecurityException; import java.util.Optional; public class EventJob implements Job { @@ -69,10 +72,12 @@ public class EventJob implements Job { private Optional<HttpClientAdapter> getHttpClientAdapter(JobDataMap jobDataMap, String vesUrl) { HttpClientAdapter adapter = null; try { - adapter = (HttpClientAdapter) jobDataMap - .getOrDefault(CLIENT_ADAPTER, new HttpClientAdapterImpl(vesUrl)); + adapter = (HttpClientAdapter) (jobDataMap.containsKey(CLIENT_ADAPTER) ? jobDataMap.get(CLIENT_ADAPTER) : + new HttpClientAdapterImpl(vesUrl, new SSLAuthenticationHelper())); } catch (MalformedURLException e) { LOGGER.error("Invalid format of vesServerUr: {}", vesUrl); + } catch (IOException | GeneralSecurityException e){ + LOGGER.error("Invalid configuration of client certificate"); } return Optional.ofNullable(adapter); } diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventScheduler.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventScheduler.java index 1b1746fa5..08e24f816 100644 --- a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventScheduler.java +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventScheduler.java @@ -30,12 +30,15 @@ import static org.quartz.SimpleScheduleBuilder.simpleSchedule; import com.google.gson.JsonObject; +import java.io.IOException; import java.net.MalformedURLException; +import java.security.GeneralSecurityException; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; import org.onap.pnfsimulator.simulator.KeywordsHandler; import org.onap.pnfsimulator.simulator.client.HttpClientAdapterImpl; +import org.onap.pnfsimulator.simulator.client.utils.ssl.SSLAuthenticationHelper; import org.quartz.JobBuilder; import org.quartz.JobDataMap; import org.quartz.JobDetail; @@ -54,16 +57,18 @@ public class EventScheduler { private final Scheduler scheduler; private final KeywordsHandler keywordsHandler; + private final SSLAuthenticationHelper SSLAuthenticationHelper; @Autowired - public EventScheduler(Scheduler scheduler, KeywordsHandler keywordsHandler) { + public EventScheduler(Scheduler scheduler, KeywordsHandler keywordsHandler, SSLAuthenticationHelper SSLAuthenticationHelper) { this.scheduler = scheduler; this.keywordsHandler = keywordsHandler; + this.SSLAuthenticationHelper = SSLAuthenticationHelper; } public String scheduleEvent(String vesUrl, Integer repeatInterval, Integer repeatCount, String templateName, String eventId, JsonObject body) - throws SchedulerException, MalformedURLException { + throws SchedulerException, IOException, GeneralSecurityException { JobDetail jobDetail = createJobDetail(vesUrl, templateName, eventId, body); SimpleTrigger trigger = createTrigger(repeatInterval, repeatCount); @@ -90,14 +95,14 @@ public class EventScheduler { .build(); } - private JobDetail createJobDetail(String vesUrl, String templateName, String eventId, JsonObject body) throws MalformedURLException { + private JobDetail createJobDetail(String vesUrl, String templateName, String eventId, JsonObject body) throws IOException, GeneralSecurityException { JobDataMap jobDataMap = new JobDataMap(); jobDataMap.put(TEMPLATE_NAME, templateName); jobDataMap.put(VES_URL, vesUrl); jobDataMap.put(EVENT_ID, eventId); jobDataMap.put(KEYWORDS_HANDLER, keywordsHandler); jobDataMap.put(BODY, body); - jobDataMap.put(CLIENT_ADAPTER, new HttpClientAdapterImpl(vesUrl)); + jobDataMap.put(CLIENT_ADAPTER, new HttpClientAdapterImpl(vesUrl, SSLAuthenticationHelper)); return JobBuilder .newJob(EventJob.class) diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/resources/application.properties b/test/mocks/pnfsimulator/pnfsimulator/src/main/resources/application.properties index ae21b674c..e2c763944 100644 --- a/test/mocks/pnfsimulator/pnfsimulator/src/main/resources/application.properties +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/resources/application.properties @@ -5,3 +5,14 @@ spring.data.mongodb.port=27017 spring.data.mongodb.username=pnf_simulator_user spring.data.mongodb.password=zXcVbN123! spring.data.mongodb.database=pnf_simulator +management.endpoints.enabled-by-default=true +management.endpoint.configprops.enabled=true +management.endpoints.web.base-path=/ +management.server.port=5001 +management.endpoints.web.exposure.include=refresh + +ssl.clientCertificateEnabled=true +ssl.clientCertificateDir=/app/store/client.p12 +ssl.clientCertificatePassword=collector +ssl.trustStoreDir=/app/store/trustStore +ssl.trustStorePassword=collector diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/SimulatorControllerTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/SimulatorControllerTest.java index 36e8e6609..dae16c7c3 100644 --- a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/SimulatorControllerTest.java +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/SimulatorControllerTest.java @@ -45,6 +45,7 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders; import java.io.IOException; import java.net.URL; +import java.security.GeneralSecurityException; import static org.assertj.core.api.Java6Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -85,7 +86,7 @@ class SimulatorControllerTest { } @BeforeEach - void setup() throws IOException, SchedulerException { + void setup() throws IOException, SchedulerException, GeneralSecurityException { MockitoAnnotations.initMocks(this); when(simulatorService.triggerEvent(any())).thenReturn("jobName"); mockMvc = MockMvcBuilders diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/SimulatorServiceTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/SimulatorServiceTest.java index 32dd532aa..0196eb05c 100644 --- a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/SimulatorServiceTest.java +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/SimulatorServiceTest.java @@ -33,6 +33,7 @@ import org.onap.pnfsimulator.rest.model.FullEvent; import org.onap.pnfsimulator.rest.model.SimulatorParams; import org.onap.pnfsimulator.rest.model.SimulatorRequest; import org.onap.pnfsimulator.simulator.client.HttpClientAdapter; +import org.onap.pnfsimulator.simulator.client.utils.ssl.SSLAuthenticationHelper; import org.onap.pnfsimulator.simulator.scheduler.EventScheduler; import org.onap.pnfsimulator.simulatorconfig.SimulatorConfig; import org.onap.pnfsimulator.simulatorconfig.SimulatorConfigService; @@ -41,6 +42,7 @@ import org.quartz.SchedulerException; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.security.GeneralSecurityException; import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -102,11 +104,11 @@ class SimulatorServiceTest { simulatorConfigService = mock(SimulatorConfigService.class); simulatorService = new SimulatorService(templatePatcher, templateReader, - eventScheduler, eventDataService, simulatorConfigService); + eventScheduler, eventDataService, simulatorConfigService, new SSLAuthenticationHelper()); } @Test - void shouldTriggerEventWithGivenParams() throws IOException, SchedulerException { + void shouldTriggerEventWithGivenParams() throws IOException, SchedulerException, GeneralSecurityException { String templateName = "validExampleMeasurementEvent.json"; SimulatorParams simulatorParams = new SimulatorParams(VES_URL, 1, 1); SimulatorRequest simulatorRequest = new SimulatorRequest(simulatorParams, @@ -120,7 +122,7 @@ class SimulatorServiceTest { } @Test - void shouldTriggerEventWithDefaultVesUrlWhenNotProvidedInRequest() throws IOException, SchedulerException { + void shouldTriggerEventWithDefaultVesUrlWhenNotProvidedInRequest() throws IOException, SchedulerException, GeneralSecurityException { String templateName = "validExampleMeasurementEvent.json"; SimulatorRequest simulatorRequest = new SimulatorRequest( new SimulatorParams("", 1, 1), @@ -158,12 +160,11 @@ class SimulatorServiceTest { } @Test - void shouldHandleNonExistingPatchSection() throws IOException, SchedulerException { + void shouldHandleNonExistingPatchSection() throws IOException, SchedulerException, GeneralSecurityException { String templateName = "validExampleMeasurementEvent.json"; - JsonObject nullPatch = null; SimulatorRequest simulatorRequest = new SimulatorRequest( new SimulatorParams("", 1, 1), - templateName, nullPatch); + templateName, null); URL inDbVesUrl = new URL("http://0.0.0.0:8080/eventListener/v6"); doReturn(SAMPLE_EVENT).when(eventDataService).persistEventData(any(JsonObject.class), any(JsonObject.class), any(JsonObject.class), any(JsonObject.class)); @@ -175,8 +176,8 @@ class SimulatorServiceTest { } @Test - void shouldSuccessfullySendOneTimeEventWithVesUrlWhenPassed() throws MalformedURLException { - SimulatorService spiedTestedService = spy(new SimulatorService(templatePatcher,templateReader, eventScheduler, eventDataService, simulatorConfigService)); + void shouldSuccessfullySendOneTimeEventWithVesUrlWhenPassed() throws IOException, GeneralSecurityException { + SimulatorService spiedTestedService = spy(new SimulatorService(templatePatcher,templateReader, eventScheduler, eventDataService, simulatorConfigService, new SSLAuthenticationHelper())); HttpClientAdapter adapterMock = mock(HttpClientAdapter.class); doNothing().when(adapterMock).send(eventContentCaptor.capture()); @@ -191,8 +192,8 @@ class SimulatorServiceTest { } @Test - void shouldSubstituteKeywordsAndSuccessfullySendOneTimeEvent() throws MalformedURLException { - SimulatorService spiedTestedService = spy(new SimulatorService(templatePatcher,templateReader, eventScheduler, eventDataService, simulatorConfigService)); + void shouldSubstituteKeywordsAndSuccessfullySendOneTimeEvent() throws IOException, GeneralSecurityException { + SimulatorService spiedTestedService = spy(new SimulatorService(templatePatcher,templateReader, eventScheduler, eventDataService, simulatorConfigService, new SSLAuthenticationHelper())); HttpClientAdapter adapterMock = mock(HttpClientAdapter.class); doNothing().when(adapterMock).send(eventContentCaptor.capture()); @@ -207,7 +208,7 @@ class SimulatorServiceTest { } - private void assertEventHasExpectedStructure(String expectedVesUrl, String templateName, String sourceNameString) throws SchedulerException, MalformedURLException { + private void assertEventHasExpectedStructure(String expectedVesUrl, String templateName, String sourceNameString) throws SchedulerException, IOException, GeneralSecurityException { verify(eventScheduler, times(1)).scheduleEvent(vesUrlCaptor.capture(), intervalCaptor.capture(), repeatCountCaptor.capture(), templateNameCaptor.capture(), eventIdCaptor.capture(), bodyCaptor.capture()); assertThat(vesUrlCaptor.getValue()).isEqualTo(expectedVesUrl); diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImplTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImplTest.java index 41bd7b1e6..63c1b7221 100644 --- a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImplTest.java +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImplTest.java @@ -26,9 +26,11 @@ import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.onap.pnfsimulator.simulator.client.utils.ssl.SSLAuthenticationHelper; import java.io.IOException; import java.net.MalformedURLException; +import java.security.GeneralSecurityException; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -63,11 +65,11 @@ class HttpClientAdapterImplTest { @Test void shouldThrowExceptionWhenMalformedVesUrlPassed(){ - assertThrows(MalformedURLException.class, () -> new HttpClientAdapterImpl("http://blablabla:VES-PORT")); + assertThrows(MalformedURLException.class, () -> new HttpClientAdapterImpl("http://blablabla:VES-PORT", new SSLAuthenticationHelper())); } @Test - void shouldCreateAdapterWithClientNotSupportingSSLConnection() throws MalformedURLException { - HttpClientAdapter adapterWithHttps = new HttpClientAdapterImpl(HTTPS_URL); + void shouldCreateAdapterWithClientNotSupportingSSLConnection() throws IOException, GeneralSecurityException { + HttpClientAdapter adapterWithHttps = new HttpClientAdapterImpl(HTTPS_URL, new SSLAuthenticationHelper()); try { adapterWithHttps.send("sample"); } catch (Exception actualException) { @@ -76,8 +78,8 @@ class HttpClientAdapterImplTest { } @Test - void shouldCreateAdapterWithClientSupportingPlainConnectionOnly() throws MalformedURLException { - HttpClientAdapter adapterWithHttps = new HttpClientAdapterImpl(HTTP_URL); + void shouldCreateAdapterWithClientSupportingPlainConnectionOnly() throws IOException, GeneralSecurityException { + HttpClientAdapter adapterWithHttps = new HttpClientAdapterImpl(HTTP_URL, new SSLAuthenticationHelper()); try { adapterWithHttps.send("sample"); } catch (Exception actualException) { diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/scheduler/EventSchedulerTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/scheduler/EventSchedulerTest.java index 9d0f7d84f..84df5e9e0 100644 --- a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/scheduler/EventSchedulerTest.java +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/scheduler/EventSchedulerTest.java @@ -27,7 +27,9 @@ import static org.mockito.Mockito.when; import com.google.gson.JsonObject; +import java.io.IOException; import java.net.MalformedURLException; +import java.security.GeneralSecurityException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -37,6 +39,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.onap.pnfsimulator.simulator.client.utils.ssl.SSLAuthenticationHelper; import org.quartz.JobDataMap; import org.quartz.JobDetail; import org.quartz.JobExecutionContext; @@ -52,6 +55,9 @@ class EventSchedulerTest { @Mock Scheduler quartzScheduler; + + @Mock + SSLAuthenticationHelper sslAuthenticationHelper; @BeforeEach void setUp() { @@ -59,7 +65,7 @@ class EventSchedulerTest { } @Test - void shouldTriggerEventWithGivenConfiguration() throws SchedulerException, MalformedURLException { + void shouldTriggerEventWithGivenConfiguration() throws SchedulerException, IOException, GeneralSecurityException { //given ArgumentCaptor<JobDetail> jobDetailCaptor = ArgumentCaptor.forClass(JobDetail.class); ArgumentCaptor<SimpleTrigger> triggerCaptor = ArgumentCaptor.forClass(SimpleTrigger.class); diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/application.properties b/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/application.properties index fe10b41ce..681568073 100644 --- a/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/application.properties +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/application.properties @@ -1 +1,2 @@ -templates.dir=src/test/resources/org/onap/pnfsimulator/simulator
\ No newline at end of file +templates.dir=src/test/resources/org/onap/pnfsimulator/simulator +ssl.clientCertificateEnabled=false diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/client.p12 b/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/client.p12 Binary files differnew file mode 100644 index 000000000..0bbec381c --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/client.p12 diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/trustStore b/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/trustStore Binary files differnew file mode 100644 index 000000000..e90b71098 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/trustStore diff --git a/test/mocks/pnfsimulator/pnfsimulator/store/client.p12 b/test/mocks/pnfsimulator/pnfsimulator/store/client.p12 Binary files differnew file mode 100644 index 000000000..0bbec381c --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/store/client.p12 diff --git a/test/mocks/pnfsimulator/pnfsimulator/store/trustStore b/test/mocks/pnfsimulator/pnfsimulator/store/trustStore Binary files differnew file mode 100644 index 000000000..e90b71098 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/store/trustStore |