2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2024 Nordix Foundation
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * SPDX-License-Identifier: Apache-2.0
18 * ============LICENSE_END=========================================================
21 package org.onap.cps.integration.functional
23 import static org.springframework.http.HttpMethod.GET
24 import static org.springframework.http.HttpMethod.DELETE
25 import static org.springframework.http.HttpMethod.PATCH
26 import static org.springframework.http.HttpMethod.POST
27 import static org.springframework.http.HttpMethod.PUT
28 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.request
29 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
31 import okhttp3.mockwebserver.Dispatcher
32 import okhttp3.mockwebserver.MockResponse
33 import okhttp3.mockwebserver.RecordedRequest
34 import org.jetbrains.annotations.NotNull
35 import org.onap.cps.integration.base.CpsIntegrationSpecBase
36 import org.springframework.http.HttpHeaders
37 import org.springframework.http.HttpStatus
38 import org.springframework.http.MediaType
39 import spock.util.concurrent.PollingConditions
41 class NcmpBearerTokenPassthroughSpec extends CpsIntegrationSpecBase {
43 def lastAuthHeaderReceived = null
46 dmiDispatcher.moduleNamesPerCmHandleId['ch-1'] = ['M1', 'M2']
47 registerCmHandle(DMI_URL, 'ch-1', NO_MODULE_SET_TAG)
49 mockDmiServer.setDispatcher(new Dispatcher() {
51 MockResponse dispatch(@NotNull RecordedRequest request) throws InterruptedException {
52 if (request.path == '/actuator/health') {
53 return new MockResponse()
54 .addHeader("Content-Type", MediaType.APPLICATION_JSON).setBody('{"status":"UP"}')
55 .setResponseCode(HttpStatus.OK.value())
57 lastAuthHeaderReceived = request.getHeader('Authorization')
58 return new MockResponse().setResponseCode(HttpStatus.OK.value())
65 deregisterCmHandle(DMI_URL, 'ch-1')
68 def 'Bearer token is passed from NCMP to DMI in pass-through data operations.'() {
69 when: 'a pass-through data request is sent to NCMP with a bearer token'
70 mvc.perform(request(httpMethod, '/ncmp/v1/ch/ch-1/data/ds/ncmp-datastore:passthrough-running')
71 .queryParam('resourceIdentifier', 'my-resource-id')
72 .contentType(MediaType.APPLICATION_JSON)
73 .content('{ "some-json": "data" }')
74 .header(HttpHeaders.AUTHORIZATION, 'Bearer some-bearer-token'))
75 .andExpect(status().is2xxSuccessful())
77 then: 'DMI has received request with bearer token'
78 lastAuthHeaderReceived == 'Bearer some-bearer-token'
80 where: 'all HTTP operations are applied'
81 httpMethod << [GET, POST, PUT, PATCH, DELETE]
84 def 'Basic auth header is NOT passed from NCMP to DMI in pass-through data operations.'() {
85 when: 'a pass-through data request is sent to NCMP with basic authentication'
86 mvc.perform(request(httpMethod, '/ncmp/v1/ch/ch-1/data/ds/ncmp-datastore:passthrough-running')
87 .queryParam('resourceIdentifier', 'my-resource-id')
88 .contentType(MediaType.APPLICATION_JSON)
89 .content('{ "some-json": "data" }')
90 .header(HttpHeaders.AUTHORIZATION, 'Basic Y3BzdXNlcjpjcHNyMGNrcyE='))
91 .andExpect(status().is2xxSuccessful())
93 then: 'DMI has received request with no authorization header'
94 lastAuthHeaderReceived == null
96 where: 'all HTTP operations are applied'
97 httpMethod << [GET, POST, PUT, PATCH, DELETE]
100 def 'Bearer token is passed from NCMP to DMI in async batch pass-through data operation.'() {
101 when: 'a pass-through async data request is sent to NCMP with a bearer token'
102 def requestBody = """{"operations": [{
104 "operationId": "operational-1",
105 "datastore": "ncmp-datastore:passthrough-running",
106 "resourceIdentifier": "my-resource-id",
107 "targetIds": ["ch-1"]
109 mvc.perform(request(POST, '/ncmp/v1/data')
110 .queryParam('topic', 'my-topic')
111 .contentType(MediaType.APPLICATION_JSON)
112 .content(requestBody)
113 .header(HttpHeaders.AUTHORIZATION, 'Bearer some-bearer-token'))
114 .andExpect(status().is2xxSuccessful())
116 then: 'DMI will receive the async request with bearer token'
117 new PollingConditions().within(3, () -> {
118 assert lastAuthHeaderReceived == 'Bearer some-bearer-token'