diff options
author | 2020-10-16 13:01:29 +0200 | |
---|---|---|
committer | 2020-10-21 20:11:48 +0200 | |
commit | 384b7b14722c5a2e351d61b3779869d680cebf8f (patch) | |
tree | b22cdd6ebe422728bc462a774c3af6f79de7e036 /pnfsimulator | |
parent | 9d44aaf054a1746149ce3bbc4c1e54e68d25f712 (diff) |
Adjust PNF simulator to use strict hostname checking.
Use separate keystore/truststore for ves.
Add network for communication between ves and pnfsim.
Issue-ID: INT-1744
Signed-off-by: tkogut <tomasz.kogut@nokia.com>
Change-Id: I6626ac6d6f74e739aeb93879eddfd44f9e9383ea
Diffstat (limited to 'pnfsimulator')
15 files changed, 561 insertions, 200 deletions
diff --git a/pnfsimulator/README.md b/pnfsimulator/README.md index 25f84da..81e59fc 100644 --- a/pnfsimulator/README.md +++ b/pnfsimulator/README.md @@ -398,7 +398,7 @@ Warning: according to VES implementation which uses certificate with Common Name 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 + 4. Convert the client certificate and private key to pkcs#12 format: ```openssl pkcs12 -export -inkey client.key -in client.crt -out client.p12``` 5. Copy pkcs file into pnf simulators folder: ```/app/store/``` #### How to generate correct truststore for pnf-simulator @@ -417,8 +417,9 @@ For this purpose: 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.strictHostnameVerification=true (to disable/enable hostname verification) - 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 by sending simple POST request to correct actuator endpoint at: ```curl http://localhost:5001/refresh -H 'Content-type: application/json' -X POST --data '{}'``` +4. Refresh configuration by sending simple POST request to correct actuator endpoint at: ```curl http://localhost:5000/refresh -H 'Content-type: application/json' -X POST --data '{}'``` diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImpl.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImpl.java index a881698..5d2a024 100644 --- a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImpl.java +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImpl.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * PNF-REGISTRATION-HANDLER * ================================================================================ - * Copyright (C) 2018 Nokia. All rights reserved. + * Copyright (C) 2020 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. @@ -22,12 +22,11 @@ package org.onap.pnfsimulator.simulator.client; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; -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.HttpClientFactoryFacade; 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; import org.slf4j.MDC; @@ -45,26 +44,16 @@ import static org.onap.pnfsimulator.logging.MdcVariables.X_ONAP_REQUEST_ID; public class HttpClientAdapterImpl implements HttpClientAdapter { - 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"; - private static final RequestConfig CONFIG = RequestConfig.custom() - .setConnectTimeout(CONNECTION_TIMEOUT) - .setConnectionRequestTimeout(CONNECTION_TIMEOUT) - .setSocketTimeout(CONNECTION_TIMEOUT) - .build(); private static final Marker INVOKE = MarkerFactory.getMarker("INVOKE"); - private SslSupportLevel sslSupportLevel; - private HttpClient client; + private final HttpClient client; private final String targetUrl; 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); + throws IOException, GeneralSecurityException { + this.client = HttpClientFactoryFacade.create(targetUrl, sslAuthenticationHelper); this.targetUrl = targetUrl; } @@ -84,10 +73,6 @@ public class HttpClientAdapterImpl implements HttpClientAdapter { } } - public SslSupportLevel getSslSupportLevel() { - return sslSupportLevel; - } - private HttpResponse sendAndRetrieve(String content) throws IOException { HttpPost request = createRequest(content); HttpResponse httpResponse = client.execute(request); diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/CertificateReader.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/CertificateReader.java new file mode 100644 index 0000000..e0b8cc2 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/CertificateReader.java @@ -0,0 +1,38 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2020 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.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.GeneralSecurityException; +import java.security.KeyStore; + +class CertificateReader { + + KeyStore read(String certificate, String password, String type) throws GeneralSecurityException, IOException { + try (InputStream keyStoreStream = new FileInputStream(certificate)) { + KeyStore keyStore = KeyStore.getInstance(type); + keyStore.load(keyStoreStream, PasswordConverter.convert(password)); + return keyStore; + } + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/HttpClientFactory.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/HttpClientFactory.java new file mode 100644 index 0000000..ca57a64 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/HttpClientFactory.java @@ -0,0 +1,104 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2020 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 io.vavr.control.Try; +import org.apache.http.client.HttpClient; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.conn.ssl.DefaultHostnameVerifier; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; +import java.io.IOException; +import java.net.URL; +import java.security.GeneralSecurityException; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; + +class HttpClientFactory { + private static final int CONNECTION_TIMEOUT = 1000; + private static final RequestConfig CONFIG = RequestConfig.custom() + .setConnectTimeout(CONNECTION_TIMEOUT) + .setConnectionRequestTimeout(CONNECTION_TIMEOUT) + .setSocketTimeout(CONNECTION_TIMEOUT) + .build(); + private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientFactory.class); + private final SSLContextFactory sslContextFactory; + + HttpClientFactory(SSLContextFactory sslContextFactory) { + this.sslContextFactory = sslContextFactory; + } + + HttpClient create(String url, SslAuthenticationHelper sslAuthenticationHelper) throws GeneralSecurityException, IOException { + HttpClient client; + if (!sslAuthenticationHelper.isClientCertificateEnabled()) { + client = "https".equals(new URL(url).getProtocol()) ? createForHttps() : createBasic(); + } else if (sslAuthenticationHelper.isStrictHostnameVerification()) { + client = createSecured(sslContextFactory.create(sslAuthenticationHelper), new DefaultHostnameVerifier()); + } else { + client = createSecured(sslContextFactory.create(sslAuthenticationHelper), new NoopHostnameVerifier()); + } + return client; + } + + private HttpClient createForHttps() { + return Try.of(this::createSecuredTrustAlways) + .onFailure(this::logErrorMessage) + .getOrElse(createBasic()); + } + + private void logErrorMessage(Throwable e) { + String message = String.format( + "Could not initialize client due to SSL exception: %s. " + + "Default client without SSL support will be used instead." + + "\nCause: %s", + e.getMessage(), + e.getCause() + ); + LOGGER.error(message, e); + } + + + private HttpClient createBasic() { + return HttpClientBuilder + .create() + .setDefaultRequestConfig(CONFIG) + .build(); + } + + private HttpClient createSecuredTrustAlways() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException { + return createSecured(sslContextFactory.createTrustAlways(), new NoopHostnameVerifier()); + } + + private HttpClient createSecured(SSLContext trustAlways, HostnameVerifier hostnameVerifier) { + return HttpClients.custom() + .setSSLContext(trustAlways) + .setDefaultRequestConfig(CONFIG) + .setSSLHostnameVerifier(hostnameVerifier) + .build(); + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/HttpClientFactoryFacade.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/HttpClientFactoryFacade.java new file mode 100644 index 0000000..521b584 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/HttpClientFactoryFacade.java @@ -0,0 +1,40 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2020 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 org.apache.http.client.HttpClient; + +import java.io.IOException; +import java.security.GeneralSecurityException; + +public class HttpClientFactoryFacade { + + private HttpClientFactoryFacade() { + } + + private static final CertificateReader CERTIFICATE_READER = new CertificateReader(); + private static final SSLContextFactory SSL_CONTEXT_FACTORY = new SSLContextFactory(CERTIFICATE_READER); + private static final HttpClientFactory HTTP_CLIENT_FACTORY = new HttpClientFactory(SSL_CONTEXT_FACTORY); + + public static HttpClient create(String url, SslAuthenticationHelper sslAuthenticationHelper) throws GeneralSecurityException, IOException { + return HTTP_CLIENT_FACTORY.create(url, sslAuthenticationHelper); + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/PasswordConverter.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/PasswordConverter.java new file mode 100644 index 0000000..7a645ae --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/PasswordConverter.java @@ -0,0 +1,32 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2020 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.util.Optional; + +class PasswordConverter { + private PasswordConverter() { + } + + static char[] convert(String password) { + return Optional.ofNullable(password).map(String::toCharArray).orElse(null); + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SSLContextFactory.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SSLContextFactory.java new file mode 100644 index 0000000..c4839fb --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SSLContextFactory.java @@ -0,0 +1,54 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2020 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 org.apache.http.conn.ssl.TrustAllStrategy; +import org.apache.http.conn.ssl.TrustSelfSignedStrategy; +import org.apache.http.conn.ssl.TrustStrategy; +import org.apache.http.ssl.SSLContextBuilder; +import org.apache.http.ssl.SSLContexts; + +import javax.net.ssl.SSLContext; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; + +class SSLContextFactory { + private static final TrustStrategy TRUST_STRATEGY_ALWAYS = new TrustAllStrategy(); + + private final CertificateReader certificateReader; + + SSLContextFactory(CertificateReader certificateReader) { + this.certificateReader = certificateReader; + } + SSLContext create(SslAuthenticationHelper sslAuthenticationHelper) throws GeneralSecurityException, IOException { + return SSLContexts.custom() + .loadKeyMaterial(certificateReader.read(sslAuthenticationHelper.getClientCertificateDir(), sslAuthenticationHelper.getClientCertificatePassword(), "PKCS12"), PasswordConverter.convert(sslAuthenticationHelper.getClientCertificatePassword())) + .loadTrustMaterial(certificateReader.read(sslAuthenticationHelper.getTrustStoreDir(), sslAuthenticationHelper.getTrustStorePassword(), "JKS"), new TrustSelfSignedStrategy()) + .build(); + } + + SSLContext createTrustAlways() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException { + return SSLContextBuilder.create().loadTrustMaterial(TRUST_STRATEGY_ALWAYS).build(); + } + +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SslAuthenticationHelper.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SslAuthenticationHelper.java index 1887d37..b785be6 100644 --- a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SslAuthenticationHelper.java +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SslAuthenticationHelper.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * PNF-REGISTRATION-HANDLER * ================================================================================ - * Copyright (C) 2019 Nokia. All rights reserved. + * Copyright (C) 2020 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. @@ -37,6 +37,7 @@ import org.springframework.stereotype.Component; public class SslAuthenticationHelper implements Serializable { private boolean clientCertificateEnabled; + private boolean strictHostnameVerification; private String clientCertificateDir; private String clientCertificatePassword; private String trustStoreDir; diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SslSupportLevel.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SslSupportLevel.java deleted file mode 100644 index fb3b958..0000000 --- a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SslSupportLevel.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER - * ================================================================================ - * Copyright (C) 2018 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 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.KeyStore; -import java.util.Optional; - -public enum SslSupportLevel { - - NONE { - public HttpClient getClient(RequestConfig requestConfig, SslAuthenticationHelper sslAuthenticationHelper) { - LOGGER.info("<!-----IN SslSupportLevel.NONE, Creating BasicHttpClient for http protocol----!>"); - return HttpClientBuilder - .create() - .setDefaultRequestConfig(requestConfig) - .build(); - } - }, - ALWAYS_TRUST { - 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 { - SSLContext alwaysTrustSslContext = SSLContextBuilder.create().loadTrustMaterial(TRUST_STRATEGY_ALWAYS).build(); - client = HttpClients.custom() - .setSSLContext(alwaysTrustSslContext) - .setSSLHostnameVerifier(new NoopHostnameVerifier()) - .setDefaultRequestConfig(requestConfig) - .build(); - - } catch (GeneralSecurityException e) { - String errorMessage = - String.format( - "Could not initialize client due to SSL exception: %s. " + - "Default client without SSL support will be used instead." + - "\nCause: %s", - e.getMessage(), - e.getCause() - ); - LOGGER.error(errorMessage, e); - 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; - } - - public abstract HttpClient getClient(RequestConfig config, SslAuthenticationHelper sslAuthenticationHelper) - throws GeneralSecurityException, IOException; - -} diff --git a/pnfsimulator/src/main/resources/application.properties b/pnfsimulator/src/main/resources/application.properties index 6c9ed42..39334d1 100644 --- a/pnfsimulator/src/main/resources/application.properties +++ b/pnfsimulator/src/main/resources/application.properties @@ -11,6 +11,7 @@ management.endpoints.web.base-path=/ management.endpoints.web.exposure.include=refresh,health ssl.clientCertificateEnabled=true +ssl.strictHostnameVerification=${STRICT_HOSTNAME_VERIFICATION:false} ssl.clientCertificateDir=/app/store/cert.p12 ssl.clientCertificatePassword=${CLIENT_CERT_PASS:collector} ssl.trustStoreDir=/app/store/trust.jks diff --git a/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/utils/ssl/HttpClientFactoryFacadeTest.java b/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/utils/ssl/HttpClientFactoryFacadeTest.java new file mode 100644 index 0000000..e6d3d03 --- /dev/null +++ b/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/utils/ssl/HttpClientFactoryFacadeTest.java @@ -0,0 +1,35 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2020 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 org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.security.GeneralSecurityException; + +import static org.junit.Assert.assertNotNull; + +class HttpClientFactoryFacadeTest { + @Test + void shouldSuccessfullyCreateHttpClient() throws GeneralSecurityException, IOException { + assertNotNull(HttpClientFactoryFacade.create("http://example.com", new SslAuthenticationHelper())); + } +} diff --git a/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/utils/ssl/HttpClientFactoryTest.java b/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/utils/ssl/HttpClientFactoryTest.java new file mode 100644 index 0000000..c213982 --- /dev/null +++ b/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/utils/ssl/HttpClientFactoryTest.java @@ -0,0 +1,143 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2020 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 org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.security.GeneralSecurityException; +import java.security.KeyStoreException; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class HttpClientFactoryTest { + private static final String HTTPS_URL = "https://example.com"; + private static final String HTTP_URL = "http://example.com"; + + private SSLContextFactory sslContextFactoryMock; + private HttpClientFactory httpClientFactory; + private SslAuthenticationHelper sslAuthenticationHelper; + + @BeforeEach + public void setup() { + sslContextFactoryMock = mock(SSLContextFactory.class); + httpClientFactory = new HttpClientFactory(sslContextFactoryMock); + sslAuthenticationHelper = new SslAuthenticationHelper(); + } + + @Test + void shouldCreateHttpsClient_whenClientCertificationDisabled() throws GeneralSecurityException, IOException { + // given + sslAuthenticationHelper.setClientCertificateEnabled(false); + + // when + final var httpClient = httpClientFactory.create(HTTPS_URL, sslAuthenticationHelper); + + // then + assertNotNull(httpClient); + verifySslContextFactoryMockCalls(0, 1); + } + + @Test + void shouldCreateHttpsClient_whenClientCertificationDisabled_AndCannotCreateTrustAlwaysSslContext() throws GeneralSecurityException, IOException { + // given + sslAuthenticationHelper.setClientCertificateEnabled(false); + when(sslContextFactoryMock.createTrustAlways()).thenThrow(KeyStoreException.class); + + // when + final var httpClient = httpClientFactory.create(HTTPS_URL, sslAuthenticationHelper); + + // then + assertNotNull(httpClient); + verifySslContextFactoryMockCalls(0, 1); + } + + @Test + void shouldCreateHttpClient_whenClientCertificationDisabled() throws GeneralSecurityException, IOException { + // given + sslAuthenticationHelper.setClientCertificateEnabled(false); + + // when + final var httpClient = httpClientFactory.create(HTTP_URL, sslAuthenticationHelper); + + // then + assertNotNull(httpClient); + verifySslContextFactoryMockCalls(0, 0); + } + + + @Test + void shouldCreateHttpClient_whenClientCertificationAndStrictHostnameVerificationAreEnabled() throws GeneralSecurityException, IOException { + // given + sslAuthenticationHelper.setClientCertificateEnabled(true); + sslAuthenticationHelper.setStrictHostnameVerification(true); + + // when + final var httpClient = httpClientFactory.create(HTTP_URL, sslAuthenticationHelper); + + // then + assertNotNull(httpClient); + verifySslContextFactoryMockCalls(1, 0); + } + + @Test + void shouldCreateHttpClient_whenClientCertificationEnabledAndStrictHostnameVerificationDisabled() throws GeneralSecurityException, IOException { + // given + sslAuthenticationHelper.setClientCertificateEnabled(true); + sslAuthenticationHelper.setStrictHostnameVerification(false); + + // when + final var httpClient = httpClientFactory.create(HTTP_URL, sslAuthenticationHelper); + + // then + assertNotNull(httpClient); + verifySslContextFactoryMockCalls(1, 0); + } + + @Test + void shouldThrowMalformedURLException_whenInvalidUrl() throws GeneralSecurityException, IOException { + // given + var invalidUrl = "invalid"; + + // when + final var exception = assertThrows(MalformedURLException.class, + () -> httpClientFactory.create(invalidUrl, sslAuthenticationHelper)); + + // then + assertThat(exception.getMessage(), CoreMatchers.containsString("invalid")); + } + + private void verifySslContextFactoryMockCalls(int createCalls, int createTrustAlwaysCalls) throws GeneralSecurityException, IOException { + verify(sslContextFactoryMock, times(createCalls)).create(any()); + verify(sslContextFactoryMock, times(createTrustAlwaysCalls)).createTrustAlways(); + } + +} diff --git a/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/utils/ssl/PasswordConverterTest.java b/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/utils/ssl/PasswordConverterTest.java new file mode 100644 index 0000000..fddfc5f --- /dev/null +++ b/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/utils/ssl/PasswordConverterTest.java @@ -0,0 +1,44 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2020 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 org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +class PasswordConverterTest { + + @Test + void shouldSuccessfullyConvert() { + // given, when + final char[] result = PasswordConverter.convert("sw ./#%"); + + // then + assertArrayEquals(new char[]{'s', 'w', ' ', '.', '/', '#', '%'}, result); + } + + @Test + void shouldReturnNull_whenNullPasswordUsed() { + // given, when, then + assertNull(PasswordConverter.convert(null)); + } +} diff --git a/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SSLContextFactoryTest.java b/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SSLContextFactoryTest.java new file mode 100644 index 0000000..8e82706 --- /dev/null +++ b/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SSLContextFactoryTest.java @@ -0,0 +1,60 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2020 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 org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.security.GeneralSecurityException; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +class SSLContextFactoryTest { + private CertificateReader certificateReaderMock; + private SSLContextFactory sslContextFactory; + + @BeforeEach + void setup() { + certificateReaderMock = mock(CertificateReader.class); + sslContextFactory = new SSLContextFactory(certificateReaderMock); + } + + @Test + void shouldSuccessfullyCreateTrustAlwaysSSLContext() throws GeneralSecurityException, IOException { + // given, when, then + assertNotNull(sslContextFactory.createTrustAlways()); + verify(certificateReaderMock, times(0)).read(any(), any(), any()); + } + + @Test + void shouldSuccessfullyCreateSSLContext() throws GeneralSecurityException, IOException { + // given, when, then + assertNotNull(sslContextFactory.create(new SslAuthenticationHelper())); + verify(certificateReaderMock, times(2)).read(any(), any(), any()); + } + +} + diff --git a/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SslSupportLevelTest.java b/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SslSupportLevelTest.java deleted file mode 100644 index 3a7dbf2..0000000 --- a/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SslSupportLevelTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER - * ================================================================================ - * Copyright (C) 2018 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 org.junit.jupiter.api.Test; - -import java.net.MalformedURLException; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - -class SslSupportLevelTest { - - private static final String HTTPS_URL = "https://127.0.0.1:8443/"; - private static final String HTTP_URL = "http://127.0.0.1:8080/"; - - @Test - void testShouldReturnAlwaysTrustSupportLevelForHttpsUrl() throws MalformedURLException { - SslSupportLevel actualSupportLevel = SslSupportLevel.getSupportLevelBasedOnProtocol(HTTPS_URL); - assertEquals(SslSupportLevel.ALWAYS_TRUST, actualSupportLevel); - } - - @Test - void testShouldReturnNoneSupportLevelForHttpUrl() throws MalformedURLException { - SslSupportLevel actualSupportLevel = SslSupportLevel.getSupportLevelBasedOnProtocol(HTTP_URL); - assertEquals(SslSupportLevel.NONE, actualSupportLevel); - } - - @Test - void testShouldRaiseExceptionWhenInvalidUrlPassed() { - assertThrows(MalformedURLException.class, () -> SslSupportLevel.getSupportLevelBasedOnProtocol("http://bla:VES-PORT/")); - } - -} |