diff options
Diffstat (limited to 'ms/blueprintsprocessor/modules/commons')
24 files changed, 914 insertions, 239 deletions
diff --git a/ms/blueprintsprocessor/modules/commons/db-lib/pom.xml b/ms/blueprintsprocessor/modules/commons/db-lib/pom.xml index 783d8efbe..67b84240c 100644 --- a/ms/blueprintsprocessor/modules/commons/db-lib/pom.xml +++ b/ms/blueprintsprocessor/modules/commons/db-lib/pom.xml @@ -20,7 +20,7 @@ <parent> <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId> <artifactId>commons</artifactId> - <version>0.6.1-SNAPSHOT</version> + <version>0.7.0-SNAPSHOT</version> </parent> <artifactId>db-lib</artifactId> diff --git a/ms/blueprintsprocessor/modules/commons/dmaap-lib/pom.xml b/ms/blueprintsprocessor/modules/commons/dmaap-lib/pom.xml index b8d418f27..3ed0424ee 100644 --- a/ms/blueprintsprocessor/modules/commons/dmaap-lib/pom.xml +++ b/ms/blueprintsprocessor/modules/commons/dmaap-lib/pom.xml @@ -23,7 +23,7 @@ <parent> <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId> <artifactId>commons</artifactId> - <version>0.6.1-SNAPSHOT</version> + <version>0.7.0-SNAPSHOT</version> </parent> <artifactId>dmaap-lib</artifactId> diff --git a/ms/blueprintsprocessor/modules/commons/grpc-lib/pom.xml b/ms/blueprintsprocessor/modules/commons/grpc-lib/pom.xml index ad16eb908..e5214e139 100644 --- a/ms/blueprintsprocessor/modules/commons/grpc-lib/pom.xml +++ b/ms/blueprintsprocessor/modules/commons/grpc-lib/pom.xml @@ -18,7 +18,7 @@ <parent> <artifactId>commons</artifactId> <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId> - <version>0.6.1-SNAPSHOT</version> + <version>0.7.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> diff --git a/ms/blueprintsprocessor/modules/commons/message-lib/pom.xml b/ms/blueprintsprocessor/modules/commons/message-lib/pom.xml index 2a67da10a..b5b8c46a3 100644 --- a/ms/blueprintsprocessor/modules/commons/message-lib/pom.xml +++ b/ms/blueprintsprocessor/modules/commons/message-lib/pom.xml @@ -18,7 +18,7 @@ <parent> <artifactId>commons</artifactId> <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId> - <version>0.6.1-SNAPSHOT</version> + <version>0.7.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> diff --git a/ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/BluePrintMessageLibConfiguration.kt b/ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/BluePrintMessageLibConfiguration.kt index 644c51860..27a444bdc 100644 --- a/ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/BluePrintMessageLibConfiguration.kt +++ b/ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/BluePrintMessageLibConfiguration.kt @@ -17,6 +17,11 @@ package org.onap.ccsdk.cds.blueprintsprocessor.message +import com.fasterxml.jackson.databind.JsonNode +import org.onap.ccsdk.cds.blueprintsprocessor.message.service.BluePrintMessageLibPropertyService +import org.onap.ccsdk.cds.blueprintsprocessor.message.service.BlueprintMessageConsumerService +import org.onap.ccsdk.cds.blueprintsprocessor.message.service.BlueprintMessageProducerService +import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintDependencyService import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.context.annotation.ComponentScan import org.springframework.context.annotation.Configuration @@ -26,10 +31,36 @@ import org.springframework.context.annotation.Configuration @EnableConfigurationProperties open class BluePrintMessageLibConfiguration +/** + * Exposed Dependency Service by this Message Lib Module + */ +fun BluePrintDependencyService.messageLibPropertyService(): BluePrintMessageLibPropertyService = + instance(MessageLibConstants.SERVICE_BLUEPRINT_MESSAGE_LIB_PROPERTY) + +/** Extension functions for message producer service **/ +fun BluePrintDependencyService.messageProducerService(selector: String): BlueprintMessageProducerService { + return messageLibPropertyService().blueprintMessageProducerService(selector) +} + + +fun BluePrintDependencyService.messageProducerService(jsonNode: JsonNode): BlueprintMessageProducerService { + return messageLibPropertyService().blueprintMessageProducerService(jsonNode) +} + +/** Extension functions for message consumer service **/ +fun BluePrintDependencyService.messageConsumerService(selector: String): BlueprintMessageConsumerService { + return messageLibPropertyService().blueprintMessageConsumerService(selector) +} + +fun BluePrintDependencyService.messageConsumerService(jsonNode: JsonNode): BlueprintMessageConsumerService { + return messageLibPropertyService().blueprintMessageConsumerService(jsonNode) +} + class MessageLibConstants { companion object { const val SERVICE_BLUEPRINT_MESSAGE_LIB_PROPERTY = "blueprint-message-lib-property-service" - const val PROPERTY_MESSAGE_CLIENT_PREFIX = "blueprintsprocessor.messageclient." + const val PROPERTY_MESSAGE_CONSUMER_PREFIX = "blueprintsprocessor.messageconsumer." + const val PROPERTY_MESSAGE_PRODUCER_PREFIX = "blueprintsprocessor.messageproducer." const val TYPE_KAFKA_BASIC_AUTH = "kafka-basic-auth" } }
\ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/BluePrintMessageLibData.kt b/ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/BluePrintMessageLibData.kt index e621ec66f..ab04054fe 100644 --- a/ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/BluePrintMessageLibData.kt +++ b/ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/BluePrintMessageLibData.kt @@ -16,7 +16,7 @@ package org.onap.ccsdk.cds.blueprintsprocessor.message - +/** Producer Properties **/ open class MessageProducerProperties @@ -24,4 +24,18 @@ open class KafkaBasicAuthMessageProducerProperties : MessageProducerProperties() lateinit var bootstrapServers: String var topic: String? = null var clientId: String? = null -}
\ No newline at end of file +} + +/** Consumer Properties **/ + +open class MessageConsumerProperties + +open class KafkaMessageConsumerProperties : MessageConsumerProperties() { + lateinit var bootstrapServers: String + lateinit var groupId: String + var clientId: String? = null + var topic: String? = null + var pollMillSec: Long = 1000 +} + +open class KafkaBasicAuthMessageConsumerProperties : KafkaMessageConsumerProperties() diff --git a/ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/service/BluePrintMessageLibPropertyService.kt b/ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/service/BluePrintMessageLibPropertyService.kt index fb01ce179..7c56ea432 100644 --- a/ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/service/BluePrintMessageLibPropertyService.kt +++ b/ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/service/BluePrintMessageLibPropertyService.kt @@ -18,9 +18,7 @@ package org.onap.ccsdk.cds.blueprintsprocessor.message.service import com.fasterxml.jackson.databind.JsonNode import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintProperties -import org.onap.ccsdk.cds.blueprintsprocessor.message.KafkaBasicAuthMessageProducerProperties -import org.onap.ccsdk.cds.blueprintsprocessor.message.MessageLibConstants -import org.onap.ccsdk.cds.blueprintsprocessor.message.MessageProducerProperties +import org.onap.ccsdk.cds.blueprintsprocessor.message.* import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils import org.springframework.stereotype.Service @@ -28,22 +26,22 @@ import org.springframework.stereotype.Service @Service(MessageLibConstants.SERVICE_BLUEPRINT_MESSAGE_LIB_PROPERTY) open class BluePrintMessageLibPropertyService(private var bluePrintProperties: BluePrintProperties) { - fun blueprintMessageClientService(jsonNode: JsonNode): BlueprintMessageProducerService { - val messageClientProperties = messageClientProperties(jsonNode) - return blueprintMessageClientService(messageClientProperties) + fun blueprintMessageProducerService(jsonNode: JsonNode): BlueprintMessageProducerService { + val messageClientProperties = messageProducerProperties(jsonNode) + return blueprintMessageProducerService(messageClientProperties) } - fun blueprintMessageClientService(selector: String): BlueprintMessageProducerService { - val prefix = "${MessageLibConstants.PROPERTY_MESSAGE_CLIENT_PREFIX}$selector" - val messageClientProperties = messageClientProperties(prefix) - return blueprintMessageClientService(messageClientProperties) + fun blueprintMessageProducerService(selector: String): BlueprintMessageProducerService { + val prefix = "${MessageLibConstants.PROPERTY_MESSAGE_PRODUCER_PREFIX}$selector" + val messageClientProperties = messageProducerProperties(prefix) + return blueprintMessageProducerService(messageClientProperties) } - fun messageClientProperties(prefix: String): MessageProducerProperties { + fun messageProducerProperties(prefix: String): MessageProducerProperties { val type = bluePrintProperties.propertyBeanType("$prefix.type", String::class.java) return when (type) { MessageLibConstants.TYPE_KAFKA_BASIC_AUTH -> { - kafkaBasicAuthMessageClientProperties(prefix) + kafkaBasicAuthMessageProducerProperties(prefix) } else -> { throw BluePrintProcessorException("Message adaptor($type) is not supported") @@ -51,7 +49,7 @@ open class BluePrintMessageLibPropertyService(private var bluePrintProperties: B } } - fun messageClientProperties(jsonNode: JsonNode): MessageProducerProperties { + fun messageProducerProperties(jsonNode: JsonNode): MessageProducerProperties { val type = jsonNode.get("type").textValue() return when (type) { MessageLibConstants.TYPE_KAFKA_BASIC_AUTH -> { @@ -63,7 +61,7 @@ open class BluePrintMessageLibPropertyService(private var bluePrintProperties: B } } - private fun blueprintMessageClientService(MessageProducerProperties: MessageProducerProperties) + private fun blueprintMessageProducerService(MessageProducerProperties: MessageProducerProperties) : BlueprintMessageProducerService { when (MessageProducerProperties) { @@ -76,9 +74,67 @@ open class BluePrintMessageLibPropertyService(private var bluePrintProperties: B } } - private fun kafkaBasicAuthMessageClientProperties(prefix: String): KafkaBasicAuthMessageProducerProperties { + private fun kafkaBasicAuthMessageProducerProperties(prefix: String): KafkaBasicAuthMessageProducerProperties { return bluePrintProperties.propertyBeanType( prefix, KafkaBasicAuthMessageProducerProperties::class.java) } + /** Consumer Property Lib Service Implementation **/ + + /** Return Message Consumer Service for [jsonNode] definitions. */ + fun blueprintMessageConsumerService(jsonNode: JsonNode): BlueprintMessageConsumerService { + val messageConsumerProperties = messageConsumerProperties(jsonNode) + return blueprintMessageConsumerService(messageConsumerProperties) + } + + /** Return Message Consumer Service for [selector] definitions. */ + fun blueprintMessageConsumerService(selector: String): BlueprintMessageConsumerService { + val prefix = "${MessageLibConstants.PROPERTY_MESSAGE_CONSUMER_PREFIX}$selector" + val messageClientProperties = messageConsumerProperties(prefix) + return blueprintMessageConsumerService(messageClientProperties) + } + + /** Return Message Consumer Properties for [prefix] definitions. */ + fun messageConsumerProperties(prefix: String): MessageConsumerProperties { + val type = bluePrintProperties.propertyBeanType("$prefix.type", String::class.java) + return when (type) { + MessageLibConstants.TYPE_KAFKA_BASIC_AUTH -> { + kafkaBasicAuthMessageConsumerProperties(prefix) + } + else -> { + throw BluePrintProcessorException("Message adaptor($type) is not supported") + } + } + } + + fun messageConsumerProperties(jsonNode: JsonNode): MessageConsumerProperties { + val type = jsonNode.get("type").textValue() + return when (type) { + MessageLibConstants.TYPE_KAFKA_BASIC_AUTH -> { + JacksonUtils.readValue(jsonNode, KafkaBasicAuthMessageConsumerProperties::class.java)!! + } + else -> { + throw BluePrintProcessorException("Message adaptor($type) is not supported") + } + } + } + + private fun blueprintMessageConsumerService(messageConsumerProperties: MessageConsumerProperties) + : BlueprintMessageConsumerService { + + when (messageConsumerProperties) { + is KafkaBasicAuthMessageConsumerProperties -> { + return KafkaBasicAuthMessageConsumerService(messageConsumerProperties) + } + else -> { + throw BluePrintProcessorException("couldn't get Message client service for") + } + } + } + + private fun kafkaBasicAuthMessageConsumerProperties(prefix: String): KafkaBasicAuthMessageConsumerProperties { + return bluePrintProperties.propertyBeanType( + prefix, KafkaBasicAuthMessageConsumerProperties::class.java) + } + } diff --git a/ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/service/BlueprintMessageConsumerService.kt b/ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/service/BlueprintMessageConsumerService.kt new file mode 100644 index 000000000..25f0bf44d --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/service/BlueprintMessageConsumerService.kt @@ -0,0 +1,32 @@ +/* + * Copyright © 2019 IBM. + * + * 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. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.message.service + +import kotlinx.coroutines.channels.Channel + +interface BlueprintMessageConsumerService { + + /** Subscribe to the Kafka channel with [additionalConfig] */ + suspend fun subscribe(additionalConfig: Map<String, Any>?): Channel<String> + + /** Subscribe to the Kafka channel with [additionalConfig] for dynamic [topics]*/ + suspend fun subscribe(topics: List<String>, additionalConfig: Map<String, Any>? = null): Channel<String> + + /** close the channel, consumer and other resources */ + suspend fun shutDown() + +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/service/KafkaBasicAuthMessageConsumerService.kt b/ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/service/KafkaBasicAuthMessageConsumerService.kt new file mode 100644 index 000000000..5a9e61bfd --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/service/KafkaBasicAuthMessageConsumerService.kt @@ -0,0 +1,116 @@ +/* + * Copyright © 2019 IBM. + * + * 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. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.message.service + +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import org.apache.kafka.clients.CommonClientConfigs +import org.apache.kafka.clients.consumer.Consumer +import org.apache.kafka.clients.consumer.ConsumerConfig +import org.apache.kafka.clients.consumer.KafkaConsumer +import org.apache.kafka.common.serialization.StringDeserializer +import org.onap.ccsdk.cds.blueprintsprocessor.message.KafkaBasicAuthMessageConsumerProperties +import org.onap.ccsdk.cds.controllerblueprints.core.logger +import java.time.Duration +import kotlin.concurrent.thread + +class KafkaBasicAuthMessageConsumerService( + private val messageConsumerProperties: KafkaBasicAuthMessageConsumerProperties) + : BlueprintMessageConsumerService { + + private val channel = Channel<String>() + private var kafkaConsumer: Consumer<String, String>? = null + val log = logger(KafkaBasicAuthMessageConsumerService::class) + + @Volatile + var keepGoing = true + + fun kafkaConsumer(additionalConfig: Map<String, Any>? = null): Consumer<String, String> { + val configProperties = hashMapOf<String, Any>() + configProperties[CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG] = messageConsumerProperties.bootstrapServers + configProperties[ConsumerConfig.GROUP_ID_CONFIG] = messageConsumerProperties.groupId + configProperties[ConsumerConfig.AUTO_OFFSET_RESET_CONFIG] = "latest" + configProperties[ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG] = StringDeserializer::class.java + configProperties[ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG] = StringDeserializer::class.java + if (messageConsumerProperties.clientId != null) { + configProperties[ConsumerConfig.CLIENT_ID_CONFIG] = messageConsumerProperties.clientId!! + } + // TODO("Security Implementation based on type") + /** add or override already set properties */ + additionalConfig?.let { configProperties.putAll(it) } + /** Create Kafka consumer */ + return KafkaConsumer(configProperties) + } + + override suspend fun subscribe(additionalConfig: Map<String, Any>?): Channel<String> { + /** get to topic names */ + val consumerTopic = messageConsumerProperties.topic?.split(",")?.map { it.trim() } + check(!consumerTopic.isNullOrEmpty()) { "couldn't get topic information" } + return subscribe(consumerTopic, additionalConfig) + } + + + override suspend fun subscribe(consumerTopic: List<String>, additionalConfig: Map<String, Any>?): Channel<String> { + /** Create Kafka consumer */ + kafkaConsumer = kafkaConsumer(additionalConfig) + + checkNotNull(kafkaConsumer) { + "failed to create kafka consumer for " + + "server(${messageConsumerProperties.bootstrapServers})'s " + + "topics(${messageConsumerProperties.bootstrapServers})" + } + + kafkaConsumer!!.subscribe(consumerTopic) + log.info("Successfully consumed topic($consumerTopic)") + + thread(start = true, name = "KafkaConsumer") { + keepGoing = true + kafkaConsumer!!.use { kc -> + while (keepGoing) { + val consumerRecords = kc.poll(Duration.ofMillis(messageConsumerProperties.pollMillSec)) + runBlocking { + consumerRecords?.forEach { consumerRecord -> + /** execute the command block */ + consumerRecord.value()?.let { + launch { + if (!channel.isClosedForSend) { + channel.send(it) + } else { + log.error("Channel is closed to receive message") + } + } + } + } + } + } + log.info("message listener shutting down.....") + } + } + return channel + } + + override suspend fun shutDown() { + /** stop the polling loop */ + keepGoing = false + /** Close the Channel */ + channel.cancel() + /** TO shutdown gracefully, need to wait for the maximum poll time */ + delay(messageConsumerProperties.pollMillSec) + } +} diff --git a/ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/service/KafkaBasicAuthMessageProducerService.kt b/ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/service/KafkaBasicAuthMessageProducerService.kt index 008e92437..1c93bb0fc 100644 --- a/ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/service/KafkaBasicAuthMessageProducerService.kt +++ b/ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/service/KafkaBasicAuthMessageProducerService.kt @@ -83,7 +83,6 @@ class KafkaBasicAuthMessageProducerService( } fun messageTemplate(additionalConfig: Map<String, Any>? = null): KafkaTemplate<String, Any> { - log.info("Prepering templates") if (kafkaTemplate == null) { kafkaTemplate = KafkaTemplate(producerFactory(additionalConfig)) } diff --git a/ms/blueprintsprocessor/modules/commons/message-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/service/BlueprintMessageConsumerServiceTest.kt b/ms/blueprintsprocessor/modules/commons/message-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/service/BlueprintMessageConsumerServiceTest.kt new file mode 100644 index 000000000..2b84eaa78 --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/message-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/service/BlueprintMessageConsumerServiceTest.kt @@ -0,0 +1,140 @@ +/* + * Copyright © 2019 IBM. + * + * 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. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.message.service + +import io.mockk.every +import io.mockk.spyk +import kotlinx.coroutines.channels.consumeEach +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import org.apache.kafka.clients.consumer.ConsumerRecord +import org.apache.kafka.clients.consumer.MockConsumer +import org.apache.kafka.clients.consumer.OffsetResetStrategy +import org.apache.kafka.common.TopicPartition +import org.junit.Test +import org.junit.runner.RunWith +import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintProperties +import org.onap.ccsdk.cds.blueprintsprocessor.core.BlueprintPropertyConfiguration +import org.onap.ccsdk.cds.blueprintsprocessor.message.BluePrintMessageLibConfiguration +import org.onap.ccsdk.cds.controllerblueprints.core.logger +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.test.annotation.DirtiesContext +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.TestPropertySource +import org.springframework.test.context.junit4.SpringRunner +import kotlin.test.assertNotNull +import kotlin.test.assertTrue + + +@RunWith(SpringRunner::class) +@DirtiesContext +@ContextConfiguration(classes = [BluePrintMessageLibConfiguration::class, + BlueprintPropertyConfiguration::class, BluePrintProperties::class]) +@TestPropertySource(properties = +["blueprintsprocessor.messageconsumer.sample.type=kafka-basic-auth", + "blueprintsprocessor.messageconsumer.sample.bootstrapServers=127.0.0.1:9092", + "blueprintsprocessor.messageconsumer.sample.groupId=sample-group", + "blueprintsprocessor.messageconsumer.sample.topic=default-topic", + "blueprintsprocessor.messageconsumer.sample.clientId=default-client-id", + "blueprintsprocessor.messageconsumer.sample.pollMillSec=10", + + "blueprintsprocessor.messageproducer.sample.type=kafka-basic-auth", + "blueprintsprocessor.messageproducer.sample.bootstrapServers=127.0.0.1:9092", + "blueprintsprocessor.messageproducer.sample.topic=default-topic", + "blueprintsprocessor.messageproducer.sample.clientId=default-client-id" +]) +open class BlueprintMessageConsumerServiceTest { + val log = logger(BlueprintMessageConsumerServiceTest::class) + + @Autowired + lateinit var bluePrintMessageLibPropertyService: BluePrintMessageLibPropertyService + + @Test + fun testKafkaBasicAuthConsumerService() { + runBlocking { + val blueprintMessageConsumerService = bluePrintMessageLibPropertyService + .blueprintMessageConsumerService("sample") as KafkaBasicAuthMessageConsumerService + assertNotNull(blueprintMessageConsumerService, "failed to get blueprintMessageConsumerService") + + val spyBlueprintMessageConsumerService = spyk(blueprintMessageConsumerService, recordPrivateCalls = true) + + val topic = "default-topic" + val partitions: MutableList<TopicPartition> = arrayListOf() + val topicsCollection: MutableList<String> = arrayListOf() + partitions.add(TopicPartition(topic, 1)) + val partitionsBeginningMap: MutableMap<TopicPartition, Long> = mutableMapOf() + val partitionsEndMap: MutableMap<TopicPartition, Long> = mutableMapOf() + + val records: Long = 10 + partitions.forEach { partition -> + partitionsBeginningMap[partition] = 0L + partitionsEndMap[partition] = records + topicsCollection.add(partition.topic()) + } + val mockKafkaConsumer = MockConsumer<String, String>(OffsetResetStrategy.EARLIEST) + mockKafkaConsumer.subscribe(topicsCollection) + mockKafkaConsumer.rebalance(partitions) + mockKafkaConsumer.updateBeginningOffsets(partitionsBeginningMap) + mockKafkaConsumer.updateEndOffsets(partitionsEndMap) + for (i in 1..10) { + val record = ConsumerRecord<String, String>(topic, 1, i.toLong(), "key_$i", + "I am message $i") + mockKafkaConsumer.addRecord(record) + } + + every { spyBlueprintMessageConsumerService.kafkaConsumer(any()) } returns mockKafkaConsumer + val channel = spyBlueprintMessageConsumerService.subscribe(null) + launch { + channel.consumeEach { + assertTrue(it.startsWith("I am message"), "failed to get the actual message") + } + } + delay(10) + spyBlueprintMessageConsumerService.shutDown() + } + } + + /** Integration Kafka Testing, Enable and use this test case only for local desktop testing with real kafka broker */ + //@Test + fun testKafkaIntegration() { + runBlocking { + val blueprintMessageConsumerService = bluePrintMessageLibPropertyService + .blueprintMessageConsumerService("sample") as KafkaBasicAuthMessageConsumerService + assertNotNull(blueprintMessageConsumerService, "failed to get blueprintMessageConsumerService") + + val channel = blueprintMessageConsumerService.subscribe(null) + launch { + channel.consumeEach { + log.info("Consumed Message : $it") + } + } + + /** Send message with every 1 sec */ + val blueprintMessageProducerService = bluePrintMessageLibPropertyService + .blueprintMessageProducerService("sample") as KafkaBasicAuthMessageProducerService + launch { + repeat(5) { + delay(1000) + blueprintMessageProducerService.sendMessage("this is my message($it)") + } + } + delay(10000) + blueprintMessageConsumerService.shutDown() + } + } +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/commons/message-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/service/BlueprintMessageProducerServiceTest.kt b/ms/blueprintsprocessor/modules/commons/message-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/service/BlueprintMessageProducerServiceTest.kt index 0f8367d7e..31bcc1517 100644 --- a/ms/blueprintsprocessor/modules/commons/message-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/service/BlueprintMessageProducerServiceTest.kt +++ b/ms/blueprintsprocessor/modules/commons/message-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/service/BlueprintMessageProducerServiceTest.kt @@ -41,10 +41,10 @@ import kotlin.test.assertTrue @ContextConfiguration(classes = [BluePrintMessageLibConfiguration::class, BlueprintPropertyConfiguration::class, BluePrintProperties::class]) @TestPropertySource(properties = -["blueprintsprocessor.messageclient.sample.type=kafka-basic-auth", - "blueprintsprocessor.messageclient.sample.bootstrapServers=127:0.0.1:9092", - "blueprintsprocessor.messageclient.sample.topic=default-topic", - "blueprintsprocessor.messageclient.sample.clientId=default-client-id" +["blueprintsprocessor.messageproducer.sample.type=kafka-basic-auth", + "blueprintsprocessor.messageproducer.sample.bootstrapServers=127.0.0.1:9092", + "blueprintsprocessor.messageproducer.sample.topic=default-topic", + "blueprintsprocessor.messageproducer.sample.clientId=default-client-id" ]) open class BlueprintMessageProducerServiceTest { @@ -52,10 +52,10 @@ open class BlueprintMessageProducerServiceTest { lateinit var bluePrintMessageLibPropertyService: BluePrintMessageLibPropertyService @Test - fun testKafkaBasicAuthClientService() { + fun testKafkaBasicAuthProducertService() { runBlocking { - val bluePrintMessageClientService = bluePrintMessageLibPropertyService - .blueprintMessageClientService("sample") as KafkaBasicAuthMessageProducerService + val blueprintMessageProducerService = bluePrintMessageLibPropertyService + .blueprintMessageProducerService("sample") as KafkaBasicAuthMessageProducerService val mockKafkaTemplate = mockk<KafkaTemplate<String, Any>>() @@ -64,11 +64,11 @@ open class BlueprintMessageProducerServiceTest { every { mockKafkaTemplate.send(any(), any()) } returns future - val spyBluePrintMessageClientService = spyk(bluePrintMessageClientService, recordPrivateCalls = true) + val spyBluePrintMessageProducerService = spyk(blueprintMessageProducerService, recordPrivateCalls = true) - every { spyBluePrintMessageClientService.messageTemplate(any()) } returns mockKafkaTemplate + every { spyBluePrintMessageProducerService.messageTemplate(any()) } returns mockKafkaTemplate - val response = spyBluePrintMessageClientService.sendMessage("Testing message") + val response = spyBluePrintMessageProducerService.sendMessage("Testing message") assertTrue(response, "failed to get command response") } } diff --git a/ms/blueprintsprocessor/modules/commons/message-lib/src/test/resources/logback-test.xml b/ms/blueprintsprocessor/modules/commons/message-lib/src/test/resources/logback-test.xml index 626b8f911..3868440c7 100644 --- a/ms/blueprintsprocessor/modules/commons/message-lib/src/test/resources/logback-test.xml +++ b/ms/blueprintsprocessor/modules/commons/message-lib/src/test/resources/logback-test.xml @@ -19,7 +19,7 @@ <!-- encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder by default --> <encoder> - <pattern>%d{HH:mm:ss.SSS} %-5level %logger{100} - %msg%n</pattern> + <pattern>%d{HH:mm:ss.SSS} %-5level [%thread] %logger{50} - %msg%n</pattern> </encoder> </appender> diff --git a/ms/blueprintsprocessor/modules/commons/pom.xml b/ms/blueprintsprocessor/modules/commons/pom.xml index 8c88db424..37dd5d77e 100755 --- a/ms/blueprintsprocessor/modules/commons/pom.xml +++ b/ms/blueprintsprocessor/modules/commons/pom.xml @@ -22,7 +22,7 @@ <parent> <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId> <artifactId>modules</artifactId> - <version>0.6.1-SNAPSHOT</version> + <version>0.7.0-SNAPSHOT</version> </parent> <artifactId>commons</artifactId> diff --git a/ms/blueprintsprocessor/modules/commons/processor-core/pom.xml b/ms/blueprintsprocessor/modules/commons/processor-core/pom.xml index 8ebbc6768..673d1277c 100644 --- a/ms/blueprintsprocessor/modules/commons/processor-core/pom.xml +++ b/ms/blueprintsprocessor/modules/commons/processor-core/pom.xml @@ -21,7 +21,7 @@ <parent> <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId> <artifactId>commons</artifactId> - <version>0.6.1-SNAPSHOT</version> + <version>0.7.0-SNAPSHOT</version> </parent> <artifactId>processor-core</artifactId> diff --git a/ms/blueprintsprocessor/modules/commons/rest-lib/pom.xml b/ms/blueprintsprocessor/modules/commons/rest-lib/pom.xml index 7602853f8..7c6cceb23 100644 --- a/ms/blueprintsprocessor/modules/commons/rest-lib/pom.xml +++ b/ms/blueprintsprocessor/modules/commons/rest-lib/pom.xml @@ -21,7 +21,7 @@ <parent> <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId> <artifactId>commons</artifactId> - <version>0.6.1-SNAPSHOT</version> + <version>0.7.0-SNAPSHOT</version> </parent> <artifactId>rest-lib</artifactId> diff --git a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/BluePrintRestLibData.kt b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/BluePrintRestLibData.kt index 75a9409fd..68672f227 100644 --- a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/BluePrintRestLibData.kt +++ b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/BluePrintRestLibData.kt @@ -1,6 +1,7 @@ /* * Copyright © 2017-2018 AT&T Intellectual Property. * Modifications Copyright © 2019 Huawei. + * Modifications Copyright © 2019 Bell Canada. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +21,7 @@ package org.onap.ccsdk.cds.blueprintsprocessor.rest open class RestClientProperties { lateinit var type: String lateinit var url: String + var additionalHeaders: Map<String, String>? = null } open class SSLRestClientProperties : RestClientProperties() { @@ -63,4 +65,4 @@ open class PolicyManagerRestClientProperties : RestClientProperties() { lateinit var env: String lateinit var clientAuth: String lateinit var authorisation: String -}
\ No newline at end of file +} diff --git a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BasicAuthRestClientService.kt b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BasicAuthRestClientService.kt index 3190cd1c6..bb6937d7c 100644 --- a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BasicAuthRestClientService.kt +++ b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BasicAuthRestClientService.kt @@ -18,6 +18,10 @@ package org.onap.ccsdk.cds.blueprintsprocessor.rest.service import org.apache.http.message.BasicHeader import org.onap.ccsdk.cds.blueprintsprocessor.rest.BasicAuthRestClientProperties +import org.onap.ccsdk.cds.blueprintsprocessor.rest.RestClientProperties +import org.onap.ccsdk.cds.blueprintsprocessor.rest.RestLibConstants +import org.onap.ccsdk.cds.blueprintsprocessor.rest.utils.WebClientUtils +import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException import org.springframework.http.HttpHeaders import org.springframework.http.MediaType import java.nio.charset.Charset @@ -25,42 +29,43 @@ import java.util.* class BasicAuthRestClientService(private val restClientProperties: BasicAuthRestClientProperties) : - BlueprintWebClientService { + BlueprintWebClientService { override fun defaultHeaders(): Map<String, String> { val encodedCredentials = setBasicAuth(restClientProperties.username, - restClientProperties.password) + restClientProperties.password) return mapOf( - HttpHeaders.CONTENT_TYPE to MediaType.APPLICATION_JSON_VALUE, - HttpHeaders.ACCEPT to MediaType.APPLICATION_JSON_VALUE, - HttpHeaders.AUTHORIZATION to "Basic $encodedCredentials") + HttpHeaders.CONTENT_TYPE to MediaType.APPLICATION_JSON_VALUE, + HttpHeaders.ACCEPT to MediaType.APPLICATION_JSON_VALUE, + HttpHeaders.AUTHORIZATION to "Basic $encodedCredentials") } override fun host(uri: String): String { return restClientProperties.url + uri } - override fun convertToBasicHeaders(headers: Map<String, String>): - Array<BasicHeader> { + override fun convertToBasicHeaders(headers: Map<String, String>): + Array<BasicHeader> { val customHeaders: MutableMap<String, String> = headers.toMutableMap() + //inject additionalHeaders + customHeaders.putAll(verifyAdditionalHeaders(restClientProperties)) + if (!headers.containsKey(HttpHeaders.AUTHORIZATION)) { val encodedCredentials = setBasicAuth( - restClientProperties.username, - restClientProperties.password) + restClientProperties.username, + restClientProperties.password) customHeaders[HttpHeaders.AUTHORIZATION] = - "Basic $encodedCredentials" + "Basic $encodedCredentials" } return super.convertToBasicHeaders(customHeaders) } private fun setBasicAuth(username: String, password: String): String { - val credentialsString = "$username:$password" return Base64.getEncoder().encodeToString( - credentialsString.toByteArray(Charset.defaultCharset())) + credentialsString.toByteArray(Charset.defaultCharset())) } - -}
\ No newline at end of file +} diff --git a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BluePrintRestLibPropertyService.kt b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BluePrintRestLibPropertyService.kt index 4f6865764..8d4f0ca63 100644 --- a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BluePrintRestLibPropertyService.kt +++ b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BluePrintRestLibPropertyService.kt @@ -38,7 +38,7 @@ open class BluePrintRestLibPropertyService(private var bluePrintProperties: BluePrintProperties) { open fun blueprintWebClientService(jsonNode: JsonNode): - BlueprintWebClientService { + BlueprintWebClientService { val restClientProperties = restClientProperties(jsonNode) return blueprintWebClientService(restClientProperties) } @@ -51,7 +51,7 @@ open class BluePrintRestLibPropertyService(private var bluePrintProperties: fun restClientProperties(prefix: String): RestClientProperties { val type = bluePrintProperties.propertyBeanType( - "$prefix.type", String::class.java) + "$prefix.type", String::class.java) return when (type) { RestLibConstants.TYPE_BASIC_AUTH -> { basicAuthRestClientProperties(prefix) @@ -76,7 +76,7 @@ open class BluePrintRestLibPropertyService(private var bluePrintProperties: } else -> { throw BluePrintProcessorException("Rest adaptor($type) is" + - " not supported") + " not supported") } } } @@ -86,43 +86,35 @@ open class BluePrintRestLibPropertyService(private var bluePrintProperties: val type = jsonNode.get("type").textValue() return when (type) { RestLibConstants.TYPE_TOKEN_AUTH -> { - JacksonUtils.readValue(jsonNode, - TokenAuthRestClientProperties::class.java)!! + JacksonUtils.readValue(jsonNode, TokenAuthRestClientProperties::class.java)!! } RestLibConstants.TYPE_BASIC_AUTH -> { - JacksonUtils.readValue(jsonNode, - BasicAuthRestClientProperties::class.java)!! + JacksonUtils.readValue(jsonNode, BasicAuthRestClientProperties::class.java)!! } RestLibConstants.TYPE_DME2_PROXY -> { - JacksonUtils.readValue(jsonNode, - DME2RestClientProperties::class.java)!! + JacksonUtils.readValue(jsonNode, DME2RestClientProperties::class.java)!! } RestLibConstants.TYPE_POLICY_MANAGER -> { - JacksonUtils.readValue(jsonNode, - PolicyManagerRestClientProperties::class.java)!! + JacksonUtils.readValue(jsonNode, PolicyManagerRestClientProperties::class.java)!! } RestLibConstants.TYPE_SSL_BASIC_AUTH -> { - JacksonUtils.readValue(jsonNode, - SSLBasicAuthRestClientProperties::class.java)!! + JacksonUtils.readValue(jsonNode, SSLBasicAuthRestClientProperties::class.java)!! } RestLibConstants.TYPE_SSL_TOKEN_AUTH -> { - JacksonUtils.readValue(jsonNode, - SSLTokenAuthRestClientProperties::class.java)!! + JacksonUtils.readValue(jsonNode, SSLTokenAuthRestClientProperties::class.java)!! } RestLibConstants.TYPE_SSL_NO_AUTH -> { - JacksonUtils.readValue( - jsonNode, SSLRestClientProperties::class.java)!! + JacksonUtils.readValue(jsonNode, SSLRestClientProperties::class.java)!! } else -> { - throw BluePrintProcessorException("Rest adaptor($type) is" + - " not supported") + throw BluePrintProcessorException( + "Rest adaptor($type) is not supported") } } } - - private fun blueprintWebClientService( - restClientProperties: RestClientProperties): - BlueprintWebClientService { + + private fun blueprintWebClientService(restClientProperties: RestClientProperties): + BlueprintWebClientService { when (restClientProperties) { is SSLRestClientProperties -> { @@ -138,66 +130,65 @@ open class BluePrintRestLibPropertyService(private var bluePrintProperties: return DME2ProxyRestClientService(restClientProperties) } else -> { - throw BluePrintProcessorException("couldn't get rest " + - "service for") + throw BluePrintProcessorException("couldn't get rest service for type:${restClientProperties.type} uri: ${restClientProperties.url}") } } } private fun tokenRestClientProperties(prefix: String): - TokenAuthRestClientProperties { + TokenAuthRestClientProperties { return bluePrintProperties.propertyBeanType( - prefix, TokenAuthRestClientProperties::class.java) + prefix, TokenAuthRestClientProperties::class.java) } private fun basicAuthRestClientProperties(prefix: String): - BasicAuthRestClientProperties { + BasicAuthRestClientProperties { return bluePrintProperties.propertyBeanType( - prefix, BasicAuthRestClientProperties::class.java) + prefix, BasicAuthRestClientProperties::class.java) } private fun sslBasicAuthRestClientProperties(prefix: String): - SSLRestClientProperties { + SSLRestClientProperties { val sslProps: SSLBasicAuthRestClientProperties = - bluePrintProperties.propertyBeanType( - prefix, SSLBasicAuthRestClientProperties::class.java) - val basicProps : BasicAuthRestClientProperties = - bluePrintProperties.propertyBeanType( - prefix, BasicAuthRestClientProperties::class.java) + bluePrintProperties.propertyBeanType( + prefix, SSLBasicAuthRestClientProperties::class.java) + val basicProps: BasicAuthRestClientProperties = + bluePrintProperties.propertyBeanType( + prefix, BasicAuthRestClientProperties::class.java) sslProps.basicAuth = basicProps return sslProps } private fun sslTokenAuthRestClientProperties(prefix: String): - SSLRestClientProperties { + SSLRestClientProperties { val sslProps: SSLTokenAuthRestClientProperties = - bluePrintProperties.propertyBeanType(prefix, - SSLTokenAuthRestClientProperties::class.java) - val basicProps : TokenAuthRestClientProperties = - bluePrintProperties.propertyBeanType(prefix, - TokenAuthRestClientProperties::class.java) + bluePrintProperties.propertyBeanType(prefix, + SSLTokenAuthRestClientProperties::class.java) + val basicProps: TokenAuthRestClientProperties = + bluePrintProperties.propertyBeanType(prefix, + TokenAuthRestClientProperties::class.java) sslProps.tokenAuth = basicProps return sslProps } private fun sslNoAuthRestClientProperties(prefix: String): - SSLRestClientProperties { + SSLRestClientProperties { return bluePrintProperties.propertyBeanType( - prefix, SSLRestClientProperties::class.java) + prefix, SSLRestClientProperties::class.java) } private fun dme2ProxyClientProperties(prefix: String): - DME2RestClientProperties { + DME2RestClientProperties { return bluePrintProperties.propertyBeanType( - prefix, DME2RestClientProperties::class.java) + prefix, DME2RestClientProperties::class.java) } private fun policyManagerRestClientProperties(prefix: String): - PolicyManagerRestClientProperties { + PolicyManagerRestClientProperties { return bluePrintProperties.propertyBeanType( - prefix, PolicyManagerRestClientProperties::class.java) + prefix, PolicyManagerRestClientProperties::class.java) } } diff --git a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BlueprintWebClientService.kt b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BlueprintWebClientService.kt index 1acd07b7b..26c808874 100644 --- a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BlueprintWebClientService.kt +++ b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BlueprintWebClientService.kt @@ -28,11 +28,14 @@ import org.apache.http.entity.StringEntity import org.apache.http.impl.client.CloseableHttpClient import org.apache.http.impl.client.HttpClients import org.apache.http.message.BasicHeader +import org.onap.ccsdk.cds.blueprintsprocessor.rest.RestClientProperties +import org.onap.ccsdk.cds.blueprintsprocessor.rest.RestLibConstants import org.onap.ccsdk.cds.blueprintsprocessor.rest.utils.WebClientUtils import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintRetryException import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintIOUtils import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils +import org.springframework.http.HttpHeaders import org.springframework.http.HttpMethod import java.io.IOException import java.io.InputStream @@ -46,9 +49,9 @@ interface BlueprintWebClientService { fun httpClient(): CloseableHttpClient { return HttpClients.custom() - .addInterceptorFirst(WebClientUtils.logRequest()) - .addInterceptorLast(WebClientUtils.logResponse()) - .build() + .addInterceptorFirst(WebClientUtils.logRequest()) + .addInterceptorLast(WebClientUtils.logResponse()) + .build() } /** High performance non blocking Retry function, If execution block [block] throws BluePrintRetryException @@ -82,10 +85,12 @@ interface BlueprintWebClientService { HttpMethod.POST -> post(path, request, convertedHeaders, String::class.java) HttpMethod.PUT -> put(path, request, convertedHeaders, String::class.java) HttpMethod.PATCH -> patch(path, request, convertedHeaders, String::class.java) - else -> throw BluePrintProcessorException("Unsupported methodType($methodType)") + else -> throw BluePrintProcessorException( + "Unsupported methodType($methodType) attempted on path($path)") } } + //TODO: convert to multi-map fun convertToBasicHeaders(headers: Map<String, String>): Array<BasicHeader> { return headers.map { BasicHeader(it.key, it.value) }.toTypedArray() } @@ -135,8 +140,8 @@ interface BlueprintWebClientService { @Throws(IOException::class, ClientProtocolException::class) private fun <T> performCallAndExtractTypedWebClientResponse( - httpUriRequest: HttpUriRequest, responseType: Class<T>): - WebClientResponse<T> { + httpUriRequest: HttpUriRequest, responseType: Class<T>): + WebClientResponse<T> { val httpResponse = httpClient().execute(httpUriRequest) val statusCode = httpResponse.statusLine.statusCode httpResponse.entity.content.use { @@ -154,7 +159,7 @@ interface BlueprintWebClientService { } suspend fun <T> getNB(path: String, additionalHeaders: Array<BasicHeader>?, responseType: Class<T>): - WebClientResponse<T> = withContext(Dispatchers.IO) { + WebClientResponse<T> = withContext(Dispatchers.IO) { get(path, additionalHeaders!!, responseType) } @@ -191,27 +196,27 @@ interface BlueprintWebClientService { } suspend fun <T> deleteNB(path: String, additionalHeaders: Array<BasicHeader>?): - WebClientResponse<String> { + WebClientResponse<String> { return deleteNB(path, additionalHeaders, String::class.java) } suspend fun <T> deleteNB(path: String, additionalHeaders: Array<BasicHeader>?, responseType: Class<T>): - WebClientResponse<T> = withContext(Dispatchers.IO) { + WebClientResponse<T> = withContext(Dispatchers.IO) { delete(path, additionalHeaders!!, responseType) } suspend fun <T> patchNB(path: String, request: Any, additionalHeaders: Array<BasicHeader>?, responseType: Class<T>): - WebClientResponse<T> = withContext(Dispatchers.IO) { + WebClientResponse<T> = withContext(Dispatchers.IO) { patch(path, request, additionalHeaders!!, responseType) } suspend fun exchangeNB(methodType: String, path: String, request: Any): WebClientResponse<String> { return exchangeNB(methodType, path, request, hashMapOf(), - String::class.java) + String::class.java) } suspend fun exchangeNB(methodType: String, path: String, request: Any, additionalHeaders: Map<String, String>?): - WebClientResponse<String> { + WebClientResponse<String> { return exchangeNB(methodType, path, request, additionalHeaders, String::class.java) } @@ -249,7 +254,7 @@ interface BlueprintWebClientService { } private fun basicHeaders(headers: Map<String, String>?): - Array<BasicHeader> { + Array<BasicHeader> { val basicHeaders = mutableListOf<BasicHeader>() defaultHeaders().forEach { (name, value) -> basicHeaders.add(BasicHeader(name, value)) @@ -263,11 +268,29 @@ interface BlueprintWebClientService { // Non Blocking Rest Implementation suspend fun httpClientNB(): CloseableHttpClient { return HttpClients.custom() - .addInterceptorFirst(WebClientUtils.logRequest()) - .addInterceptorLast(WebClientUtils.logResponse()) - .build() + .addInterceptorFirst(WebClientUtils.logRequest()) + .addInterceptorLast(WebClientUtils.logResponse()) + .build() } //TODO maybe there could be cases where we care about return headers? data class WebClientResponse<T>(val status: Int, val body: T) + + fun verifyAdditionalHeaders(restClientProperties: RestClientProperties): Map<String, String> { + val customHeaders: MutableMap<String, String> = mutableMapOf() + //Extract additionalHeaders from the requestProperties and + //throw an error if HttpHeaders.AUTHORIZATION key (headers are case-insensitive) + restClientProperties.additionalHeaders?.let { + if (it.keys.map { k -> k.toLowerCase().trim() }.contains(HttpHeaders.AUTHORIZATION.toLowerCase())) { + val errMsg = "Error in definition of endpoint ${restClientProperties.url}." + + " User-supplied \"additionalHeaders\" cannot contain AUTHORIZATION header with" + + " auth-type \"${RestLibConstants.TYPE_BASIC_AUTH}\"" + WebClientUtils.log.error(errMsg) + throw BluePrintProcessorException(errMsg) + } else { + customHeaders.putAll(it) + } + } + return customHeaders + } } diff --git a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/SSLRestClientService.kt b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/SSLRestClientService.kt index 30dd49018..2acf776ca 100644 --- a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/SSLRestClientService.kt +++ b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/SSLRestClientService.kt @@ -33,25 +33,31 @@ import java.io.FileInputStream import java.security.KeyStore import java.security.cert.X509Certificate -class SSLRestClientService(private val restClientProperties: - SSLRestClientProperties) : - BlueprintWebClientService { +class SSLRestClientService(private val restClientProperties: SSLRestClientProperties) : + BlueprintWebClientService { var auth: BlueprintWebClientService? = null init { - auth = getAuthService() + auth = getAuthService() } - private fun getAuthService() : BlueprintWebClientService? { - - return when(restClientProperties) { + private fun getAuthService(): BlueprintWebClientService? { + //type,url and additional headers don't get carried over to TokenAuthRestClientProperties from SSLTokenAuthRestClientProperties + //set them in auth obj to be consistent. TODO: refactor + return when (restClientProperties) { is SSLBasicAuthRestClientProperties -> { - val basic = restClientProperties.basicAuth!! - BasicAuthRestClientService(basic) + val basicAuthProps = restClientProperties.basicAuth!! + basicAuthProps.additionalHeaders = restClientProperties.additionalHeaders + basicAuthProps.url = restClientProperties.url + basicAuthProps.type = restClientProperties.type + BasicAuthRestClientService(basicAuthProps) } is SSLTokenAuthRestClientProperties -> { - val token = restClientProperties.tokenAuth!! + val token = restClientProperties.tokenAuth!! + token.additionalHeaders = restClientProperties.additionalHeaders + token.url = restClientProperties.url + token.type = restClientProperties.type TokenAuthRestClientService(token) } else -> { @@ -61,19 +67,16 @@ class SSLRestClientService(private val restClientProperties: } } - override fun defaultHeaders(): Map<String, String> { - if (auth != null) { return auth!!.defaultHeaders() } return mapOf( - HttpHeaders.CONTENT_TYPE to MediaType.APPLICATION_JSON_VALUE, - HttpHeaders.ACCEPT to MediaType.APPLICATION_JSON_VALUE) + HttpHeaders.CONTENT_TYPE to MediaType.APPLICATION_JSON_VALUE, + HttpHeaders.ACCEPT to MediaType.APPLICATION_JSON_VALUE) } override fun host(uri: String): String { - return restClientProperties.url + uri } @@ -85,8 +88,9 @@ class SSLRestClientService(private val restClientProperties: val sslTrust = restClientProperties.sslTrust val sslTrustPwd = restClientProperties.sslTrustPassword - val acceptingTrustStrategy = { chain: Array<X509Certificate>, - authType: String -> true } + val acceptingTrustStrategy = { _: Array<X509Certificate>, _: String -> + true + } val sslContext = SSLContextBuilder.create() if (sslKey != null && sslKeyPwd != null) { @@ -98,13 +102,12 @@ class SSLRestClientService(private val restClientProperties: } sslContext.loadTrustMaterial(File(sslTrust), sslTrustPwd.toCharArray(), - acceptingTrustStrategy) + acceptingTrustStrategy) val csf = SSLConnectionSocketFactory(sslContext.build()) return HttpClients.custom() - .addInterceptorFirst(WebClientUtils.logRequest()) - .addInterceptorLast(WebClientUtils.logResponse()) - .setSSLSocketFactory(csf).build() - + .addInterceptorFirst(WebClientUtils.logRequest()) + .addInterceptorLast(WebClientUtils.logResponse()) + .setSSLSocketFactory(csf).build() } // Non Blocking Rest Implementation @@ -113,13 +116,15 @@ class SSLRestClientService(private val restClientProperties: } override fun convertToBasicHeaders(headers: Map<String, String>): Array<BasicHeader> { - var head1: Map<String, String> = defaultHeaders() - var head2: MutableMap<String, String> = head1.toMutableMap() - head2.putAll(headers) + val mergedDefaultAndSuppliedHeaders = defaultHeaders().plus(headers) + //During the initialization, getAuthService() sets the auth variable. + //If it's not null, then we have an authentication mechanism. + //If null - indicates no-auth used if (auth != null) { - return auth!!.convertToBasicHeaders(head2) + return auth!!.convertToBasicHeaders(mergedDefaultAndSuppliedHeaders) } - return super.convertToBasicHeaders(head2) + //inject additionalHeaders + return super.convertToBasicHeaders(mergedDefaultAndSuppliedHeaders + .plus(verifyAdditionalHeaders(restClientProperties))) } - -}
\ No newline at end of file +} diff --git a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/TokenAuthRestClientService.kt b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/TokenAuthRestClientService.kt index 82446994c..73b534143 100644 --- a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/TokenAuthRestClientService.kt +++ b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/TokenAuthRestClientService.kt @@ -23,20 +23,20 @@ import org.springframework.http.MediaType class TokenAuthRestClientService(private val restClientProperties: TokenAuthRestClientProperties) : - BlueprintWebClientService { + BlueprintWebClientService { override fun defaultHeaders(): Map<String, String> { - return mapOf( - HttpHeaders.CONTENT_TYPE to MediaType.APPLICATION_JSON_VALUE, - HttpHeaders.ACCEPT to MediaType.APPLICATION_JSON_VALUE, - HttpHeaders.AUTHORIZATION to restClientProperties.token!!) + HttpHeaders.CONTENT_TYPE to MediaType.APPLICATION_JSON_VALUE, + HttpHeaders.ACCEPT to MediaType.APPLICATION_JSON_VALUE, + HttpHeaders.AUTHORIZATION to restClientProperties.token!!) } override fun convertToBasicHeaders(headers: Map<String, String>): - Array<BasicHeader> { - + Array<BasicHeader> { val customHeaders: MutableMap<String, String> = headers.toMutableMap() + //inject additionalHeaders + customHeaders.putAll(verifyAdditionalHeaders(restClientProperties)) if (!headers.containsKey(HttpHeaders.AUTHORIZATION)) { customHeaders[HttpHeaders.AUTHORIZATION] = restClientProperties.token!! } diff --git a/ms/blueprintsprocessor/modules/commons/rest-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BluePrintRestLibPropertyServiceTest.kt b/ms/blueprintsprocessor/modules/commons/rest-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BluePrintRestLibPropertyServiceTest.kt index 37a797f78..b617dab90 100644 --- a/ms/blueprintsprocessor/modules/commons/rest-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BluePrintRestLibPropertyServiceTest.kt +++ b/ms/blueprintsprocessor/modules/commons/rest-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BluePrintRestLibPropertyServiceTest.kt @@ -2,6 +2,7 @@ * Copyright © 2017-2018 AT&T Intellectual Property. * Modifications Copyright © 2018 IBM. * Modifications Copyright © 2019 Huawei. + * Modifications Copyright © 2019 Bell Canada. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,11 +29,15 @@ import org.onap.ccsdk.cds.blueprintsprocessor.rest.BluePrintRestLibConfiguration import org.onap.ccsdk.cds.blueprintsprocessor.rest.SSLBasicAuthRestClientProperties import org.onap.ccsdk.cds.blueprintsprocessor.rest.SSLRestClientProperties import org.onap.ccsdk.cds.blueprintsprocessor.rest.SSLTokenAuthRestClientProperties +import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.HttpHeaders +import org.springframework.http.MediaType import org.springframework.test.context.ContextConfiguration import org.springframework.test.context.TestPropertySource import org.springframework.test.context.junit4.SpringRunner import kotlin.test.assertEquals +import kotlin.test.assertFailsWith import kotlin.test.assertNotNull @RunWith(SpringRunner::class) @@ -63,26 +68,25 @@ import kotlin.test.assertNotNull "blueprintsprocessor.restclient.ssl.sslKeyPassword=changeit" ]) class BluePrintRestLibPropertyServiceTest { - @Autowired lateinit var bluePrintRestLibPropertyService: BluePrintRestLibPropertyService @Test fun testRestClientProperties() { val properties = bluePrintRestLibPropertyService.restClientProperties( - "blueprintsprocessor.restclient.sample") + "blueprintsprocessor.restclient.sample") assertNotNull(properties, "failed to create property bean") assertNotNull(properties.url, "failed to get url property in" + - " property bean") + " property bean") } @Test fun testSSLBasicProperties() { val properties = bluePrintRestLibPropertyService.restClientProperties( - "blueprintsprocessor.restclient.sslbasic") + "blueprintsprocessor.restclient.sslbasic") assertNotNull(properties, "failed to create property bean") val p: SSLBasicAuthRestClientProperties = - properties as SSLBasicAuthRestClientProperties + properties as SSLBasicAuthRestClientProperties assertEquals(p.basicAuth!!.username, "admin") assertEquals(p.basicAuth!!.password, "cds") @@ -94,11 +98,11 @@ class BluePrintRestLibPropertyServiceTest { @Test fun testSSLTokenProperties() { val properties = bluePrintRestLibPropertyService.restClientProperties( - "blueprintsprocessor.restclient.ssltoken") + "blueprintsprocessor.restclient.ssltoken") assertNotNull(properties, "failed to create property bean") val p: SSLTokenAuthRestClientProperties = - properties as SSLTokenAuthRestClientProperties + properties as SSLTokenAuthRestClientProperties assertEquals(p.tokenAuth!!.token!!, "72178473kjshdkjgvbsdkjv903274908") assertEquals(p.sslTrust, "src/test/resources/keystore.p12") @@ -109,11 +113,11 @@ class BluePrintRestLibPropertyServiceTest { @Test fun testSSLNoAuthProperties() { val properties = bluePrintRestLibPropertyService.restClientProperties( - "blueprintsprocessor.restclient.ssl") + "blueprintsprocessor.restclient.ssl") assertNotNull(properties, "failed to create property bean") val p: SSLRestClientProperties = - properties as SSLRestClientProperties + properties as SSLRestClientProperties assertEquals(p.sslTrust, "src/test/resources/keystore.p12") assertEquals(p.sslTrustPassword, "changeit") @@ -125,113 +129,370 @@ class BluePrintRestLibPropertyServiceTest { @Test fun testSSLBasicPropertiesAsJson() { - val json: String = "{\n" + - " \"type\" : \"ssl-basic-auth\",\n" + - " \"url\" : \"https://localhost:8443\",\n" + - " \"keyStoreInstance\" : \"PKCS12\",\n" + - " \"sslTrust\" : \"src/test/resources/keystore.p12\",\n" + - " \"sslTrustPassword\" : \"changeit\",\n" + - " \"basicAuth\" : {\n" + - " \"username\" : \"admin\",\n" + - " \"password\" : \"cds\"\n" + - " }\n" + - "}" - val mapper = ObjectMapper() - val actualObj: JsonNode = mapper.readTree(json) + val actualObj: JsonNode = defaultMapper.readTree(sslBasicAuthEndpointWithHeadersField()) val properties = bluePrintRestLibPropertyService.restClientProperties( - actualObj) + actualObj) assertNotNull(properties, "failed to create property bean") - val p: SSLBasicAuthRestClientProperties = - properties as SSLBasicAuthRestClientProperties + val p: SSLBasicAuthRestClientProperties = properties as SSLBasicAuthRestClientProperties - assertEquals(p.basicAuth!!.username, "admin") - assertEquals(p.basicAuth!!.password, "cds") - assertEquals(p.sslTrust, "src/test/resources/keystore.p12") - assertEquals(p.sslTrustPassword, "changeit") - assertEquals(p.keyStoreInstance, "PKCS12") + assertEquals("admin", p.basicAuth!!.username) + assertEquals("cds", p.basicAuth!!.password) + assertEquals("src/test/resources/keystore.p12", p.sslTrust) + assertEquals("changeit", p.sslTrustPassword) + assertEquals("PKCS12", p.keyStoreInstance) + assertEquals("ssl-basic-auth", p.type) + assertEquals("https://localhost:8443", p.url) } @Test fun testSSLTokenPropertiesAsJson() { - val json: String = "{\n" + - " \"type\" : \"ssl-token-auth\",\n" + - " \"url\" : \"https://localhost:8443\",\n" + - " \"keyStoreInstance\" : \"PKCS12\",\n" + - " \"sslTrust\" : \"src/test/resources/keystore.p12\",\n" + - " \"sslTrustPassword\" : \"changeit\",\n" + - " \"tokenAuth\" : {\n" + - " \"token\" : \"72178473kjshdkjgvbsdkjv903274908\"\n" + - " }\n" + - "}" - val mapper = ObjectMapper() - val actualObj: JsonNode = mapper.readTree(json) - val properties = bluePrintRestLibPropertyService.restClientProperties( - actualObj) + val actualObj: JsonNode = defaultMapper.readTree(sslTokenAuthEndpointWithHeadersField()) + val properties = + bluePrintRestLibPropertyService.restClientProperties(actualObj) assertNotNull(properties, "failed to create property bean") - val p: SSLTokenAuthRestClientProperties = - properties as SSLTokenAuthRestClientProperties + val p: SSLTokenAuthRestClientProperties = properties as SSLTokenAuthRestClientProperties - assertEquals(p.tokenAuth!!.token!!, "72178473kjshdkjgvbsdkjv903274908") - assertEquals(p.sslTrust, "src/test/resources/keystore.p12") - assertEquals(p.sslTrustPassword, "changeit") - assertEquals(p.keyStoreInstance, "PKCS12") + assertEquals("72178473kjshdkjgvbsdkjv903274908", p.tokenAuth!!.token!!) + assertEquals("src/test/resources/keystore.p12", p.sslTrust) + assertEquals("changeit", p.sslTrustPassword) + assertEquals("PKCS12", p.keyStoreInstance) + assertEquals("ssl-token-auth", p.type) + assertEquals("https://localhost:8443", p.url) } @Test fun testSSLNoAuthPropertiesAsJson() { - val json: String = "{\n" + - " \"type\" : \"ssl-basic-auth\",\n" + - " \"url\" : \"https://localhost:8443\",\n" + - " \"keyStoreInstance\" : \"PKCS12\",\n" + - " \"sslTrust\" : \"src/test/resources/keystore.p12\",\n" + - " \"sslTrustPassword\" : \"changeit\",\n" + - " \"sslKey\" : \"src/test/resources/keystore.p12\",\n" + - " \"sslKeyPassword\" : \"changeit\"\n" + - "}" - val mapper = ObjectMapper() - val actualObj: JsonNode = mapper.readTree(json) + val actualObj: JsonNode = defaultMapper.readTree(sslNoAuthEndpointWithHeadersField()) val properties = bluePrintRestLibPropertyService.restClientProperties( - actualObj) + actualObj) assertNotNull(properties, "failed to create property bean") val p: SSLRestClientProperties = - properties as SSLRestClientProperties + properties as SSLRestClientProperties - assertEquals(p.sslTrust, "src/test/resources/keystore.p12") - assertEquals(p.sslTrustPassword, "changeit") - assertEquals(p.keyStoreInstance, "PKCS12") - assertEquals(p.sslKey, "src/test/resources/keystore.p12") - assertEquals(p.sslKeyPassword, "changeit") + assertEquals("src/test/resources/keystore.p12", p.sslTrust) + assertEquals("changeit", p.sslTrustPassword) + assertEquals("PKCS12", p.keyStoreInstance) + assertEquals("src/test/resources/keystore.p12", p.sslKey) + assertEquals("changeit", p.sslKeyPassword) + assertEquals("ssl-no-auth", p.type) + assertEquals("https://localhost:8443", p.url) } @Test fun testBlueprintWebClientService() { val blueprintWebClientService = bluePrintRestLibPropertyService - .blueprintWebClientService("sample") - assertNotNull(blueprintWebClientService, "failed to create blu" + - "eprintWebClientService") + .blueprintWebClientService("sample") + assertNotNull(blueprintWebClientService, + "failed to create blueprintWebClientService") } @Test fun testBlueprintWebClientServiceWithJsonNode() { - val json: String = "{\n" + - " \"type\" : \"ssl-basic-auth\",\n" + - " \"url\" : \"https://localhost:8443\",\n" + - " \"keyStoreInstance\" : \"PKCS12\",\n" + - " \"sslTrust\" : \"src/test/resources/keystore.p12\",\n" + - " \"sslTrustPassword\" : \"changeit\",\n" + - " \"basicAuth\" : {\n" + - " \"username\" : \"admin\",\n" + - " \"password\" : \"cds\"\n" + - " }\n" + - "}" - val mapper = ObjectMapper() - val actualObj: JsonNode = mapper.readTree(json) + val actualObj: JsonNode = defaultMapper.readTree(sslBasicAuthEndpointWithHeadersField()) val blueprintWebClientService = bluePrintRestLibPropertyService - .blueprintWebClientService(actualObj) - assertNotNull(blueprintWebClientService, "failed to create blu" + - "eprintWebClientService") + .blueprintWebClientService(actualObj) + assertNotNull(blueprintWebClientService, "failed to create blueprintWebClientService") + } + + //pass the result of $typeEndpointWithHeadersField() output with and without headers to compare. + private fun validateHeadersDidNotChangeWithEmptyAdditionalHeaders(noHeaders: String, withHeaders: String) { + val parsedObj: JsonNode = defaultMapper.readTree(noHeaders) + val bpWebClientService = + bluePrintRestLibPropertyService.blueprintWebClientService(parsedObj) + val extractedHeaders = bpWebClientService.convertToBasicHeaders(mapOf()) + + val parsedObjWithHeaders: JsonNode = defaultMapper.readTree(withHeaders) + val bpWebClientServiceWithHeaders = + bluePrintRestLibPropertyService.blueprintWebClientService(parsedObjWithHeaders) + val extractedHeadersWithAdditionalHeaders = bpWebClientServiceWithHeaders.convertToBasicHeaders(mapOf()) + //Array<BasicHeader<>> -> Map<String,String> + val headersMap = extractedHeaders.map { it.name to it.value }.toMap() + val additionalHeadersMap = extractedHeadersWithAdditionalHeaders.map { it.name to it.value }.toMap() + assertEquals(headersMap, additionalHeadersMap) + } + + @Test + fun `BasicAuth WebClientService with empty additionalHeaders does not modify headers`() { + val endPointJson = basicAuthEndpointWithHeadersField() + val endPointWithHeadersJson = basicAuthEndpointWithHeadersField(emptyAdditionalHeaders) + validateHeadersDidNotChangeWithEmptyAdditionalHeaders(endPointJson, endPointWithHeadersJson) + } + + private fun acceptsOneAdditionalHeadersTest(endPointWithHeadersJson: String) { + val parsedObj: JsonNode = defaultMapper.readTree(endPointWithHeadersJson) + val bpWebClientService = + bluePrintRestLibPropertyService.blueprintWebClientService(parsedObj) + val extractedHeaders = bpWebClientService.convertToBasicHeaders(mapOf()) + assertEquals(1, extractedHeaders.filter { it.name == "key1" }.count()) + } + + @Test + fun `BasicAuth WebClientService accepts one additionalHeaders`() { + val endPointWithHeadersJson = basicAuthEndpointWithHeadersField(oneAdditionalParameter) + acceptsOneAdditionalHeadersTest(endPointWithHeadersJson) + } + + private fun acceptsMultipleAdditionalHeaders(endPointWithHeadersJson: String) { + val parsedObj: JsonNode = defaultMapper.readTree(endPointWithHeadersJson) + val bpWebClientService = + bluePrintRestLibPropertyService.blueprintWebClientService(parsedObj) + val extractedHeaders = bpWebClientService.convertToBasicHeaders(mapOf()) + assertEquals(1, extractedHeaders.filter { it.name == "key1" }.count()) + assertEquals(1, extractedHeaders.filter { it.name == "key2" }.count()) + assertEquals(1, extractedHeaders.filter { it.name == "key3" }.count()) + } + + @Test + fun `BasicAuth WebClientService accepts multiple additionalHeaders`() { + val endPointWithHeadersJson = basicAuthEndpointWithHeadersField(threeAdditionalHeaders) + acceptsMultipleAdditionalHeaders(endPointWithHeadersJson) + } + + private fun additionalHeadersChangedContentTypeToAPPLICATION_XML(endPointWithHeadersJson: String) { + val parsedObj: JsonNode = defaultMapper.readTree(endPointWithHeadersJson) + val bpWebClientService = + bluePrintRestLibPropertyService.blueprintWebClientService(parsedObj) + val extractedHeaders = bpWebClientService.convertToBasicHeaders(mapOf()) + assertEquals(MediaType.APPLICATION_XML.toString(), + extractedHeaders.filter { it.name == HttpHeaders.CONTENT_TYPE }[0].value!!) + } + + @Test + fun `BasicAuth WebClientService additionalHeaders can overwrite default Content-Type`() { + //default content type is application/json + val endPointWithHeadersJson = basicAuthEndpointWithHeadersField(contentTypeAdditionalHeader) + additionalHeadersChangedContentTypeToAPPLICATION_XML(endPointWithHeadersJson) + } + + //called from within "assertFailsWith(exceptionClass = BluePrintProcessorException::class) {" + private fun attemptToPutAuthorizationHeaderIntoAdditionalHeaders(endPointWithHeadersJson: String) { + val parsedObj: JsonNode = defaultMapper.readTree(endPointWithHeadersJson) + val bpWebClientService = + bluePrintRestLibPropertyService.blueprintWebClientService(parsedObj) + bpWebClientService.convertToBasicHeaders(mapOf()) + } + + @Test + fun `BasicAuth WebClientService throws BlueprintProcessorException if additionalHeaders contain Authorization`() { + assertFailsWith(exceptionClass = BluePrintProcessorException::class) { + val endPointWithHeadersJson = basicAuthEndpointWithHeadersField(additionalHeadersWithAuth) + attemptToPutAuthorizationHeaderIntoAdditionalHeaders(endPointWithHeadersJson) + } + //spec says headers are case insensitive... + assertFailsWith(exceptionClass = BluePrintProcessorException::class) { + val endPointWithHeadersJson = basicAuthEndpointWithHeadersField(additionalHeadersWithAuthLowercased) + attemptToPutAuthorizationHeaderIntoAdditionalHeaders(endPointWithHeadersJson) + } + } + + @Test + fun `TokenAuth WebClientService with empty additionalHeaders does not modify headers`() { + val endPointJson = sslTokenAuthEndpointWithHeadersField() + val endPointWithHeadersJson = sslTokenAuthEndpointWithHeadersField(emptyAdditionalHeaders) + validateHeadersDidNotChangeWithEmptyAdditionalHeaders(endPointJson, endPointWithHeadersJson) + } + + @Test + fun `TokenAuth WebClientService accepts one additionalHeaders`() { + val endPointWithHeadersJson = sslTokenAuthEndpointWithHeadersField(oneAdditionalParameter) + acceptsOneAdditionalHeadersTest(endPointWithHeadersJson) + } + + @Test + fun `TokenAuth WebClientService accepts multiple additionalHeaders`() { + val endPointWithHeadersJson = sslTokenAuthEndpointWithHeadersField(threeAdditionalHeaders) + acceptsMultipleAdditionalHeaders(endPointWithHeadersJson) + } + + @Test + fun `TokenAuth WebClientService additionalHeaders can overwrite default Content-Type`() { + //default content type is application/json + val endPointWithHeadersJson = sslTokenAuthEndpointWithHeadersField(contentTypeAdditionalHeader) + additionalHeadersChangedContentTypeToAPPLICATION_XML(endPointWithHeadersJson) + } + + @Test + fun `TokenAuth WebClientService throws BlueprintProcessorException if additionalHeaders contain Authorization`() { + assertFailsWith(exceptionClass = BluePrintProcessorException::class) { + val endPointWithHeadersJson = sslTokenAuthEndpointWithHeadersField(additionalHeadersWithAuth) + attemptToPutAuthorizationHeaderIntoAdditionalHeaders(endPointWithHeadersJson) + } + //spec says headers are case insensitive... + assertFailsWith(exceptionClass = BluePrintProcessorException::class) { + val endPointWithHeadersJson = sslTokenAuthEndpointWithHeadersField(additionalHeadersWithAuthLowercased) + attemptToPutAuthorizationHeaderIntoAdditionalHeaders(endPointWithHeadersJson) + } + } + + //TESTS FOR SSL BASIC AUTH headers + @Test + fun `SSLBasicAuth WebClientService with empty additionalHeaders does not modify headers`() { + val endPointJson = sslBasicAuthEndpointWithHeadersField() + val endPointWithHeadersJson = sslBasicAuthEndpointWithHeadersField(emptyAdditionalHeaders) + validateHeadersDidNotChangeWithEmptyAdditionalHeaders(endPointJson, endPointWithHeadersJson) + } + + @Test + fun `SSLBasicAuth WebClientService accepts one additionalHeaders`() { + val endPointWithHeadersJson = sslBasicAuthEndpointWithHeadersField(oneAdditionalParameter) + acceptsOneAdditionalHeadersTest(endPointWithHeadersJson) + } + + @Test + fun `SSLBasicAuth WebClientService accepts multiple additionalHeaders`() { + val endPointWithHeadersJson = sslBasicAuthEndpointWithHeadersField(threeAdditionalHeaders) + acceptsMultipleAdditionalHeaders(endPointWithHeadersJson) + } + + @Test + fun `SSLBasicAuth WebClientService additionalHeaders can overwrite default Content-Type`() { + //default content type is application/json + val endPointWithHeadersJson = sslBasicAuthEndpointWithHeadersField(contentTypeAdditionalHeader) + additionalHeadersChangedContentTypeToAPPLICATION_XML(endPointWithHeadersJson) + } + + @Test + fun `SSLBasicAuth WebClientService throws BlueprintProcessorException if additionalHeaders contain Authorization`() { + assertFailsWith(exceptionClass = BluePrintProcessorException::class) { + val endPointWithHeadersJson = sslBasicAuthEndpointWithHeadersField(additionalHeadersWithAuth) + attemptToPutAuthorizationHeaderIntoAdditionalHeaders(endPointWithHeadersJson) + } + //spec says headers are case insensitive... + assertFailsWith(exceptionClass = BluePrintProcessorException::class) { + val endPointWithHeadersJson = sslBasicAuthEndpointWithHeadersField(additionalHeadersWithAuthLowercased) + attemptToPutAuthorizationHeaderIntoAdditionalHeaders(endPointWithHeadersJson) + } + } + + //SSL-NO-AUTH headers tests + @Test + fun `SSLNoAuth WebClientService with empty additionalHeaders does not modify headers`() { + val endPointJson = sslNoAuthEndpointWithHeadersField() + val endPointWithHeadersJson = sslNoAuthEndpointWithHeadersField(emptyAdditionalHeaders) + validateHeadersDidNotChangeWithEmptyAdditionalHeaders(endPointJson, endPointWithHeadersJson) + } + + @Test + fun `SSLNoAuth WebClientService accepts one additionalHeaders`() { + val endPointWithHeadersJson = sslNoAuthEndpointWithHeadersField(oneAdditionalParameter) + acceptsOneAdditionalHeadersTest(endPointWithHeadersJson) + } + + @Test + fun `SSLNoAuth WebClientService accepts multiple additionalHeaders`() { + val endPointWithHeadersJson = sslNoAuthEndpointWithHeadersField(threeAdditionalHeaders) + acceptsMultipleAdditionalHeaders(endPointWithHeadersJson) + } + + @Test + fun `SSLNoAuth WebClientService additionalHeaders can overwrite default Content-Type`() { + //default content type is application/json + val endPointWithHeadersJson = sslNoAuthEndpointWithHeadersField(contentTypeAdditionalHeader) + additionalHeadersChangedContentTypeToAPPLICATION_XML(endPointWithHeadersJson) + } + + @Test + fun `SSLNoAuth WebClientService throws BlueprintProcessorException if additionalHeaders contain Authorization`() { + assertFailsWith(exceptionClass = BluePrintProcessorException::class) { + val endPointWithHeadersJson = sslNoAuthEndpointWithHeadersField(additionalHeadersWithAuth) + attemptToPutAuthorizationHeaderIntoAdditionalHeaders(endPointWithHeadersJson) + } + //spec says headers are case insensitive... + assertFailsWith(exceptionClass = BluePrintProcessorException::class) { + val endPointWithHeadersJson = sslNoAuthEndpointWithHeadersField(additionalHeadersWithAuthLowercased) + attemptToPutAuthorizationHeaderIntoAdditionalHeaders(endPointWithHeadersJson) + } + } + + companion object BluePrintRestLibPropertyServiceTest { + val defaultMapper = ObjectMapper() + val expectedTokenAuthDefaultHeaders = mapOf<String, String>( + "Content-Type" to "application/json", + "Accept" to "application/json", + "Authorization" to "72178473kjshdkjgvbsdkjv903274908") + + val endPointWithHeadersJsonWithBasicAuthHeader = basicAuthEndpointWithHeadersField(""", + "additionalHeaders" : { + "authorization": "Basic aGF2ZTphbmljZWRheQo=" + }""".trimIndent()) + + private fun sslTokenAuthEndpointWithHeadersField(headers: String = ""): String = + """{ + "type" : "ssl-token-auth", + "url" : "https://localhost:8443", + "keyStoreInstance" : "PKCS12", + "sslTrust" : "src/test/resources/keystore.p12", + "sslTrustPassword" : "changeit", + "tokenAuth" : { + "token" : "72178473kjshdkjgvbsdkjv903274908" + }$headers + } + """.trimIndent() + + private fun sslBasicAuthEndpointWithHeadersField(headers: String = ""): String = + """{ + "type" : "ssl-basic-auth", + "url" : "https://localhost:8443", + "keyStoreInstance" : "PKCS12", + "sslTrust" : "src/test/resources/keystore.p12", + "sslTrustPassword" : "changeit", + "basicAuth" : { + "username" : "admin", + "password" : "cds" + }$headers + }""".trimIndent() + + private fun sslNoAuthEndpointWithHeadersField(headers: String = ""): String = """{ + "type" : "ssl-no-auth", + "url" : "https://localhost:8443", + "keyStoreInstance" : "PKCS12", + "sslTrust" : "src/test/resources/keystore.p12", + "sslTrustPassword" : "changeit", + "sslKey" : "src/test/resources/keystore.p12", + "sslKeyPassword" : "changeit"$headers + }""".trimIndent() + + //Don't forget to supply "," as the first char to make valid JSON + private fun basicAuthEndpointWithHeadersField(headers: String = ""): String = + """{ + "type": "basic-auth", + "url": "http://127.0.0.1:8000", + "username": "user", + "password": "pass"$headers + }""".trimIndent() + + private val emptyAdditionalHeaders = """, + "additionalHeaders" : { + }""".trimIndent() + + private val oneAdditionalParameter = """, + "additionalHeaders" : { + "key1": "value1" + }""".trimIndent() + + private val threeAdditionalHeaders = """, + "additionalHeaders" : { + "key1": "value1", + "key2": "value2", + "key3": "value3" + }""".trimIndent() + + private val contentTypeAdditionalHeader = """, + "additionalHeaders" : { + "${HttpHeaders.CONTENT_TYPE}": "${MediaType.APPLICATION_XML}" + }""".trimIndent() + + private val additionalHeadersWithAuth = """, + "additionalHeaders" : { + "Authorization": "Basic aGF2ZTphbmljZWRheQo=" + }""".trimIndent() + + private val additionalHeadersWithAuthLowercased = """, + "additionalHeaders" : { + "authorization": "Basic aGF2ZTphbmljZWRheQo=" + }""".trimIndent() } } diff --git a/ms/blueprintsprocessor/modules/commons/ssh-lib/pom.xml b/ms/blueprintsprocessor/modules/commons/ssh-lib/pom.xml index a13d0cc9c..ff09b83f3 100644 --- a/ms/blueprintsprocessor/modules/commons/ssh-lib/pom.xml +++ b/ms/blueprintsprocessor/modules/commons/ssh-lib/pom.xml @@ -18,7 +18,7 @@ <parent> <artifactId>commons</artifactId> <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId> - <version>0.6.1-SNAPSHOT</version> + <version>0.7.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> |