Merge "HTTP headers feature for BP REST endpoints def'ns"
authorBrinda Santh Muthuramalingam <brindasanth@in.ibm.com>
Mon, 9 Sep 2019 20:46:43 +0000 (20:46 +0000)
committerGerrit Code Review <gerrit@onap.org>
Mon, 9 Sep 2019 20:46:43 +0000 (20:46 +0000)
ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/BluePrintRestLibData.kt
ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BasicAuthRestClientService.kt
ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BluePrintRestLibPropertyService.kt
ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BlueprintWebClientService.kt
ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/SSLRestClientService.kt
ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/TokenAuthRestClientService.kt
ms/blueprintsprocessor/modules/commons/rest-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BluePrintRestLibPropertyServiceTest.kt
ms/controllerblueprints/modules/blueprint-validation/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/validation/utils/PropertyAssignmentValidationUtils.kt

index 75a9409..68672f2 100644 (file)
@@ -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
+}
index 3190cd1..bb6937d 100644 (file)
@@ -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
+}
index 4f68657..8d4f0ca 100644 (file)
@@ -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)
     }
 }
 
index 1acd07b..26c8088 100644 (file)
@@ -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
+    }
 }
index 30dd490..2acf776 100644 (file)
@@ -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
+}
index 8244699..73b5341 100644 (file)
@@ -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!!
         }
index 37a797f..b617dab 100644 (file)
@@ -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()
     }
 }
 
index 2ef7016..d493481 100644 (file)
@@ -1,5 +1,6 @@
 /*
  *  Copyright © 2019 IBM.
+ *  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.
@@ -51,7 +52,7 @@ open class PropertyAssignmentValidationUtils(private val bluePrintContext: BlueP
                                          properties: MutableMap<String, JsonNode>) {
         properties.forEach { propertyName, propertyAssignment ->
             val propertyDefinition: PropertyDefinition = nodeTypeProperties[propertyName]
-                    ?: throw BluePrintException("failed to get definition for the property ($propertyName)")
+                    ?: throw BluePrintException("validatePropertyAssignments failed to get definition for the property ($propertyName)")
 
             validatePropertyAssignment(propertyName, propertyDefinition, propertyAssignment)
 
@@ -91,7 +92,7 @@ open class PropertyAssignmentValidationUtils(private val bluePrintContext: BlueP
         }
 
         check(isValid) {
-            throw BluePrintException("property($propertyName) defined of type($propertyType) is not comptable with the value ($propertyAssignment)")
+            throw BluePrintException("property($propertyName) defined of type($propertyType) is not compatible with the value ($propertyAssignment)")
         }
     }