Refactor rest clients and support timeouts
[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.NoopHostnameVerifier
21 import org.apache.http.conn.ssl.SSLConnectionSocketFactory
22 import org.apache.http.impl.client.CloseableHttpClient
23 import org.apache.http.impl.client.HttpClients
24 import org.apache.http.message.BasicHeader
25 import org.apache.http.ssl.SSLContextBuilder
26 import org.onap.ccsdk.cds.blueprintsprocessor.rest.BasicAuthRestClientProperties
27 import org.onap.ccsdk.cds.blueprintsprocessor.rest.RestClientProperties
28 import org.onap.ccsdk.cds.blueprintsprocessor.rest.SSLBasicAuthRestClientProperties
29 import org.onap.ccsdk.cds.blueprintsprocessor.rest.SSLRestClientProperties
30 import org.onap.ccsdk.cds.blueprintsprocessor.rest.SSLTokenAuthRestClientProperties
31 import org.onap.ccsdk.cds.blueprintsprocessor.rest.utils.WebClientUtils
32 import org.springframework.http.HttpHeaders
33 import org.springframework.http.MediaType
34 import java.io.File
35 import java.io.FileInputStream
36 import java.security.KeyStore
37 import java.security.cert.X509Certificate
38
39 open class SSLRestClientService(private val restClientProperties: SSLRestClientProperties) :
40     BaseBlueprintWebClientService<SSLRestClientProperties>() {
41
42     var auth: BlueprintWebClientService? = null
43
44     init {
45         auth = getAuthService()
46     }
47
48     override fun getRestClientProperties(): SSLRestClientProperties {
49         return restClientProperties
50     }
51
52     private fun getAuthService(): BaseBlueprintWebClientService<RestClientProperties>? {
53         // type,url and additional headers don't get carried over to TokenAuthRestClientProperties from SSLTokenAuthRestClientProperties
54         // set them in auth obj to be consistent. TODO: refactor
55         return when (restClientProperties) {
56             is SSLBasicAuthRestClientProperties -> {
57                 val basicAuthProps = BasicAuthRestClientProperties()
58                 basicAuthProps.username = restClientProperties.username
59                 basicAuthProps.password = restClientProperties.password
60                 basicAuthProps.additionalHeaders = restClientProperties.additionalHeaders
61                 basicAuthProps.url = restClientProperties.url
62                 basicAuthProps.type = restClientProperties.type
63                 BasicAuthRestClientService(basicAuthProps)
64             }
65             is SSLTokenAuthRestClientProperties -> {
66                 val token = restClientProperties.tokenAuth!!
67                 token.additionalHeaders = restClientProperties.additionalHeaders
68                 token.url = restClientProperties.url
69                 token.type = restClientProperties.type
70                 TokenAuthRestClientService(token)
71             }
72             else -> {
73                 // Returns null for No auth
74                 null
75             }
76         }
77     }
78
79     override fun defaultHeaders(): Map<String, String> {
80         if (auth != null) {
81             return auth!!.defaultHeaders()
82         }
83         return mapOf(
84             HttpHeaders.CONTENT_TYPE to MediaType.APPLICATION_JSON_VALUE,
85             HttpHeaders.ACCEPT to MediaType.APPLICATION_JSON_VALUE
86         )
87     }
88
89     override fun httpClient(): CloseableHttpClient {
90
91         val keystoreInstance = restClientProperties.keyStoreInstance
92         val sslKey = restClientProperties.sslKey
93         val sslKeyPwd = restClientProperties.sslKeyPassword
94         val sslTrust = restClientProperties.sslTrust
95         val sslTrustPwd = restClientProperties.sslTrustPassword
96         val sslTrustIgnoreHostname = restClientProperties.sslTrustIgnoreHostname
97
98         val acceptingTrustStrategy = { _: Array<X509Certificate>, _: String ->
99             true
100         }
101         val sslContext = SSLContextBuilder.create()
102
103         if (sslKey != null && sslKeyPwd != null) {
104             FileInputStream(sslKey).use { keyInput ->
105                 val keyStore = KeyStore.getInstance(keystoreInstance)
106                 keyStore.load(keyInput, sslKeyPwd.toCharArray())
107                 sslContext.loadKeyMaterial(keyStore, sslKeyPwd.toCharArray())
108             }
109         }
110
111         sslContext.loadTrustMaterial(File(sslTrust), sslTrustPwd.toCharArray(), acceptingTrustStrategy)
112         var csf: SSLConnectionSocketFactory
113         if (sslTrustIgnoreHostname) {
114             csf = SSLConnectionSocketFactory(sslContext.build(), NoopHostnameVerifier())
115         } else {
116             csf = SSLConnectionSocketFactory(sslContext.build())
117         }
118         return HttpClients.custom()
119             .addInterceptorFirst(WebClientUtils.logRequest())
120             .addInterceptorLast(WebClientUtils.logResponse())
121             .setDefaultRequestConfig(getRequestConfig())
122             .setSSLSocketFactory(csf).build()
123     }
124
125     override fun convertToBasicHeaders(headers: Map<String, String>): Array<BasicHeader> {
126         val mergedDefaultAndSuppliedHeaders = defaultHeaders().plus(headers)
127         // During the initialization, getAuthService() sets the auth variable.
128         // If it's not null, then we have an authentication mechanism.
129         // If null - indicates no-auth used
130         if (auth != null) {
131             return auth!!.convertToBasicHeaders(mergedDefaultAndSuppliedHeaders)
132         }
133         // inject additionalHeaders
134         return super.convertToBasicHeaders(
135             mergedDefaultAndSuppliedHeaders
136                 .plus(verifyAdditionalHeaders(restClientProperties))
137         )
138     }
139 }