2a35313f740742b863305e54c79d876349f76ca4
[cps.git] /
1 /*
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
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  *  SPDX-License-Identifier: Apache-2.0
18  *  ============LICENSE_END=========================================================
19  */
20
21 package org.onap.cps.integration.functional
22
23 import okhttp3.mockwebserver.Dispatcher
24 import okhttp3.mockwebserver.MockResponse
25 import okhttp3.mockwebserver.RecordedRequest
26 import org.jetbrains.annotations.NotNull
27 import org.onap.cps.integration.base.CpsIntegrationSpecBase
28 import org.springframework.http.HttpHeaders
29 import org.springframework.http.HttpStatus
30 import org.springframework.http.MediaType
31 import spock.util.concurrent.PollingConditions
32
33 import static org.springframework.http.HttpMethod.DELETE
34 import static org.springframework.http.HttpMethod.GET
35 import static org.springframework.http.HttpMethod.PATCH
36 import static org.springframework.http.HttpMethod.POST
37 import static org.springframework.http.HttpMethod.PUT
38 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.request
39 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
40
41 class NcmpBearerTokenPassthroughSpec extends CpsIntegrationSpecBase {
42
43     def lastAuthHeaderReceived = null
44
45     def setup() {
46         dmiDispatcher.moduleNamesPerCmHandleId['ch-1'] = ['M1', 'M2']
47         registerCmHandle(DMI_URL, 'ch-1', NO_MODULE_SET_TAG)
48
49         mockDmiServer.setDispatcher(new Dispatcher() {
50             @Override
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())
56                 } else {
57                     lastAuthHeaderReceived = request.getHeader('Authorization')
58                     return new MockResponse().setResponseCode(HttpStatus.OK.value())
59                 }
60             }
61         })
62     }
63
64     def cleanup() {
65         deregisterCmHandle(DMI_URL, 'ch-1')
66     }
67
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())
76
77         then: 'DMI has received request with bearer token'
78             lastAuthHeaderReceived == 'Bearer some-bearer-token'
79
80         where: 'all HTTP operations are applied'
81             httpMethod << [GET, POST, PUT, PATCH, DELETE]
82     }
83
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())
92
93         then: 'DMI has received request with no authorization header'
94             lastAuthHeaderReceived == null
95
96         where: 'all HTTP operations are applied'
97             httpMethod << [GET, POST, PUT, PATCH, DELETE]
98     }
99
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": [{
103                 "operation": "read",
104                 "operationId": "operational-1",
105                 "datastore": "ncmp-datastore:passthrough-running",
106                 "resourceIdentifier": "my-resource-id",
107                 "targetIds": ["ch-1"]
108             }]}"""
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())
115
116         then: 'DMI will receive the async request with bearer token'
117             new PollingConditions().within(3, () -> {
118                 assert lastAuthHeaderReceived == 'Bearer some-bearer-token'
119             })
120     }
121
122 }