diff options
Diffstat (limited to 'hv-collector-core/src')
10 files changed, 239 insertions, 8 deletions
diff --git a/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/boundary/adapters.kt b/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/boundary/adapters.kt index d4de1b5b..2cda86e9 100644 --- a/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/boundary/adapters.kt +++ b/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/boundary/adapters.kt @@ -22,7 +22,6 @@ package org.onap.dcae.collectors.veshv.boundary import org.onap.dcae.collectors.veshv.domain.CollectorConfiguration import org.onap.dcae.collectors.veshv.domain.RoutedMessage import org.onap.dcae.collectors.veshv.domain.VesMessage -import org.onap.ves.VesEventV5.VesEvent.CommonEventHeader import reactor.core.publisher.Flux interface Sink { diff --git a/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/domain/SecurityConfiguration.kt b/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/domain/SecurityConfiguration.kt new file mode 100644 index 00000000..ea430c2c --- /dev/null +++ b/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/domain/SecurityConfiguration.kt @@ -0,0 +1,31 @@ +/* + * ============LICENSE_START======================================================= + * dcaegen2-collectors-veshv + * ================================================================================ + * Copyright (C) 2018 NOKIA Intellectual Property. 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.dcae.collectors.veshv.domain + +import java.nio.file.Path + +/** + * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> + * @since May 2018 + */ +data class SecurityConfiguration( + val privateKey: Path, + val cert: Path, + val trustedCert: Path) diff --git a/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/domain/ServerConfiguration.kt b/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/domain/ServerConfiguration.kt index cf484d7c..b58dffbf 100644 --- a/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/domain/ServerConfiguration.kt +++ b/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/domain/ServerConfiguration.kt @@ -23,4 +23,7 @@ package org.onap.dcae.collectors.veshv.domain * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> * @since May 2018 */ -data class ServerConfiguration( val configurationUrl: String, val port: Int) +data class ServerConfiguration( + val port: Int, + val configurationUrl: String, + val securityConfiguration: SecurityConfiguration) 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 5e60fa56..ca81d69d 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 @@ -22,12 +22,14 @@ 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.domain.ServerConfiguration -import org.onap.dcae.collectors.veshv.impl.NettyTcpServer +import org.onap.dcae.collectors.veshv.impl.socket.NettyTcpServer +import org.onap.dcae.collectors.veshv.impl.socket.SslContextFactory /** * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> * @since May 2018 */ object ServerFactory { - val createNettyTcpServer: (ServerConfiguration, CollectorProvider) -> Server = ::NettyTcpServer + fun createNettyTcpServer(serverConfiguration: ServerConfiguration, collectorProvider: CollectorProvider): Server = + NettyTcpServer(serverConfiguration, SslContextFactory(), collectorProvider) } diff --git a/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/impl/NettyTcpServer.kt b/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/impl/socket/NettyTcpServer.kt index ca77df2a..34aa2e8f 100644 --- a/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/impl/NettyTcpServer.kt +++ b/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/impl/socket/NettyTcpServer.kt @@ -17,7 +17,7 @@ * limitations under the License. * ============LICENSE_END========================================================= */ -package org.onap.dcae.collectors.veshv.impl +package org.onap.dcae.collectors.veshv.impl.socket import org.onap.dcae.collectors.veshv.boundary.CollectorProvider import org.onap.dcae.collectors.veshv.boundary.Server @@ -27,6 +27,7 @@ import org.reactivestreams.Publisher import reactor.core.publisher.Mono import reactor.ipc.netty.NettyInbound import reactor.ipc.netty.NettyOutbound +import reactor.ipc.netty.options.ServerOptions import reactor.ipc.netty.tcp.TcpServer import java.util.function.BiFunction @@ -34,13 +35,16 @@ import java.util.function.BiFunction * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> * @since May 2018 */ -internal class NettyTcpServer(val serverConfig: ServerConfiguration, - val collectorProvider: CollectorProvider) : Server { +internal class NettyTcpServer(private val serverConfig: ServerConfiguration, + private val sslContextFactory: SslContextFactory, + private val collectorProvider: CollectorProvider) : Server { override fun start(): Mono<Void> { logger.info { "Listening on port ${serverConfig.port}" } return Mono.defer { - val nettyContext = TcpServer.create(serverConfig.port) + val nettyContext = TcpServer.builder() + .options(this::configureServer) + .build() .start(BiFunction<NettyInbound, NettyOutbound, Publisher<Void>> { t, u -> handleConnection(t, u) }) @@ -48,6 +52,11 @@ internal class NettyTcpServer(val serverConfig: ServerConfiguration, } } + private fun configureServer(opts: ServerOptions.Builder<*>) { + opts.port(serverConfig.port) + opts.sslContext(sslContextFactory.createSslContext(serverConfig.securityConfiguration)) + } + private fun handleConnection(nettyInbound: NettyInbound, nettyOutbound: NettyOutbound): Mono<Void> { logger.debug("Got connection") val pipe = collectorProvider().handleConnection(nettyInbound.receive()) diff --git a/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/impl/socket/SslContextFactory.kt b/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/impl/socket/SslContextFactory.kt new file mode 100644 index 00000000..e94965cd --- /dev/null +++ b/hv-collector-core/src/main/kotlin/org/onap/dcae/collectors/veshv/impl/socket/SslContextFactory.kt @@ -0,0 +1,40 @@ +/* + * ============LICENSE_START======================================================= + * dcaegen2-collectors-veshv + * ================================================================================ + * Copyright (C) 2018 NOKIA Intellectual Property. 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.dcae.collectors.veshv.impl.socket + +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.SecurityConfiguration + + +internal open class SslContextFactory { + fun createSslContext(secConfig: SecurityConfiguration): SslContext = + createSslContextWithConfiguredCerts(secConfig) + .sslProvider(SslProvider.OPENSSL) + .clientAuth(ClientAuth.REQUIRE) + .build() + + protected open fun createSslContextWithConfiguredCerts(secConfig: SecurityConfiguration): SslContextBuilder = + SslContextBuilder.forServer(secConfig.cert.toFile(), secConfig.privateKey.toFile()) + .trustManager(secConfig.trustedCert.toFile()) + +} 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 new file mode 100644 index 00000000..2b72620b --- /dev/null +++ b/hv-collector-core/src/test/kotlin/org/onap/dcae/collectors/veshv/impl/socket/SslContextFactoryTest.kt @@ -0,0 +1,79 @@ +/* + * ============LICENSE_START======================================================= + * dcaegen2-collectors-veshv + * ================================================================================ + * Copyright (C) 2018 NOKIA Intellectual Property. 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.dcae.collectors.veshv.impl.socket + +import io.netty.handler.ssl.ClientAuth +import io.netty.handler.ssl.OpenSslServerContext +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.it +import org.jetbrains.spek.api.dsl.xit +import org.onap.dcae.collectors.veshv.domain.SecurityConfiguration +import java.nio.file.Paths + +/** + * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> + * @since June 2018 + */ +object SslContextFactoryTest : Spek({ + describe("SslContextFactory") { + 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() { + var actualConfig: SecurityConfiguration? = null + override fun createSslContextWithConfiguredCerts(secConfig: SecurityConfiguration): SslContextBuilder { + actualConfig = secConfig + return SslContextBuilder.forServer(resource("/ssl/ca.crt"), resource("/ssl/server.key")) + } + + private fun resource(path: String) = SslContextFactoryTest.javaClass.getResourceAsStream(path) + } + + val result = cut.createSslContext(sampleConfig) + + it("should be server context") { + assertThat(result.isServer).isTrue() + } + + it("should use OpenSSL provider") { + assertThat(result).isInstanceOf(OpenSslServerContext::class.java) + } + + /* + * 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) as ClientAuth + } + assertThat(clientAuth).isEqualTo(ClientAuth.REQUIRE) + } + } +}) diff --git a/hv-collector-core/src/test/resources/ssl/ca.crt b/hv-collector-core/src/test/resources/ssl/ca.crt new file mode 100644 index 00000000..29057f26 --- /dev/null +++ b/hv-collector-core/src/test/resources/ssl/ca.crt @@ -0,0 +1,21 @@ +-----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 new file mode 100644 index 00000000..0af22e29 --- /dev/null +++ b/hv-collector-core/src/test/resources/ssl/server.crt @@ -0,0 +1,19 @@ +-----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 new file mode 100644 index 00000000..033c99af --- /dev/null +++ b/hv-collector-core/src/test/resources/ssl/server.key @@ -0,0 +1,28 @@ +-----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----- |