Merge "SSLRestClientProperties does not allow ignoring hostname discrepancies with...
[ccsdk/cds.git] / ms / blueprintsprocessor / modules / commons / rest-lib / src / main / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / rest / service / SSLRestClientService.kt
1 /*
2  * Copyright © 2017-2019 AT&T, Bell Canada
3  * Modifications Copyright © 2019 Huawei.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 package org.onap.ccsdk.cds.blueprintsprocessor.rest.service
19
20 import org.apache.http.conn.ssl.SSLConnectionSocketFactory
21 import org.apache.http.impl.client.CloseableHttpClient
22 import org.apache.http.impl.client.HttpClients
23 import org.apache.http.message.BasicHeader
24 import org.apache.http.ssl.SSLContextBuilder
25 import org.onap.ccsdk.cds.blueprintsprocessor.rest.SSLBasicAuthRestClientProperties
26 import org.onap.ccsdk.cds.blueprintsprocessor.rest.SSLRestClientProperties
27 import org.onap.ccsdk.cds.blueprintsprocessor.rest.SSLTokenAuthRestClientProperties
28 import org.onap.ccsdk.cds.blueprintsprocessor.rest.utils.WebClientUtils
29 import org.springframework.http.HttpHeaders
30 import org.springframework.http.MediaType
31 import java.io.File
32 import java.io.FileInputStream
33 import java.security.KeyStore
34 import java.security.cert.X509Certificate
35 import org.apache.http.conn.ssl.NoopHostnameVerifier
36
37 class SSLRestClientService(private val restClientProperties: SSLRestClientProperties) :
38     BlueprintWebClientService {
39
40     var auth: BlueprintWebClientService? = null
41
42     init {
43         auth = getAuthService()
44     }
45
46     private fun getAuthService(): BlueprintWebClientService? {
47         //type,url and additional headers don't get carried over to TokenAuthRestClientProperties from SSLTokenAuthRestClientProperties
48         //set them in auth obj to be consistent. TODO: refactor
49         return when (restClientProperties) {
50             is SSLBasicAuthRestClientProperties -> {
51                 val basicAuthProps = restClientProperties.basicAuth!!
52                 basicAuthProps.additionalHeaders = restClientProperties.additionalHeaders
53                 basicAuthProps.url = restClientProperties.url
54                 basicAuthProps.type = restClientProperties.type
55                 BasicAuthRestClientService(basicAuthProps)
56             }
57             is SSLTokenAuthRestClientProperties -> {
58                 val token = restClientProperties.tokenAuth!!
59                 token.additionalHeaders = restClientProperties.additionalHeaders
60                 token.url = restClientProperties.url
61                 token.type = restClientProperties.type
62                 TokenAuthRestClientService(token)
63             }
64             else -> {
65                 //Returns null for No auth
66                 null
67             }
68         }
69     }
70
71     override fun defaultHeaders(): Map<String, String> {
72         if (auth != null) {
73             return auth!!.defaultHeaders()
74         }
75         return mapOf(
76             HttpHeaders.CONTENT_TYPE to MediaType.APPLICATION_JSON_VALUE,
77             HttpHeaders.ACCEPT to MediaType.APPLICATION_JSON_VALUE)
78     }
79
80     override fun host(uri: String): String {
81         return restClientProperties.url + uri
82     }
83
84     override fun httpClient(): CloseableHttpClient {
85
86         val keystoreInstance = restClientProperties.keyStoreInstance
87         val sslKey = restClientProperties.sslKey
88         val sslKeyPwd = restClientProperties.sslKeyPassword
89         val sslTrust = restClientProperties.sslTrust
90         val sslTrustPwd = restClientProperties.sslTrustPassword
91         val sslTrustIgnoreHostname = restClientProperties.sslTrustIgnoreHostname
92
93         val acceptingTrustStrategy = { _: Array<X509Certificate>, _: String ->
94             true
95         }
96         val sslContext = SSLContextBuilder.create()
97
98         if (sslKey != null && sslKeyPwd != null) {
99             FileInputStream(sslKey).use { keyInput ->
100                 val keyStore = KeyStore.getInstance(keystoreInstance)
101                 keyStore.load(keyInput, sslKeyPwd.toCharArray())
102                 sslContext.loadKeyMaterial(keyStore, sslKeyPwd.toCharArray())
103             }
104         }
105
106         sslContext.loadTrustMaterial(File(sslTrust), sslTrustPwd.toCharArray(), acceptingTrustStrategy)
107         var csf : SSLConnectionSocketFactory
108         if (sslTrustIgnoreHostname) {
109             csf = SSLConnectionSocketFactory(sslContext.build(), NoopHostnameVerifier())
110         } else {
111             csf = SSLConnectionSocketFactory(sslContext.build())
112         }
113         return HttpClients.custom()
114             .addInterceptorFirst(WebClientUtils.logRequest())
115             .addInterceptorLast(WebClientUtils.logResponse())
116             .setSSLSocketFactory(csf).build()
117     }
118
119     // Non Blocking Rest Implementation
120     override suspend fun httpClientNB(): CloseableHttpClient {
121         return httpClient()
122     }
123
124     override fun convertToBasicHeaders(headers: Map<String, String>): Array<BasicHeader> {
125         val mergedDefaultAndSuppliedHeaders = defaultHeaders().plus(headers)
126         //During the initialization, getAuthService() sets the auth variable.
127         //If it's not null, then we have an authentication mechanism.
128         //If null - indicates no-auth used
129         if (auth != null) {
130             return auth!!.convertToBasicHeaders(mergedDefaultAndSuppliedHeaders)
131         }
132         //inject additionalHeaders
133         return super.convertToBasicHeaders(mergedDefaultAndSuppliedHeaders
134             .plus(verifyAdditionalHeaders(restClientProperties)))
135     }
136 }