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