diff options
author | Piotr Jaszczyk <piotr.jaszczyk@nokia.com> | 2018-09-20 12:04:03 +0200 |
---|---|---|
committer | Piotr Jaszczyk <piotr.jaszczyk@nokia.com> | 2018-09-24 14:25:32 +0200 |
commit | 069dcc194fd049e1c52e60d03ce2a9c0553289a7 (patch) | |
tree | 7916a4fa6b15734301c1e78bb8a20adf22532b4f | |
parent | 7b269674526a267f14895df8b825f3b59b30b98a (diff) |
Use JDK security provider
Replace netty-tcnative bindings for OpenSSL with JDK provided
implementation by default.
Change-Id: I59a4797ce43d15a791eab00bfd25cb730a271207
Issue-ID: DCAEGEN2-816
Signed-off-by: Piotr Jaszczyk <piotr.jaszczyk@nokia.com>
41 files changed, 948 insertions, 600 deletions
diff --git a/docker-compose.yml b/docker-compose.yml index f37c823a..fb8ff566 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -39,7 +39,9 @@ services: "-cp", "*:", "org.onap.dcae.collectors.veshv.main.MainKt"] command: ["--listen-port", "6061", "--health-check-api-port", "6060", - "--config-url", "http://consul:8500/v1/kv/veshv-config"] + "--config-url", "http://consul:8500/v1/kv/veshv-config", + "--key-store-password", "onaponap", + "--trust-store-password", "onaponap"] healthcheck: test: curl -f http://localhost:6060/health/ready || exit 1 interval: 10s @@ -59,7 +61,11 @@ services: # dockerfile: Dockerfile ports: - "6062:6062/tcp" - command: ["--listen-port", "6062", "--ves-host", "ves-hv-collector", "--ves-port", "6061"] + command: ["--listen-port", "6062", + "--ves-host", "ves-hv-collector", + "--ves-port", "6061", + "--key-store-password", "onaponap", + "--trust-store-password", "onaponap"] depends_on: - ves-hv-collector volumes: @@ -72,6 +78,8 @@ services: # dockerfile: Dockerfile ports: - "6063:6063/tcp" - command: ["--listen-port", "6063", "--kafka-bootstrap-servers", "kafka:9092", "--kafka-topics", "ves_hvRanMeas"] + command: ["--listen-port", "6063", + "--kafka-bootstrap-servers", "kafka:9092", + "--kafka-topics", "ves_hvRanMeas"] depends_on: - kafka diff --git a/hv-collector-core/pom.xml b/hv-collector-core/pom.xml index 9f4afe4b..edc3e2f2 100644 --- a/hv-collector-core/pom.xml +++ b/hv-collector-core/pom.xml @@ -64,6 +64,11 @@ <dependencies> <dependency> <groupId>${project.parent.groupId}</groupId> + <artifactId>hv-collector-ssl</artifactId> + <version>${project.parent.version}</version> + </dependency> + <dependency> + <groupId>${project.parent.groupId}</groupId> <artifactId>hv-collector-utils</artifactId> <version>${project.parent.version}</version> </dependency> @@ -114,12 +119,6 @@ <artifactId>reactor-kafka</artifactId> </dependency> <dependency> - <groupId>io.netty</groupId> - <artifactId>netty-tcnative-boringssl-static</artifactId> - <scope>runtime</scope> - <classifier>${os.detected.classifier}</classifier> - </dependency> - <dependency> <groupId>javax.json</groupId> <artifactId>javax.json-api</artifactId> </dependency> diff --git a/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/factory/ServerFactory.kt b/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/factory/ServerFactory.kt index 32fe6eb6..dce933ab 100644 --- a/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/factory/ServerFactory.kt +++ b/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/factory/ServerFactory.kt @@ -21,9 +21,9 @@ package org.onap.dcae.collectors.veshv.factory import org.onap.dcae.collectors.veshv.boundary.CollectorProvider import org.onap.dcae.collectors.veshv.boundary.Server -import org.onap.dcae.collectors.veshv.model.ServerConfiguration import org.onap.dcae.collectors.veshv.impl.socket.NettyTcpServer -import org.onap.dcae.collectors.veshv.impl.socket.SslContextFactory +import org.onap.dcae.collectors.veshv.model.ServerConfiguration +import org.onap.dcae.collectors.veshv.ssl.boundary.ServerSslContextFactory /** * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> @@ -31,5 +31,5 @@ import org.onap.dcae.collectors.veshv.impl.socket.SslContextFactory */ object ServerFactory { fun createNettyTcpServer(serverConfiguration: ServerConfiguration, collectorProvider: CollectorProvider): Server = - NettyTcpServer(serverConfiguration, SslContextFactory(), collectorProvider) + NettyTcpServer(serverConfiguration, ServerSslContextFactory(), collectorProvider) } diff --git a/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/impl/socket/NettyTcpServer.kt b/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/impl/socket/NettyTcpServer.kt index b4ad4b7d..ede5a667 100644 --- a/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/impl/socket/NettyTcpServer.kt +++ b/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/impl/socket/NettyTcpServer.kt @@ -25,6 +25,7 @@ import io.netty.handler.ssl.SslContext import org.onap.dcae.collectors.veshv.boundary.CollectorProvider import org.onap.dcae.collectors.veshv.boundary.Server import org.onap.dcae.collectors.veshv.model.ServerConfiguration +import org.onap.dcae.collectors.veshv.ssl.boundary.ServerSslContextFactory import org.onap.dcae.collectors.veshv.utils.NettyServerHandle import org.onap.dcae.collectors.veshv.utils.ServerHandle import org.onap.dcae.collectors.veshv.utils.logging.Logger @@ -43,7 +44,7 @@ import java.util.function.BiFunction * @since May 2018 */ internal class NettyTcpServer(private val serverConfig: ServerConfiguration, - private val sslContextFactory: SslContextFactory, + private val sslContextFactory: ServerSslContextFactory, private val collectorProvider: CollectorProvider) : Server { override fun start(): IO<ServerHandle> = IO { diff --git a/hv-collector-core/src/test/kotlin/org/onap/dcae/collectors/veshv/impl/socket/SslContextFactoryTest.kt b/hv-collector-core/src/test/kotlin/org/onap/dcae/collectors/veshv/impl/socket/SslContextFactoryTest.kt deleted file mode 100644 index deb4e183..00000000 --- a/hv-collector-core/src/test/kotlin/org/onap/dcae/collectors/veshv/impl/socket/SslContextFactoryTest.kt +++ /dev/null @@ -1,103 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * dcaegen2-collectors-veshv - * ================================================================================ - * Copyright (C) 2018 NOKIA - * ================================================================================ - * 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.dcae.collectors.veshv.impl.socket - -import io.netty.handler.ssl.ClientAuth -import io.netty.handler.ssl.ReferenceCountedOpenSslContext -import io.netty.handler.ssl.SslContextBuilder -import org.assertj.core.api.Assertions.assertThat -import org.jetbrains.spek.api.Spek -import org.jetbrains.spek.api.dsl.describe -import org.jetbrains.spek.api.dsl.given -import org.jetbrains.spek.api.dsl.it -import org.jetbrains.spek.api.dsl.on -import org.onap.dcae.collectors.veshv.domain.SecurityConfiguration -import java.nio.file.Paths -import kotlin.test.assertTrue - -/** - * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> - * @since June 2018 - */ -object SslContextFactoryTest : Spek({ - describe("SslContextFactory") { - given("config without disabled SSL") { - val sampleConfig = SecurityConfiguration( - privateKey = Paths.get("/", "tmp", "pk.pem"), - cert = Paths.get("/", "tmp", "cert.crt"), - trustedCert = Paths.get("/", "tmp", "clientCa.crt")) - - val cut = object : SslContextFactory() { - override fun createSslContextWithConfiguredCerts(secConfig: SecurityConfiguration): SslContextBuilder { - return SslContextBuilder.forServer(resource("/ssl/ca.crt"), resource("/ssl/server.key")) - } - - private fun resource(path: String) = SslContextFactoryTest.javaClass.getResourceAsStream(path) - } - - on("creation of SSL context") { - val result = cut.createSslContext(sampleConfig) - - it("should be server context") { - assertTrue(result.exists { - it.isServer - }) - } - - it("should use OpenSSL provider") { - assertTrue(result.isDefined()) - } - - /* - * It is too important to leave it untested on unit level. - * Because of the Netty API design we need to do it this way. - */ - it("should turn on client authentication") { - val clientAuth: ClientAuth = ReferenceCountedOpenSslContext::class.java - .getDeclaredField("clientAuth") - .run { - isAccessible = true - get(result.orNull()) as ClientAuth - } - assertThat(clientAuth).isEqualTo(ClientAuth.REQUIRE) - } - } - } - - given("config with SSL disabled") { - val securityConfiguration = SecurityConfiguration( - sslDisable = true, - privateKey = Paths.get("sample", "key"), - cert = Paths.get("sample", "cert"), - trustedCert = Paths.get("/", "sample", "trusted", "cert") - ) - val cut = SslContextFactory() - - on("creation of SSL context") { - val result = cut.createSslContext(securityConfiguration) - - it("should not create any SSL context ") { - assertThat(result.isDefined()).isFalse() - } - } - } - - } -}) diff --git a/hv-collector-core/src/test/resources/logback-test.xml b/hv-collector-core/src/test/resources/logback-test.xml index 84abc9d3..9a4eacfe 100644 --- a/hv-collector-core/src/test/resources/logback-test.xml +++ b/hv-collector-core/src/test/resources/logback-test.xml @@ -32,4 +32,4 @@ <appender-ref ref="CONSOLE"/> <appender-ref ref="ROLLING-FILE"/> </root> -</configuration>
\ No newline at end of file +</configuration> diff --git a/hv-collector-core/src/test/resources/ssl/ca.crt b/hv-collector-core/src/test/resources/ssl/ca.crt deleted file mode 100644 index 29057f26..00000000 --- a/hv-collector-core/src/test/resources/ssl/ca.crt +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDbDCCAlSgAwIBAgIJANad+zi5MeDSMA0GCSqGSIb3DQEBCwUAMEsxCzAJBgNV -BAYTAlBMMQswCQYDVQQIDAJETDEQMA4GA1UEBwwHV3JvY2xhdzEOMAwGA1UECgwF -Tm9raWExDTALBgNVBAsMBE1BTk8wHhcNMTgwNjAxMTMwOTE2WhcNMTkwNjAxMTMw -OTE2WjBLMQswCQYDVQQGEwJQTDELMAkGA1UECAwCREwxEDAOBgNVBAcMB1dyb2Ns -YXcxDjAMBgNVBAoMBU5va2lhMQ0wCwYDVQQLDARNQU5PMIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEArqcdlj5G4OTByGfZQ+vvdFX2ZPGKKUmUV6JYjbQH -v9C131WD2GFpbE9fAXG+R0n9c+0mbqUj3rnHzB6g5zUJBCJZXk4mM9KTq5iUfFU1 -uSQGWVCkgqmWijCROR2Eqm+v/vaSCqj77EuDEqmLe8EkFOaOKGMMdlJYYfPAyExu -k1qfmeXGzD0c/YR6ks72GW2q2xWDujvddOuxAC7CYa1iLTYSh39KLfDuoOvktqI0 -syCTyPExvmltJsb9N3AN78g+TObfAWGnkpD+QHlB1X52DU0S05+8OUkhV43aX1cd -8cIQrCvJUL/FPKe3AKgyEbLjbhkQhGQhOyjM1ptKuMucSwIDAQABo1MwUTAdBgNV -HQ4EFgQUBtX8BzxCxBS7ZTTL0pe8XcSp+McwHwYDVR0jBBgwFoAUBtX8BzxCxBS7 -ZTTL0pe8XcSp+McwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEA -niw6/qRG5ULJ6OTUd4kvw4i42EV3aV9ypd+EIzv3IuqNZBu4vqYoUSRoc1n6YwPZ -YcDq0xrVi5uw8zRR8M4/GhhT4jGLxjPHD1Jby7IyuPzByBsMJUNfdjYHjebEC820 -WJ8nbHaGm3cJVB4zMlJd5gA5+R8vp4OQmQsULxoWhDn09X4IXb/izOSK5YClf/XB -W2mQyYeAb+2H7q9fT5VVJved6h2BZsmq+SQSKlXnBMIvEjpgh7RLUuuANMgival6 -NlSezPQD9iuyj9g2Xz3z8ggRGahYPSKAb6+fg3TGg/Vokd4GYEMflfC2tw+eM07n -oTa03o8tD9V4paP/vx7cUg== ------END CERTIFICATE----- diff --git a/hv-collector-core/src/test/resources/ssl/server.crt b/hv-collector-core/src/test/resources/ssl/server.crt deleted file mode 100644 index 0af22e29..00000000 --- a/hv-collector-core/src/test/resources/ssl/server.crt +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDEjCCAfoCCQDSzpBZljMk+jANBgkqhkiG9w0BAQsFADBLMQswCQYDVQQGEwJQ -TDELMAkGA1UECAwCREwxEDAOBgNVBAcMB1dyb2NsYXcxDjAMBgNVBAoMBU5va2lh -MQ0wCwYDVQQLDARNQU5PMB4XDTE4MDYwMTEzMDkxNloXDTE5MDUyNzEzMDkxNlow -SzELMAkGA1UEBhMCUEwxCzAJBgNVBAgMAkRMMRAwDgYDVQQHDAdXcm9jbGF3MQ4w -DAYDVQQKDAVOb2tpYTENMAsGA1UECwwETUFOTzCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBAOdOjGM8+5+ArMawknY+QPTO4Q//QuRi46OxkU28DshayG1o -pyCoKD6zYB4Q7cgSY8xrwX7Ct6QINaGefSddKdDJl4zzjiVCUK7vaKxaOK2hOl7k -Iq7HuvAG6TaO7CaeBFafGNxpocgC2WkoZCIqQ32gXHjU5mpTrzwtUyX91Xc43puP -nHGBz6XDVlV52DvJQ1v9xed4bM70DgSg3FcD77mcPDbr98UvPa477RKeAz8eAc+J -jxMg8uNGYX0sthGEcOiOf1Dz8UeMU1M2Qw6MGDqrW+RMaM9K8/mlbQ/SFqoPg4MD -q3zbQie0IzfanQuygz9Zy7dDAVgzmjrX8/tf+nMCAwEAATANBgkqhkiG9w0BAQsF -AAOCAQEALPII5UXwBSNGcVa14t3NUUb0jtXdtmKr6sRMqFdR81tREcJHGnMauxO9 -IuECQuDkIRkv2XR+Swn2vZdOkYtHSAHSRLxPUhwjYKFC7uTd6T1ljTiYJ/NtGCV3 -75n0qh2aneCXr9KVExK6KzYVFJKMKmbEJludaQrM/Z+kDXGwwUMcyb8LLO+avgek -ke1796f0MJ56csHejT9V69/6zc07T/zn0gVcR42AnMr/MzhAkiqUOhy0Cxzek0Xv -72/1PKaf2r9F+WtjQuPRd6LJrM7yTnkzLz7xK+yX17mycIN4KsVf8zhrsCgVJZGL -kLkC4O9faHnrtj0qqV+BPhyF1Ii95w== ------END CERTIFICATE----- diff --git a/hv-collector-core/src/test/resources/ssl/server.key b/hv-collector-core/src/test/resources/ssl/server.key deleted file mode 100644 index 033c99af..00000000 --- a/hv-collector-core/src/test/resources/ssl/server.key +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDnToxjPPufgKzG -sJJ2PkD0zuEP/0LkYuOjsZFNvA7IWshtaKcgqCg+s2AeEO3IEmPMa8F+wrekCDWh -nn0nXSnQyZeM844lQlCu72isWjitoTpe5CKux7rwBuk2juwmngRWnxjcaaHIAtlp -KGQiKkN9oFx41OZqU688LVMl/dV3ON6bj5xxgc+lw1ZVedg7yUNb/cXneGzO9A4E -oNxXA++5nDw26/fFLz2uO+0SngM/HgHPiY8TIPLjRmF9LLYRhHDojn9Q8/FHjFNT -NkMOjBg6q1vkTGjPSvP5pW0P0haqD4ODA6t820IntCM32p0LsoM/Wcu3QwFYM5o6 -1/P7X/pzAgMBAAECggEAYBIL1Rv7FqCHIm8sJdhtekCC0fYffmRkUBTsWPEG4shx -/p886x9st74g6dv2JuccdEc9Mr0FMSgHvnzpVnQnbgSM4Yo3O9pzUHU3cH54lAUn -DUqL7TQfvJniOzrZcqCnBKNH3CQzgbNNQZP5IweSyJbWUYl7uiXP3pqksl7fToiS -JBSKzKphwtHRUHS3RCwN118N5RyZH+0LZi0EAOjxi1BVqmKQos0Zr8Gnl/7nHF+g -oRG4vgDZUopNEGX5AELvMBq/hbSrfGT1z+wJkOtoRdinRMGFKO528vCqhEr629Sh -FFUOv3xL7HUEEnDu97I0TxK1o6C5fG/QbeP9viiJIQKBgQD2upLpuyP6iTCdAl/S -lLmQxwEUyD3vhF4oG+B0jKyNkzO7QzM695HH/bXV9GnRH+9HPgxLqtozVpztsuu2 -MXrac2tmJR9OiSchJwgDRvhSUyezEULFAzsIaSeGK16wrcT6xqwVeKumsKp1dW7I -n0w5NxC/N2U87ffjmyOwldOAHwKBgQDv/58mMUutViwicw8ddRJP38QZs804vm7R -YFb5sqt6L7hcSQCszVXdjHP2v/GeK+jl0vZrGS932kY3T2+FhA8ClbKByVdaFzXj -PSEuY/Ow+ebGrlBPBH6sPN4Uvc00MEk1eZXRL8IaT32xJnq2vF4M7SvGNFeH39tc -qOq9VqrrLQKBgQCRzdYN6/qqDrK8xm9sGVnD9eZsqpz3U2j1GOw+0/cQvyG+E0tO -GIl8/zCa3JI/9DhKCJ/pg3DpD9EzIx3qkDkCqVyZg2yJ08Fc9RzmGuWaeOuoBZZI -qM0U/ldOEYkmrboPXKLLGYGOwy4otZofUwwPb7wk1A6uwA5S4hZoP1I6jwKBgQCS -yfH5ViVHO3F7EIyqI7SzjdVPMx3OGwuEnDwWNSWUciN8rlnvVxexjfpPbU7Gw2yL -RODa2GikEajoo3k+XGsh1ZV8tDztKU0YU4c77H5cPDzeQDd2XPVtOz1Jylz8Epx0 -TI1JiMBbf0sNUs+zfLq5hUZE0DbJMC3nGpmYfK3FcQKBgQCFlXdwWzhu33HHa+wc -X7JT0m8W81ex08ndNOCgdYqgOxmZ+VhK8WN91sj3N0X9nMsfSJ9WTRib+FVa8D4M -e7hOddjrKxNcqAhjbnxeCHLExq9kYdjeXa0dS9ywP89nMlGm7qja7+9DSBPisRPe -lcaTvr7E/zSTHK5WDBCzOsV3lQ== ------END PRIVATE KEY----- diff --git a/hv-collector-dcae-app-simulator/src/main/kotlin/org/onap/dcae/collectors/veshv/simulators/dcaeapp/impl/config/ArgDcaeAppSimConfiguration.kt b/hv-collector-dcae-app-simulator/src/main/kotlin/org/onap/dcae/collectors/veshv/simulators/dcaeapp/impl/config/ArgDcaeAppSimConfiguration.kt index d5f55605..d0820616 100644 --- a/hv-collector-dcae-app-simulator/src/main/kotlin/org/onap/dcae/collectors/veshv/simulators/dcaeapp/impl/config/ArgDcaeAppSimConfiguration.kt +++ b/hv-collector-dcae-app-simulator/src/main/kotlin/org/onap/dcae/collectors/veshv/simulators/dcaeapp/impl/config/ArgDcaeAppSimConfiguration.kt @@ -31,6 +31,8 @@ import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.KAFKA_SERVERS import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.KAFKA_TOPICS import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.LISTEN_PORT +import org.onap.dcae.collectors.veshv.utils.commandline.intValue +import org.onap.dcae.collectors.veshv.utils.commandline.stringValue class ArgDcaeAppSimConfiguration : ArgBasedConfiguration<DcaeAppSimConfiguration>(DefaultParser()) { override val cmdLineOptionsList: List<CommandLineOption> = listOf( diff --git a/hv-collector-domain/src/main/kotlin/org/onap/dcae/collectors/veshv/domain/SecurityConfiguration.kt b/hv-collector-domain/src/main/kotlin/org/onap/dcae/collectors/veshv/domain/SecurityConfiguration.kt index e409eb7a..7f566a6d 100644 --- a/hv-collector-domain/src/main/kotlin/org/onap/dcae/collectors/veshv/domain/SecurityConfiguration.kt +++ b/hv-collector-domain/src/main/kotlin/org/onap/dcae/collectors/veshv/domain/SecurityConfiguration.kt @@ -19,6 +19,8 @@ */ package org.onap.dcae.collectors.veshv.domain +import arrow.core.Option +import java.io.InputStream import java.nio.file.Path /** @@ -27,6 +29,22 @@ import java.nio.file.Path */ data class SecurityConfiguration( val sslDisable: Boolean = false, - val privateKey: Path, - val cert: Path, - val trustedCert: Path) + val keys: Option<SslKeys>) + +sealed class SslKeys + +data class OpenSslKeys(val privateKey: Path, + val cert: Path, + val trustedCert: Path) : SslKeys() + +data class JdkKeys(val keyStore: StreamProvider, + val keyStorePassword: CharArray, + val trustStore: StreamProvider, + val trustStorePassword: CharArray) : SslKeys() { + fun forgetPasswords() { + keyStorePassword.fill('x') + trustStorePassword.fill('x') + } +} + +typealias StreamProvider = () -> InputStream diff --git a/hv-collector-main/Dockerfile b/hv-collector-main/Dockerfile index 8216ac46..746deb51 100644 --- a/hv-collector-main/Dockerfile +++ b/hv-collector-main/Dockerfile @@ -6,8 +6,7 @@ LABEL license.url="http://www.apache.org/licenses/LICENSE-2.0" LABEL maintainer="Nokia Wroclaw ONAP Team" RUN apt-get update \ - && apt-get install -y --no-install-recommends curl \ - && apt-get install -y --no-install-recommends netcat \ + && apt-get install -y --no-install-recommends curl netcat \ && apt-get clean WORKDIR /opt/ves-hv-collector diff --git a/hv-collector-main/pom.xml b/hv-collector-main/pom.xml index ed37515d..571821a6 100644 --- a/hv-collector-main/pom.xml +++ b/hv-collector-main/pom.xml @@ -117,12 +117,18 @@ <groupId>commons-cli</groupId> <artifactId>commons-cli</artifactId> </dependency> + <!-- See comment in main pom + <dependency> + <groupId>io.netty</groupId> + <artifactId>netty-transport-native-epoll</artifactId> + <classifier>${os.detected.classifier}</classifier> + </dependency> <dependency> <groupId>io.netty</groupId> <artifactId>netty-tcnative-boringssl-static</artifactId> - <scope>runtime</scope> <classifier>${os.detected.classifier}</classifier> </dependency> + --> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-jmx</artifactId> diff --git a/hv-collector-main/src/main/kotlin/org/onap/dcae/collectors/veshv/main/ArgVesHvConfiguration.kt b/hv-collector-main/src/main/kotlin/org/onap/dcae/collectors/veshv/main/ArgVesHvConfiguration.kt index 26230cd3..d6ff9efa 100644 --- a/hv-collector-main/src/main/kotlin/org/onap/dcae/collectors/veshv/main/ArgVesHvConfiguration.kt +++ b/hv-collector-main/src/main/kotlin/org/onap/dcae/collectors/veshv/main/ArgVesHvConfiguration.kt @@ -22,25 +22,31 @@ package org.onap.dcae.collectors.veshv.main import arrow.core.ForOption import arrow.core.Option import arrow.core.fix +import arrow.core.monad import arrow.instances.extensions import arrow.typeclasses.binding import org.apache.commons.cli.CommandLine import org.apache.commons.cli.DefaultParser -import org.onap.dcae.collectors.veshv.domain.SecurityConfiguration import org.onap.dcae.collectors.veshv.model.ConfigurationProviderParams import org.onap.dcae.collectors.veshv.model.ServerConfiguration +import org.onap.dcae.collectors.veshv.ssl.boundary.createSecurityConfiguration import org.onap.dcae.collectors.veshv.utils.commandline.ArgBasedConfiguration -import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.CERT_FILE import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.CONSUL_CONFIG_URL import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.CONSUL_FIRST_REQUEST_DELAY import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.CONSUL_REQUEST_INTERVAL import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.DUMMY_MODE import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.HEALTH_CHECK_API_PORT import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.IDLE_TIMEOUT_SEC +import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.KEY_STORE_FILE +import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.KEY_STORE_PASSWORD import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.LISTEN_PORT -import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.PRIVATE_KEY_FILE import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.SSL_DISABLE -import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.TRUST_CERT_FILE +import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.TRUST_STORE_FILE +import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.TRUST_STORE_PASSWORD +import org.onap.dcae.collectors.veshv.utils.commandline.hasOption +import org.onap.dcae.collectors.veshv.utils.commandline.intValue +import org.onap.dcae.collectors.veshv.utils.commandline.longValue +import org.onap.dcae.collectors.veshv.utils.commandline.stringValue import java.time.Duration internal class ArgVesHvConfiguration : ArgBasedConfiguration<ServerConfiguration>(DefaultParser()) { @@ -51,34 +57,33 @@ internal class ArgVesHvConfiguration : ArgBasedConfiguration<ServerConfiguration CONSUL_FIRST_REQUEST_DELAY, CONSUL_REQUEST_INTERVAL, SSL_DISABLE, - PRIVATE_KEY_FILE, - CERT_FILE, - TRUST_CERT_FILE, + KEY_STORE_FILE, + KEY_STORE_PASSWORD, + TRUST_STORE_FILE, + TRUST_STORE_PASSWORD, IDLE_TIMEOUT_SEC, DUMMY_MODE ) override fun getConfiguration(cmdLine: CommandLine): Option<ServerConfiguration> = - ForOption extensions { - binding { - val healthCheckApiPort = cmdLine.intValue( - HEALTH_CHECK_API_PORT, - DefaultValues.HEALTH_CHECK_API_PORT - ) - val listenPort = cmdLine.intValue(LISTEN_PORT).bind() - val idleTimeoutSec = cmdLine.longValue(IDLE_TIMEOUT_SEC, DefaultValues.IDLE_TIMEOUT_SEC) - val dummyMode = cmdLine.hasOption(DUMMY_MODE) - val security = createSecurityConfiguration(cmdLine) - val configurationProviderParams = createConfigurationProviderParams(cmdLine).bind() - ServerConfiguration( - healthCheckApiPort = healthCheckApiPort, - listenPort = listenPort, - configurationProviderParams = configurationProviderParams, - securityConfiguration = security, - idleTimeout = Duration.ofSeconds(idleTimeoutSec), - dummyMode = dummyMode) - }.fix() - } + Option.monad().binding { + val healthCheckApiPort = cmdLine.intValue( + HEALTH_CHECK_API_PORT, + DefaultValues.HEALTH_CHECK_API_PORT + ) + val listenPort = cmdLine.intValue(LISTEN_PORT).bind() + val idleTimeoutSec = cmdLine.longValue(IDLE_TIMEOUT_SEC, DefaultValues.IDLE_TIMEOUT_SEC) + val dummyMode = cmdLine.hasOption(DUMMY_MODE) + val security = createSecurityConfiguration(cmdLine).bind() + val configurationProviderParams = createConfigurationProviderParams(cmdLine).bind() + ServerConfiguration( + healthCheckApiPort = healthCheckApiPort, + listenPort = listenPort, + configurationProviderParams = configurationProviderParams, + securityConfiguration = security, + idleTimeout = Duration.ofSeconds(idleTimeoutSec), + dummyMode = dummyMode) + }.fix() private fun createConfigurationProviderParams(cmdLine: CommandLine): Option<ConfigurationProviderParams> = ForOption extensions { @@ -100,27 +105,10 @@ internal class ArgVesHvConfiguration : ArgBasedConfiguration<ServerConfiguration }.fix() } - private fun createSecurityConfiguration(cmdLine: CommandLine): SecurityConfiguration { - val sslDisable = cmdLine.hasOption(SSL_DISABLE) - val pkFile = cmdLine.stringValue(PRIVATE_KEY_FILE, DefaultValues.PRIVATE_KEY_FILE) - val certFile = cmdLine.stringValue(CERT_FILE, DefaultValues.CERT_FILE) - val trustCertFile = cmdLine.stringValue(TRUST_CERT_FILE, DefaultValues.TRUST_CERT_FILE) - - return SecurityConfiguration( - sslDisable = sslDisable, - privateKey = stringPathToPath(pkFile), - cert = stringPathToPath(certFile), - trustedCert = stringPathToPath(trustCertFile) - ) - } - internal object DefaultValues { const val HEALTH_CHECK_API_PORT = 6060 const val CONSUL_FIRST_REQUEST_DELAY = 10L const val CONSUL_REQUEST_INTERVAL = 5L - const val PRIVATE_KEY_FILE = "/etc/ves-hv/server.key" - const val CERT_FILE = "/etc/ves-hv/server.crt" - const val TRUST_CERT_FILE = "/etc/ves-hv/trust.crt" const val IDLE_TIMEOUT_SEC = 60L } } diff --git a/hv-collector-main/src/test/kotlin/org/onap/dcae/collectors/veshv/main/ArgVesHvConfigurationTest.kt b/hv-collector-main/src/test/kotlin/org/onap/dcae/collectors/veshv/main/ArgVesHvConfigurationTest.kt index 26507197..0cf0bb2c 100644 --- a/hv-collector-main/src/test/kotlin/org/onap/dcae/collectors/veshv/main/ArgVesHvConfigurationTest.kt +++ b/hv-collector-main/src/test/kotlin/org/onap/dcae/collectors/veshv/main/ArgVesHvConfigurationTest.kt @@ -19,20 +19,20 @@ */ package org.onap.dcae.collectors.veshv.main +import arrow.core.identity import org.assertj.core.api.Assertions.assertThat import org.jetbrains.spek.api.Spek import org.jetbrains.spek.api.dsl.describe import org.jetbrains.spek.api.dsl.given import org.jetbrains.spek.api.dsl.it import org.jetbrains.spek.api.dsl.on -import org.onap.dcae.collectors.veshv.domain.SecurityConfiguration -import org.onap.dcae.collectors.veshv.main.ArgVesHvConfiguration.DefaultValues +import org.onap.dcae.collectors.veshv.domain.JdkKeys import org.onap.dcae.collectors.veshv.model.ServerConfiguration import org.onap.dcae.collectors.veshv.tests.utils.parseExpectingFailure import org.onap.dcae.collectors.veshv.tests.utils.parseExpectingSuccess import org.onap.dcae.collectors.veshv.utils.commandline.WrongArgumentError -import java.nio.file.Paths import java.time.Duration +import kotlin.test.assertNotNull /** * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> @@ -45,9 +45,8 @@ object ArgVesHvConfigurationTest : Spek({ val firstRequestDelay = "10" val requestInterval = "5" val listenPort = "6969" - val pk = Paths.get("/", "etc", "ves", "pk.pem") - val cert = Paths.get("/", "etc", "ssl", "certs", "ca-bundle.crt") - val trustCert = Paths.get("/", "etc", "ves", "trusted.crt") + val keyStorePassword = "kspass" + val trustStorePassword = "tspass" beforeEachTest { cut = ArgVesHvConfiguration() @@ -58,15 +57,17 @@ object ArgVesHvConfigurationTest : Spek({ lateinit var result: ServerConfiguration beforeEachTest { - result = cut.parseExpectingSuccess("--ssl-disable", + result = cut.parseExpectingSuccess( "--health-check-api-port", healthCheckApiPort, "--listen-port", listenPort, "--config-url", configurationUrl, "--first-request-delay", firstRequestDelay, "--request-interval", requestInterval, - "--private-key-file", pk.toFile().absolutePath, - "--cert-file", cert.toFile().absolutePath, - "--trust-cert-file", trustCert.toFile().absolutePath) + "--key-store", "/tmp/keys.p12", + "--trust-store", "/tmp/trust.p12", + "--key-store-password", keyStorePassword, + "--trust-store-password", trustStorePassword + ) } it("should set proper health check api port") { @@ -93,69 +94,13 @@ object ArgVesHvConfigurationTest : Spek({ } it("should set proper security configuration") { - assertThat(result.securityConfiguration).isEqualTo( - SecurityConfiguration(sslDisable = true, privateKey = pk, cert = cert, trustedCert = trustCert) - ) - } - } - - given("some parameters are present in the short form") { - lateinit var result: ServerConfiguration - - beforeEachTest { - result = cut.parseExpectingSuccess( - "-p", listenPort, "-c", configurationUrl, "-d", firstRequestDelay - ) - } + assertThat(result.securityConfiguration.sslDisable).isFalse() - it("should set proper port") { - assertThat(result.listenPort).isEqualTo(listenPort.toInt()) - } - - it("should set proper first consul request delay") { - assertThat(result.configurationProviderParams.firstRequestDelay) - .isEqualTo(Duration.ofSeconds(firstRequestDelay.toLong())) - } - - it("should set proper config url") { - assertThat(result.configurationProviderParams.configurationUrl) - .isEqualTo(configurationUrl) - } - } - - given("all optional parameters are absent") { - lateinit var result: ServerConfiguration - - beforeEachTest { - result = cut.parseExpectingSuccess( - "--listen-port", listenPort, "--config-url", configurationUrl - ) - } - - it("should set default first consul request delay") { - assertThat(result.configurationProviderParams.firstRequestDelay) - .isEqualTo(Duration.ofSeconds(DefaultValues.CONSUL_FIRST_REQUEST_DELAY)) - } - - it("should set default consul request interval") { - assertThat(result.configurationProviderParams.requestInterval) - .isEqualTo(Duration.ofSeconds(DefaultValues.CONSUL_REQUEST_INTERVAL)) - } - - on("security config") { - val securityConfiguration = result.securityConfiguration - - it("should set default trust cert file") { - assertThat(securityConfiguration.trustedCert.toString()).isEqualTo(DefaultValues.TRUST_CERT_FILE) - } - - it("should set default server cert file") { - assertThat(securityConfiguration.cert.toString()).isEqualTo(DefaultValues.CERT_FILE) - } - - it("should set default private key file") { - assertThat(securityConfiguration.privateKey.toString()).isEqualTo(DefaultValues.PRIVATE_KEY_FILE) - } + val keys = result.securityConfiguration.keys.orNull() as JdkKeys + assertNotNull(keys.keyStore) + assertNotNull(keys.trustStore) + assertThat(keys.keyStorePassword).isEqualTo(keyStorePassword.toCharArray()) + assertThat(keys.trustStorePassword).isEqualTo(trustStorePassword.toCharArray()) } } @@ -166,10 +111,7 @@ object ArgVesHvConfigurationTest : Spek({ "--config-url", configurationUrl, "--ssl-disable", "--first-request-delay", firstRequestDelay, - "--request-interval", requestInterval, - "--private-key-file", pk.toFile().absolutePath, - "--cert-file", cert.toFile().absolutePath, - "--trust-cert-file", trustCert.toFile().absolutePath) + "--request-interval", requestInterval) ).isInstanceOf(WrongArgumentError::class.java) } } @@ -179,10 +121,7 @@ object ArgVesHvConfigurationTest : Spek({ "--listen-port", listenPort, "--ssl-disable", "--first-request-delay", firstRequestDelay, - "--request-interval", requestInterval, - "--private-key-file", pk.toFile().absolutePath, - "--cert-file", cert.toFile().absolutePath, - "--trust-cert-file", trustCert.toFile().absolutePath) + "--request-interval", requestInterval) ).isInstanceOf(WrongArgumentError::class.java) } } diff --git a/hv-collector-ssl/pom.xml b/hv-collector-ssl/pom.xml new file mode 100644 index 00000000..f5ea00ca --- /dev/null +++ b/hv-collector-ssl/pom.xml @@ -0,0 +1,118 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ ============LICENSE_START======================================================= + ~ dcaegen2-collectors-veshv + ~ ================================================================================ + ~ Copyright (C) 2018 NOKIA + ~ ================================================================================ + ~ 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========================================================= + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <licenses> + <license> + <name>The Apache Software License, Version 2.0</name> + <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> + </license> + </licenses> + + <parent> + <groupId>org.onap.dcaegen2.collectors.hv-ves</groupId> + <artifactId>ves-hv-collector</artifactId> + <version>1.0.0-SNAPSHOT</version> + <relativePath>..</relativePath> + </parent> + + <artifactId>hv-collector-ssl</artifactId> + <description>VES HighVolume Collector :: SSL</description> + + <properties> + <skipAnalysis>false</skipAnalysis> + </properties> + + <build> + <plugins> + <plugin> + <artifactId>kotlin-maven-plugin</artifactId> + <groupId>org.jetbrains.kotlin</groupId> + </plugin> + <plugin> + <artifactId>maven-surefire-plugin</artifactId> + <groupId>org.apache.maven.plugins</groupId> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>${project.parent.groupId}</groupId> + <artifactId>hv-collector-domain</artifactId> + <version>${project.parent.version}</version> + </dependency> + <dependency> + <groupId>${project.parent.groupId}</groupId> + <artifactId>hv-collector-utils</artifactId> + <version>${project.parent.version}</version> + </dependency> + <dependency> + <groupId>${project.parent.groupId}</groupId> + <artifactId>hv-collector-test-utils</artifactId> + <version>${project.parent.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>io.netty</groupId> + <artifactId>netty-tcnative-boringssl-static</artifactId> + <classifier>${os.detected.classifier}</classifier> + <scope>test</scope> + </dependency> + <dependency> + <groupId>io.arrow-kt</groupId> + <artifactId>arrow-core</artifactId> + </dependency> + <dependency> + <groupId>io.arrow-kt</groupId> + <artifactId>arrow-syntax</artifactId> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + </dependency> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + </dependency> + <dependency> + <groupId>org.jetbrains.kotlin</groupId> + <artifactId>kotlin-test</artifactId> + </dependency> + <dependency> + <groupId>org.jetbrains.spek</groupId> + <artifactId>spek-api</artifactId> + </dependency> + <dependency> + <groupId>org.jetbrains.spek</groupId> + <artifactId>spek-junit-platform-engine</artifactId> + </dependency> + </dependencies> + + +</project> diff --git a/hv-collector-ssl/src/main/kotlin/org/onap/dcae/collectors/veshv/ssl/boundary/ClientSslContextFactory.kt b/hv-collector-ssl/src/main/kotlin/org/onap/dcae/collectors/veshv/ssl/boundary/ClientSslContextFactory.kt new file mode 100644 index 00000000..0ad3d7b4 --- /dev/null +++ b/hv-collector-ssl/src/main/kotlin/org/onap/dcae/collectors/veshv/ssl/boundary/ClientSslContextFactory.kt @@ -0,0 +1,52 @@ +/* + * ============LICENSE_START======================================================= + * dcaegen2-collectors-veshv + * ================================================================================ + * Copyright (C) 2018 NOKIA + * ================================================================================ + * 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.dcae.collectors.veshv.ssl.boundary + +import io.netty.handler.ssl.SslContextBuilder +import io.netty.handler.ssl.SslProvider +import org.onap.dcae.collectors.veshv.domain.JdkKeys +import org.onap.dcae.collectors.veshv.domain.OpenSslKeys +import org.onap.dcae.collectors.veshv.ssl.impl.SslFactories.keyManagerFactory +import org.onap.dcae.collectors.veshv.ssl.impl.SslFactories.trustManagerFactory + +/** + * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> + * @since September 2018 + */ +open class ClientSslContextFactory : SslContextFactory() { + + override fun openSslContext(openSslKeys: OpenSslKeys) = SslContextBuilder.forClient() + .keyManager(openSslKeys.cert.toFile(), openSslKeys.privateKey.toFile()) + .trustManager(openSslKeys.trustedCert.toFile()) + .sslProvider(SslProvider.OPENSSL)!! + + override fun jdkContext(jdkKeys: JdkKeys) = + try { + val kmf = keyManagerFactory(jdkKeys) + val tmf = trustManagerFactory(jdkKeys) + SslContextBuilder.forClient() + .keyManager(kmf) + .trustManager(tmf) + .sslProvider(SslProvider.JDK)!! + } finally { + jdkKeys.forgetPasswords() + } + +} diff --git a/hv-collector-ssl/src/main/kotlin/org/onap/dcae/collectors/veshv/ssl/boundary/ServerSslContextFactory.kt b/hv-collector-ssl/src/main/kotlin/org/onap/dcae/collectors/veshv/ssl/boundary/ServerSslContextFactory.kt new file mode 100644 index 00000000..d26937fc --- /dev/null +++ b/hv-collector-ssl/src/main/kotlin/org/onap/dcae/collectors/veshv/ssl/boundary/ServerSslContextFactory.kt @@ -0,0 +1,50 @@ +/* + * ============LICENSE_START======================================================= + * dcaegen2-collectors-veshv + * ================================================================================ + * Copyright (C) 2018 NOKIA + * ================================================================================ + * 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.dcae.collectors.veshv.ssl.boundary + +import io.netty.handler.ssl.SslContextBuilder +import io.netty.handler.ssl.SslProvider +import org.onap.dcae.collectors.veshv.domain.JdkKeys +import org.onap.dcae.collectors.veshv.domain.OpenSslKeys +import org.onap.dcae.collectors.veshv.ssl.impl.SslFactories.keyManagerFactory +import org.onap.dcae.collectors.veshv.ssl.impl.SslFactories.trustManagerFactory + +/** + * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> + * @since September 2018 + */ +open class ServerSslContextFactory : SslContextFactory() { + + override fun openSslContext(openSslKeys: OpenSslKeys) = SslContextBuilder + .forServer(openSslKeys.cert.toFile(), openSslKeys.privateKey.toFile()) + .trustManager(openSslKeys.trustedCert.toFile()) + .sslProvider(SslProvider.OPENSSL)!! + + override fun jdkContext(jdkKeys: JdkKeys) = + try { + val kmf = keyManagerFactory(jdkKeys) + val tmf = trustManagerFactory(jdkKeys) + SslContextBuilder.forServer(kmf) + .trustManager(tmf) + .sslProvider(SslProvider.JDK)!! + } finally { + jdkKeys.forgetPasswords() + } +} diff --git a/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/impl/socket/SslContextFactory.kt b/hv-collector-ssl/src/main/kotlin/org/onap/dcae/collectors/veshv/ssl/boundary/SslContextFactory.kt index 3f7238f4..1fa20229 100644 --- a/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/impl/socket/SslContextFactory.kt +++ b/hv-collector-ssl/src/main/kotlin/org/onap/dcae/collectors/veshv/ssl/boundary/SslContextFactory.kt @@ -17,29 +17,40 @@ * limitations under the License. * ============LICENSE_END========================================================= */ -package org.onap.dcae.collectors.veshv.impl.socket +package org.onap.dcae.collectors.veshv.ssl.boundary import arrow.core.Option import io.netty.handler.ssl.ClientAuth import io.netty.handler.ssl.SslContext import io.netty.handler.ssl.SslContextBuilder -import io.netty.handler.ssl.SslProvider +import org.onap.dcae.collectors.veshv.domain.JdkKeys +import org.onap.dcae.collectors.veshv.domain.OpenSslKeys import org.onap.dcae.collectors.veshv.domain.SecurityConfiguration - -internal open class SslContextFactory { +/** + * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> + * @since September 2018 + */ +abstract class SslContextFactory { fun createSslContext(secConfig: SecurityConfiguration): Option<SslContext> = if (secConfig.sslDisable) { Option.empty() } else { - Option.just(createSslContextWithConfiguredCerts(secConfig) - .sslProvider(SslProvider.OPENSSL) - .clientAuth(ClientAuth.REQUIRE) - .build()) + createSslContextWithConfiguredCerts(secConfig) + .map { builder -> + builder.clientAuth(ClientAuth.REQUIRE) + .build() + } } - protected open fun createSslContextWithConfiguredCerts(secConfig: SecurityConfiguration): SslContextBuilder = - SslContextBuilder.forServer(secConfig.cert.toFile(), secConfig.privateKey.toFile()) - .trustManager(secConfig.trustedCert.toFile()) + protected open fun createSslContextWithConfiguredCerts(secConfig: SecurityConfiguration): Option<SslContextBuilder> = + secConfig.keys.map { keys -> + when (keys) { + is JdkKeys -> jdkContext(keys) + is OpenSslKeys -> openSslContext(keys) + } + } + protected abstract fun openSslContext(openSslKeys: OpenSslKeys): SslContextBuilder + protected abstract fun jdkContext(jdkKeys: JdkKeys): SslContextBuilder } diff --git a/hv-collector-ssl/src/main/kotlin/org/onap/dcae/collectors/veshv/ssl/boundary/utils.kt b/hv-collector-ssl/src/main/kotlin/org/onap/dcae/collectors/veshv/ssl/boundary/utils.kt new file mode 100644 index 00000000..2f2d02ec --- /dev/null +++ b/hv-collector-ssl/src/main/kotlin/org/onap/dcae/collectors/veshv/ssl/boundary/utils.kt @@ -0,0 +1,79 @@ +/* + * ============LICENSE_START======================================================= + * dcaegen2-collectors-veshv + * ================================================================================ + * Copyright (C) 2018 NOKIA + * ================================================================================ + * 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.dcae.collectors.veshv.ssl.boundary + +import arrow.core.None +import arrow.core.Option +import arrow.core.Some +import arrow.core.fix +import arrow.core.monad +import arrow.typeclasses.binding +import org.apache.commons.cli.CommandLine +import org.onap.dcae.collectors.veshv.domain.JdkKeys +import org.onap.dcae.collectors.veshv.domain.SecurityConfiguration +import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption +import org.onap.dcae.collectors.veshv.utils.commandline.hasOption +import org.onap.dcae.collectors.veshv.utils.commandline.stringValue +import java.io.File + +/** + * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> + * @since September 2018 + */ + + +const val KEY_STORE_FILE = "/etc/ves-hv/server.p12" +const val TRUST_STORE_FILE = "/etc/ves-hv/trust.p12" + +fun createSecurityConfiguration(cmdLine: CommandLine): Option<SecurityConfiguration> { + val sslDisable = cmdLine.hasOption(CommandLineOption.SSL_DISABLE) + + return if (sslDisable) disabledSecurityConfiguration(sslDisable) else enabledSecurityConfiguration(cmdLine) +} + +private fun disabledSecurityConfiguration(sslDisable: Boolean): Some<SecurityConfiguration> { + return Some(SecurityConfiguration( + sslDisable = sslDisable, + keys = None + )) +} + +private fun enabledSecurityConfiguration(cmdLine: CommandLine): Option<SecurityConfiguration> { + return Option.monad().binding { + val ksFile = cmdLine.stringValue(CommandLineOption.KEY_STORE_FILE, KEY_STORE_FILE) + val ksPass = cmdLine.stringValue(CommandLineOption.KEY_STORE_PASSWORD).bind() + val tsFile = cmdLine.stringValue(CommandLineOption.TRUST_STORE_FILE, TRUST_STORE_FILE) + val tsPass = cmdLine.stringValue(CommandLineOption.TRUST_STORE_PASSWORD).bind() + + val keys = JdkKeys( + keyStore = streamFromFile(ksFile), + keyStorePassword = ksPass.toCharArray(), + trustStore = streamFromFile(tsFile), + trustStorePassword = tsPass.toCharArray() + ) + + SecurityConfiguration( + sslDisable = false, + keys = Some(keys) + ) + }.fix() +} + +private fun streamFromFile(file: String) = { File(file).inputStream() } diff --git a/hv-collector-ssl/src/main/kotlin/org/onap/dcae/collectors/veshv/ssl/impl/SslFactories.kt b/hv-collector-ssl/src/main/kotlin/org/onap/dcae/collectors/veshv/ssl/impl/SslFactories.kt new file mode 100644 index 00000000..4a73a2aa --- /dev/null +++ b/hv-collector-ssl/src/main/kotlin/org/onap/dcae/collectors/veshv/ssl/impl/SslFactories.kt @@ -0,0 +1,55 @@ +/* + * ============LICENSE_START======================================================= + * dcaegen2-collectors-veshv + * ================================================================================ + * Copyright (C) 2018 NOKIA + * ================================================================================ + * 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.dcae.collectors.veshv.ssl.impl + +import org.onap.dcae.collectors.veshv.domain.JdkKeys +import org.onap.dcae.collectors.veshv.domain.StreamProvider +import java.security.KeyStore +import javax.net.ssl.KeyManagerFactory +import javax.net.ssl.TrustManagerFactory + +/** + * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> + * @since September 2018 + */ +internal object SslFactories { + + fun trustManagerFactory(jdkKeys: JdkKeys): TrustManagerFactory? { + val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) + val ts = loadKeyStoreFromFile(jdkKeys.trustStore, jdkKeys.trustStorePassword) + tmf.init(ts) + return tmf + } + + fun keyManagerFactory(jdkKeys: JdkKeys): KeyManagerFactory? { + val kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()) + val ks = loadKeyStoreFromFile(jdkKeys.keyStore, jdkKeys.keyStorePassword) + kmf.init(ks, jdkKeys.keyStorePassword) + return kmf + } + + private fun loadKeyStoreFromFile(streamProvider: StreamProvider, password: CharArray): KeyStore { + val ks = KeyStore.getInstance("pkcs12") + streamProvider().use { + ks.load(it, password) + } + return ks + } +} diff --git a/hv-collector-ssl/src/test/kotlin/org/onap/dcae/collectors/veshv/ssl/boundary/ServerSslContextFactoryTest.kt b/hv-collector-ssl/src/test/kotlin/org/onap/dcae/collectors/veshv/ssl/boundary/ServerSslContextFactoryTest.kt new file mode 100644 index 00000000..b4d72353 --- /dev/null +++ b/hv-collector-ssl/src/test/kotlin/org/onap/dcae/collectors/veshv/ssl/boundary/ServerSslContextFactoryTest.kt @@ -0,0 +1,163 @@ +/* + * ============LICENSE_START======================================================= + * dcaegen2-collectors-veshv + * ================================================================================ + * Copyright (C) 2018 NOKIA + * ================================================================================ + * 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.dcae.collectors.veshv.ssl.boundary + +import arrow.core.Left +import arrow.core.Option +import arrow.core.Right +import arrow.core.Some +import arrow.core.toOption +import io.netty.handler.ssl.ClientAuth +import io.netty.handler.ssl.JdkSslContext +import io.netty.handler.ssl.ReferenceCountedOpenSslContext +import io.netty.handler.ssl.SslContextBuilder +import org.assertj.core.api.Assertions +import org.assertj.core.api.Assertions.assertThat +import org.jetbrains.spek.api.Spek +import org.jetbrains.spek.api.dsl.describe +import org.jetbrains.spek.api.dsl.given +import org.jetbrains.spek.api.dsl.it +import org.jetbrains.spek.api.dsl.on +import org.onap.dcae.collectors.veshv.domain.JdkKeys +import org.onap.dcae.collectors.veshv.domain.OpenSslKeys +import org.onap.dcae.collectors.veshv.domain.SecurityConfiguration +import java.nio.file.Paths +import kotlin.test.assertTrue + +/** + * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> + * @since June 2018 + */ +object ServerSslContextFactoryTest : Spek({ + val PASSWORD = "onap" + + describe("SslContextFactory (OpenSSL)") { + val keys = OpenSslKeys( + privateKey = Paths.get("/", "tmp", "pk.pem"), + cert = Paths.get("/", "tmp", "cert.crt"), + trustedCert = Paths.get("/", "tmp", "clientCa.crt")) + + given("config with security enabled") { + val sampleConfig = SecurityConfiguration(keys = Some(keys)) + + val cut = object : ServerSslContextFactory() { + override fun createSslContextWithConfiguredCerts(secConfig: SecurityConfiguration) = + SslContextBuilder.forServer(resource("/ssl/ca.crt"), resource("/ssl/server.key")).toOption() + + private fun resource(path: String) = ServerSslContextFactoryTest.javaClass.getResourceAsStream(path) + } + + on("creation of SSL context") { + val result = cut.createSslContext(sampleConfig) + + it("should be server context") { + assertTrue(result.exists { + it.isServer + }) + } + + it("should use OpenSSL provider") { + assertTrue(result.isDefined()) + } + + /* + * It is too important to leave it untested on unit level. + * Because of the Netty API design we need to do it this way. + */ + it("should turn on client authentication") { + val clientAuth: ClientAuth = ReferenceCountedOpenSslContext::class.java + .getDeclaredField("clientAuth") + .run { + isAccessible = true + get(result.orNull()) as ClientAuth + } + Assertions.assertThat(clientAuth).isEqualTo(ClientAuth.REQUIRE) + } + } + } + + given("config with SSL disabled") { + val securityConfiguration = SecurityConfiguration( + sslDisable = true, + keys = Some(keys) + ) + val cut = ServerSslContextFactory() + + on("creation of SSL context") { + val result = cut.createSslContext(securityConfiguration) + + it("should not create any SSL context ") { + assertThat(result.isDefined()).isFalse() + } + } + } + } + + describe("SslContextFactory (JDK)") { + val keys = JdkKeys( + keyStore = resourceStreamProvider("/ssl/server.ks.pkcs12"), + keyStorePassword = PASSWORD.toCharArray(), + trustStore = resourceStreamProvider("/ssl/trust.pkcs12"), + trustStorePassword = PASSWORD.toCharArray() + ) + + given("config without disabled SSL") { + val sampleConfig = SecurityConfiguration(keys = Some(keys)) + val cut = ServerSslContextFactory() + + on("creation of SSL context") { + val result = cut.createSslContext(sampleConfig) + + it("should work") { + assertTrue(result.isDefined()) + } + + it("should be server context") { + assertTrue(result.exists { + it.isServer + }) + } + + /* + * It is too important to leave it untested on unit level. + * Because of the Netty API design we need to do it this way. + */ + it("should turn on client authentication") { + val clientAuth: ClientAuth = JdkSslContext::class.java + .getDeclaredField("clientAuth") + .run { + isAccessible = true + get(result.orNull()) as ClientAuth + } + Assertions.assertThat(clientAuth).isEqualTo(ClientAuth.REQUIRE) + } + + it("should clear passwords so heap dumps won't contain them") { + val xedPassword = PASSWORD.toCharArray() + xedPassword.fill('x') + Assertions.assertThat(keys.keyStorePassword).isEqualTo(xedPassword) + Assertions.assertThat(keys.trustStorePassword).isEqualTo(xedPassword) + } + } + } + } +}) + +fun resourceStreamProvider(resource: String) = { ServerSslContextFactoryTest::class.java.getResourceAsStream(resource) } diff --git a/hv-collector-ssl/src/test/resources/logback-test.xml b/hv-collector-ssl/src/test/resources/logback-test.xml new file mode 100644 index 00000000..9a4eacfe --- /dev/null +++ b/hv-collector-ssl/src/test/resources/logback-test.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration> + <property name="LOG_FILE" + value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}ves-hv.log}"/> + <property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX,UTC} %-5level [%-40.40logger{10}] - %msg%n"/> + + <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern> + %d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX,UTC} %highlight(%-5level) [%-40.40logger{10}] - %msg%n + </pattern> + </encoder> + </appender> + + <appender name="ROLLING-FILE" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <encoder> + <pattern>${FILE_LOG_PATTERN}</pattern> + </encoder> + <file>${LOG_FILE}</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.log</fileNamePattern> + <maxFileSize>50MB</maxFileSize> + <maxHistory>30</maxHistory> + <totalSizeCap>10GB</totalSizeCap> + </rollingPolicy> + </appender> + + <logger name="org.onap.dcae.collectors.veshv" level="TRACE"/> + + <root level="INFO"> + <appender-ref ref="CONSOLE"/> + <appender-ref ref="ROLLING-FILE"/> + </root> +</configuration> diff --git a/hv-collector-ssl/src/test/resources/ssl/ca.crt b/hv-collector-ssl/src/test/resources/ssl/ca.crt new file mode 100644 index 00000000..f9a05b90 --- /dev/null +++ b/hv-collector-ssl/src/test/resources/ssl/ca.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDbDCCAlSgAwIBAgIJAMsh09jY3jSBMA0GCSqGSIb3DQEBCwUAMEsxCzAJBgNV +BAYTAlBMMQswCQYDVQQIDAJETDEQMA4GA1UEBwwHV3JvY2xhdzEOMAwGA1UECgwF +Tm9raWExDTALBgNVBAsMBE1BTk8wHhcNMTgwODEzMTE1OTE5WhcNMTkwODEzMTE1 +OTE5WjBLMQswCQYDVQQGEwJQTDELMAkGA1UECAwCREwxEDAOBgNVBAcMB1dyb2Ns +YXcxDjAMBgNVBAoMBU5va2lhMQ0wCwYDVQQLDARNQU5PMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAyIs4sk5SlBRltDHZDDIGHdazzdduPRKdDBMUTE5i +++iZe1MU9WnbPWgbnfj/1DN+VbbJEa32agDXBhS9mPiSrflDe8oqPPk12miiflsY +TxGxY1bjH58kRNey164fPznzc9LqKqV1brUPktgBkHumM4zPVZYue5cp1T2FiWcE +nFdqOKK2F0mdby+Pim9JHil34YcvavOlMXULkqayR7hxfUIAmMZtl59BKVx9BcKD +9Sv9TQYRIYHhymrKnwIb8RolDaDdVUnr2ryREjZ8WfoBsOpraIYDUjKijF5FlgLs +Fp8wcIflF6JyMbtchTm5acQZkcqK1AGYTD1wxT33E2pdDQIDAQABo1MwUTAdBgNV +HQ4EFgQUOL9AR068MxqYCsKkEfgDzF2HrY8wHwYDVR0jBBgwFoAUOL9AR068MxqY +CsKkEfgDzF2HrY8wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEA +OXNDDqrk8bTJfy78mkMZame/bLEUQ2h4EvWT6trd5XYNfPwQW/u6laLJAtLFbzth +lpNBRK//sK+AYgwDURq0HcW5YczhgzZbfG9ab1J/7GUrFJh+DHL3bNL1YFX84JbI +coUbxaJFkmIvlQDLWDYfpQ/gNwUbuUPZjGZC2bWobZw9sRC+e51TIoAmgZwvTElC +v3vD2BwbIs7C4ylrIQU9Q1rY17MeWH9m8ZhEX1C4W4+N54V6jJ7czE9HQEnapeEu +5rmEoDqP191x+tOxp/Xg8j+wcAK/dVy1Q3xQQZCW84rv0TBHbdaAPamBLUzHeW3W +F7BpnVhn1NfYVOKx5W0NfA== +-----END CERTIFICATE----- diff --git a/hv-collector-ssl/src/test/resources/ssl/server.crt b/hv-collector-ssl/src/test/resources/ssl/server.crt new file mode 100644 index 00000000..2b06108b --- /dev/null +++ b/hv-collector-ssl/src/test/resources/ssl/server.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDEjCCAfoCCQCId29lGbm5LjANBgkqhkiG9w0BAQsFADBLMQswCQYDVQQGEwJQ +TDELMAkGA1UECAwCREwxEDAOBgNVBAcMB1dyb2NsYXcxDjAMBgNVBAoMBU5va2lh +MQ0wCwYDVQQLDARNQU5PMB4XDTE4MDgxMzEyMDAyNFoXDTE5MDgwODEyMDAyNFow +SzELMAkGA1UEBhMCUEwxCzAJBgNVBAgMAkRMMRAwDgYDVQQHDAdXcm9jbGF3MQ4w +DAYDVQQKDAVOb2tpYTENMAsGA1UECwwETUFOTzCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALbblOyqeJayotBiY6aZnGWnMHCHNTileJF8hkFS5P5qM9BU +XH7NW/p5wSNcQWBB81HrRVneHpm6zfZtUPtcqXC4vpTk/sy3WT8rlEU+uv1YYVP8 +r0jxXr1WZ8sGcxOjhiMMRpMqImoALRak3ombtktfMc2Yeab4J25941wpDSQoUjT8 +LlXhfyjbBijum0LY+cqsuV5qk2qrzo0ZLD6m51aaWEyeysQ/3JanYKvPZDKdvAYN ++98ud6d/rjdWIJXwxEGp1fpW0p+fHOUhjMB1a5gkPDIpU68ME6BZJ3xJZb1qqXLS +pkUitMIWZSWx5xNhcifsnxWyhZfnhd8GnxU3Lf8CAwEAATANBgkqhkiG9w0BAQsF +AAOCAQEAJCrPdc8R7kBOmeIPyVX8QBOsrVTBBDzhskpi51nMsAKvcGjtYdXknYPj +bw3YVASE2efrq5QWHC0maIxDAHzI/kmWGH8F0s8S6QRH/7fstvxaNaSArzQB/thW +qIWs7AufUSsLMwtcXQ6KdYNbnaMwTynuuK+ANilcLvV8GxRAzXgFdoWZ2OuJRyzu +BWQZS49WanyqX1kDLMsrLtdJyl/yVEfsmDcUyhapuuGwtconkWK/CVrJlV1vh1Z+ +Svh9IfvAF7WPPpGsM/y9+hGNtK6sPVUKl4acBzIAv6aN1QS5H4zRvtbwv7xpUp4M +P84PY3lv1X3NJCGrfVByh2lFWParKA== +-----END CERTIFICATE----- diff --git a/hv-collector-ssl/src/test/resources/ssl/server.key b/hv-collector-ssl/src/test/resources/ssl/server.key new file mode 100644 index 00000000..40e25932 --- /dev/null +++ b/hv-collector-ssl/src/test/resources/ssl/server.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC225TsqniWsqLQ +YmOmmZxlpzBwhzU4pXiRfIZBUuT+ajPQVFx+zVv6ecEjXEFgQfNR60VZ3h6Zus32 +bVD7XKlwuL6U5P7Mt1k/K5RFPrr9WGFT/K9I8V69VmfLBnMTo4YjDEaTKiJqAC0W +pN6Jm7ZLXzHNmHmm+CdufeNcKQ0kKFI0/C5V4X8o2wYo7ptC2PnKrLleapNqq86N +GSw+pudWmlhMnsrEP9yWp2Crz2QynbwGDfvfLnenf643ViCV8MRBqdX6VtKfnxzl +IYzAdWuYJDwyKVOvDBOgWSd8SWW9aqly0qZFIrTCFmUlsecTYXIn7J8VsoWX54Xf +Bp8VNy3/AgMBAAECggEATzN4o7GKnast/hg/lU9/gEAUKQlHMgvp1woalHy1FsUl +QBzqGzoTlr/Zudkhr/Gg1GCVH0Gn+2n//7aFlvohoeNDGPa+rijUDRpxFDUBhO4c +6eXOfkedg2DDgBqBCYaQeOm+P8vGMCd3YBF1GiFJqgfHaIecWYeufJsmOSrGuFvK +1OvHpvg4/FLLQqgVcVO812kD4UwSOKnZVnPuZ3pzQviUZvO8ZxI/LkzQB1EdH6u3 +rBtiGslYkiKl5cGpH39/Dx2nKhHfvSnkfsm7koB00Bl41yy61GPwdl4XUwg8LUhX +TbsuoIPGTJX/2FUMn0UnAdDJm29hE4eyHyYOhew8gQKBgQDlAeUcnFr9uxe0i7cg +6ctJlNIKJjlA1tH4qIMEytdn06STo9g2j8X5HVE0FX/3+gAYDtEVICTF66w8Y474 +aeazvf+TCfkxtEOiH2afvaNkIkfzKR0ceB48DECT0DCF7xha5rJVf/W4GpCz2WkZ +ojDzw5ZVvzbx/FaF9A/IseJ63wKBgQDMaSjiephhdlCERGPdwWMg3AfthEX/VHM0 +YugbVjjYjDbn2pMkntW2hUuVXP8HD+9DnQZo0/c/hxe28Q5b+2fjZephdctnY8tL +XWbaEerM2lxEjmrpA4jYTBZJ9nMsxkEYHGHb5I586aS2YaZ12e7DoKMFdl0EZzvi +zGPIxSzQ4QKBgAxVv8t8uIH2M96rr997+FEsTOvzBx5w87pbCUOW0WdsRO8W4ix+ +LgGvDJKrncrzklG5apWit5hZi1ttWWQUADMqRrvay6tbtFDlNBfilQxttEZqroC8 +D5TYbBoKGrL8H+m1h2GHlOqns6ecTEbvL4fRvyU7OXBrURXCAZ+jxTktAoGACbQI +O9AEAcRjCBRTBUjT0tB/E9hOllNE8LytNfb+1dC6HoFysK9Vh8eGEf4LISOxgO0o +S7ucJgjcqFODEfy6LsI8wQmdcTf8g4RYiIuHMNhAvwRfsNX5HgNmn3Yye3Khzmoy +fwS3etiAeCPkif2hZunuMykuOzJHVnnLVtF9UiECgYEA41d7FgUcnfPIyA5xLg7K +lRgjFMsc68uzoCBQww2kio0HNJpdOPBJlg6oHHfYKriv2r9793jETRVwjSNPlKZb +vqm9yhnbXuahYBZSgdo2W+NbhP6IbJ0vrF4t9g6byjancQptaCjNIr9St9g+Ugly +8m0n3gIT/+Lr+it63cgk8SA= +-----END PRIVATE KEY----- diff --git a/hv-collector-ssl/src/test/resources/ssl/server.ks.pkcs12 b/hv-collector-ssl/src/test/resources/ssl/server.ks.pkcs12 Binary files differnew file mode 100644 index 00000000..a97eb65a --- /dev/null +++ b/hv-collector-ssl/src/test/resources/ssl/server.ks.pkcs12 diff --git a/hv-collector-ssl/src/test/resources/ssl/trust.pkcs12 b/hv-collector-ssl/src/test/resources/ssl/trust.pkcs12 Binary files differnew file mode 100644 index 00000000..01b61373 --- /dev/null +++ b/hv-collector-ssl/src/test/resources/ssl/trust.pkcs12 diff --git a/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/ArgBasedConfiguration.kt b/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/ArgBasedConfiguration.kt index 44d425ea..da5ff918 100644 --- a/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/ArgBasedConfiguration.kt +++ b/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/ArgBasedConfiguration.kt @@ -55,31 +55,5 @@ abstract class ArgBasedConfiguration<T>(private val parser: CommandLineParser) { protected abstract fun getConfiguration(cmdLine: CommandLine): Option<T> - protected fun CommandLine.longValue(cmdLineOpt: CommandLineOption, default: Long): Long = - longValue(cmdLineOpt).getOrElse { default } - - protected fun CommandLine.stringValue(cmdLineOpt: CommandLineOption, default: String): String = - optionValue(cmdLineOpt).getOrElse { default } - - protected fun CommandLine.intValue(cmdLineOpt: CommandLineOption, default: Int): Int = - intValue(cmdLineOpt).getOrElse { default } - - protected fun CommandLine.intValue(cmdLineOpt: CommandLineOption): Option<Int> = - optionValue(cmdLineOpt).map(String::toInt) - - private fun CommandLine.longValue(cmdLineOpt: CommandLineOption): Option<Long> = - optionValue(cmdLineOpt).map(String::toLong) - - protected fun CommandLine.stringValue(cmdLineOpt: CommandLineOption): Option<String> = - optionValue(cmdLineOpt) - - protected fun CommandLine.hasOption(cmdLineOpt: CommandLineOption): Boolean = - this.hasOption(cmdLineOpt.option.opt) || - System.getenv(cmdLineOpt.environmentVariableName()) != null - protected fun stringPathToPath(path: String): Path = Paths.get(File(path).toURI()) - - private fun CommandLine.optionValue(cmdLineOpt: CommandLineOption) = Option.fromNullablesChain( - getOptionValue(cmdLineOpt.option.opt), - { System.getenv(cmdLineOpt.environmentVariableName()) }) } diff --git a/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/CommandLineOption.kt b/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/CommandLineOption.kt index 9379c409..288a578d 100644 --- a/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/CommandLineOption.kt +++ b/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/CommandLineOption.kt @@ -88,22 +88,28 @@ enum class CommandLineOption(val option: Option, val required: Boolean = false) .desc("Disable SSL encryption") .build() ), - PRIVATE_KEY_FILE(Option.builder("k") - .longOpt("private-key-file") + KEY_STORE_FILE(Option.builder("k") + .longOpt("key-store") .hasArg() - .desc("File with private key in PEM format") + .desc("Key store in PKCS12 format") .build() ), - CERT_FILE(Option.builder("e") - .longOpt("cert-file") + KEY_STORE_PASSWORD(Option.builder("kp") + .longOpt("key-store-password") .hasArg() - .desc("File with certificate bundle") + .desc("Key store password") .build() ), - TRUST_CERT_FILE(Option.builder("t") - .longOpt("trust-cert-file") + TRUST_STORE_FILE(Option.builder("t") + .longOpt("trust-store") .hasArg() - .desc("File with trusted certificate bundle for trusting connections") + .desc("File with trusted certificate bundle in PKCS12 format") + .build() + ), + TRUST_STORE_PASSWORD(Option.builder("tp") + .longOpt("trust-store-password") + .hasArg() + .desc("Trust store password") .build() ), IDLE_TIMEOUT_SEC(Option.builder("i") diff --git a/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/extensions.kt b/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/extensions.kt index 718ebf8b..ba4c0802 100644 --- a/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/extensions.kt +++ b/hv-collector-utils/src/main/kotlin/org/onap/dcae/collectors/veshv/utils/commandline/extensions.kt @@ -19,9 +19,13 @@ */ package org.onap.dcae.collectors.veshv.utils.commandline +import arrow.core.Option +import arrow.core.getOrElse import arrow.effects.IO import arrow.syntax.function.curried +import org.apache.commons.cli.CommandLine import org.onap.dcae.collectors.veshv.utils.arrow.ExitFailure +import org.onap.dcae.collectors.veshv.utils.arrow.fromNullablesChain /** * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> @@ -34,3 +38,29 @@ fun handleWrongArgumentError(programName: String, err: WrongArgumentError): IO<U }.flatMap { ExitFailure(2).io() } val handleWrongArgumentErrorCurried = ::handleWrongArgumentError.curried() + +fun CommandLine.longValue(cmdLineOpt: CommandLineOption, default: Long): Long = + longValue(cmdLineOpt).getOrElse { default } + +fun CommandLine.stringValue(cmdLineOpt: CommandLineOption, default: String): String = + optionValue(cmdLineOpt).getOrElse { default } + +fun CommandLine.intValue(cmdLineOpt: CommandLineOption, default: Int): Int = + intValue(cmdLineOpt).getOrElse { default } + +fun CommandLine.intValue(cmdLineOpt: CommandLineOption): Option<Int> = + optionValue(cmdLineOpt).map(String::toInt) + +fun CommandLine.longValue(cmdLineOpt: CommandLineOption): Option<Long> = + optionValue(cmdLineOpt).map(String::toLong) + +fun CommandLine.stringValue(cmdLineOpt: CommandLineOption): Option<String> = + optionValue(cmdLineOpt) + +fun CommandLine.hasOption(cmdLineOpt: CommandLineOption): Boolean = + this.hasOption(cmdLineOpt.option.opt) || + System.getenv(cmdLineOpt.environmentVariableName()) != null + +private fun CommandLine.optionValue(cmdLineOpt: CommandLineOption) = Option.fromNullablesChain( + getOptionValue(cmdLineOpt.option.opt), + { System.getenv(cmdLineOpt.environmentVariableName()) })
\ No newline at end of file diff --git a/hv-collector-xnf-simulator/Dockerfile b/hv-collector-xnf-simulator/Dockerfile index 53406459..ed9dd9b4 100644 --- a/hv-collector-xnf-simulator/Dockerfile +++ b/hv-collector-xnf-simulator/Dockerfile @@ -6,7 +6,7 @@ LABEL license.url="http://www.apache.org/licenses/LICENSE-2.0" LABEL maintainer="Nokia Wroclaw ONAP Team" RUN apt-get update \ - && apt-get install -y --no-install-recommends curl \ + && apt-get install -y --no-install-recommends curl \ && apt-get clean WORKDIR /opt/ves-hv-client-simulator diff --git a/hv-collector-xnf-simulator/pom.xml b/hv-collector-xnf-simulator/pom.xml index cfe1dc14..b3de6b2d 100644 --- a/hv-collector-xnf-simulator/pom.xml +++ b/hv-collector-xnf-simulator/pom.xml @@ -87,6 +87,11 @@ </dependency> <dependency> <groupId>${project.parent.groupId}</groupId> + <artifactId>hv-collector-ssl</artifactId> + <version>${project.parent.version}</version> + </dependency> + <dependency> + <groupId>${project.parent.groupId}</groupId> <artifactId>hv-collector-utils</artifactId> <version>${project.parent.version}</version> </dependency> @@ -121,12 +126,18 @@ <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-stdlib-jdk8</artifactId> </dependency> + <!-- See comment in main pom + <dependency> + <groupId>io.netty</groupId> + <artifactId>netty-transport-native-epoll</artifactId> + <classifier>${os.detected.classifier}</classifier> + </dependency> <dependency> <groupId>io.netty</groupId> <artifactId>netty-tcnative-boringssl-static</artifactId> - <scope>runtime</scope> <classifier>${os.detected.classifier}</classifier> </dependency> + --> <dependency> <groupId>com.nhaarman</groupId> <artifactId>mockito-kotlin</artifactId> diff --git a/hv-collector-xnf-simulator/src/main/kotlin/org/onap/dcae/collectors/veshv/simulators/xnf/impl/adapters/VesHvClient.kt b/hv-collector-xnf-simulator/src/main/kotlin/org/onap/dcae/collectors/veshv/simulators/xnf/impl/adapters/VesHvClient.kt index af71e9ce..7a280c10 100644 --- a/hv-collector-xnf-simulator/src/main/kotlin/org/onap/dcae/collectors/veshv/simulators/xnf/impl/adapters/VesHvClient.kt +++ b/hv-collector-xnf-simulator/src/main/kotlin/org/onap/dcae/collectors/veshv/simulators/xnf/impl/adapters/VesHvClient.kt @@ -28,6 +28,7 @@ import org.onap.dcae.collectors.veshv.domain.WireFrameMessage import org.onap.dcae.collectors.veshv.domain.SecurityConfiguration import org.onap.dcae.collectors.veshv.domain.WireFrameEncoder import org.onap.dcae.collectors.veshv.simulators.xnf.impl.config.SimulatorConfiguration +import org.onap.dcae.collectors.veshv.ssl.boundary.ClientSslContextFactory import org.onap.dcae.collectors.veshv.utils.arrow.asIo import org.onap.dcae.collectors.veshv.utils.logging.Logger import org.reactivestreams.Publisher @@ -37,7 +38,6 @@ import reactor.core.publisher.ReplayProcessor import reactor.ipc.netty.NettyOutbound import reactor.ipc.netty.tcp.TcpClient - /** * @author Jakub Dudycz <jakub.dudycz@nokia.com> * @since June 2018 @@ -92,18 +92,7 @@ class VesHvClient(private val configuration: SimulatorConfiguration) { } private fun createSslContext(config: SecurityConfiguration): Option<SslContext> = - if (config.sslDisable) { - Option.empty() - } else { - Option.just( - SslContextBuilder.forClient() - .keyManager(config.cert.toFile(), config.privateKey.toFile()) - .trustManager(config.trustedCert.toFile()) - .sslProvider(SslProvider.OPENSSL) - .clientAuth(ClientAuth.REQUIRE) - .build() - ) - } + ClientSslContextFactory().createSslContext(config) private fun NettyOutbound.logConnectionClosed(): NettyOutbound { context().onClose { diff --git a/hv-collector-xnf-simulator/src/main/kotlin/org/onap/dcae/collectors/veshv/simulators/xnf/impl/config/ArgXnfSimulatorConfiguration.kt b/hv-collector-xnf-simulator/src/main/kotlin/org/onap/dcae/collectors/veshv/simulators/xnf/impl/config/ArgXnfSimulatorConfiguration.kt index 56d6212a..3d8dc948 100644 --- a/hv-collector-xnf-simulator/src/main/kotlin/org/onap/dcae/collectors/veshv/simulators/xnf/impl/config/ArgXnfSimulatorConfiguration.kt +++ b/hv-collector-xnf-simulator/src/main/kotlin/org/onap/dcae/collectors/veshv/simulators/xnf/impl/config/ArgXnfSimulatorConfiguration.kt @@ -19,16 +19,24 @@ */ package org.onap.dcae.collectors.veshv.simulators.xnf.impl.config -import arrow.core.ForOption import arrow.core.Option import arrow.core.fix -import arrow.instances.extensions +import arrow.core.monad import arrow.typeclasses.binding import org.apache.commons.cli.CommandLine import org.apache.commons.cli.DefaultParser -import org.onap.dcae.collectors.veshv.domain.SecurityConfiguration +import org.onap.dcae.collectors.veshv.ssl.boundary.createSecurityConfiguration import org.onap.dcae.collectors.veshv.utils.commandline.ArgBasedConfiguration -import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.* +import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.KEY_STORE_FILE +import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.KEY_STORE_PASSWORD +import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.LISTEN_PORT +import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.SSL_DISABLE +import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.TRUST_STORE_FILE +import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.TRUST_STORE_PASSWORD +import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.VES_HV_HOST +import org.onap.dcae.collectors.veshv.utils.commandline.CommandLineOption.VES_HV_PORT +import org.onap.dcae.collectors.veshv.utils.commandline.intValue +import org.onap.dcae.collectors.veshv.utils.commandline.stringValue /** @@ -41,42 +49,22 @@ internal class ArgXnfSimulatorConfiguration : ArgBasedConfiguration<SimulatorCon VES_HV_HOST, LISTEN_PORT, SSL_DISABLE, - PRIVATE_KEY_FILE, - CERT_FILE, - TRUST_CERT_FILE - ) + KEY_STORE_FILE, + KEY_STORE_PASSWORD, + TRUST_STORE_FILE, + TRUST_STORE_PASSWORD) override fun getConfiguration(cmdLine: CommandLine): Option<SimulatorConfiguration> = - ForOption extensions { - binding { - val listenPort = cmdLine.intValue(LISTEN_PORT).bind() - val vesHost = cmdLine.stringValue(VES_HV_HOST).bind() - val vesPort = cmdLine.intValue(VES_HV_PORT).bind() + Option.monad().binding { + val listenPort = cmdLine.intValue(LISTEN_PORT).bind() + val vesHost = cmdLine.stringValue(VES_HV_HOST).bind() + val vesPort = cmdLine.intValue(VES_HV_PORT).bind() - SimulatorConfiguration( - listenPort, - vesHost, - vesPort, - parseSecurityConfig(cmdLine)) - }.fix() - } + SimulatorConfiguration( + listenPort, + vesHost, + vesPort, + createSecurityConfiguration(cmdLine).bind()) + }.fix() - private fun parseSecurityConfig(cmdLine: CommandLine): SecurityConfiguration { - val sslDisable = cmdLine.hasOption(SSL_DISABLE) - val pkFile = cmdLine.stringValue(PRIVATE_KEY_FILE, DefaultValues.PRIVATE_KEY_FILE) - val certFile = cmdLine.stringValue(CERT_FILE, DefaultValues.CERT_FILE) - val trustCertFile = cmdLine.stringValue(TRUST_CERT_FILE, DefaultValues.TRUST_CERT_FILE) - - return SecurityConfiguration( - sslDisable = sslDisable, - privateKey = stringPathToPath(pkFile), - cert = stringPathToPath(certFile), - trustedCert = stringPathToPath(trustCertFile)) - } - - internal object DefaultValues { - const val PRIVATE_KEY_FILE = "/etc/ves-hv/client.key" - const val CERT_FILE = "/etc/ves-hv/client.crt" - const val TRUST_CERT_FILE = "/etc/ves-hv/trust.crt" - } } diff --git a/hv-collector-xnf-simulator/src/test/kotlin/org/onap/dcae/collectors/veshv/main/config/ArgXnfSimulatorConfiurationTest.kt b/hv-collector-xnf-simulator/src/test/kotlin/org/onap/dcae/collectors/veshv/main/config/ArgXnfSimulatorConfiurationTest.kt deleted file mode 100644 index 69caf727..00000000 --- a/hv-collector-xnf-simulator/src/test/kotlin/org/onap/dcae/collectors/veshv/main/config/ArgXnfSimulatorConfiurationTest.kt +++ /dev/null @@ -1,181 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * dcaegen2-collectors-veshv - * ================================================================================ - * Copyright (C) 2018 NOKIA - * ================================================================================ - * 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.dcae.collectors.veshv.main.config - -import org.assertj.core.api.Assertions.assertThat -import org.jetbrains.spek.api.Spek -import org.jetbrains.spek.api.dsl.describe -import org.jetbrains.spek.api.dsl.given -import org.jetbrains.spek.api.dsl.it -import org.jetbrains.spek.api.dsl.on -import org.onap.dcae.collectors.veshv.domain.SecurityConfiguration -import org.onap.dcae.collectors.veshv.simulators.xnf.impl.config.ArgXnfSimulatorConfiguration -import org.onap.dcae.collectors.veshv.simulators.xnf.impl.config.ArgXnfSimulatorConfiguration.DefaultValues -import org.onap.dcae.collectors.veshv.simulators.xnf.impl.config.SimulatorConfiguration -import org.onap.dcae.collectors.veshv.tests.utils.parseExpectingFailure -import org.onap.dcae.collectors.veshv.tests.utils.parseExpectingSuccess -import org.onap.dcae.collectors.veshv.utils.commandline.WrongArgumentError -import java.nio.file.Paths -import kotlin.test.assertTrue - - -object ArgXnfSimulatorConfiurationTest : Spek({ - lateinit var cut: ArgXnfSimulatorConfiguration - val listenPort = "4321" - val vesHost = "localhost" - val vesPort = "1234" - val pk = Paths.get("/", "etc", "ves", "pk.pem") - val cert = Paths.get("/", "etc", "ssl", "certs", "ca-bundle.crt") - val trustCert = Paths.get("/", "etc", "ves", "trusted.crt") - - beforeEachTest { - cut = ArgXnfSimulatorConfiguration() - } - - describe("parsing arguments") { - lateinit var result: SimulatorConfiguration - - given("all parameters are present in the long form") { - - beforeEachTest { - result = cut.parseExpectingSuccess("--ssl-disable", - "--listen-port", listenPort, - "--ves-host", vesHost, - "--ves-port", vesPort, - "--private-key-file", pk.toFile().absolutePath, - "--cert-file", cert.toFile().absolutePath, - "--trust-cert-file", trustCert.toFile().absolutePath) - } - - it("should set proper listen port") { - assertThat(result.listenPort).isEqualTo(listenPort.toInt()) - } - - it("should set proper ves host") { - assertThat(result.vesHost).isEqualTo(vesHost) - } - - it("should set proper ves port") { - assertThat(result.vesPort).isEqualTo(vesPort.toInt()) - } - - it("should set proper security configuration") { - assertThat(result.security).isEqualTo( - SecurityConfiguration(sslDisable = true, privateKey = pk, cert = cert, trustedCert = trustCert) - ) - } - } - - given("some parameters are present in the short form") { - - beforeEachTest { - result = cut.parseExpectingSuccess("-p", listenPort, "-h", vesHost, "--ves-port", vesPort) - } - - it("should set proper listen port") { - assertThat(result.listenPort).isEqualTo(listenPort.toInt()) - } - - it("should set proper ves host") { - assertThat(result.vesHost).isEqualTo(vesHost) - } - - it("should set proper ves port") { - assertThat(result.vesPort).isEqualTo(vesPort.toInt()) - } - } - - given("all optional parameters are absent") { - - beforeEachTest { - result = cut.parseExpectingSuccess("-p", listenPort, "-h", vesHost, "-v", vesPort) - } - - on("security config") { - val securityConfiguration = result.security - - it("should set default trust cert file") { - assertThat(securityConfiguration.trustedCert.toString()).isEqualTo(DefaultValues.TRUST_CERT_FILE) - } - - it("should set default server cert file") { - assertThat(securityConfiguration.cert.toString()).isEqualTo(DefaultValues.CERT_FILE) - } - - it("should set default private key file") { - assertThat(securityConfiguration.privateKey.toString()).isEqualTo(DefaultValues.PRIVATE_KEY_FILE) - } - } - } - - given("disabled ssl certs together with all other parameters") { - beforeEachTest { - result = cut.parseExpectingSuccess("--ssl-disable", - "--listen-port", listenPort, - "--ves-port", "888", - "--ves-host", vesHost, - "--private-key-file", pk.toFile().absolutePath, - "--cert-file", cert.toFile().absolutePath, - "--trust-cert-file", trustCert.toFile().absolutePath) - } - - on("security config") { - val securityConfiguration = result.security - - it("should set ssl disable to true") { - assertTrue(securityConfiguration.sslDisable) - } - - it("should set proper security configuration") { - assertThat(securityConfiguration).isEqualTo( - SecurityConfiguration( - sslDisable = true, - privateKey = pk, - cert = cert, - trustedCert = trustCert) - ) - } - } - } - - describe("required parameter is absent") { - given("ves port is missing") { - it("should throw exception") { - assertThat(cut.parseExpectingFailure("-p", listenPort, "-h", vesHost)) - .isInstanceOf(WrongArgumentError::class.java) - } - } - - given("ves host is missing") { - it("should throw exception") { - assertThat(cut.parseExpectingFailure("-p", listenPort, "-v", vesPort)) - .isInstanceOf(WrongArgumentError::class.java) - } - } - - given("listen port is missing") { - it("should throw exception") { - assertThat(cut.parseExpectingFailure("-h", vesHost, "-v", vesPort)) - .isInstanceOf(WrongArgumentError::class.java) - } - } - } - } -}) @@ -52,6 +52,7 @@ <module>hv-collector-domain</module> <module>hv-collector-health-check</module> <module>hv-collector-main</module> + <module>hv-collector-ssl</module> <module>hv-collector-test-utils</module> <module>hv-collector-utils</module> <module>hv-collector-ves-message-generator</module> @@ -64,7 +65,7 @@ <maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.version> <build-helper-maven-plugin.version>1.7</build-helper-maven-plugin.version> <jacoco.version>0.8.2</jacoco.version> - <jacoco.minimum.coverage>66</jacoco.minimum.coverage> + <jacoco.minimum.coverage>60</jacoco.minimum.coverage> <!-- Protocol buffers --> <protobuf.version>3.5.1</protobuf.version> @@ -586,16 +587,31 @@ <dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-bom</artifactId> - <version>Bismuth-SR10</version> + <!-- remember to update netty native bindings versions --> + <version>Bismuth-SR11</version> <type>pom</type> <scope>import</scope> </dependency> + + <!-- + Disable native extensions (ssl and epoll) on production for now. + Might be reintroduced if performance tests prove there is some performance issue. + --> <dependency> <groupId>io.netty</groupId> <artifactId>netty-tcnative-boringssl-static</artifactId> - <version>2.0.8.Final</version> + <version>2.0.15.Final</version> + <scope>runtime</scope> + <classifier>${os.detected.classifier}</classifier> + </dependency> + <!-- + <dependency> + <groupId>io.netty</groupId> + <artifactId>netty-transport-native-epoll</artifactId> + <version>4.1.29.Final</version> <classifier>${os.detected.classifier}</classifier> </dependency> + --> <dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> diff --git a/ssl/.gitignore b/ssl/.gitignore index 598dc753..23888eb0 100644 --- a/ssl/.gitignore +++ b/ssl/.gitignore @@ -2,3 +2,6 @@ *.key *.srl *.csr +*.pkcs12 +*.p12 + diff --git a/ssl/Makefile b/ssl/Makefile-openssl index 28326505..09802ce4 100644 --- a/ssl/Makefile +++ b/ssl/Makefile-openssl @@ -1,12 +1,13 @@ FILE=sample -CA_PASSWD=onap +PASSWD=onaponap +CA_PASSWD=onaponap SUBJ=/C=PL/ST=DL/L=Wroclaw/O=Nokia/OU=MANO CA=trust sign: $(FILE).crt clean: - rm -f *.crt *.key *.srl *.csr + rm -f *.crt *.key *.srl *.csr *.pkcs12 generate-ca-certificate: $(CA).crt @@ -16,6 +17,11 @@ create-public-key: $(FILE).pub create-sign-request: $(FILE).csr +create-key-store: $(FILE).ks.pkcs12 + +create-trust-store: $(CA).crt + openssl pkcs12 -export -in $(CA).crt -CAfile $(CA).crt -out $(CA).pkcs12 -nokeys -noiter -nomaciter -passout pass:$(PASSWD) + $(CA).crt: openssl req -new -x509 -keyout $(CA).key -out $(CA).crt -days 365 -passout pass:$(CA_PASSWD) -subj "$(SUBJ)" @@ -31,3 +37,5 @@ $(FILE).csr: $(FILE).key $(FILE).crt: $(CA).crt $(FILE).csr openssl x509 -req -days 360 -in $(FILE).csr -CA $(CA).crt -CAkey $(CA).key -out $(FILE).crt -CAcreateserial -passin pass:$(CA_PASSWD) +$(FILE).ks.pkcs12: $(FILE).key $(FILE).crt $(CA).crt + openssl pkcs12 -export -in $(FILE).crt -inkey $(FILE).key -CAfile $(CA).crt -out $(FILE).ks.pkcs12 -noiter -nomaciter -passout pass:$(PASSWD) diff --git a/ssl/README.md b/ssl/README.md index efba6107..c2819d24 100644 --- a/ssl/README.md +++ b/ssl/README.md @@ -1,5 +1,23 @@ # Generating SSL certificates +## Java keytool way (recommended) + +To generate: + +```shell +./gen-certs.sh +``` + +To clean (remove generated files): + +```shell +./gen-certs.sh clean +``` + +## OpenSSL way (currently might not work) + +> Add `-f Makefile-openssl` to each command + Typical usage: ```shell @@ -7,6 +25,14 @@ make FILE=client make FILE=server ``` +or (to generate PKCS12 key and trust stores): + +```shell +make create-key-store FILE=client +make create-key-store FILE=server +make create-trust-store +``` + Will generate CA certificate and signed client and server certificates. More "low-level" usage: diff --git a/ssl/gen-certs.sh b/ssl/gen-certs.sh new file mode 100755 index 00000000..b4f78227 --- /dev/null +++ b/ssl/gen-certs.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash + +set -eu -o pipefail -o xtrace + +STORE_PASS=onaponap +CN_PREFIX=dcaegen2-hvves +DNAME_PREFIX="C=PL,ST=DL,L=Wroclaw,O=Nokia,OU=MANO,CN=${CN_PREFIX}" +TRUST=trust + +store_opts="-storetype PKCS12 -storepass ${STORE_PASS} -noprompt" + +function gen_key() { + local key_name="$1" + local ca="$2" + local keystore="-keystore ${key_name}.p12 ${store_opts}" + keytool -genkey -alias ${key_name} \ + ${keystore} \ + -keyalg RSA \ + -validity 730 \ + -keysize 2048 \ + -dname "${DNAME_PREFIX}-${key_name}" + keytool -import -trustcacerts -alias ${ca} -file ${ca}.crt ${keystore} + + keytool -certreq -alias ${key_name} -keyalg RSA ${keystore} | \ + keytool -alias ${ca} -gencert -ext "san=dns:${CN_PREFIX}-${ca}" ${store_opts} -keystore ${ca}.p12 | \ + keytool -alias ${key_name} -importcert ${keystore} +} + + +function gen_ca() { + local ca="$1" + keytool -genkeypair ${store_opts} -alias ${ca} -dname "${DNAME_PREFIX}-${ca}" -keystore ${ca}.p12 + keytool -export -alias ${ca} -file ${ca}.crt ${store_opts} -keystore ${ca}.p12 +} + +function gen_truststore() { + local trusted_ca="$1" + keytool -import -trustcacerts -alias ca -file ${trusted_ca}.crt ${store_opts} -keystore ${TRUST}.p12 +} + +function clean() { + rm -f *.crt *.p12 +} + +if [[ $# -eq 0 ]]; then + gen_ca ca + gen_ca untrustedca + gen_truststore ca + gen_key client ca + gen_key server ca + gen_key untrustedclient untrustedca +elif [[ $1 == "clean" ]]; then + clean +else + echo "usage: $0 [clean]" + exit 1 +fi + |