From c5222a72ef11bd440f5c2bd017e820922ff6735a Mon Sep 17 00:00:00 2001 From: danielhanrahan Date: Wed, 28 Feb 2024 16:05:07 +0000 Subject: [PATCH] Add bearer token to NCMP passthrough operations (CPS-2126 #2) For NCMP resource data passthrough operations, accept an authorization header and propagate it to outgoing DMI request if it has a bearer token, otherwise use same behaviour as before Issue-ID: CPS-2128 Change-Id: Ib3bf401abce4221a8b706989fb6f07618aa33fe2 Signed-off-by: danielhanrahan --- .../controller/NetworkCmProxyStubController.java | 36 +++++++++++++--------- cps-ncmp-rest/docs/openapi/components.yaml | 7 +++++ cps-ncmp-rest/docs/openapi/ncmp.yml | 8 ++++- .../rest/controller/NetworkCmProxyController.java | 35 +++++++++++++-------- .../handlers/NcmpCachedResourceRequestHandler.java | 3 +- .../handlers/NcmpDatastoreRequestHandler.java | 17 ++++++---- .../NcmpPassthroughResourceRequestHandler.java | 6 ++-- .../controller/NetworkCmProxyControllerSpec.groovy | 13 ++++---- .../NcmpDatastoreRequestHandlerSpec.groovy | 6 ++-- .../cps/ncmp/api/NetworkCmProxyDataService.java | 8 +++-- .../api/impl/NetworkCmProxyDataServiceImpl.java | 11 ++++--- .../cps/ncmp/api/impl/client/DmiRestClient.java | 14 ++++++--- .../api/impl/operations/DmiDataOperations.java | 16 ++++++---- .../api/impl/operations/DmiModelOperations.java | 2 +- .../impl/NetworkCmProxyDataServiceImplSpec.groovy | 17 +++++----- .../ncmp/api/impl/client/DmiRestClientSpec.groovy | 23 +++++++++----- .../impl/operations/DmiDataOperationsSpec.groovy | 15 ++++----- .../impl/operations/DmiModelOperationsSpec.groovy | 11 ++++--- .../stub/controller/DmiRestStubController.java | 7 +++-- 19 files changed, 164 insertions(+), 91 deletions(-) diff --git a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java index 0e4f7f987..08a492e0f 100644 --- a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java +++ b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java @@ -69,7 +69,8 @@ public class NetworkCmProxyStubController implements NetworkCmProxyApi { final String resourceIdentifier, final String optionsParamInQuery, final String topicParamInQuery, - final Boolean includeDescendants) { + final Boolean includeDescendants, + final String authorization) { if (DatastoreType.PASSTHROUGH_OPERATIONAL == DatastoreType.fromDatastoreName(datastoreName)) { final ResponseEntity> asyncResponse = populateAsyncResponse(topicParamInQuery); final Map asyncResponseData = asyncResponse.getBody(); @@ -142,16 +143,18 @@ public class NetworkCmProxyStubController implements NetworkCmProxyApi { @Override public ResponseEntity createResourceDataRunningForCmHandle(final String datastoreName, final String cmHandle, - @NotNull @Valid final String resourceIdentifier, - @Valid final Object body, - final String contentType) { + @NotNull @Valid final String resourceIdentifier, + @Valid final Object body, + final String contentType, + final String authorization) { return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); } - + @Override public ResponseEntity deleteResourceDataRunningForCmHandle(final String datastoreName, final String cmHandle, @NotNull @Valid final String resourceIdentifier, - final String contentType) { + final String contentType, + final String authorization) { return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); } @@ -180,18 +183,20 @@ public class NetworkCmProxyStubController implements NetworkCmProxyApi { @Override public ResponseEntity executeDataOperationForCmHandles(final String topicParamInQuery, - final DataOperationRequest dataOperationRequest) { + final DataOperationRequest dataOperationRequest, + final String authorization) { return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); } @Override public ResponseEntity patchResourceDataRunningForCmHandle(final String datastoreName, final String cmHandle, - @NotNull @Valid final String resourceIdentifier, - @Valid final Object body, - final String contentType) { + @NotNull @Valid final String resourceIdentifier, + @Valid final Object body, + final String contentType, + final String authorization) { return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); } - + @Override public ResponseEntity queryResourceDataForCmHandle(final String datastoreName, final String cmHandle, @Valid final String cpsPath, @Valid final String options, @@ -220,11 +225,12 @@ public class NetworkCmProxyStubController implements NetworkCmProxyApi { } @Override - public ResponseEntity updateResourceDataRunningForCmHandle(final String datastoreName, - final String cmHandle, - @NotNull @Valid final String resourceIdentifier, + public ResponseEntity updateResourceDataRunningForCmHandle(final String datastoreName, + final String cmHandle, + @NotNull @Valid final String resourceIdentifier, @Valid final Object body, - final String contentType) { + final String contentType, + final String authorization) { return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); } diff --git a/cps-ncmp-rest/docs/openapi/components.yaml b/cps-ncmp-rest/docs/openapi/components.yaml index 6b53292af..cd77effc8 100644 --- a/cps-ncmp-rest/docs/openapi/components.yaml +++ b/cps-ncmp-rest/docs/openapi/components.yaml @@ -629,6 +629,13 @@ components: type: string default: application/json example: application/yang-data+json + authorizationParamInHeader: + name: Authorization + in: header + required: false + description: Authorization parameter for request. + schema: + type: string datastoreName: name: datastore-name in: path diff --git a/cps-ncmp-rest/docs/openapi/ncmp.yml b/cps-ncmp-rest/docs/openapi/ncmp.yml index 2787a0837..0cb1cdffb 100755 --- a/cps-ncmp-rest/docs/openapi/ncmp.yml +++ b/cps-ncmp-rest/docs/openapi/ncmp.yml @@ -32,6 +32,7 @@ resourceDataForCmHandle: - $ref: 'components.yaml#/components/parameters/optionsParamInQuery' - $ref: 'components.yaml#/components/parameters/topicParamInQuery' - $ref: 'components.yaml#/components/parameters/includeDescendantsOptionInQuery' + - $ref: 'components.yaml#/components/parameters/authorizationParamInHeader' responses: 200: description: OK @@ -62,6 +63,7 @@ resourceDataForCmHandle: - $ref: 'components.yaml#/components/parameters/cmHandleInPath' - $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery' - $ref: 'components.yaml#/components/parameters/contentParamInHeader' + - $ref: 'components.yaml#/components/parameters/authorizationParamInHeader' requestBody: required: true content: @@ -100,6 +102,7 @@ resourceDataForCmHandle: - $ref: 'components.yaml#/components/parameters/cmHandleInPath' - $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery' - $ref: 'components.yaml#/components/parameters/contentParamInHeader' + - $ref: 'components.yaml#/components/parameters/authorizationParamInHeader' requestBody: required: true content: @@ -138,6 +141,7 @@ resourceDataForCmHandle: - $ref: 'components.yaml#/components/parameters/cmHandleInPath' - $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery' - $ref: 'components.yaml#/components/parameters/contentParamInHeader' + - $ref: 'components.yaml#/components/parameters/authorizationParamInHeader' requestBody: required: true content: @@ -170,6 +174,7 @@ resourceDataForCmHandle: - $ref: 'components.yaml#/components/parameters/cmHandleInPath' - $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery' - $ref: 'components.yaml#/components/parameters/contentParamInHeader' + - $ref: 'components.yaml#/components/parameters/authorizationParamInHeader' responses: 204: $ref: 'components.yaml#/components/responses/NoContent' @@ -193,6 +198,7 @@ dataOperationForCmHandle: operationId: executeDataOperationForCmHandles parameters: - $ref: 'components.yaml#/components/parameters/requiredTopicParamInQuery' + - $ref: 'components.yaml#/components/parameters/authorizationParamInHeader' requestBody: required: true content: @@ -469,4 +475,4 @@ setDataSyncEnabledFlag: 500: $ref: 'components.yaml#/components/responses/InternalServerError' 502: - $ref: 'components.yaml#/components/responses/BadGateway' \ No newline at end of file + $ref: 'components.yaml#/components/responses/BadGateway' diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java index 6ec24448d..1c6aaf226 100755 --- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java @@ -94,6 +94,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { * @param optionsParamInQuery options query parameter * @param topicParamInQuery topic query parameter * @param includeDescendants whether to include descendants or not + * @param authorization contents of Authorization header, or null if not present * @return {@code ResponseEntity} response from dmi plugin */ @Override @@ -103,16 +104,17 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { final String resourceIdentifier, final String optionsParamInQuery, final String topicParamInQuery, - final Boolean includeDescendants) { + final Boolean includeDescendants, + final String authorization) { final NcmpDatastoreRequestHandler ncmpDatastoreRequestHandler = getNcmpDatastoreRequestHandler(datastoreName); return ncmpDatastoreRequestHandler.executeRequest(datastoreName, cmHandle, resourceIdentifier, - optionsParamInQuery, topicParamInQuery, includeDescendants); + optionsParamInQuery, topicParamInQuery, includeDescendants, authorization); } @Override public ResponseEntity executeDataOperationForCmHandles(final String topicParamInQuery, - final DataOperationRequest - dataOperationRequest) { + final DataOperationRequest dataOperationRequest, + final String authorization) { return ncmpPassthroughResourceRequestHandler.executeRequest(topicParamInQuery, dataOperationRequestMapper.toDataOperationRequest(dataOperationRequest)); } @@ -148,6 +150,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { * @param resourceIdentifier resource identifier * @param requestBody the request body * @param contentType content type of body + * @param authorization contents of Authorization header, or null if not present * @return {@code ResponseEntity} response from dmi plugin */ @@ -156,14 +159,15 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { final String cmHandle, final String resourceIdentifier, final Object requestBody, - final String contentType) { + final String contentType, + final String authorization) { validateDataStore(PASSTHROUGH_RUNNING, datastoreName); final Object responseObject = networkCmProxyDataService .writeResourceDataPassThroughRunningForCmHandle( cmHandle, resourceIdentifier, PATCH, - jsonObjectMapper.asJsonString(requestBody), contentType); + jsonObjectMapper.asJsonString(requestBody), contentType, authorization); return ResponseEntity.ok(responseObject); } @@ -175,6 +179,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { * @param resourceIdentifier resource identifier * @param requestBody the request body * @param contentType content type of body + * @param authorization contents of Authorization header, or null if not present * @return {@code ResponseEntity} response from dmi plugin */ @Override @@ -182,12 +187,12 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { final String cmHandle, final String resourceIdentifier, final Object requestBody, - final String contentType) { - + final String contentType, + final String authorization) { validateDataStore(PASSTHROUGH_RUNNING, datastoreName); networkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle(cmHandle, - resourceIdentifier, CREATE, jsonObjectMapper.asJsonString(requestBody), contentType); + resourceIdentifier, CREATE, jsonObjectMapper.asJsonString(requestBody), contentType, authorization); return new ResponseEntity<>(HttpStatus.CREATED); } @@ -199,6 +204,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { * @param resourceIdentifier resource identifier * @param requestBody the request body * @param contentType content type of the body + * @param authorization contents of Authorization header, or null if not present * @return response entity */ @@ -207,11 +213,12 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { final String cmHandle, final String resourceIdentifier, final Object requestBody, - final String contentType) { + final String contentType, + final String authorization) { validateDataStore(PASSTHROUGH_RUNNING, datastoreName); networkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle(cmHandle, - resourceIdentifier, UPDATE, jsonObjectMapper.asJsonString(requestBody), contentType); + resourceIdentifier, UPDATE, jsonObjectMapper.asJsonString(requestBody), contentType, authorization); return new ResponseEntity<>(HttpStatus.OK); } @@ -222,18 +229,20 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { * @param cmHandle cm handle identifier * @param resourceIdentifier resource identifier * @param contentType content type of the body + * @param authorization contents of Authorization header, or null if not present * @return response entity no content if request is successful */ @Override public ResponseEntity deleteResourceDataRunningForCmHandle(final String datastoreName, final String cmHandle, final String resourceIdentifier, - final String contentType) { + final String contentType, + final String authorization) { validateDataStore(PASSTHROUGH_RUNNING, datastoreName); networkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle(cmHandle, - resourceIdentifier, DELETE, NO_BODY, contentType); + resourceIdentifier, DELETE, NO_BODY, contentType, authorization); return new ResponseEntity<>(HttpStatus.NO_CONTENT); } diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpCachedResourceRequestHandler.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpCachedResourceRequestHandler.java index 85a1eae23..430c0996f 100644 --- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpCachedResourceRequestHandler.java +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpCachedResourceRequestHandler.java @@ -74,7 +74,8 @@ public class NcmpCachedResourceRequestHandler extends NcmpDatastoreRequestHandle final String optionsParamInQuery, final String topicParamInQuery, final String requestId, - final boolean includeDescendants) { + final boolean includeDescendants, + final String authorization) { final FetchDescendantsOption fetchDescendantsOption = getFetchDescendantsOption(includeDescendants); diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreRequestHandler.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreRequestHandler.java index d40ab9b39..8b0809090 100644 --- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreRequestHandler.java +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreRequestHandler.java @@ -56,6 +56,7 @@ public abstract class NcmpDatastoreRequestHandler { * @param optionsParamInQuery the options param in query * @param topicParamInQuery the topic param in query * @param includeDescendants whether include descendants + * @param authorization contents of Authorization header, or null if not present * @return the response entity */ public ResponseEntity executeRequest(final String datastoreName, @@ -63,12 +64,13 @@ public abstract class NcmpDatastoreRequestHandler { final String resourceIdentifier, final String optionsParamInQuery, final String topicParamInQuery, - final boolean includeDescendants) { + final boolean includeDescendants, + final String authorization) { final boolean asyncResponseRequested = topicParamInQuery != null; if (asyncResponseRequested && notificationFeatureEnabled) { return executeAsyncTaskAndGetResponseEntity(datastoreName, cmHandleId, resourceIdentifier, - optionsParamInQuery, topicParamInQuery, includeDescendants); + optionsParamInQuery, topicParamInQuery, includeDescendants, authorization); } if (asyncResponseRequested) { @@ -76,7 +78,7 @@ public abstract class NcmpDatastoreRequestHandler { + "will use synchronous operation."); } final Supplier taskSupplier = getTaskSupplierForGetRequest(datastoreName, cmHandleId, - resourceIdentifier, optionsParamInQuery, NO_TOPIC, NO_REQUEST_ID, includeDescendants); + resourceIdentifier, optionsParamInQuery, NO_TOPIC, NO_REQUEST_ID, includeDescendants, authorization); return executeTaskSync(taskSupplier); } @@ -99,10 +101,12 @@ public abstract class NcmpDatastoreRequestHandler { final String resourceIdentifier, final String optionsParamInQuery, final String topicParamInQuery, - final boolean includeDescendants) { + final boolean includeDescendants, + final String authorization) { final String requestId = UUID.randomUUID().toString(); final Supplier taskSupplier = getTaskSupplierForGetRequest(datastoreName, cmHandleId, - resourceIdentifier, optionsParamInQuery, topicParamInQuery, requestId, includeDescendants); + resourceIdentifier, optionsParamInQuery, topicParamInQuery, requestId, includeDescendants, + authorization); return executeTaskAsync(topicParamInQuery, requestId, taskSupplier); } @@ -112,6 +116,7 @@ public abstract class NcmpDatastoreRequestHandler { final String optionsParamInQuery, final String topicParamInQuery, final String requestId, - final boolean includeDescendant); + final boolean includeDescendant, + final String authorization); } diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpPassthroughResourceRequestHandler.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpPassthroughResourceRequestHandler.java index 8a3257576..5da8c9120 100644 --- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpPassthroughResourceRequestHandler.java +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpPassthroughResourceRequestHandler.java @@ -81,10 +81,12 @@ public class NcmpPassthroughResourceRequestHandler extends NcmpDatastoreRequestH final String optionsParamInQuery, final String topicParamInQuery, final String requestId, - final boolean includeDescendants) { + final boolean includeDescendants, + final String authorization) { return () -> networkCmProxyDataService.getResourceDataForCmHandle( - datastoreName, cmHandleId, resourceIdentifier, optionsParamInQuery, topicParamInQuery, requestId); + datastoreName, cmHandleId, resourceIdentifier, optionsParamInQuery, topicParamInQuery, requestId, + authorization); } private ResponseEntity getRequestIdAndSendDataOperationRequestToDmiService(final String topicParamInQuery, diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy index 983f2438c..dba2b30fd 100644 --- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy +++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy @@ -135,6 +135,7 @@ class NetworkCmProxyControllerSpec extends Specification { @Shared def NO_TOPIC = null def NO_REQUEST_ID = null + def NO_AUTH_HEADER = null def TIMOUT_FOR_TEST = 1234 def logger = Spy(ListAppender) @@ -162,7 +163,7 @@ class NetworkCmProxyControllerSpec extends Specification { ).andReturn().response then: 'the NCMP data service is called with getResourceDataOperationalForCmHandle' 1 * mockNetworkCmProxyDataService.getResourceDataForCmHandle(PASSTHROUGH_OPERATIONAL.datastoreName, 'testCmHandle', - 'parent/child','(a=1,b=2)', NO_TOPIC, NO_REQUEST_ID) + 'parent/child','(a=1,b=2)', NO_TOPIC, NO_REQUEST_ID, NO_AUTH_HEADER) and: 'response status is Ok' response.status == HttpStatus.OK.value() } @@ -279,7 +280,7 @@ class NetworkCmProxyControllerSpec extends Specification { "?resourceIdentifier=" + resourceIdentifier + "&options=(a=1,b=2)" and: 'ncmp service returns json object' mockNetworkCmProxyDataService.getResourceDataForCmHandle(PASSTHROUGH_RUNNING.datastoreName, 'testCmHandle', - resourceIdentifier,'(a=1,b=2)', NO_TOPIC, NO_REQUEST_ID) >> '{valid-json}' + resourceIdentifier,'(a=1,b=2)', NO_TOPIC, NO_REQUEST_ID, NO_AUTH_HEADER) >> '{valid-json}' when: 'get data resource request is performed' def response = mvc.perform( get(getUrl) @@ -310,7 +311,7 @@ class NetworkCmProxyControllerSpec extends Specification { ).andReturn().response then: 'ncmp service method to update resource is called' 1 * mockNetworkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle('testCmHandle', - 'parent/child', UPDATE, requestBody, 'application/json;charset=UTF-8') + 'parent/child', UPDATE, requestBody, 'application/json;charset=UTF-8', NO_AUTH_HEADER) and: 'the response status is OK' response.status == HttpStatus.OK.value() } @@ -326,7 +327,7 @@ class NetworkCmProxyControllerSpec extends Specification { ).andReturn().response then: 'ncmp service method to create resource called' 1 * mockNetworkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle('testCmHandle', - 'parent/child', CREATE, requestBody, 'application/json;charset=UTF-8') + 'parent/child', CREATE, requestBody, 'application/json;charset=UTF-8', NO_AUTH_HEADER) and: 'resource is created' response.status == HttpStatus.CREATED.value() } @@ -492,7 +493,7 @@ class NetworkCmProxyControllerSpec extends Specification { ).andReturn().response then: 'ncmp service method to update resource is called' 1 * mockNetworkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle('testCmHandle', - 'parent/child', PATCH, requestBody, 'application/json;charset=UTF-8') + 'parent/child', PATCH, requestBody, 'application/json;charset=UTF-8', NO_AUTH_HEADER) and: 'the response status is OK' response.status == HttpStatus.OK.value() } @@ -507,7 +508,7 @@ class NetworkCmProxyControllerSpec extends Specification { .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)).andReturn().response then: 'the ncmp service method to delete resource is called (with null as body)' 1 * mockNetworkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle('testCmHandle', - 'parent/child', DELETE, null, 'application/json;charset=UTF-8') + 'parent/child', DELETE, null, 'application/json;charset=UTF-8', NO_AUTH_HEADER) and: 'the response is No Content' response.status == HttpStatus.NO_CONTENT.value() } diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreRequestHandlerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreRequestHandlerSpec.groovy index 4edbf3569..328a85e71 100644 --- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreRequestHandlerSpec.groovy +++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreRequestHandlerSpec.groovy @@ -37,6 +37,8 @@ class NcmpDatastoreRequestHandlerSpec extends Specification { def objectUnderTest = new NcmpPassthroughResourceRequestHandler(spiedCpsNcmpTaskExecutor, mockNetworkCmProxyDataService) + def NO_AUTH_HEADER = null + def setup() { objectUnderTest.timeOutInMilliSeconds = 100 } @@ -47,11 +49,11 @@ class NcmpDatastoreRequestHandlerSpec extends Specification { and: 'a flag to track the network service call' def networkServiceMethodCalled = false and: 'the (mocked) service will use the flag to indicate if it is called' - mockNetworkCmProxyDataService.getResourceDataForCmHandle('ds', 'ch1', 'resource1', 'options', _, _) >> { + mockNetworkCmProxyDataService.getResourceDataForCmHandle('ds', 'ch1', 'resource1', 'options', _, _, NO_AUTH_HEADER) >> { networkServiceMethodCalled = true } when: 'get request is executed with topic = #topic' - objectUnderTest.executeRequest('ds', 'ch1', 'resource1', 'options', topic, false) + objectUnderTest.executeRequest('ds', 'ch1', 'resource1', 'options', topic, false, NO_AUTH_HEADER) then: 'the task is executed in an async fashion or not' expectedCalls * spiedCpsNcmpTaskExecutor.executeTask(*_) and: 'the service request is invoked' diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java index 0c8474839..dbfeca180 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java @@ -59,6 +59,7 @@ public interface NetworkCmProxyDataService { * @param optionsParamInQuery options query * @param topicParamInQuery topic name for (triggering) async responses * @param requestId unique requestId for async request + * @param authorization contents of Authorization header, or null if not present * @return {@code Object} resource data */ Object getResourceDataForCmHandle(String datastoreName, @@ -66,7 +67,8 @@ public interface NetworkCmProxyDataService { String resourceIdentifier, String optionsParamInQuery, String topicParamInQuery, - String requestId); + String requestId, + String authorization); /** * Get resource data for operational. @@ -101,13 +103,15 @@ public interface NetworkCmProxyDataService { * @param operationType required operation type * @param requestBody request body to create resource * @param contentType content type in body + * @param authorization contents of Authorization header, or null if not present * @return {@code Object} return data */ Object writeResourceDataPassThroughRunningForCmHandle(String cmHandleId, String resourceIdentifier, OperationType operationType, String requestBody, - String contentType); + String contentType, + String authorization); /** * Retrieve module references for the given cm handle. diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java index 08afde49a..3e304a4fd 100755 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java @@ -132,12 +132,14 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService final String resourceIdentifier, final String optionsParamInQuery, final String topicParamInQuery, - final String requestId) { + final String requestId, + final String authorization) { final ResponseEntity responseEntity = dmiDataOperations.getResourceDataFromDmi(datastoreName, cmHandleId, resourceIdentifier, optionsParamInQuery, topicParamInQuery, - requestId); + requestId, + authorization); return responseEntity.getBody(); } @@ -163,9 +165,10 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService final String resourceIdentifier, final OperationType operationType, final String requestData, - final String dataType) { + final String dataType, + final String authorization) { return dmiDataOperations.writeResourceDataPassThroughRunningFromDmi(cmHandleId, resourceIdentifier, - operationType, requestData, dataType); + operationType, requestData, dataType, authorization); } @Override diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java index 5b93eb485..798a280c8 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java @@ -22,6 +22,7 @@ package org.onap.cps.ncmp.api.impl.client; import com.fasterxml.jackson.databind.JsonNode; +import java.util.Locale; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration.DmiProperties; @@ -51,12 +52,15 @@ public class DmiRestClient { * @param dmiResourceUrl dmi resource url * @param requestBodyAsJsonString json data body * @param operationType the type of operation being executed (for error reporting only) + * @param authorization contents of Authorization header, or null if not present * @return response entity of type String */ public ResponseEntity postOperationWithJsonData(final String dmiResourceUrl, final String requestBodyAsJsonString, - final OperationType operationType) { - final var httpEntity = new HttpEntity<>(requestBodyAsJsonString, configureHttpHeaders(new HttpHeaders())); + final OperationType operationType, + final String authorization) { + final var httpEntity = new HttpEntity<>(requestBodyAsJsonString, configureHttpHeaders(new HttpHeaders(), + authorization)); try { return restTemplate.postForEntity(dmiResourceUrl, httpEntity, Object.class); } catch (final HttpStatusCodeException httpStatusCodeException) { @@ -73,7 +77,7 @@ public class DmiRestClient { * @return plugin health status ("UP" is all OK, "" (not-specified) in case of any exception) */ public String getDmiHealthStatus(final String dmiPluginBaseUrl) { - final HttpEntity httpHeaders = new HttpEntity<>(configureHttpHeaders(new HttpHeaders())); + final HttpEntity httpHeaders = new HttpEntity<>(configureHttpHeaders(new HttpHeaders(), null)); try { final JsonNode responseHealthStatus = restTemplate.getForObject(dmiPluginBaseUrl + HEALTH_CHECK_URL_EXTENSION, @@ -86,9 +90,11 @@ public class DmiRestClient { } } - private HttpHeaders configureHttpHeaders(final HttpHeaders httpHeaders) { + private HttpHeaders configureHttpHeaders(final HttpHeaders httpHeaders, final String authorization) { if (dmiProperties.isDmiBasicAuthEnabled()) { httpHeaders.setBasicAuth(dmiProperties.getAuthUsername(), dmiProperties.getAuthPassword()); + } else if (authorization != null && authorization.toLowerCase(Locale.getDefault()).startsWith("bearer ")) { + httpHeaders.add(HttpHeaders.AUTHORIZATION, authorization); } httpHeaders.setContentType(MediaType.APPLICATION_JSON); return httpHeaders; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java index fa18767db..05b6ec300 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java @@ -79,6 +79,7 @@ public class DmiDataOperations extends DmiOperations { * @param optionsParamInQuery options query * @param topicParamInQuery topic name for (triggering) async responses * @param requestId requestId for async responses + * @param authorization contents of Authorization header, or null if not present * @return {@code ResponseEntity} response entity */ @Timed(value = "cps.ncmp.dmi.get", @@ -89,7 +90,8 @@ public class DmiDataOperations extends DmiOperations { final String resourceId, final String optionsParamInQuery, final String topicParamInQuery, - final String requestId) { + final String requestId, + final String authorization) { final YangModelCmHandle yangModelCmHandle = getYangModelCmHandle(cmHandleId); final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState(); validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState); @@ -97,7 +99,7 @@ public class DmiDataOperations extends DmiOperations { yangModelCmHandle); final String dmiResourceDataUrl = getDmiRequestUrl(dataStoreName, cmHandleId, resourceId, optionsParamInQuery, topicParamInQuery, yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA)); - return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonRequestBody, READ); + return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonRequestBody, READ, authorization); } /** @@ -120,7 +122,7 @@ public class DmiDataOperations extends DmiOperations { yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA)); final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState(); validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState); - return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonRequestBody, READ); + return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonRequestBody, READ, null); } /** @@ -157,13 +159,15 @@ public class DmiDataOperations extends DmiOperations { * @param operationType operation enum * @param requestData the request data * @param dataType data type + * @param authorization contents of Authorization header, or null if not present * @return {@code ResponseEntity} response entity */ public ResponseEntity writeResourceDataPassThroughRunningFromDmi(final String cmHandleId, final String resourceId, final OperationType operationType, final String requestData, - final String dataType) { + final String dataType, + final String authorization) { final YangModelCmHandle yangModelCmHandle = getYangModelCmHandle(cmHandleId); final String jsonRequestBody = getDmiRequestBody(operationType, null, requestData, dataType, yangModelCmHandle); @@ -172,7 +176,7 @@ public class DmiDataOperations extends DmiOperations { yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA)); final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState(); validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState); - return dmiRestClient.postOperationWithJsonData(dmiUrl, jsonRequestBody, operationType); + return dmiRestClient.postOperationWithJsonData(dmiUrl, jsonRequestBody, operationType, authorization); } private YangModelCmHandle getYangModelCmHandle(final String cmHandleId) { @@ -250,7 +254,7 @@ public class DmiDataOperations extends DmiOperations { final String dmiDataOperationRequestAsJsonString = jsonObjectMapper.asJsonString(dmiDataOperationRequest); TaskExecutor.executeTask(() -> dmiRestClient.postOperationWithJsonData(dataOperationResourceUrl, - dmiDataOperationRequestAsJsonString, READ), + dmiDataOperationRequestAsJsonString, READ, null), DEFAULT_ASYNC_TASK_EXECUTOR_TIMEOUT_IN_MILLISECONDS) .whenCompleteAsync((response, throwable) -> handleTaskCompletionException(throwable, dataOperationResourceUrl, dmiDataOperationRequestBodies)); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java index dbe386d7c..f99fe86f6 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java @@ -112,7 +112,7 @@ public class DmiModelOperations extends DmiOperations { final String resourceName) { final String dmiResourceDataUrl = getDmiResourceUrl(dmiServiceName, cmHandle, resourceName); return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonRequestBody, - OperationType.READ); + OperationType.READ, null); } private static String getRequestBodyToFetchYangResources(final Collection newModuleReferences, diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy index 9b4fe146b..71380d46a 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy @@ -86,6 +86,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { def NO_TOPIC = null def NO_REQUEST_ID = null + def NO_AUTH_HEADER = null def OPTIONS_PARAM = '(a=1,b=2)' def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: 'test-cm-handle-id') @@ -113,10 +114,10 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { when: 'write resource data is called' objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle', 'testResourceId', CREATE, - '{some-json}', 'application/json') + '{some-json}', 'application/json', null) then: 'DMI called with correct data' 1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId', - CREATE, '{some-json}', 'application/json') + CREATE, '{some-json}', 'application/json', null) >> { new ResponseEntity<>(HttpStatus.CREATED) } } @@ -124,10 +125,10 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { given: 'cpsDataService returns valid data node' mockDataNode() and: 'get resource data from DMI is called' - mockDmiDataOperations.getResourceDataFromDmi(PASSTHROUGH_OPERATIONAL.datastoreName,'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID) >> + mockDmiDataOperations.getResourceDataFromDmi(PASSTHROUGH_OPERATIONAL.datastoreName,'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID, NO_AUTH_HEADER) >> new ResponseEntity<>('dmi-response', HttpStatus.OK) when: 'get resource data operational for cm-handle is called' - def response = objectUnderTest.getResourceDataForCmHandle(PASSTHROUGH_OPERATIONAL.datastoreName, 'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID) + def response = objectUnderTest.getResourceDataForCmHandle(PASSTHROUGH_OPERATIONAL.datastoreName, 'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID, NO_AUTH_HEADER) then: 'DMI returns a json response' assert response == 'dmi-response' } @@ -136,10 +137,10 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { given: 'cpsDataService returns valid data node' mockDataNode() and: 'DMI returns valid response and data' - mockDmiDataOperations.getResourceDataFromDmi(PASSTHROUGH_RUNNING.datastoreName, 'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID) >> + mockDmiDataOperations.getResourceDataFromDmi(PASSTHROUGH_RUNNING.datastoreName, 'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID, NO_AUTH_HEADER) >> new ResponseEntity<>('{dmi-response}', HttpStatus.OK) when: 'get resource data is called' - def response = objectUnderTest.getResourceDataForCmHandle(PASSTHROUGH_RUNNING.datastoreName, 'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID) + def response = objectUnderTest.getResourceDataForCmHandle(PASSTHROUGH_RUNNING.datastoreName, 'testCmHandle', 'testResourceId', OPTIONS_PARAM, NO_TOPIC, NO_REQUEST_ID, NO_AUTH_HEADER) then: 'get resource data returns expected response' assert response == '{dmi-response}' } @@ -259,10 +260,10 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { when: 'get resource data is called' objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle', 'testResourceId', UPDATE, - '{some-json}', 'application/json') + '{some-json}', 'application/json', NO_AUTH_HEADER) then: 'DMI called with correct data' 1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId', - UPDATE, '{some-json}', 'application/json') + UPDATE, '{some-json}', 'application/json', NO_AUTH_HEADER) >> { new ResponseEntity<>(HttpStatus.OK) } } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy index 0176de714..c8e34b1a5 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy @@ -48,6 +48,10 @@ import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE @ContextConfiguration(classes = [DmiProperties, DmiRestClient, ObjectMapper]) class DmiRestClientSpec extends Specification { + static final NO_AUTH_HEADER = null + static final BASIC_AUTH_HEADER = 'Basic c29tZS11c2VyOnNvbWUtcGFzc3dvcmQ=' + static final BEARER_AUTH_HEADER = 'Bearer my-bearer-token' + @SpringBean RestTemplate mockRestTemplate = Mock(RestTemplate) @@ -66,7 +70,7 @@ class DmiRestClientSpec extends Specification { given: 'the rest template returns a valid response entity for the expected parameters' mockRestTemplate.postForEntity('my url', _ as HttpEntity, Object.class) >> responseFromRestTemplate when: 'POST operation is invoked' - def result = objectUnderTest.postOperationWithJsonData('my url', 'some json', READ) + def result = objectUnderTest.postOperationWithJsonData('my url', 'some json', READ, null) then: 'the output of the method is equal to the output from the test template' result == responseFromRestTemplate } @@ -77,7 +81,7 @@ class DmiRestClientSpec extends Specification { def httpServerErrorException = new HttpServerErrorException(HttpStatus.FORBIDDEN, 'status text', serverResponse, null) mockRestTemplate.postForEntity(*_) >> { throw httpServerErrorException } when: 'POST operation is invoked' - def result = objectUnderTest.postOperationWithJsonData('some url', 'some json', operation) + def result = objectUnderTest.postOperationWithJsonData('some url', 'some json', operation, null) then: 'a Http Client Exception is thrown' def thrown = thrown(HttpClientRequestException) and: 'the exception has the relevant details from the error response' @@ -113,15 +117,20 @@ class DmiRestClientSpec extends Specification { 'exception' | {throw new Exception()} } - def 'Basic auth header #scenario'() { + def 'DMI auth header #scenario'() { when: 'Specific dmi properties are provided' dmiProperties.dmiBasicAuthEnabled = authEnabled then: 'http headers to conditionally have Authorization header' - assert (objectUnderTest.configureHttpHeaders(new HttpHeaders()).get('Authorization') != null) == isPresentInHttpHeader + def authHeaderValues = objectUnderTest.configureHttpHeaders(new HttpHeaders(), ncmpAuthHeader).getOrEmpty('Authorization') + def outputAuthHeader = (authHeaderValues == null ? null : authHeaderValues[0]) + assert outputAuthHeader == expectedAuthHeader where: 'the following configurations are used' - scenario | authEnabled || isPresentInHttpHeader - 'auth enabled' | true || true - 'auth disabled' | false || false + scenario | authEnabled | ncmpAuthHeader || expectedAuthHeader + 'DMI basic auth enabled, no NCMP bearer token' | true | NO_AUTH_HEADER || BASIC_AUTH_HEADER + 'DMI basic auth enabled, with NCMP bearer token' | true | BEARER_AUTH_HEADER || BASIC_AUTH_HEADER + 'DMI basic auth disabled, no NCMP bearer token' | false | NO_AUTH_HEADER || NO_AUTH_HEADER + 'DMI basic auth disabled, with NCMP bearer token' | false | BEARER_AUTH_HEADER || BEARER_AUTH_HEADER + 'DMI basic auth disabled, with NCMP basic auth' | false | BASIC_AUTH_HEADER || NO_AUTH_HEADER } } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy index 2229b32b0..26d44f28b 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy @@ -59,6 +59,7 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { def dmiServiceBaseUrl = "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/data/ds/ncmp-datastore:" def NO_TOPIC = null def NO_REQUEST_ID = null + def NO_AUTH_HEADER = null @Shared def OPTIONS_PARAM = '(a=1,b=2)' @@ -77,11 +78,11 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { and: 'a positive response from DMI service when it is called with the expected parameters' def responseFromDmi = new ResponseEntity(HttpStatus.OK) def expectedUrl = dmiServiceBaseUrl + "${expectedDatastoreInUrl}?resourceIdentifier=${resourceIdentifier}${expectedOptionsInUrl}" - mockDmiRestClient.postOperationWithJsonData(expectedUrl, expectedJson, READ) >> responseFromDmi + mockDmiRestClient.postOperationWithJsonData(expectedUrl, expectedJson, READ, NO_AUTH_HEADER) >> responseFromDmi dmiServiceUrlBuilder.getDmiDatastoreUrl(_, _) >> expectedUrl when: 'get resource data is invoked' def result = objectUnderTest.getResourceDataFromDmi(dataStore.datastoreName, cmHandleId, resourceIdentifier, - options, NO_TOPIC, NO_REQUEST_ID) + options, NO_TOPIC, NO_REQUEST_ID, NO_AUTH_HEADER) then: 'the result is the response from the DMI service' assert result == responseFromDmi where: 'the following parameters are used' @@ -104,12 +105,12 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { def responseFromDmi = new ResponseEntity(HttpStatus.ACCEPTED) def expectedDmiBatchResourceDataUrl = "ncmp/v1/data/topic=my-topic-name" def expectedBatchRequestAsJson = '{"operations":[{"operation":"read","operationId":"operational-14","datastore":"ncmp-datastore:passthrough-operational","options":"some option","resourceIdentifier":"some resource identifier","cmHandles":[{"id":"some-cm-handle","cmHandleProperties":{"prop1":"val1"}}]}]}' - mockDmiRestClient.postOperationWithJsonData(expectedDmiBatchResourceDataUrl, _, READ.operationName) >> responseFromDmi + mockDmiRestClient.postOperationWithJsonData(expectedDmiBatchResourceDataUrl, _, READ.operationName, NO_AUTH_HEADER) >> responseFromDmi dmiServiceUrlBuilder.getDataOperationRequestUrl(_, _) >> expectedDmiBatchResourceDataUrl and: ' a flag to track the post operation call' def postOperationWithJsonDataMethodCalled = false and: 'the (mocked) dmi rest client will use the flag to indicate it is called and capture the request body' - mockDmiRestClient.postOperationWithJsonData(expectedDmiBatchResourceDataUrl, expectedBatchRequestAsJson, READ) >> { + mockDmiRestClient.postOperationWithJsonData(expectedDmiBatchResourceDataUrl, expectedBatchRequestAsJson, READ, null) >> { postOperationWithJsonDataMethodCalled = true } when: 'get resource data for group of cm handles are invoked' @@ -148,7 +149,7 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { and: 'a positive response from DMI service when it is called with the expected parameters' def responseFromDmi = new ResponseEntity(HttpStatus.OK) def expectedUrl = dmiServiceBaseUrl + "passthrough-operational?resourceIdentifier=/" - mockDmiRestClient.postOperationWithJsonData(expectedUrl, '{"operation":"read","cmHandleProperties":{"prop1":"val1"}}', READ) >> responseFromDmi + mockDmiRestClient.postOperationWithJsonData(expectedUrl, '{"operation":"read","cmHandleProperties":{"prop1":"val1"}}', READ, null) >> responseFromDmi dmiServiceUrlBuilder.getDmiDatastoreUrl(_, _) >> expectedUrl when: 'get resource data is invoked' def result = objectUnderTest.getResourceDataFromDmi( PASSTHROUGH_OPERATIONAL.datastoreName, cmHandleId, NO_REQUEST_ID) @@ -164,9 +165,9 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { def expectedJson = '{"operation":"' + expectedOperationInUrl + '","dataType":"some data type","data":"requestData","cmHandleProperties":{"prop1":"val1"}}' def responseFromDmi = new ResponseEntity(HttpStatus.OK) dmiServiceUrlBuilder.getDmiDatastoreUrl(_, _) >> expectedUrl - mockDmiRestClient.postOperationWithJsonData(expectedUrl, expectedJson, operation) >> responseFromDmi + mockDmiRestClient.postOperationWithJsonData(expectedUrl, expectedJson, operation, NO_AUTH_HEADER) >> responseFromDmi when: 'write resource method is invoked' - def result = objectUnderTest.writeResourceDataPassThroughRunningFromDmi(cmHandleId, 'parent/child', operation, 'requestData', 'some data type') + def result = objectUnderTest.writeResourceDataPassThroughRunningFromDmi(cmHandleId, 'parent/child', operation, 'requestData', 'some data type', NO_AUTH_HEADER) then: 'the result is the response from the DMI service' assert result == responseFromDmi where: 'the following operation is performed' diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy index a105f84eb..ae17c56ef 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy @@ -51,6 +51,8 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { @SpringBean JsonObjectMapper spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper())) + def NO_AUTH_HEADER = null + def 'Retrieving module references.'() { given: 'a cm handle' mockYangModelCmHandleRetrieval([]) @@ -58,7 +60,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { def moduleReferencesAsLisOfMaps = [[moduleName: 'mod1', revision: 'A'], [moduleName: 'mod2', revision: 'X']] def expectedUrl = "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/modules" def responseFromDmi = new ResponseEntity([schemas: moduleReferencesAsLisOfMaps], HttpStatus.OK) - mockDmiRestClient.postOperationWithJsonData(expectedUrl, '{"cmHandleProperties":{}}', READ) + mockDmiRestClient.postOperationWithJsonData(expectedUrl, '{"cmHandleProperties":{}}', READ, NO_AUTH_HEADER) >> responseFromDmi when: 'get module references is called' def result = objectUnderTest.getModuleReferences(yangModelCmHandle) @@ -91,7 +93,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { and: 'a positive response from DMI service when it is called with tha expected parameters' def responseFromDmi = new ResponseEntity(HttpStatus.OK) mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/modules", - '{"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + '}', READ) >> responseFromDmi + '{"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + '}', READ, NO_AUTH_HEADER) >> responseFromDmi when: 'a get module references is called' def result = objectUnderTest.getModuleReferences(yangModelCmHandle) then: 'the result is the response from DMI service' @@ -110,7 +112,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { [moduleName: 'mod2', revision: 'C', yangSource: 'other yang source']], HttpStatus.OK) def expectedModuleReferencesInRequest = '{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}' mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources", - '{"data":{"modules":[' + expectedModuleReferencesInRequest + ']},"cmHandleProperties":{}}', READ) >> responseFromDmi + '{"data":{"modules":[' + expectedModuleReferencesInRequest + ']},"cmHandleProperties":{}}', READ, NO_AUTH_HEADER) >> responseFromDmi when: 'get new yang resources from DMI service' def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, newModuleReferences) then: 'the result has the 2 expected yang (re)sources (order is not guaranteed)' @@ -142,7 +144,8 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { and: 'a positive response from DMI service when it is called with the expected parameters' def responseFromDmi = new ResponseEntity<>([[moduleName: 'mod1', revision: 'A', yangSource: 'some yang source']], HttpStatus.OK) mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources", - '{"data":{"modules":[{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}]},"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + '}', READ) >> responseFromDmi + '{"data":{"modules":[{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}]},"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + '}', + READ, NO_AUTH_HEADER) >> responseFromDmi when: 'get new yang resources from DMI service' def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, newModuleReferences) then: 'the result is the response from DMI service' diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/controller/DmiRestStubController.java b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/controller/DmiRestStubController.java index 9d5e383b1..b536c75fb 100644 --- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/controller/DmiRestStubController.java +++ b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/controller/DmiRestStubController.java @@ -52,6 +52,7 @@ import org.springframework.kafka.core.KafkaTemplate; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -118,7 +119,7 @@ public class DmiRestStubController { } /** - * Get resource data from passthrough operational or running for a cm handle. + * Create resource data from passthrough operational or running for a cm handle. * * @param cmHandleId The identifier for a network function, network element, subnetwork, * or any other cm object by managed Network CM Proxy @@ -134,7 +135,9 @@ public class DmiRestStubController { @PathVariable("datastoreName") final String datastoreName, @RequestParam(value = "resourceIdentifier") final String resourceIdentifier, @RequestParam(value = "options", required = false) final String options, - @RequestParam(value = "topic", required = false) final String topic) { + @RequestParam(value = "topic", required = false) final String topic, + @RequestHeader(value = "Authorization", required = false) final String authorization) { + log.info("DMI AUTH HEADER: {}", authorization); delay(dataForCmHandleDelayMs); final String sampleJson = ResourceFileReaderUtil.getResourceFileContent(applicationContext.getResource( ResourceLoader.CLASSPATH_URL_PREFIX + "data/operational/ietf-network-topology-sample-rfc8345.json")); -- 2.16.6