2 * Copyright © 2017-2018 AT&T Intellectual Property.
3 * Copyright (C) 2019 Nordix Foundation
4 * Modifications Copyright © 2019 Huawei.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 package org.onap.ccsdk.cds.blueprintsprocessor.rest.service
21 import com.fasterxml.jackson.databind.JsonNode
22 import com.fasterxml.jackson.databind.ObjectMapper
23 import kotlinx.coroutines.CoroutineStart
24 import kotlinx.coroutines.async
25 import kotlinx.coroutines.runBlocking
26 import org.apache.catalina.connector.Connector
27 import org.junit.Ignore
29 import org.junit.runner.RunWith
30 import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintProperties
31 import org.onap.ccsdk.cds.blueprintsprocessor.core.BlueprintPropertyConfiguration
32 import org.onap.ccsdk.cds.blueprintsprocessor.rest.BluePrintRestLibConfiguration
33 import org.springframework.beans.factory.annotation.Autowired
34 import org.springframework.boot.autoconfigure.EnableAutoConfiguration
35 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
36 import org.springframework.boot.test.context.SpringBootTest
37 import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory
38 import org.springframework.boot.web.servlet.server.ServletWebServerFactory
39 import org.springframework.context.annotation.Bean
40 import org.springframework.context.annotation.Configuration
41 import org.springframework.http.HttpMethod
42 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
43 import org.springframework.security.config.annotation.web.builders.HttpSecurity
44 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
45 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
46 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
47 import org.springframework.security.crypto.password.PasswordEncoder
48 import org.springframework.stereotype.Component
49 import org.springframework.test.context.ContextConfiguration
50 import org.springframework.test.context.TestPropertySource
51 import org.springframework.test.context.junit4.SpringRunner
52 import org.springframework.web.bind.annotation.DeleteMapping
53 import org.springframework.web.bind.annotation.GetMapping
54 import org.springframework.web.bind.annotation.PatchMapping
55 import org.springframework.web.bind.annotation.PostMapping
56 import org.springframework.web.bind.annotation.PutMapping
57 import org.springframework.web.bind.annotation.RequestHeader
58 import org.springframework.web.bind.annotation.RequestMapping
59 import org.springframework.web.bind.annotation.RestController
60 import kotlin.test.assertEquals
61 import kotlin.test.assertNotNull
63 @RunWith(SpringRunner::class)
64 @EnableAutoConfiguration(exclude = [DataSourceAutoConfiguration::class])
65 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
66 @ContextConfiguration(classes = [BluePrintRestLibConfiguration::class,
67 BlueprintPropertyConfiguration::class,
68 SampleController::class, BluePrintProperties::class,
69 BluePrintProperties::class])
70 @TestPropertySource(properties =
73 "server.ssl.enabled=true",
74 "server.ssl.key-store=classpath:keystore.p12",
75 "server.ssl.key-store-password=changeit",
76 "server.ssl.keyStoreType=PKCS12",
77 "server.ssl.keyAlias=tomcat",
78 "blueprintsprocessor.restclient.sample.type=basic-auth",
79 "blueprintsprocessor.restclient.sample.url=http://127.0.0.1:8080",
80 "blueprintsprocessor.restclient.sample.username=admin",
81 "blueprintsprocessor.restclient.sample.password=jans",
82 "blueprintsprocessor.restclient.test.type=ssl-basic-auth",
83 "blueprintsprocessor.restclient.test.url=https://localhost:8443",
84 "blueprintsprocessor.restclient.test.username=admin",
85 "blueprintsprocessor.restclient.test.password=jans",
86 "blueprintsprocessor.restclient.test.keyStoreInstance=PKCS12",
87 "blueprintsprocessor.restclient.test.sslTrust=src/test/resources/keystore.p12",
88 "blueprintsprocessor.restclient.test.sslTrustPassword=changeit"
91 class RestClientServiceTest {
94 lateinit var bluePrintRestLibPropertyService: BluePrintRestLibPropertyService
98 val restClientService = bluePrintRestLibPropertyService
99 .blueprintWebClientService("sample")
100 val response = restClientService.exchangeResource(
101 HttpMethod.PATCH.name, "/sample/name", "")
102 assertEquals("Patch request successful", response.body,
103 "failed to get patch response")
108 val restClientService = bluePrintRestLibPropertyService
109 .blueprintWebClientService("sample")
110 val headers = mutableMapOf<String, String>()
111 headers["X-Transaction-Id"] = "1234"
112 val response = restClientService.exchangeResource(HttpMethod.GET.name,
114 assertNotNull(response.body, "failed to get response")
118 fun testSimpleBasicAuth() {
119 val json: String = "{\n" +
120 " \"type\" : \"basic-auth\",\n" +
121 " \"url\" : \"http://localhost:8080\",\n" +
122 " \"username\" : \"admin\",\n" +
123 " \"password\" : \"jans\"\n" +
125 val mapper = ObjectMapper()
126 val actualObj: JsonNode = mapper.readTree(json)
127 val restClientService = bluePrintRestLibPropertyService
128 .blueprintWebClientService(actualObj)
129 lateinit var res:String
131 val get = async(start = CoroutineStart.LAZY) {
132 restClientService.exchangeNB(HttpMethod.GET.name,
133 "/sample/basic", "").body}
137 assertNotNull(res, "failed to get response")
138 assertEquals(res, "Basic request arrived successfully")
142 fun testSampleAaiReq() {
143 val restClientService = bluePrintRestLibPropertyService
144 .blueprintWebClientService("test")
145 val headers = mutableMapOf<String, String>()
146 headers["X-TransactionId"] = "9999"
147 headers["X-FromAppId"] = "AAI"
149 " \"customer\": {\n" +
150 " \"global-customer-id\": \"ONSDEMOBJHKCustomer\",\n" +
151 " \"subscriber-name\": \"ONSDEMOBJHKCustomer\",\n" +
152 " \"subscriber-type\": \"CUST\",\n" +
153 " \"resource-version\": \"1552985011163\"\n" +
156 lateinit var res1: Customer
157 lateinit var res2: Customer
158 lateinit var res3: String
159 lateinit var res4: String
160 lateinit var res5: String
161 lateinit var res6: String
163 val get1 = async(start = CoroutineStart.LAZY) {
164 restClientService.exchangeNB(HttpMethod.GET.name,
165 "/sample/aai/v14/business/customers", "", headers,
166 Customer::class.java).body}
168 val get2 = async(start = CoroutineStart.LAZY) {
169 restClientService.exchangeNB(HttpMethod.GET.name,
170 "/sample/aai/v14/business/customers", "", headers,
171 Customer::class.java).body}
173 val post = async(start = CoroutineStart.LAZY) {
174 restClientService.exchangeNB(HttpMethod.POST.name,
175 "/sample/aai/v14/business/customers", post1, headers,
176 String::class.java).body}
178 val put = async(start = CoroutineStart.LAZY) {
179 restClientService.exchangeNB(HttpMethod.PUT.name,
180 "/sample/aai/v14/business/customers", post1, headers,
181 String::class.java).body}
183 val patch = async(start = CoroutineStart.LAZY) {
184 restClientService.exchangeNB(HttpMethod.PATCH.name,
185 "/sample/aai/v14/business/customers", post1, headers,
186 String::class.java).body}
188 val delete = async(start = CoroutineStart.LAZY) {
189 restClientService.exchangeNB(HttpMethod.DELETE.name,
190 "/sample/aai/v14/business/customers", "", headers,
191 String::class.java).body}
204 res6 = delete.await()
206 assertNotNull(res1, "failed to get response")
207 assertNotNull(res2, "failed to get response")
208 assertEquals(res1.id, "ONSDEMOBJHKCustomer")
209 assertEquals(res1.name, "ONSDEMOBJHKCustomer")
210 assertEquals(res1.type, "CUST")
211 assertEquals(res1.resource, "1552985011163")
212 assertEquals(res2.id, "ONSDEMOBJHKCustomer")
213 assertEquals(res2.name, "ONSDEMOBJHKCustomer")
214 assertEquals(res2.type, "CUST")
215 assertEquals(res2.resource, "1552985011163")
216 assertEquals(res3, "The message is successfully posted")
217 assertEquals(res4, "The put request is success")
218 assertEquals(res5, "The patch request is success")
219 assertEquals(res6, "The message is successfully deleted")
224 * Sample controller code for testing both http and https requests.
227 @RequestMapping("/sample")
228 open class SampleController {
231 fun getName(): String = "Sample Controller"
233 @PatchMapping("/name")
234 fun patchName(): String = "Patch request successful"
236 @GetMapping("/basic")
237 fun getBasic(): String = "Basic request arrived successfully"
240 @GetMapping("/aai/v14/business/customers")
242 @RequestHeader(name = "X-TransactionId", required = true)
244 @RequestHeader(name = "X-FromAppId", required = true)
245 appId: String) : String {
246 if (transId != "9999" || appId != "AAI") {
250 " \"id\": \"ONSDEMOBJHKCustomer\",\n" +
251 " \"name\": \"ONSDEMOBJHKCustomer\",\n" +
252 " \"type\": \"CUST\",\n" +
253 " \"resource\": \"1552985011163\"\n" +
257 @PostMapping("/aai/v14/business/customers")
258 fun postAaiCustomers(
259 @RequestHeader(name = "X-TransactionId", required = true)
261 @RequestHeader(name = "X-FromAppId", required = true)
262 appId: String) : String {
263 if (transId != "9999" || appId != "AAI") {
266 return "The message is successfully posted"
270 @PutMapping("/aai/v14/business/customers")
272 @RequestHeader(name = "X-TransactionId", required = true)
274 @RequestHeader(name = "X-FromAppId", required = true)
275 appId: String) : String {
276 if (transId != "9999" || appId != "AAI") {
279 return "The put request is success"
282 @PatchMapping("/aai/v14/business/customers")
283 fun patchAaiCustomers(
284 @RequestHeader(name = "X-TransactionId", required = true)
286 @RequestHeader(name = "X-FromAppId", required = true)
287 appId: String) : String {
288 if (transId != "9999" || appId != "AAI") {
291 return "The patch request is success"
294 @DeleteMapping("/aai/v14/business/customers")
295 fun deleteAaiCustomers(
296 @RequestHeader(name = "X-TransactionId", required = true)
298 @RequestHeader(name = "X-FromAppId", required = true)
299 appId: String) : String {
300 if (transId != "9999" || appId != "AAI") {
303 return "The message is successfully deleted"
308 * Security configuration required for basic authentication with username and
309 * password for any request in the server.
313 open class SecurityConfig : WebSecurityConfigurerAdapter() {
315 @Throws(Exception::class)
316 override fun configure(http: HttpSecurity) {
319 .authorizeRequests().anyRequest().authenticated()
325 @Throws(Exception::class)
326 open fun configureGlobal(auth: AuthenticationManagerBuilder) {
327 auth.inMemoryAuthentication()
329 .password(passwordEncoder().encode("jans"))
334 open fun passwordEncoder(): PasswordEncoder {
335 return BCryptPasswordEncoder()
340 * Http server required for http request to be processed along with the https
346 fun servletContainer(): ServletWebServerFactory {
348 val connector = Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL)
349 connector.port = 8080
351 val tomcat = TomcatServletWebServerFactory()
352 tomcat.addAdditionalTomcatConnectors(connector)
358 * Data class required for response
364 val resource: String)