diff options
77 files changed, 736 insertions, 1029 deletions
diff --git a/checkstyle/pom.xml b/checkstyle/pom.xml index 2676dcbc2c..83f112056c 100644 --- a/checkstyle/pom.xml +++ b/checkstyle/pom.xml @@ -26,7 +26,7 @@ <modelVersion>4.0.0</modelVersion> <groupId>org.onap.cps</groupId> <artifactId>checkstyle</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <profiles> <profile> diff --git a/cps-application/pom.xml b/cps-application/pom.xml index 871b92980b..ac75c0b8e8 100644 --- a/cps-application/pom.xml +++ b/cps-application/pom.xml @@ -28,7 +28,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> @@ -37,7 +37,7 @@ <properties> <app>org.onap.cps.Application</app> <maven.build.timestamp.format>yyyyMMdd'T'HHmmss'Z'</maven.build.timestamp.format> - <minimum-coverage>0.86</minimum-coverage> + <minimum-coverage>0.68</minimum-coverage> <base.image>${docker.pull.registry}/onap/integration-java17:12.0.0</base.image> <image.tag>${project.version}-${maven.build.timestamp}</image.tag> </properties> @@ -59,10 +59,6 @@ </dependency> <dependency> <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-security</artifactId> - </dependency> - <dependency> - <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> @@ -70,6 +66,18 @@ <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> </dependency> <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-http</artifactId> + </dependency> + <dependency> + <groupId>jakarta.servlet</groupId> + <artifactId>jakarta.servlet-api</artifactId> + </dependency> + <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency> diff --git a/cps-application/src/main/java/org/onap/cps/config/WebSecurityConfig.java b/cps-application/src/main/java/org/onap/cps/config/WebSecurityConfig.java deleted file mode 100644 index 0b6d0dba1e..0000000000 --- a/cps-application/src/main/java/org/onap/cps/config/WebSecurityConfig.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (c) 2021 Bell Canada. - * Modification Copyright (C) 2021 Pantheon.tech - * Modification Copyright (C) 2023 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.config; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.provisioning.InMemoryUserDetailsManager; -import org.springframework.security.web.SecurityFilterChain; - -/** - * Configuration class to implement application security. - * It enforces Basic Authentication access control. - */ -@Configuration -@EnableWebSecurity -public class WebSecurityConfig { - private static final String USER_ROLE = "USER"; - private final String username; - private final String password; - private final String[] permitUris; - - /** - * Constructor. Accepts parameters from configuration. - * - * @param permitUris comma-separated list of uri patterns for endpoints permitted - * @param username username - * @param password password - */ - public WebSecurityConfig( - @Autowired @Value("${security.permit-uri}") final String permitUris, - @Autowired @Value("${security.auth.username}") final String username, - @Autowired @Value("${security.auth.password}") final String password - ) { - super(); - this.permitUris = permitUris.isEmpty() ? new String[] {"/v3/api-docs"} : permitUris.split("\\s{0,9},\\s{0,9}"); - this.username = username; - this.password = password; - } - - /** - * Return the configuration for secure access to the modules REST end points. - * - * @param http the HTTP security settings. - * @return the HTTP security settings. - */ - @Bean - // The team decided to disable default CSRF Spring protection and not implement CSRF tokens validation. - // CPS is a stateless REST API that is not as vulnerable to CSRF attacks as web applications running in - // web browsers are. CPS does not manage sessions, each request requires the authentication token in the header. - // See https://docs.spring.io/spring-security/site/docs/5.3.8.RELEASE/reference/html5/#csrf - @SuppressWarnings("squid:S4502") - public SecurityFilterChain filterChain(final HttpSecurity http) throws Exception { - http - .httpBasic(httpBasicCustomizer -> {}) - .authorizeHttpRequests(authorizeHttpRequestsCustomizer -> { - authorizeHttpRequestsCustomizer.requestMatchers(permitUris).permitAll(); - authorizeHttpRequestsCustomizer.anyRequest().authenticated(); - }) - .csrf(AbstractHttpConfigurer::disable); - return http.build(); - } - - /** - * In memory user authentication details. - * - * @return in memory authentication - */ - @Bean - public InMemoryUserDetailsManager userDetailsService() { - final UserDetails user = User.builder() - .username(username) - .password("{noop}" + password) - .roles(USER_ROLE) - .build(); - return new InMemoryUserDetailsManager(user); - } -} diff --git a/cps-application/src/main/resources/application.yml b/cps-application/src/main/resources/application.yml index 207341ccde..9f03fc2708 100644 --- a/cps-application/src/main/resources/application.yml +++ b/cps-application/src/main/resources/application.yml @@ -64,7 +64,7 @@ spring: liquibase: change-log: classpath:changelog/changelog-master.yaml - label-filter: ${LIQUIBASE_LABELS} + labels: ${LIQUIBASE_LABELS} servlet: multipart: diff --git a/cps-application/src/test/groovy/org/onap/cps/rest/controller/ControllerSecuritySpec.groovy b/cps-application/src/test/groovy/org/onap/cps/rest/controller/ControllerSecuritySpec.groovy index ccadc57240..b86f824888 100755 --- a/cps-application/src/test/groovy/org/onap/cps/rest/controller/ControllerSecuritySpec.groovy +++ b/cps-application/src/test/groovy/org/onap/cps/rest/controller/ControllerSecuritySpec.groovy @@ -20,19 +20,16 @@ package org.onap.cps.rest.controller -import org.onap.cps.config.WebSecurityConfig -import org.springframework.context.annotation.Import - import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest import org.springframework.http.HttpStatus import org.springframework.test.web.servlet.MockMvc +import spock.lang.Ignore import spock.lang.Specification @WebMvcTest(TestController) -@Import(WebSecurityConfig) class ControllerSecuritySpec extends Specification { @Autowired @@ -49,6 +46,7 @@ class ControllerSecuritySpec extends Specification { assert response.status == HttpStatus.OK.value() } + @Ignore // CPS-2126 def 'Get request without authentication is not authorized'() { when: 'request is sent without authentication' def response = mvc.perform(get(testEndpoint)).andReturn().response @@ -56,6 +54,7 @@ class ControllerSecuritySpec extends Specification { assert response.status == HttpStatus.UNAUTHORIZED.value() } + @Ignore // CPS-2126 def 'Get request with invalid authentication is not authorized'() { when: 'request is sent with invalid authentication' def response = mvc.perform( diff --git a/cps-bom/pom.xml b/cps-bom/pom.xml index fb6bdbd1bb..3e88be72b9 100644 --- a/cps-bom/pom.xml +++ b/cps-bom/pom.xml @@ -25,7 +25,7 @@ <modelVersion>4.0.0</modelVersion> <groupId>org.onap.cps</groupId> <artifactId>cps-bom</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <packaging>pom</packaging> <description>This artifact contains dependencyManagement declarations of all published CPS components.</description> diff --git a/cps-dependencies/pom.xml b/cps-dependencies/pom.xml index e1e7caa9eb..69ea85917f 100644 --- a/cps-dependencies/pom.xml +++ b/cps-dependencies/pom.xml @@ -27,7 +27,7 @@ <modelVersion>4.0.0</modelVersion> <groupId>org.onap.cps</groupId> <artifactId>cps-dependencies</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <packaging>pom</packaging> <name>${project.groupId}:${project.artifactId}</name> @@ -85,7 +85,7 @@ <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> - <version>3.2.2</version> + <version>3.1.2</version> <type>pom</type> <scope>import</scope> </dependency> @@ -97,6 +97,11 @@ <scope>import</scope> </dependency> <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-test</artifactId> + <version>6.0.11</version> + </dependency> + <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>3.1.2</version> @@ -167,8 +172,8 @@ </dependency> <dependency> <groupId>io.hypersistence</groupId> - <artifactId>hypersistence-utils-hibernate-63</artifactId> - <version>3.7.3</version> + <artifactId>hypersistence-utils-hibernate-60</artifactId> + <version>3.5.0</version> </dependency> <dependency> <groupId>io.micrometer</groupId> @@ -211,6 +216,16 @@ <version>${groovy.version}</version> </dependency> <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + <version>${jetty-version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-http</artifactId> + <version>${jetty-version}</version> + </dependency> + <dependency> <groupId>org.codehaus.janino</groupId> <artifactId>janino</artifactId> <version>3.1.10</version> @@ -226,6 +241,11 @@ <version>22.0.0</version> </dependency> <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-api</artifactId> + <version>5.10.0</version> + </dependency> + <dependency> <groupId>org.liquibase</groupId> <artifactId>liquibase-core</artifactId> <version>4.21.0</version> diff --git a/cps-events/pom.xml b/cps-events/pom.xml index ec62b62e63..fd75c2c87b 100644 --- a/cps-events/pom.xml +++ b/cps-events/pom.xml @@ -24,7 +24,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> diff --git a/cps-ncmp-events/pom.xml b/cps-ncmp-events/pom.xml index a6b80e563d..89785caab8 100644 --- a/cps-ncmp-events/pom.xml +++ b/cps-ncmp-events/pom.xml @@ -23,7 +23,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> diff --git a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml index e10039995e..9d306927af 100644 --- a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml +++ b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml @@ -22,7 +22,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-ncmp-rest-stub</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> </parent> <artifactId>cps-ncmp-rest-stub-app</artifactId> diff --git a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml index 480c28e79f..350bb00ffa 100644 --- a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml +++ b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml @@ -21,7 +21,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-ncmp-rest-stub</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> </parent> <artifactId>cps-ncmp-rest-stub-service</artifactId> @@ -46,6 +46,14 @@ <groupId>org.onap.cps</groupId> <artifactId>cps-ncmp-rest</artifactId> </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + </dependency> + <dependency> + <groupId>jakarta.servlet</groupId> + <artifactId>jakarta.servlet-api</artifactId> + </dependency> <!-- T E S T - D E P E N D E N C I E S --> <dependency> <groupId>org.spockframework</groupId> 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 0e4f7f987f..08a492e0f7 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<Map<String, Object>> asyncResponse = populateAsyncResponse(topicParamInQuery); final Map<String, Object> asyncResponseData = asyncResponse.getBody(); @@ -142,16 +143,18 @@ public class NetworkCmProxyStubController implements NetworkCmProxyApi { @Override public ResponseEntity<Void> 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<Void> 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<Object> executeDataOperationForCmHandles(final String topicParamInQuery, - final DataOperationRequest dataOperationRequest) { + final DataOperationRequest dataOperationRequest, + final String authorization) { return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); } @Override public ResponseEntity<Object> 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<Object> 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<Object> updateResourceDataRunningForCmHandle(final String datastoreName, - final String cmHandle, - @NotNull @Valid final String resourceIdentifier, + public ResponseEntity<Object> 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-stub/pom.xml b/cps-ncmp-rest-stub/pom.xml index ee76f0a594..3df8fa9db6 100644 --- a/cps-ncmp-rest-stub/pom.xml +++ b/cps-ncmp-rest-stub/pom.xml @@ -22,7 +22,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> diff --git a/cps-ncmp-rest/docs/openapi/components.yaml b/cps-ncmp-rest/docs/openapi/components.yaml index 6b53292af7..cd77effc89 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-inventory.yml b/cps-ncmp-rest/docs/openapi/ncmp-inventory.yml index 16083bdf39..ea020f9e81 100755 --- a/cps-ncmp-rest/docs/openapi/ncmp-inventory.yml +++ b/cps-ncmp-rest/docs/openapi/ncmp-inventory.yml @@ -35,8 +35,6 @@ updateDmiRegistration: $ref: 'components.yaml#/components/responses/NoContent' 400: $ref: 'components.yaml#/components/responses/BadRequest' - 401: - $ref: 'components.yaml#/components/responses/Unauthorized' 403: $ref: 'components.yaml#/components/responses/Forbidden' 500: @@ -116,8 +114,6 @@ getAllCmHandleIdsForRegisteredDmi: type: array items: type: string - 401: - $ref: 'components.yaml#/components/responses/Unauthorized' 403: $ref: 'components.yaml#/components/responses/Forbidden' 500: @@ -145,8 +141,6 @@ searchCmHandleIds: type: array items: type: string - 401: - $ref: 'components.yaml#/components/responses/Unauthorized' 403: $ref: 'components.yaml#/components/responses/Forbidden' 500: diff --git a/cps-ncmp-rest/docs/openapi/ncmp.yml b/cps-ncmp-rest/docs/openapi/ncmp.yml index 2f90155cbd..0cb1cdffb1 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 @@ -44,8 +45,6 @@ resourceDataForCmHandle: $ref: 'components.yaml#/components/examples/dataSampleResponse' 400: $ref: 'components.yaml#/components/responses/BadRequest' - 401: - $ref: 'components.yaml#/components/responses/Unauthorized' 403: $ref: 'components.yaml#/components/responses/Forbidden' 500: @@ -64,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: @@ -84,8 +84,6 @@ resourceDataForCmHandle: $ref: 'components.yaml#/components/responses/Created' 400: $ref: 'components.yaml#/components/responses/BadRequest' - 401: - $ref: 'components.yaml#/components/responses/Unauthorized' 403: $ref: 'components.yaml#/components/responses/Forbidden' 500: @@ -104,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: @@ -124,8 +123,6 @@ resourceDataForCmHandle: $ref: 'components.yaml#/components/responses/Ok' 400: $ref: 'components.yaml#/components/responses/BadRequest' - 401: - $ref: 'components.yaml#/components/responses/Unauthorized' 403: $ref: 'components.yaml#/components/responses/Forbidden' 500: @@ -144,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: @@ -158,8 +156,6 @@ resourceDataForCmHandle: $ref: 'components.yaml#/components/responses/Ok' 400: $ref: 'components.yaml#/components/responses/BadRequest' - 401: - $ref: 'components.yaml#/components/responses/Unauthorized' 403: $ref: 'components.yaml#/components/responses/Forbidden' 500: @@ -178,13 +174,12 @@ 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' 400: $ref: 'components.yaml#/components/responses/BadRequest' - 401: - $ref: 'components.yaml#/components/responses/Unauthorized' 403: $ref: 'components.yaml#/components/responses/Forbidden' 404: @@ -203,6 +198,7 @@ dataOperationForCmHandle: operationId: executeDataOperationForCmHandles parameters: - $ref: 'components.yaml#/components/parameters/requiredTopicParamInQuery' + - $ref: 'components.yaml#/components/parameters/authorizationParamInHeader' requestBody: required: true content: @@ -218,8 +214,6 @@ dataOperationForCmHandle: type: object 400: $ref: 'components.yaml#/components/responses/BadRequest' - 401: - $ref: 'components.yaml#/components/responses/Unauthorized' 403: $ref: 'components.yaml#/components/responses/Forbidden' 500: @@ -253,8 +247,6 @@ queryResourceDataForCmHandle: $ref: 'components.yaml#/components/examples/dataSampleResponse' 400: $ref: 'components.yaml#/components/responses/BadRequest' - 401: - $ref: 'components.yaml#/components/responses/Unauthorized' 403: $ref: 'components.yaml#/components/responses/Forbidden' 500: @@ -282,8 +274,6 @@ fetchModuleReferencesByCmHandle: $ref: 'components.yaml#/components/schemas/RestModuleReference' 400: $ref: 'components.yaml#/components/responses/BadRequest' - 401: - $ref: 'components.yaml#/components/responses/Unauthorized' 403: $ref: 'components.yaml#/components/responses/Forbidden' 500: @@ -309,8 +299,6 @@ getModuleDefinitions: type: array items: $ref: 'components.yaml#/components/schemas/RestModuleDefinition' - 401: - $ref: 'components.yaml#/components/responses/Unauthorized' 403: $ref: 'components.yaml#/components/responses/Forbidden' 500: @@ -351,8 +339,6 @@ searchCmHandles: $ref: 'components.yaml#/components/schemas/RestOutputCmHandle' 400: $ref: 'components.yaml#/components/responses/BadRequest' - 401: - $ref: 'components.yaml#/components/responses/Unauthorized' 403: $ref: 'components.yaml#/components/responses/Forbidden' 500: @@ -376,8 +362,6 @@ retrieveCmHandleDetailsById: $ref: 'components.yaml#/components/schemas/RestOutputCmHandle' 400: $ref: 'components.yaml#/components/responses/BadRequest' - 401: - $ref: 'components.yaml#/components/responses/Unauthorized' 404: $ref: 'components.yaml#/components/responses/NotFound' 500: @@ -401,8 +385,6 @@ getCmHandlePropertiesById: $ref: 'components.yaml#/components/schemas/RestOutputCmHandlePublicProperties' 400: $ref: 'components.yaml#/components/responses/BadRequest' - 401: - $ref: 'components.yaml#/components/responses/Unauthorized' 404: $ref: 'components.yaml#/components/responses/NotFound' 500: @@ -426,8 +408,6 @@ getCmHandleStateById: $ref: 'components.yaml#/components/schemas/RestOutputCmHandleCompositeState' 400: $ref: 'components.yaml#/components/responses/BadRequest' - 401: - $ref: 'components.yaml#/components/responses/Unauthorized' 404: $ref: 'components.yaml#/components/responses/NotFound' 500: @@ -468,8 +448,6 @@ searchCmHandleIds: type: string 400: $ref: 'components.yaml#/components/responses/BadRequest' - 401: - $ref: 'components.yaml#/components/responses/Unauthorized' 403: $ref: 'components.yaml#/components/responses/Forbidden' 404: @@ -492,11 +470,9 @@ setDataSyncEnabledFlag: $ref: 'components.yaml#/components/responses/Ok' 400: $ref: 'components.yaml#/components/responses/BadRequest' - 401: - $ref: 'components.yaml#/components/responses/Unauthorized' 403: $ref: 'components.yaml#/components/responses/Forbidden' 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/lombok.config b/cps-ncmp-rest/lombok.config index e4122df33c..041897443e 100644 --- a/cps-ncmp-rest/lombok.config +++ b/cps-ncmp-rest/lombok.config @@ -17,5 +17,4 @@ # ============LICENSE_END========================================================= config.stopBubbling = true -lombok.addLombokGeneratedAnnotation = true -lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier +lombok.addLombokGeneratedAnnotation = true
\ No newline at end of file diff --git a/cps-ncmp-rest/pom.xml b/cps-ncmp-rest/pom.xml index fc3bd8cb92..7e03120c6e 100644 --- a/cps-ncmp-rest/pom.xml +++ b/cps-ncmp-rest/pom.xml @@ -27,7 +27,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> 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 73bd8d72b0..b567ba2e73 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 @@ -39,7 +39,6 @@ import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.api.NetworkCmProxyDataService; -import org.onap.cps.ncmp.api.impl.config.embeddedcache.TrustLevelCacheConfig; import org.onap.cps.ncmp.api.impl.exception.InvalidDatastoreException; import org.onap.cps.ncmp.api.impl.inventory.CompositeState; import org.onap.cps.ncmp.api.impl.operations.DatastoreType; @@ -63,7 +62,6 @@ import org.onap.cps.ncmp.rest.model.RestOutputCmHandlePublicProperties; import org.onap.cps.ncmp.rest.util.DeprecationHelper; import org.onap.cps.spi.model.ModuleDefinition; import org.onap.cps.utils.JsonObjectMapper; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.util.StringUtils; @@ -85,7 +83,6 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { private final NcmpCachedResourceRequestHandler ncmpCachedResourceRequestHandler; private final NcmpPassthroughResourceRequestHandler ncmpPassthroughResourceRequestHandler; private final DataOperationRequestMapper dataOperationRequestMapper; - @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_CM_HANDLE_BEAN_NAME) private final Map<String, TrustLevel> trustLevelPerCmHandle; /** @@ -97,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 @@ -106,18 +104,19 @@ 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<Object> executeDataOperationForCmHandles(final String topicParamInQuery, - final DataOperationRequest - dataOperationRequest) { + final DataOperationRequest dataOperationRequest, + final String authorization) { return ncmpPassthroughResourceRequestHandler.executeRequest(topicParamInQuery, - dataOperationRequestMapper.toDataOperationRequest(dataOperationRequest)); + dataOperationRequestMapper.toDataOperationRequest(dataOperationRequest), authorization); } /** @@ -151,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 */ @@ -159,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); } @@ -178,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 @@ -185,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); } @@ -202,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 */ @@ -210,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); } @@ -225,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<Void> 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 85a1eae234..430c0996f9 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 d40ab9b390..8b08090905 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<Object> 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<Object> 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<Object> 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 8a3257576d..430b749eff 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 @@ -61,17 +61,19 @@ public class NcmpPassthroughResourceRequestHandler extends NcmpDatastoreRequestH * * @param topicParamInQuery the topic param in query * @param dataOperationRequest data operation request details for resource data + * @param authorization contents of Authorization header, or null if not present * @return the response entity */ public ResponseEntity<Object> executeRequest(final String topicParamInQuery, - final DataOperationRequest - dataOperationRequest) { + final DataOperationRequest dataOperationRequest, + final String authorization) { validateDataOperationRequest(topicParamInQuery, dataOperationRequest); if (!notificationFeatureEnabled) { return ResponseEntity.ok(Map.of("status", "Asynchronous request is unavailable as notification feature is currently disabled.")); } - return getRequestIdAndSendDataOperationRequestToDmiService(topicParamInQuery, dataOperationRequest); + return getRequestIdAndSendDataOperationRequestToDmiService(topicParamInQuery, dataOperationRequest, + authorization); } @Override @@ -81,18 +83,21 @@ 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<Object> getRequestIdAndSendDataOperationRequestToDmiService(final String topicParamInQuery, - final DataOperationRequest - dataOperationRequest) { + private ResponseEntity<Object> getRequestIdAndSendDataOperationRequestToDmiService( + final String topicParamInQuery, + final DataOperationRequest dataOperationRequest, + final String authorization) { final String requestId = UUID.randomUUID().toString(); cpsNcmpTaskExecutor.executeTask( - getTaskSupplierForDataOperationRequest(topicParamInQuery, dataOperationRequest, requestId), + getTaskSupplierForDataOperationRequest(topicParamInQuery, dataOperationRequest, requestId, authorization), timeOutInMilliSeconds); return ResponseEntity.ok(Map.of("requestId", requestId)); } @@ -114,11 +119,13 @@ public class NcmpPassthroughResourceRequestHandler extends NcmpDatastoreRequestH private Supplier<Object> getTaskSupplierForDataOperationRequest(final String topicParamInQuery, final DataOperationRequest dataOperationRequest, - final String requestId) { + final String requestId, + final String authorization) { return () -> { networkCmProxyDataService.executeDataOperationForCmHandles(topicParamInQuery, dataOperationRequest, - requestId); + requestId, + authorization); return noReturn; }; } 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 983f2438c0..dba2b30fd4 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<ILoggingEvent>) @@ -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 4edbf3569f..ddeac519c3 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' @@ -72,7 +74,7 @@ class NcmpDatastoreRequestHandlerSpec extends Specification { and: 'notification feature is turned on/off' objectUnderTest.notificationFeatureEnabled = notificationFeatureEnabled when: 'data operation request is executed' - objectUnderTest.executeRequest('someTopic', new DataOperationRequest()) + objectUnderTest.executeRequest('someTopic', new DataOperationRequest(), NO_AUTH_HEADER) then: 'the task is executed in an async fashion or not' expectedCalls * spiedCpsNcmpTaskExecutor.executeTask(*_) where: 'the following parameters are used' @@ -90,11 +92,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 it is called' - mockNetworkCmProxyDataService.executeDataOperationForCmHandles('myTopic', dataOperationRequest, _) >> { + mockNetworkCmProxyDataService.executeDataOperationForCmHandles('myTopic', dataOperationRequest, _, NO_AUTH_HEADER) >> { networkServiceMethodCalled = true } when: 'data operation request is executed' - objectUnderTest.executeRequest('myTopic', dataOperationRequest) + objectUnderTest.executeRequest('myTopic', dataOperationRequest, NO_AUTH_HEADER) then: 'the task is executed in an async fashion' 1 * spiedCpsNcmpTaskExecutor.executeTask(*_) and: 'the network service is invoked' @@ -112,7 +114,7 @@ class NcmpDatastoreRequestHandlerSpec extends Specification { def dataOperationDefinition = new DataOperationDefinition(operation: 'read', datastore: datastore) when: 'data operation request is executed' def dataOperationRequest = new DataOperationRequest(dataOperationDefinitions: [dataOperationDefinition]) - objectUnderTest.executeRequest('myTopic', dataOperationRequest) + objectUnderTest.executeRequest('myTopic', dataOperationRequest, NO_AUTH_HEADER) then: 'the correct error is thrown' def thrown = thrown(InvalidDatastoreException) assert thrown.message.contains(expectedErrorMessage) @@ -128,7 +130,7 @@ class NcmpDatastoreRequestHandlerSpec extends Specification { and: 'a data operation definition with operation: #operation' def dataOperationDefinition = new DataOperationDefinition(operation: operation, datastore: 'ncmp-datastore:passthrough-running') when: 'bulk request is executed' - objectUnderTest.executeRequest('someTopic', new DataOperationRequest(dataOperationDefinitions:[dataOperationDefinition])) + objectUnderTest.executeRequest('someTopic', new DataOperationRequest(dataOperationDefinitions:[dataOperationDefinition]), NO_AUTH_HEADER) then: 'the expected type of exception is thrown' thrown(expectedException) where: 'the following operations are used' diff --git a/cps-ncmp-service/lombok.config b/cps-ncmp-service/lombok.config index 6776ef0f51..359519ca70 100644 --- a/cps-ncmp-service/lombok.config +++ b/cps-ncmp-service/lombok.config @@ -17,5 +17,4 @@ # ============LICENSE_END========================================================= config.stopBubbling = true -lombok.addLombokGeneratedAnnotation = true -lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier +lombok.addLombokGeneratedAnnotation = true
\ No newline at end of file diff --git a/cps-ncmp-service/pom.xml b/cps-ncmp-service/pom.xml index bdc23046ec..4feb676444 100644 --- a/cps-ncmp-service/pom.xml +++ b/cps-ncmp-service/pom.xml @@ -27,7 +27,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> 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 0c8474839b..4230140d26 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. @@ -87,10 +89,13 @@ public interface NetworkCmProxyDataService { * * @param topicParamInQuery topic name for (triggering) async responses * @param dataOperationRequest contains a list of operation definitions(multiple operations) + * @param requestId request ID + * @param authorization contents of Authorization header, or null if not present */ void executeDataOperationForCmHandles(String topicParamInQuery, DataOperationRequest dataOperationRequest, - String requestId); + String requestId, + String authorization); /** @@ -101,13 +106,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 ab83486bd7..4c905bf90f 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 @@ -51,7 +51,6 @@ import org.apache.commons.lang3.StringUtils; import org.onap.cps.api.CpsDataService; import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService; import org.onap.cps.ncmp.api.NetworkCmProxyDataService; -import org.onap.cps.ncmp.api.impl.config.embeddedcache.TrustLevelCacheConfig; import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler; import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueries; import org.onap.cps.ncmp.api.impl.inventory.CmHandleState; @@ -85,7 +84,6 @@ import org.onap.cps.spi.exceptions.DataValidationException; import org.onap.cps.spi.model.ModuleDefinition; import org.onap.cps.spi.model.ModuleReference; import org.onap.cps.utils.JsonObjectMapper; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; @@ -104,7 +102,6 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService private final LcmEventsCmHandleStateHandler lcmEventsCmHandleStateHandler; private final CpsDataService cpsDataService; private final IMap<String, Object> moduleSyncStartedOnCmHandles; - @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN_BEAN_NAME) private final Map<String, TrustLevel> trustLevelPerDmiPlugin; private final TrustLevelManager trustLevelManager; private final AlternateIdChecker alternateIdChecker; @@ -135,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(); } @@ -155,10 +154,11 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService @Override public void executeDataOperationForCmHandles(final String topicParamInQuery, - final DataOperationRequest - dataOperationRequest, - final String requestId) { - dmiDataOperations.requestResourceDataFromDmi(topicParamInQuery, dataOperationRequest, requestId); + final DataOperationRequest dataOperationRequest, + final String requestId, + final String authorization) { + dmiDataOperations.requestResourceDataFromDmi(topicParamInQuery, dataOperationRequest, requestId, + authorization); } @Override @@ -166,9 +166,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 @@ -423,7 +424,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService final List<NcmpServiceCmHandle> cmHandlesToBeCreated, final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses) { final Collection<String> rejectedCmHandleIds = alternateIdChecker - .getIdsOfCmHandlesWithRejectedAlternateId(cmHandlesToBeCreated); + .getIdsOfCmHandlesWithRejectedAlternateId(cmHandlesToBeCreated, AlternateIdChecker.Operation.CREATE); cmHandleRegistrationResponses.addAll(CmHandleRegistrationResponse.createFailureResponses( rejectedCmHandleIds, ALTERNATE_ID_ALREADY_ASSOCIATED)); return rejectedCmHandleIds; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java index f5d22af281..3d15291633 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandler.java @@ -22,6 +22,7 @@ package org.onap.cps.ncmp.api.impl; +import static org.onap.cps.ncmp.api.NcmpResponseStatus.ALTERNATE_ID_ALREADY_ASSOCIATED; import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_FOUND; import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_INVALID_ID; import static org.onap.cps.ncmp.api.impl.NetworkCmProxyDataServicePropertyHandler.PropertyType.DMI_PROPERTY; @@ -46,8 +47,6 @@ import lombok.extern.slf4j.Slf4j; import org.onap.cps.api.CpsDataService; import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence; import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker; -import org.onap.cps.ncmp.api.impl.utils.YangDataConverter; -import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse; import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle; import org.onap.cps.spi.exceptions.DataNodeNotFoundException; @@ -70,67 +69,76 @@ public class NetworkCmProxyDataServicePropertyHandler { private final AlternateIdChecker alternateIdChecker; /** - * Iterates over incoming ncmpServiceCmHandles and update the dataNodes based on the updated attributes. + * Iterates over incoming updatedNcmpServiceCmHandles and update the dataNodes based on the updated attributes. * The attributes which are not passed will remain as is. * - * @param ncmpServiceCmHandles collection of ncmpServiceCmHandles + * @param updatedNcmpServiceCmHandles collection of CmHandles */ public List<CmHandleRegistrationResponse> updateCmHandleProperties( - final Collection<NcmpServiceCmHandle> ncmpServiceCmHandles) { - final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses - = new ArrayList<>(ncmpServiceCmHandles.size()); - for (final NcmpServiceCmHandle ncmpServiceCmHandle : ncmpServiceCmHandles) { - final String cmHandleId = ncmpServiceCmHandle.getCmHandleId(); - try { - final DataNode existingCmHandleDataNode = inventoryPersistence - .getCmHandleDataNodeByCmHandleId(cmHandleId).iterator().next(); - updateAlternateId(existingCmHandleDataNode, ncmpServiceCmHandle); - processUpdates(existingCmHandleDataNode, ncmpServiceCmHandle); - cmHandleRegistrationResponses.add(CmHandleRegistrationResponse.createSuccessResponse(cmHandleId)); - } catch (final DataNodeNotFoundException e) { - log.error("Unable to find dataNode for cmHandleId : {} , caused by : {}", cmHandleId, e.getMessage()); - cmHandleRegistrationResponses.add( - CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLES_NOT_FOUND)); - } catch (final DataValidationException e) { - log.error("Unable to update cm handle : {}, caused by : {}", cmHandleId, e.getMessage()); - cmHandleRegistrationResponses.add( - CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLE_INVALID_ID)); - } catch (final Exception exception) { - log.error("Unable to update cmHandle : {} , caused by : {}", cmHandleId, exception.getMessage()); - cmHandleRegistrationResponses.add( - CmHandleRegistrationResponse.createFailureResponse(cmHandleId, exception)); + final Collection<NcmpServiceCmHandle> updatedNcmpServiceCmHandles) { + final Collection<String> rejectedCmHandleIds = alternateIdChecker + .getIdsOfCmHandlesWithRejectedAlternateId(updatedNcmpServiceCmHandles, AlternateIdChecker.Operation.UPDATE); + final List<CmHandleRegistrationResponse> failureResponses = + CmHandleRegistrationResponse.createFailureResponses(rejectedCmHandleIds, ALTERNATE_ID_ALREADY_ASSOCIATED); + final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses = new ArrayList<>(failureResponses); + for (final NcmpServiceCmHandle updatedNcmpServiceCmHandle : updatedNcmpServiceCmHandles) { + final String cmHandleId = updatedNcmpServiceCmHandle.getCmHandleId(); + if (!rejectedCmHandleIds.contains(cmHandleId)) { + try { + final DataNode existingCmHandleDataNode = inventoryPersistence + .getCmHandleDataNodeByCmHandleId(cmHandleId).iterator().next(); + processUpdates(existingCmHandleDataNode, updatedNcmpServiceCmHandle); + cmHandleRegistrationResponses.add(CmHandleRegistrationResponse.createSuccessResponse(cmHandleId)); + } catch (final DataNodeNotFoundException e) { + log.error("Unable to find dataNode for cmHandleId : {} , caused by : {}", cmHandleId, + e.getMessage()); + cmHandleRegistrationResponses.add( + CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLES_NOT_FOUND)); + } catch (final DataValidationException e) { + log.error("Unable to update cm handle : {}, caused by : {}", cmHandleId, e.getMessage()); + cmHandleRegistrationResponses.add( + CmHandleRegistrationResponse.createFailureResponse(cmHandleId, CM_HANDLE_INVALID_ID)); + } catch (final Exception exception) { + log.error("Unable to update cmHandle : {} , caused by : {}", cmHandleId, exception.getMessage()); + cmHandleRegistrationResponses.add( + CmHandleRegistrationResponse.createFailureResponse(cmHandleId, exception)); + } } } return cmHandleRegistrationResponses; } - private void updateAlternateId(final DataNode existingCmHandleDataNode, - final NcmpServiceCmHandle ncmpServiceCmHandle) { - final YangModelCmHandle yangModelCmHandle = - YangDataConverter.convertCmHandleToYangModel(existingCmHandleDataNode); - final String currentAlternateId = yangModelCmHandle.getAlternateId(); - final String newAlternateId = ncmpServiceCmHandle.getAlternateId(); - if (alternateIdChecker.canApplyAlternateId(ncmpServiceCmHandle.getCmHandleId(), - currentAlternateId, newAlternateId)) { - setAndUpdateAlternateId(yangModelCmHandle, newAlternateId); + private void processUpdates(final DataNode existingCmHandleDataNode, + final NcmpServiceCmHandle updatedNcmpServiceCmHandle) { + updateAlternateId(updatedNcmpServiceCmHandle); + if (!updatedNcmpServiceCmHandle.getPublicProperties().isEmpty()) { + updateProperties(existingCmHandleDataNode, PUBLIC_PROPERTY, + updatedNcmpServiceCmHandle.getPublicProperties()); + } + if (!updatedNcmpServiceCmHandle.getDmiProperties().isEmpty()) { + updateProperties(existingCmHandleDataNode, DMI_PROPERTY, updatedNcmpServiceCmHandle.getDmiProperties()); } } - private void processUpdates(final DataNode existingCmHandleDataNode, final NcmpServiceCmHandle incomingCmHandle) { - if (!incomingCmHandle.getPublicProperties().isEmpty()) { - updateProperties(existingCmHandleDataNode, PUBLIC_PROPERTY, incomingCmHandle.getPublicProperties()); - } - if (!incomingCmHandle.getDmiProperties().isEmpty()) { - updateProperties(existingCmHandleDataNode, DMI_PROPERTY, incomingCmHandle.getDmiProperties()); - } + private void updateAlternateId(final NcmpServiceCmHandle updatedNcmpServiceCmHandle) { + final String updatedAlternateId = updatedNcmpServiceCmHandle.getAlternateId(); + final String cmHandleId = updatedNcmpServiceCmHandle.getCmHandleId(); + final Map<String, String> cmHandleProperties = new HashMap<>(2); + cmHandleProperties.put("id", cmHandleId); + cmHandleProperties.put("alternate-id", updatedAlternateId); + final Map<String, Map<String, String>> dmiRegistryProperties = new HashMap<>(1); + dmiRegistryProperties.put("cm-handles", cmHandleProperties); + cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT, + jsonObjectMapper.asJsonString(dmiRegistryProperties), OffsetDateTime.now()); + log.debug("Updating alternateId for cmHandle {} with value : {})", cmHandleId, updatedAlternateId); } private void updateProperties(final DataNode existingCmHandleDataNode, final PropertyType propertyType, - final Map<String, String> incomingProperties) { + final Map<String, String> updatedProperties) { final Collection<DataNode> replacementPropertyDataNodes = - getReplacementDataNodes(existingCmHandleDataNode, propertyType, incomingProperties); + getReplacementDataNodes(existingCmHandleDataNode, propertyType, updatedProperties); replacementPropertyDataNodes.addAll( - getUnchangedPropertyDataNodes(existingCmHandleDataNode, propertyType, incomingProperties)); + getUnchangedPropertyDataNodes(existingCmHandleDataNode, propertyType, updatedProperties)); if (replacementPropertyDataNodes.isEmpty()) { removeAllProperties(existingCmHandleDataNode, propertyType); } else { @@ -149,13 +157,14 @@ public class NetworkCmProxyDataServicePropertyHandler { } private Collection<DataNode> getUnchangedPropertyDataNodes(final DataNode existingCmHandleDataNode, - final PropertyType propertyType, final Map<String, String> incomingProperties) { + final PropertyType propertyType, + final Map<String, String> updatedProperties) { final Collection<DataNode> unchangedPropertyDataNodes = new HashSet<>(); for (final DataNode existingPropertyDataNode : existingCmHandleDataNode.getChildDataNodes()) { final Matcher matcher = propertyType.propertyXpathPattern.matcher(existingPropertyDataNode.getXpath()); if (matcher.find()) { final String keyName = matcher.group(2); - if (!incomingProperties.containsKey(keyName)) { + if (!updatedProperties.containsKey(keyName)) { unchangedPropertyDataNodes.add(existingPropertyDataNode); } } @@ -164,9 +173,10 @@ public class NetworkCmProxyDataServicePropertyHandler { } private Collection<DataNode> getReplacementDataNodes(final DataNode existingCmHandleDataNode, - final PropertyType propertyType, final Map<String, String> incomingProperties) { + final PropertyType propertyType, + final Map<String, String> updatedProperties) { final Collection<DataNode> replacementPropertyDataNodes = new HashSet<>(); - incomingProperties.forEach((updatedAttributeKey, updatedAttributeValue) -> { + updatedProperties.forEach((updatedAttributeKey, updatedAttributeValue) -> { final String propertyXpath = getAttributeXpath(existingCmHandleDataNode, propertyType, updatedAttributeKey); if (updatedAttributeValue != null) { log.info("Creating a new DataNode with xpath {} , key : {} and value : {}", propertyXpath, @@ -179,7 +189,7 @@ public class NetworkCmProxyDataServicePropertyHandler { } private String getAttributeXpath(final DataNode cmHandle, final PropertyType propertyType, - final String attributeKey) { + final String attributeKey) { return cmHandle.getXpath() + "/" + propertyType.xpathPrefix + String.format("[@name='%s']", attributeKey); } @@ -192,17 +202,6 @@ public class NetworkCmProxyDataServicePropertyHandler { return new DataNodeBuilder().withXpath(xpath).withLeaves(ImmutableMap.copyOf(updatedLeaves)).build(); } - private void setAndUpdateAlternateId(final YangModelCmHandle upgradedCmHandle, final String alternateId) { - final Map<String, Map<String, String>> dmiRegistryProperties = new HashMap<>(1); - final Map<String, String> cmHandleProperties = new HashMap<>(2); - cmHandleProperties.put("id", upgradedCmHandle.getId()); - cmHandleProperties.put("alternate-id", alternateId); - dmiRegistryProperties.put("cm-handles", cmHandleProperties); - cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT, - jsonObjectMapper.asJsonString(dmiRegistryProperties), OffsetDateTime.now()); - log.info("Updating alternateId for cmHandle {} with value : {})", upgradedCmHandle.getId(), alternateId); - } - enum PropertyType { DMI_PROPERTY("additional-properties"), PUBLIC_PROPERTY("public-properties"); 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 5b93eb4853..798a280c8a 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<Object> 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<Object> httpHeaders = new HttpEntity<>(configureHttpHeaders(new HttpHeaders())); + final HttpEntity<Object> 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/config/embeddedcache/TrustLevelCacheConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfig.java index f12cc9c822..171db52998 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfig.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfig.java @@ -30,10 +30,6 @@ import org.springframework.context.annotation.Configuration; @Configuration public class TrustLevelCacheConfig extends HazelcastCacheConfig { - public static final String TRUST_LEVEL_PER_DMI_PLUGIN_BEAN_NAME = "trustLevelPerDmiPlugin"; - - public static final String TRUST_LEVEL_PER_CM_HANDLE_BEAN_NAME = "trustLevelPerCmHandle"; - private static final MapConfig trustLevelPerCmHandleCacheConfig = createMapConfig("trustLevelPerCmHandleCacheConfig"); @@ -45,7 +41,7 @@ public class TrustLevelCacheConfig extends HazelcastCacheConfig { * * @return configured map of cm handle name as keys to trust-level for values. */ - @Bean(TRUST_LEVEL_PER_CM_HANDLE_BEAN_NAME) + @Bean public Map<String, TrustLevel> trustLevelPerCmHandle() { return createHazelcastInstance("hazelcastInstanceTrustLevelPerCmHandleMap", trustLevelPerCmHandleCacheConfig).getMap("trustLevelPerCmHandle"); @@ -56,7 +52,7 @@ public class TrustLevelCacheConfig extends HazelcastCacheConfig { * * @return configured map of dmi-plugin name as keys to trust-level for values. */ - @Bean(TRUST_LEVEL_PER_DMI_PLUGIN_BEAN_NAME) + @Bean public Map<String, TrustLevel> trustLevelPerDmiPlugin() { return createHazelcastInstance("hazelcastInstanceTrustLevelPerDmiPluginMap", trustLevelPerDmiPluginCacheConfig).getMap("trustLevelPerDmiPlugin"); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImpl.java index a43da294c1..2d7ad698c5 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImpl.java @@ -34,14 +34,12 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; -import org.onap.cps.ncmp.api.impl.config.embeddedcache.TrustLevelCacheConfig; import org.onap.cps.ncmp.api.impl.inventory.enums.PropertyType; import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel; import org.onap.cps.spi.CpsDataPersistenceService; import org.onap.cps.spi.FetchDescendantsOption; import org.onap.cps.spi.model.DataNode; import org.onap.cps.spi.utils.CpsValidator; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; @RequiredArgsConstructor @@ -51,11 +49,7 @@ public class CmHandleQueriesImpl implements CmHandleQueries { private static final String DESCENDANT_PATH = "//"; private static final String ANCESTOR_CM_HANDLES = "/ancestor::cm-handles"; private final CpsDataPersistenceService cpsDataPersistenceService; - - @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN_BEAN_NAME) private final Map<String, TrustLevel> trustLevelPerDmiPlugin; - - @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_CM_HANDLE_BEAN_NAME) private final Map<String, TrustLevel> trustLevelPerCmHandle; private final CpsValidator cpsValidator; 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 fa18767dbe..a77e78a2e2 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); } /** @@ -130,10 +132,12 @@ public class DmiDataOperations extends DmiOperations { * @param topicParamInQuery topic name for (triggering) async responses * @param dataOperationRequest data operation request to execute operations * @param requestId requestId for as a response + * @param authorization contents of Authorization header, or null if not present */ public void requestResourceDataFromDmi(final String topicParamInQuery, final DataOperationRequest dataOperationRequest, - final String requestId) { + final String requestId, + final String authorization) { final Set<String> cmHandlesIds = getDistinctCmHandleIdsFromDataOperationRequest(dataOperationRequest); @@ -145,7 +149,8 @@ public class DmiDataOperations extends DmiOperations { = ResourceDataOperationRequestUtils.processPerDefinitionInDataOperationsRequest(topicParamInQuery, requestId, dataOperationRequest, yangModelCmHandles); - buildDataOperationRequestUrlAndSendToDmiService(topicParamInQuery, requestId, operationsOutPerDmiServiceName); + buildDataOperationRequestUrlAndSendToDmiService(topicParamInQuery, requestId, operationsOutPerDmiServiceName, + authorization); } /** @@ -157,13 +162,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<Object> 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 +179,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) { @@ -234,23 +241,26 @@ public class DmiDataOperations extends DmiOperations { private void buildDataOperationRequestUrlAndSendToDmiService(final String topicParamInQuery, final String requestId, final Map<String, List<DmiDataOperation>> - groupsOutPerDmiServiceName) { + groupsOutPerDmiServiceName, + final String authorization) { groupsOutPerDmiServiceName.forEach((dmiServiceName, dmiDataOperationRequestBodies) -> { final String dmiDataOperationResourceUrl = getDmiServiceDataOperationRequestUrl(dmiServiceName, topicParamInQuery, requestId); - sendDataOperationRequestToDmiService(dmiDataOperationResourceUrl, dmiDataOperationRequestBodies); + sendDataOperationRequestToDmiService(dmiDataOperationResourceUrl, dmiDataOperationRequestBodies, + authorization); }); } private void sendDataOperationRequestToDmiService(final String dataOperationResourceUrl, - final List<DmiDataOperation> dmiDataOperationRequestBodies) { + final List<DmiDataOperation> dmiDataOperationRequestBodies, + final String authorization) { final DmiDataOperationRequest dmiDataOperationRequest = DmiDataOperationRequest.builder() .operations(dmiDataOperationRequestBodies).build(); final String dmiDataOperationRequestAsJsonString = jsonObjectMapper.asJsonString(dmiDataOperationRequest); TaskExecutor.executeTask(() -> dmiRestClient.postOperationWithJsonData(dataOperationResourceUrl, - dmiDataOperationRequestAsJsonString, READ), + dmiDataOperationRequestAsJsonString, READ, authorization), 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 dbe386d7ca..f99fe86f66 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<ModuleReference> newModuleReferences, diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManager.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManager.java index 4c606a9c01..82c7204028 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManager.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManager.java @@ -24,12 +24,10 @@ import java.util.Collection; import java.util.Map; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.config.embeddedcache.TrustLevelCacheConfig; import org.onap.cps.ncmp.api.impl.events.avc.ncmptoclient.AvcEventPublisher; import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence; import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService; import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; @Slf4j @@ -37,12 +35,8 @@ import org.springframework.stereotype.Service; @RequiredArgsConstructor public class TrustLevelManager { - @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_CM_HANDLE_BEAN_NAME) private final Map<String, TrustLevel> trustLevelPerCmHandle; - - @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN_BEAN_NAME) private final Map<String, TrustLevel> trustLevelPerDmiPlugin; - private final InventoryPersistence inventoryPersistence; private final AvcEventPublisher avcEventPublisher; private static final String AVC_CHANGED_ATTRIBUTE_NAME = "trustLevel"; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDog.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDog.java index 78eaf3e6bf..72dc295bf3 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDog.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDog.java @@ -26,10 +26,8 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.api.NetworkCmProxyDataService; import org.onap.cps.ncmp.api.impl.client.DmiRestClient; -import org.onap.cps.ncmp.api.impl.config.embeddedcache.TrustLevelCacheConfig; import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel; import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevelManager; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; @@ -40,10 +38,7 @@ public class DmiPluginWatchDog { private final DmiRestClient dmiRestClient; private final NetworkCmProxyDataService networkCmProxyDataService; - private final TrustLevelManager trustLevelManager; - - @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN_BEAN_NAME) private final Map<String, TrustLevel> trustLevelPerDmiPlugin; /** diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java index 4ac6537494..f14439f690 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/AlternateIdChecker.java @@ -38,6 +38,10 @@ import org.springframework.stereotype.Service; @RequiredArgsConstructor public class AlternateIdChecker { + public enum Operation { + CREATE, UPDATE + } + private final InventoryPersistence inventoryPersistence; private static final String NO_CURRENT_ALTERNATE_ID = ""; @@ -96,15 +100,16 @@ public class AlternateIdChecker { } /** - * Check all alternate ids of a batch of NEW cm handles. + * Check all alternate ids of a batch of cm handles. * Includes cross-checks in the batch itself for duplicates. Only the first entry encountered wil be accepted. - * This method can only be used for NEW cm handle registrations NOT for updating existing ones * * @param newNcmpServiceCmHandles the proposed new cm handles + * @param operation type of operation being executed * @return collection of cm handles ids which are acceptable */ public Collection<String> getIdsOfCmHandlesWithRejectedAlternateId( - final Collection<NcmpServiceCmHandle> newNcmpServiceCmHandles) { + final Collection<NcmpServiceCmHandle> newNcmpServiceCmHandles, + final Operation operation) { final Set<String> acceptedAlternateIds = new HashSet<>(newNcmpServiceCmHandles.size()); final Collection<String> rejectedCmHandleIds = new ArrayList<>(); for (final NcmpServiceCmHandle ncmpServiceCmHandle : newNcmpServiceCmHandles) { @@ -119,7 +124,11 @@ public class AlternateIdChecker { log.warn("Alternate id update ignored, cannot update cm handle {}, alternate id is already " + "assigned to a different cm handle (in this batch)", cmHandleId); } else { - isAcceptable = canApplyAlternateId(cmHandleId, NO_CURRENT_ALTERNATE_ID, proposedAlternateId); + if (Operation.CREATE.equals(operation)) { + isAcceptable = canApplyAlternateId(cmHandleId, NO_CURRENT_ALTERNATE_ID, proposedAlternateId); + } else { + isAcceptable = canApplyAlternateId(cmHandleId, proposedAlternateId); + } } } if (isAcceptable) { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy index cb7e1ef8a9..fbfbac59e0 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy @@ -78,7 +78,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { def setup() { // always accept all cm handles - mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(_) >> [] + mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(*_) >> [] // always can find all cm handles in DB mockInventoryPersistence.getYangModelCmHandles(_) >> { args -> args[0].collect { new YangModelCmHandle(id:it) } } @@ -418,14 +418,4 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { 'an unexpected exception' | 'cmhandle' | new RuntimeException('Failed') || UNKNOWN_ERROR | 'Failed' } - def 'Adding data to alternate id caches.'() { - given: 'a registration with three CM Handles to be created' - def ncmpServiceCmHandles = [new NcmpServiceCmHandle(cmHandleId: 'cmhandle1', alternateId: 'my-alternate-id-1')] - def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server', createdCmHandles: ncmpServiceCmHandles) - when: 'the DMI plugin registration happens' - objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration) - then: 'the new alternate id is added to the cache' - 1 * mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(ncmpServiceCmHandles) >> ['cmhandle1'] - } - } 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 9b4fe146b9..74016e4c0c 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}' } @@ -157,9 +158,9 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { given: 'cpsDataService returns valid data node' def dataOperationRequest = getDataOperationRequest(datastoreName) when: 'request resource data for data operation is called' - objectUnderTest.executeDataOperationForCmHandles('some topic', dataOperationRequest, 'requestId') + objectUnderTest.executeDataOperationForCmHandles('some topic', dataOperationRequest, 'requestId', NO_AUTH_HEADER) then: 'request resource data for data operation returns expected response' - 1 * mockDmiDataOperations.requestResourceDataFromDmi('some topic', dataOperationRequest, 'requestId') + 1 * mockDmiDataOperations.requestResourceDataFromDmi('some topic', dataOperationRequest, 'requestId', NO_AUTH_HEADER) where: 'the following data stores are used' datastoreName << [PASSTHROUGH_RUNNING.datastoreName, PASSTHROUGH_OPERATIONAL.datastoreName] } @@ -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) } } @@ -273,7 +274,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { dmiPluginRegistration.createdCmHandles = [ncmpServiceCmHandle] mockDmiPluginRegistration.getCreatedCmHandles() >> [ncmpServiceCmHandle] and: 'no rejected cm handles because of alternate ids' - mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(_) >> [] + mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(*_) >> [] when: 'parse and create cm handle in dmi registration then sync module' mockDmiPluginRegistration.createdCmHandles = ['test-cm-handle-id'] objectUnderTest.processCreatedCmHandles(mockDmiPluginRegistration, new DmiPluginRegistrationResponse()) diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandlerSpec.groovy index e00a42674b..cbed4177bd 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandlerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServicePropertyHandlerSpec.groovy @@ -49,6 +49,12 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { def mockAlternateIdChecker = Mock(AlternateIdChecker) def objectUnderTest = new NetworkCmProxyDataServicePropertyHandler(mockInventoryPersistence, mockCpsDataService, jsonObjectMapper, mockAlternateIdChecker) + + def setup() { + // Always accept all alternate IDs + mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(*_) >> [] + } + def static cmHandleId = 'myHandle1' def static cmHandleXpath = "/dmi-registry/cm-handles[@id='${cmHandleId}']" @@ -66,7 +72,7 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { when: 'update data node leaves is called with the update request' objectUnderTest.updateCmHandleProperties(cmHandleUpdateRequest) then: 'the replace list method is called with correct params' - 1 * mockInventoryPersistence.replaceListContent(cmHandleXpath,_) >> { args -> + 1 * mockInventoryPersistence.replaceListContent(cmHandleXpath, _) >> { args -> { assert args[1].leaves.size() == expectedPropertiesAfterUpdate.size() assert args[1].leaves.containsAll(convertToProperties(expectedPropertiesAfterUpdate)) @@ -142,10 +148,10 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { assert it.errorText == expectedErrorText } where: - scenario | cmHandleId | exception || expectedError | expectedErrorText - 'Cm Handle does not exist' | 'cmHandleId' | new DataNodeNotFoundException(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR) || CM_HANDLES_NOT_FOUND | 'cm handle id(s) not found' - 'Unknown' | 'cmHandleId' | new RuntimeException('Failed') || UNKNOWN_ERROR | 'Failed' - 'Invalid cm handle id' | 'cmHandleId with spaces' | new DataValidationException('Name Validation Error.', cmHandleId + 'contains an invalid character') || CM_HANDLE_INVALID_ID | 'cm-handle has an invalid character(s) in id' + scenario | cmHandleId | exception || expectedError | expectedErrorText + 'Cm Handle does not exist' | 'cmHandleId' | new DataNodeNotFoundException(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR) || CM_HANDLES_NOT_FOUND | 'cm handle id(s) not found' + 'Unknown' | 'cmHandleId' | new RuntimeException('Failed') || UNKNOWN_ERROR | 'Failed' + 'Invalid cm handle id' | 'cmHandleId with spaces' | new DataValidationException('Name Validation Error.', cmHandleId + 'contains an invalid character') || CM_HANDLE_INVALID_ID | 'cm-handle has an invalid character(s) in id' } def 'Multiple update operations in a single request'() { @@ -177,42 +183,44 @@ class NetworkCmProxyDataServicePropertyHandlerSpec extends Specification { assert it.errorText == 'cm handle id(s) not found' } then: 'the replace list method is called twice' - 2 * mockInventoryPersistence.replaceListContent(cmHandleXpath,_) + 2 * mockInventoryPersistence.replaceListContent(cmHandleXpath, _) } - def 'Update CM Handle Alternate ID with #scenario'() { - given: 'an existing cm handle' - DataNode existingCmHandleDataNode = new DataNode(xpath: cmHandleXpath, leaves: ['id': cmHandleId]) - and: 'an update request with an alternate id' - def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: 'alt-1') - when: 'update alternate id method is called with the update request' - objectUnderTest.updateAlternateId(existingCmHandleDataNode, ncmpServiceCmHandle) - then: 'the update node leaves method is invoked as many times as expected' - callsToDataService * mockCpsDataService.updateNodeLeaves('NCMP-Admin', 'ncmp-dmi-registry', '/dmi-registry', _, _) >> + def 'Update alternate id of existing CM Handle.'() { + given: 'cm handles request' + def cmHandleUpdateRequest = [new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: 'alt-1')] + and: 'a data node found' + def dataNode = new DataNode(xpath: cmHandleXpath, leaves: ['id': cmHandleId, 'alternate-id': 'alt-1']) + mockInventoryPersistence.getCmHandleDataNodeByCmHandleId(cmHandleId) >> [dataNode] + when: 'cm handle properties is updated' + def response = objectUnderTest.updateCmHandleProperties(cmHandleUpdateRequest) + then: 'the update is delegated to cps data service with correct parameters' + 1 * mockCpsDataService.updateNodeLeaves('NCMP-Admin', 'ncmp-dmi-registry', '/dmi-registry', _, _) >> { args -> assert args[3].contains('alt-1') } - mockAlternateIdChecker.canApplyAlternateId(cmHandleId, '','alt-1') >> isNewMapping - where: 'following updates are attempted' - scenario | isNewMapping || callsToDataService - 'new alternate id ' | true || 1 - 'existing alternate id' | false || 0 + and: 'one successful registration response' + response.size() == 1 + and: 'the response shows success for the given cm handle id' + assert response[0].status == Status.SUCCESS + assert response[0].cmHandle == cmHandleId } - def 'Alternate ID removed from cache when persisting fails.'() { - given: 'an existing data node and an update request with an alternate id' - def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: 'alt-1') - DataNode existingCmHandleDataNode = new DataNode(xpath: cmHandleXpath, leaves: ['id': cmHandleId, 'alternate-id': null]) - and: 'an applicable alternate id for the cm handle' - mockAlternateIdChecker.canApplyAlternateId(cmHandleId, '','alt-1') >> true - and: 'but an exception occurs while saving' - def originalException = new NullPointerException('some exception') - mockCpsDataService.updateNodeLeaves(*_) >> { throw originalException } - when: 'updating of alternate id called' - objectUnderTest.updateAlternateId(existingCmHandleDataNode, ncmpServiceCmHandle) - then: 'the original exception is thrown up' - def thrownException = thrown(NullPointerException) - assert thrownException == originalException + def 'Update with rejected alternate id.'() { + given: 'cm handles request' + def updatedNcmpServiceCmHandles = [new NcmpServiceCmHandle(cmHandleId: cmHandleId, alternateId: 'alt-1')] + and: 'a data node found' + def dataNode = new DataNode(xpath: cmHandleXpath, leaves: ['id': cmHandleId, 'alternate-id': 'alt-1']) + mockInventoryPersistence.getCmHandleDataNodeByCmHandleId(cmHandleId) >> [dataNode] + when: 'attempt to update the cm handle' + def response = objectUnderTest.updateCmHandleProperties(updatedNcmpServiceCmHandles) + then: 'the update is NOT delegated to cps data service' + 0 * mockCpsDataService.updateNodeLeaves(*_) + and: 'the alternate id checker rejects the given cm handle (override default setup behavior)' + mockAlternateIdChecker.getIdsOfCmHandlesWithRejectedAlternateId(*_) >> [cmHandleId] + and: 'the response shows a failure for the given cm handle id' + assert response[0].status == Status.FAILURE + assert response[0].cmHandle == cmHandleId } def convertToProperties(expectedPropertiesAfterUpdateAsMap) { 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 0176de7147..c8e34b1a5e 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 2229b32b0c..7d8ac7485b 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<Object>(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,16 +105,16 @@ class DmiDataOperationsSpec extends DmiOperationsBaseSpec { def responseFromDmi = new ResponseEntity<Object>(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' - objectUnderTest.requestResourceDataFromDmi('my-topic-name', dataOperationRequest, 'requestId') + objectUnderTest.requestResourceDataFromDmi('my-topic-name', dataOperationRequest, 'requestId', NO_AUTH_HEADER) then: 'validate the post operation was called and ncmp generated dmi request body json args' new PollingConditions().within(1) { assert postOperationWithJsonDataMethodCalled == true @@ -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<Object>(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<Object>(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 a105f84ebe..ae17c56ef3 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<String>(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/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy index aaa034437c..0eabaa1d28 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/AlternateIdCheckerSpec.groovy @@ -20,7 +20,6 @@ package org.onap.cps.ncmp.api.impl.utils - import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle @@ -68,25 +67,41 @@ class AlternateIdCheckerSpec extends Specification { 'other alternate id' || false } - def 'Check a batch of NEW cm handles with #scenario.'() { + def 'Check a batch of created cm handles with #scenario.'() { given: 'a batch of 2 new cm handles alternate id ids #alt1 and #alt2' def batch = [new NcmpServiceCmHandle(cmHandleId: 'ch-1', alternateId: alt1), new NcmpServiceCmHandle(cmHandleId: 'ch-2', alternateId: alt2)] - and: 'the database already contains cm handle(s) with these alternate ids: #alreadyinDb' + and: 'the database already contains cm handle(s) with these alternate ids: #altAlreadyInDb' mockInventoryPersistenceService.getCmHandleDataNodeByAlternateId(_) >> { args -> altAlreadyInDb.contains(args[0]) ? new DataNode() : throwDataNodeNotFoundException() } when: 'the batch of new cm handles is checked' - def result = objectUnderTest.getIdsOfCmHandlesWithRejectedAlternateId(batch) - then: 'the result only contains the ids of the acceptable cm handles' - assert result.contains('ch-1') == rejectCh1 - assert result.contains('ch-2') == rejectCh2 + def result = objectUnderTest.getIdsOfCmHandlesWithRejectedAlternateId(batch, AlternateIdChecker.Operation.CREATE) + then: 'the result contains ids of the rejected cm handles' + assert result == expectedRejectedCmHandleIds where: 'the following alternate ids are used' - scenario | alt1 | alt2 | altAlreadyInDb || rejectCh1 | rejectCh2 - 'no alternate ids' | '' | '' | ['dont matter'] || false | false - 'new alternate ids' | 'fdn1' | 'fdn2' | ['other fdn'] || false | false - 'one already used alternate id' | 'fdn1' | 'fdn2' | ['fdn1'] || true | false - 'two already used alternate ids' | 'fdn1' | 'fdn2' | ['fdn1','fdn2'] || true | true - 'duplicate alternate id in batch' | 'fdn1' | 'fdn1' | ['dont matter'] || false | true + scenario | alt1 | alt2 | altAlreadyInDb || expectedRejectedCmHandleIds + 'no alternate ids' | '' | '' | ['dont matter'] || [] + 'new alternate ids' | 'fdn1' | 'fdn2' | ['other fdn'] || [] + 'one already used alternate id' | 'fdn1' | 'fdn2' | ['fdn1'] || ['ch-1'] + 'duplicate alternate id in batch' | 'fdn1' | 'fdn1' | ['dont matter'] || ['ch-2'] + } + + def 'Check a batch of updates to existing cm handles with #scenario.'() { + given: 'a batch of 1 existing cm handle update alternate id to #proposedAlt' + def batch = [new NcmpServiceCmHandle(cmHandleId: 'ch-1', alternateId: proposedAlt)] + and: 'the database already contains a cm handle with alternate id: #altAlreadyInDb' + mockInventoryPersistenceService.getCmHandleDataNodeByAlternateId(_) >> + { args -> altAlreadyInDb.equals(args[0]) ? new DataNode() : throwDataNodeNotFoundException() } + mockInventoryPersistenceService.getYangModelCmHandle(_) >> new YangModelCmHandle(alternateId: altAlreadyInDb) + when: 'the batch of cm handle updates is checked' + def result = objectUnderTest.getIdsOfCmHandlesWithRejectedAlternateId(batch, AlternateIdChecker.Operation.UPDATE) + then: 'the result contains ids of the rejected cm handles' + assert result == expectedRejectedCmHandleIds + where: 'the following parameters are used' + scenario | proposedAlt | altAlreadyInDb || expectedRejectedCmHandleIds + 'no alternate id' | 'fdn1' | '' || [] + 'used the same alternate id' | 'fdn1' | 'fdn1' || [] + 'used different alternate id' | 'otherFdn' | 'fdn1' || ['ch-1'] } def throwDataNodeNotFoundException() { diff --git a/cps-parent/pom.xml b/cps-parent/pom.xml index 5c49cbeeeb..699bf3c9ac 100644 --- a/cps-parent/pom.xml +++ b/cps-parent/pom.xml @@ -32,7 +32,7 @@ <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <packaging>pom</packaging> <properties> @@ -118,7 +118,7 @@ <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> - <version>3.2.2</version> + <version>3.1.2</version> <executions> <execution> <goals> diff --git a/cps-path-parser/pom.xml b/cps-path-parser/pom.xml index 023ab19696..fb161c7d56 100644 --- a/cps-path-parser/pom.xml +++ b/cps-path-parser/pom.xml @@ -23,7 +23,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> diff --git a/cps-rest/docs/openapi/cpsAdmin.yml b/cps-rest/docs/openapi/cpsAdmin.yml index f60a9be6ff..f394270dd5 100644 --- a/cps-rest/docs/openapi/cpsAdmin.yml +++ b/cps-rest/docs/openapi/cpsAdmin.yml @@ -33,8 +33,6 @@ dataspaces: $ref: 'components.yml#/components/responses/NoContent' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '409': @@ -63,8 +61,6 @@ schemaSet: $ref: 'components.yml#/components/schemas/SchemaSetDetails' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '500': @@ -90,8 +86,6 @@ schemaSetBySchemaSetName: $ref: 'components.yml#/components/schemas/SchemaSetDetails' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '500': @@ -111,8 +105,6 @@ schemaSetBySchemaSetName: $ref: 'components.yml#/components/responses/NoContent' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '409': @@ -141,8 +133,6 @@ anchorsByDataspace: $ref: 'components.yml#/components/schemas/AnchorDetails' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '500': @@ -168,8 +158,6 @@ anchorByDataspaceAndAnchorName: $ref: 'components.yml#/components/schemas/AnchorDetails' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '500': @@ -189,8 +177,6 @@ anchorByDataspaceAndAnchorName: $ref: 'components.yml#/components/responses/NoContent' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '500': @@ -216,8 +202,6 @@ adminDataspaces: $ref: 'components.yml#/components/schemas/DataspaceDetails' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '500': @@ -242,8 +226,6 @@ adminDataspace: $ref: 'components.yml#/components/schemas/DataspaceDetails' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '500': diff --git a/cps-rest/docs/openapi/cpsAdminV1Deprecated.yml b/cps-rest/docs/openapi/cpsAdminV1Deprecated.yml index 56f7f1b4fc..c92f773c30 100644 --- a/cps-rest/docs/openapi/cpsAdminV1Deprecated.yml +++ b/cps-rest/docs/openapi/cpsAdminV1Deprecated.yml @@ -31,8 +31,6 @@ dataspaces: $ref: 'components.yml#/components/responses/Created' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '409': @@ -57,8 +55,6 @@ anchorsByDataspace: $ref: 'components.yml#/components/responses/Created' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '409': @@ -88,8 +84,6 @@ schemaSet: $ref: 'components.yml#/components/responses/Created' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '409': diff --git a/cps-rest/docs/openapi/cpsAdminV2.yml b/cps-rest/docs/openapi/cpsAdminV2.yml index 14e2cfe047..e501ad8b15 100644 --- a/cps-rest/docs/openapi/cpsAdminV2.yml +++ b/cps-rest/docs/openapi/cpsAdminV2.yml @@ -30,8 +30,6 @@ dataspaces: $ref: 'components.yml#/components/responses/CreatedV2' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '409': @@ -55,8 +53,6 @@ anchorsByDataspace: $ref: 'components.yml#/components/responses/CreatedV2' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '409': @@ -85,8 +81,6 @@ schemaSet: $ref: 'components.yml#/components/responses/CreatedV2' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '409': diff --git a/cps-rest/docs/openapi/cpsData.yml b/cps-rest/docs/openapi/cpsData.yml index 0a032e4be0..b9d2e5940e 100644 --- a/cps-rest/docs/openapi/cpsData.yml +++ b/cps-rest/docs/openapi/cpsData.yml @@ -46,8 +46,6 @@ listElementByDataspaceAndAnchor: $ref: 'components.yml#/components/responses/Created' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '500': @@ -78,8 +76,6 @@ listElementByDataspaceAndAnchor: $ref: 'components.yml#/components/responses/Ok' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '500': @@ -122,8 +118,6 @@ nodesByDataspaceAndAnchor: $ref: 'components.yml#/components/responses/Created' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '409': @@ -157,8 +151,6 @@ nodesByDataspaceAndAnchor: $ref: 'components.yml#/components/responses/Ok' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '500': @@ -180,8 +172,6 @@ nodesByDataspaceAndAnchor: $ref: 'components.yml#/components/responses/NoContent' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '500': @@ -212,8 +202,6 @@ nodesByDataspaceAndAnchor: $ref: 'components.yml#/components/responses/Ok' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '500': diff --git a/cps-rest/docs/openapi/cpsDataV1Deprecated.yml b/cps-rest/docs/openapi/cpsDataV1Deprecated.yml index 67ddecd2a4..3941856422 100644 --- a/cps-rest/docs/openapi/cpsDataV1Deprecated.yml +++ b/cps-rest/docs/openapi/cpsDataV1Deprecated.yml @@ -41,8 +41,6 @@ nodeByDataspaceAndAnchor: $ref: 'components.yml#/components/examples/dataSample' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '500': @@ -67,8 +65,6 @@ listElementByDataspaceAndAnchor: $ref: 'components.yml#/components/responses/NoContent' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '500': diff --git a/cps-rest/docs/openapi/cpsDataV2.yml b/cps-rest/docs/openapi/cpsDataV2.yml index c7629b70ec..cbb5ce4104 100644 --- a/cps-rest/docs/openapi/cpsDataV2.yml +++ b/cps-rest/docs/openapi/cpsDataV2.yml @@ -40,8 +40,6 @@ nodeByDataspaceAndAnchor: $ref: 'components.yml#/components/examples/dataSample' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '500': @@ -73,8 +71,6 @@ deltaByDataspaceAndAnchors: $ref: 'components.yml#/components/examples/deltaReportSample' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '500': diff --git a/cps-rest/docs/openapi/cpsQueryV1Deprecated.yml b/cps-rest/docs/openapi/cpsQueryV1Deprecated.yml index 6ec117f313..9db2823994 100644 --- a/cps-rest/docs/openapi/cpsQueryV1Deprecated.yml +++ b/cps-rest/docs/openapi/cpsQueryV1Deprecated.yml @@ -43,8 +43,6 @@ nodesByDataspaceAndAnchorAndCpsPath: $ref: 'components.yml#/components/examples/dataSample' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '500': diff --git a/cps-rest/docs/openapi/cpsQueryV2.yml b/cps-rest/docs/openapi/cpsQueryV2.yml index 4443fb17ec..7f0ceff768 100644 --- a/cps-rest/docs/openapi/cpsQueryV2.yml +++ b/cps-rest/docs/openapi/cpsQueryV2.yml @@ -40,8 +40,6 @@ nodesByDataspaceAndAnchorAndCpsPath: $ref: 'components.yml#/components/examples/dataSample' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '500': @@ -73,8 +71,6 @@ nodesByDataspaceAndCpsPath: $ref: 'components.yml#/components/examples/dataSampleAcrossAnchors' '400': $ref: 'components.yml#/components/responses/BadRequest' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' '403': $ref: 'components.yml#/components/responses/Forbidden' '500': diff --git a/cps-rest/pom.xml b/cps-rest/pom.xml index 0af6a360e3..9e484afccc 100644 --- a/cps-rest/pom.xml +++ b/cps-rest/pom.xml @@ -28,7 +28,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> diff --git a/cps-ri/pom.xml b/cps-ri/pom.xml index bd99be153d..a6e1e10e45 100644 --- a/cps-ri/pom.xml +++ b/cps-ri/pom.xml @@ -26,7 +26,7 @@ <parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.4.6-SNAPSHOT</version>
+ <version>3.4.7-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
@@ -71,7 +71,7 @@ <!-- Add Hibernate support for Postgres datatype JSONB and Postgres arrays -->
<dependency>
<groupId>io.hypersistence</groupId>
- <artifactId>hypersistence-utils-hibernate-63</artifactId>
+ <artifactId>hypersistence-utils-hibernate-60</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java index b449a789b0..b0f9a2da52 100755 --- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java @@ -69,7 +69,6 @@ import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; import org.opendaylight.yangtools.yang.parser.api.YangSyntaxErrorException; import org.opendaylight.yangtools.yang.parser.rfc7950.repo.YangModelDependencyInfo; import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.retry.RetryContext; import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Retryable; import org.springframework.retry.support.RetrySynchronizationManager; @@ -278,8 +277,8 @@ public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceServ dataIntegrityViolationException, newYangResourceEntities); convertedException.ifPresent( e -> { - final RetryContext context = RetrySynchronizationManager.getContext(); - int retryCount = context == null ? 0 : context.getRetryCount(); + int retryCount = RetrySynchronizationManager.getContext() == null ? 0 + : RetrySynchronizationManager.getContext().getRetryCount(); log.warn("Cannot persist duplicated yang resource. System will attempt this method " + "up to 5 times. Current retry count : {}", ++retryCount, e); }); diff --git a/cps-service/pom.xml b/cps-service/pom.xml index fdc8177e44..58716f3f16 100644 --- a/cps-service/pom.xml +++ b/cps-service/pom.xml @@ -29,7 +29,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> @@ -142,6 +142,11 @@ </dependency> <!-- T E S T D E P E N D E N C I E S --> <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-test</artifactId> + <scope>test</scope> + </dependency> + <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy</artifactId> <scope>test</scope> diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/pom.xml b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/pom.xml index fffce8d05d..9b424a5ef0 100644 --- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/pom.xml +++ b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-app/pom.xml @@ -22,7 +22,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>dmi-plugin-demo-and-csit-stub</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> </parent> <artifactId>dmi-plugin-demo-and-csit-stub-app</artifactId> @@ -103,5 +103,15 @@ <artifactId>dmi-plugin-demo-and-csit-stub-service</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + <version>11.0.16</version> + </dependency> + <dependency> + <groupId>jakarta.servlet</groupId> + <artifactId>jakarta.servlet-api</artifactId> + <version>6.0.0</version> + </dependency> </dependencies> </project>
\ No newline at end of file diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/pom.xml b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/pom.xml index bddeab1872..ac9eeada5c 100644 --- a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/pom.xml +++ b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/pom.xml @@ -21,7 +21,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>dmi-plugin-demo-and-csit-stub</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> </parent> <artifactId>dmi-plugin-demo-and-csit-stub-service</artifactId> 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 1819dcc47b..b536c75fb6 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; @@ -89,7 +90,7 @@ public class DmiRestStubController { * @return ResponseEntity response entity having module response as json string. */ @PostMapping("/v1/ch/{cmHandleId}/modules") - public ResponseEntity<String> getModuleReferences(@PathVariable("cmHandleId") final String cmHandleId, + public ResponseEntity<String> getModuleReferences(@PathVariable final String cmHandleId, @RequestBody final Object moduleReferencesRequest) { delay(moduleReferencesDelayMs); final String moduleResponseContent = getModuleResourceResponse(cmHandleId, @@ -108,7 +109,7 @@ public class DmiRestStubController { */ @PostMapping("/v1/ch/{cmHandleId}/moduleResources") public ResponseEntity<String> retrieveModuleResources( - @PathVariable("cmHandleId") final String cmHandleId, + @PathVariable final String cmHandleId, @RequestBody final Object moduleResourcesReadRequest) { delay(moduleResourcesDelayMs); final String moduleResourcesResponseContent = getModuleResourceResponse(cmHandleId, @@ -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")); diff --git a/dmi-plugin-demo-and-csit-stub/pom.xml b/dmi-plugin-demo-and-csit-stub/pom.xml index ede50da81a..4cec8e6ac4 100644 --- a/dmi-plugin-demo-and-csit-stub/pom.xml +++ b/dmi-plugin-demo-and-csit-stub/pom.xml @@ -22,7 +22,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> diff --git a/docs/api/swagger/cps/openapi.yaml b/docs/api/swagger/cps/openapi.yaml index bade85ef1a..2798b78643 100644 --- a/docs/api/swagger/cps/openapi.yaml +++ b/docs/api/swagger/cps/openapi.yaml @@ -55,16 +55,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -134,16 +124,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -202,16 +182,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -279,16 +249,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -351,16 +311,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -429,16 +379,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -511,16 +451,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -595,16 +525,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -671,16 +591,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -749,16 +659,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -826,16 +726,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -907,16 +797,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -991,16 +871,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1067,16 +937,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1155,16 +1015,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1250,16 +1100,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1347,16 +1187,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1444,16 +1274,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1556,16 +1376,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1680,16 +1490,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1801,16 +1601,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1886,16 +1676,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1994,16 +1774,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -2103,16 +1873,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -2205,16 +1965,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -2300,16 +2050,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -2396,16 +2136,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -2502,16 +2232,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -2766,16 +2486,6 @@ components: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - Unauthorized: - content: - application/json: - example: - status: 401 - message: Unauthorized request - details: This request is unauthorized - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized Forbidden: content: application/json: diff --git a/docs/api/swagger/ncmp/openapi-inventory.yaml b/docs/api/swagger/ncmp/openapi-inventory.yaml index 53f51f3f8b..ff9f4ba683 100644 --- a/docs/api/swagger/ncmp/openapi-inventory.yaml +++ b/docs/api/swagger/ncmp/openapi-inventory.yaml @@ -32,16 +32,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -115,16 +105,6 @@ paths: type: string type: array description: OK - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -169,16 +149,6 @@ paths: type: string type: array description: OK - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -226,16 +196,6 @@ components: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - Unauthorized: - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized Forbidden: content: application/json: diff --git a/docs/api/swagger/ncmp/openapi.yaml b/docs/api/swagger/ncmp/openapi.yaml index a1cc5d9ba7..9203b6d4ca 100644 --- a/docs/api/swagger/ncmp/openapi.yaml +++ b/docs/api/swagger/ncmp/openapi.yaml @@ -56,6 +56,12 @@ paths: default: application/json example: application/yang-data+json type: string + - description: Authorization parameter for request. + in: header + name: Authorization + required: false + schema: + type: string responses: "204": content: {} @@ -70,16 +76,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -199,6 +195,12 @@ paths: schema: default: false type: boolean + - description: Authorization parameter for request. + in: header + name: Authorization + required: false + schema: + type: string responses: "200": content: @@ -220,16 +222,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -312,6 +304,12 @@ paths: default: application/json example: application/yang-data+json type: string + - description: Authorization parameter for request. + in: header + name: Authorization + required: false + schema: + type: string requestBody: content: '*/*': @@ -339,16 +337,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -430,6 +418,12 @@ paths: default: application/json example: application/yang-data+json type: string + - description: Authorization parameter for request. + in: header + name: Authorization + required: false + schema: + type: string requestBody: content: application/json: @@ -461,16 +455,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -553,6 +537,12 @@ paths: default: application/json example: application/yang-data+json type: string + - description: Authorization parameter for request. + in: header + name: Authorization + required: false + schema: + type: string requestBody: content: application/json: @@ -587,16 +577,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -649,6 +629,12 @@ paths: required: true schema: type: string + - description: Authorization parameter for request. + in: header + name: Authorization + required: false + schema: + type: string requestBody: content: application/json: @@ -672,16 +658,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -806,16 +782,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -883,16 +849,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -954,16 +910,6 @@ paths: $ref: '#/components/schemas/RestModuleDefinition' type: array description: OK - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1041,16 +987,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1104,16 +1040,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "404": content: application/json: @@ -1167,16 +1093,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "404": content: application/json: @@ -1254,16 +1170,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1327,16 +1233,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "404": content: application/json: @@ -1399,16 +1295,6 @@ paths: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - "401": - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized "403": content: application/json: @@ -1645,6 +1531,13 @@ components: schema: default: false type: boolean + authorizationParamInHeader: + description: Authorization parameter for request. + in: header + name: Authorization + required: false + schema: + type: string contentParamInHeader: description: "Content parameter for request, if content parameter is null, default\ \ value is application/json." @@ -1716,16 +1609,6 @@ components: schema: $ref: '#/components/schemas/ErrorMessage' description: Bad Request - Unauthorized: - content: - application/json: - example: - status: 401 - message: Unauthorized error message - details: Unauthorized error details - schema: - $ref: '#/components/schemas/ErrorMessage' - description: Unauthorized Forbidden: content: application/json: diff --git a/docs/release-notes.rst b/docs/release-notes.rst index a134d0d944..e79a188ef5 100644 --- a/docs/release-notes.rst +++ b/docs/release-notes.rst @@ -16,6 +16,33 @@ CPS Release Notes .. * * * NEW DELHI * * * .. ========================= +Version: 3.4.7 +============== + +Release Data +------------ + ++--------------------------------------+--------------------------------------------------------+ +| **CPS Project** | | +| | | ++--------------------------------------+--------------------------------------------------------+ +| **Docker images** | onap/cps-and-ncmp:3.4.7 | +| | | ++--------------------------------------+--------------------------------------------------------+ +| **Release designation** | 3.4.7 New Delhi | +| | | ++--------------------------------------+--------------------------------------------------------+ +| **Release date** | Not yet released | +| | | ++--------------------------------------+--------------------------------------------------------+ + +Bug Fixes +--------- +3.4.7 + +Features +-------- + Version: 3.4.6 ============== @@ -32,17 +59,27 @@ Release Data | **Release designation** | 3.4.6 New Delhi | | | | +--------------------------------------+--------------------------------------------------------+ -| **Release date** | Not yet released | +| **Release date** | 2024 February 29 | | | | +--------------------------------------+--------------------------------------------------------+ Bug Fixes --------- 3.4.6 + - `CPS-2126 <https://jira.onap.org/browse/CPS-2126>`_ Passing HTTP Authorization Bearer Token to DMI Plugins. Features -------- + - `CPS-2133 <https://jira.onap.org/browse/CPS-2133>`_ Revert Uplift of Spring Boot version from 3.2.2 to 3.1.2 + +Notes +----- +This release brings improvements to compatibility with Service Mesh and for that below measures are been taken. + +Basic authorization provided using Spring security is been removed from CPS-Core and NCMP and hence authorization is no longer enforced.(basic auth header will be ignored, but is still allowed). +NCMP will propagate a bearer token to DMI conditionally. +401 Unauthorized will not be returned. Best effort has been made to ensure backwards compatibility. Version: 3.4.5 ============== diff --git a/integration-test/pom.xml b/integration-test/pom.xml index 04280b9b3d..b379e9ff19 100644 --- a/integration-test/pom.xml +++ b/integration-test/pom.xml @@ -23,7 +23,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> <modelVersion>4.0.0</modelVersion> diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy index 23504e49cd..1577524f2c 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy @@ -41,12 +41,14 @@ import org.onap.cps.spi.utils.SessionManager import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.autoconfigure.EnableAutoConfiguration import org.springframework.boot.autoconfigure.domain.EntityScan +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc import org.springframework.boot.test.context.SpringBootTest import org.springframework.context.annotation.ComponentScan import org.springframework.data.jpa.repository.config.EnableJpaRepositories import org.springframework.http.HttpStatus import org.springframework.http.MediaType import org.springframework.test.web.client.MockRestServiceServer +import org.springframework.test.web.servlet.MockMvc import org.springframework.web.client.RestTemplate import org.testcontainers.spock.Testcontainers import spock.lang.Shared @@ -56,9 +58,10 @@ import spock.util.concurrent.PollingConditions import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus -@SpringBootTest(classes = [CpsDataspaceService]) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = [CpsDataspaceService]) @Testcontainers @EnableAutoConfiguration +@AutoConfigureMockMvc @EnableJpaRepositories(basePackageClasses = [DataspaceRepository]) @ComponentScan(basePackages = ['org.onap.cps']) @EntityScan('org.onap.cps.spi.entities') @@ -68,6 +71,9 @@ abstract class CpsIntegrationSpecBase extends Specification { DatabaseTestContainer databaseTestContainer = DatabaseTestContainer.getInstance() @Autowired + MockMvc mvc; + + @Autowired CpsDataspaceService cpsDataspaceService @Autowired diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpBearerTokenPassthroughSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpBearerTokenPassthroughSpec.groovy new file mode 100644 index 0000000000..0dabbf30a4 --- /dev/null +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpBearerTokenPassthroughSpec.groovy @@ -0,0 +1,124 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.integration.functional + +import java.time.Duration +import org.onap.cps.integration.base.CpsIntegrationSpecBase +import org.springframework.http.HttpHeaders +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.test.web.client.match.MockRestRequestMatchers + +import static org.springframework.http.HttpMethod.GET +import static org.springframework.http.HttpMethod.DELETE +import static org.springframework.http.HttpMethod.PATCH +import static org.springframework.http.HttpMethod.POST +import static org.springframework.http.HttpMethod.PUT +import static org.springframework.test.web.client.match.MockRestRequestMatchers.method +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo +import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.request +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status + +class NcmpBearerTokenPassthroughSpec extends CpsIntegrationSpecBase { + + static final NO_MODULE_SET_TAG = '' + static final MODULE_REFERENCES_RESPONSE = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_Response.json') + static final MODULE_RESOURCES_RESPONSE = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_ResourcesResponse.json') + + def setup() { + registerCmHandle(DMI_URL, 'ch-1', NO_MODULE_SET_TAG, MODULE_REFERENCES_RESPONSE, MODULE_RESOURCES_RESPONSE) + } + + def cleanup() { + deregisterCmHandle(DMI_URL, 'ch-1') + } + + def 'Bearer token is passed from NCMP to DMI in pass-through data operations.'() { + given: 'DMI will expect to receive a request with a bearer token' + def targetDmiUrl = "$DMI_URL/dmi/v1/ch/ch-1/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=my-resource-id" + mockDmiServer.expect(requestTo(targetDmiUrl)) + .andExpect(MockRestRequestMatchers.header(HttpHeaders.AUTHORIZATION, 'Bearer some-bearer-token')) + .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)) + + when: 'a pass-through data request is sent to NCMP with a bearer token' + mvc.perform(request(httpMethod, '/ncmp/v1/ch/ch-1/data/ds/ncmp-datastore:passthrough-running') + .queryParam('resourceIdentifier', 'my-resource-id') + .contentType(MediaType.APPLICATION_JSON) + .content('{ "some-json": "data" }') + .header(HttpHeaders.AUTHORIZATION, 'Bearer some-bearer-token')) + .andExpect(status().is2xxSuccessful()) + + then: 'DMI has received request with bearer token' + mockDmiServer.verify() + + where: 'all HTTP operations are applied' + httpMethod << [GET, POST, PUT, PATCH, DELETE] + } + + def 'Basic auth header is NOT passed from NCMP to DMI in pass-through data operations.'() { + given: 'DMI will expect to receive a request with no authorization header' + def targetDmiUrl = "$DMI_URL/dmi/v1/ch/ch-1/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=my-resource-id" + mockDmiServer.expect(requestTo(targetDmiUrl)) + .andExpect(MockRestRequestMatchers.headerDoesNotExist(HttpHeaders.AUTHORIZATION)) + .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)) + + when: 'a pass-through data request is sent to NCMP with basic authentication' + mvc.perform(request(httpMethod, '/ncmp/v1/ch/ch-1/data/ds/ncmp-datastore:passthrough-running') + .queryParam('resourceIdentifier', 'my-resource-id') + .contentType(MediaType.APPLICATION_JSON) + .content('{ "some-json": "data" }') + .header(HttpHeaders.AUTHORIZATION, 'Basic Y3BzdXNlcjpjcHNyMGNrcyE=')) + .andExpect(status().is2xxSuccessful()) + + then: 'DMI has received request with no authorization header' + mockDmiServer.verify() + + where: 'all HTTP operations are applied' + httpMethod << [GET, POST, PUT, PATCH, DELETE] + } + + def 'Bearer token is passed from NCMP to DMI in async batch pass-through data operation.'() { + given: 'DMI will expect to receive a request with a bearer token' + mockDmiServer.expect(method(POST)) + .andExpect(MockRestRequestMatchers.header(HttpHeaders.AUTHORIZATION, 'Bearer some-bearer-token')) + .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)) + + when: 'a pass-through async data request is sent to NCMP with a bearer token' + def requestBody = """{"operations": [{ + "operation": "read", + "operationId": "operational-1", + "datastore": "ncmp-datastore:passthrough-running", + "resourceIdentifier": "my-resource-id", + "targetIds": ["ch-1"] + }]}""" + mvc.perform(request(POST, '/ncmp/v1/data') + .queryParam('topic', 'my-topic') + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + .header(HttpHeaders.AUTHORIZATION, 'Bearer some-bearer-token')) + .andExpect(status().is2xxSuccessful()) + + then: 'DMI will receive the async request with bearer token' + mockDmiServer.verify(Duration.ofSeconds(1)) + } + +} diff --git a/integration-test/src/test/resources/application.yml b/integration-test/src/test/resources/application.yml index f77cb02f7a..3d61bdbea6 100644 --- a/integration-test/src/test/resources/application.yml +++ b/integration-test/src/test/resources/application.yml @@ -112,7 +112,7 @@ app: topic: ${DMI_DEVICE_HEARTBEAT_TOPIC:dmi-device-heartbeat} notification: - enabled: false + enabled: true async: executor: core-pool-size: 2 diff --git a/jacoco-report/pom.xml b/jacoco-report/pom.xml index 99ddaa84b9..9e2f8b438c 100644 --- a/jacoco-report/pom.xml +++ b/jacoco-report/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>org.onap.cps</groupId> <artifactId>cps-parent</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <relativePath>../cps-parent/pom.xml</relativePath> </parent> <modelVersion>4.0.0</modelVersion> @@ -32,7 +32,7 @@ <groupId>org.onap.cps</groupId>
<artifactId>cps-aggregator</artifactId>
- <version>3.4.6-SNAPSHOT</version>
+ <version>3.4.7-SNAPSHOT</version>
<packaging>pom</packaging>
<name>cps</name>
diff --git a/postman-collections/CPS-CORE.postman_collection.json b/postman-collections/CPS-CORE.postman_collection.json index 24717bc59b..730f69eac5 100644 --- a/postman-collections/CPS-CORE.postman_collection.json +++ b/postman-collections/CPS-CORE.postman_collection.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "e86df76f-6b33-4648-ba66-ea9d3129c052", + "_postman_id": "e864733f-4781-45b6-8ea2-0b841a703dae", "name": "CPS-CORE", "description": "A collection of the endpoints in CPS-CORE. This is not an exhaustive collection but captures the main functionality.\n\nTo perform this functionality execute the API calls in order to create a dataspace, schema set (file is provided), anchor, and data node. Then GET the nodes to retrieve the information. The APIs in CPS-ADMIN can be used after initial POST requests.\n\nbookstore-model.yang can be found at cps/postman-collections/bookstore-model.yang", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", @@ -311,7 +311,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"bookstore-address\": [\n {\n \"bookstore-name\": \"Easons\",\n \"address\": \"Dublin,Ireland\",\n \"postal-code\": \"D02HA21\"\n }\n ],\n \"bookstore\": {\n \"bookstore-name\": \"Easons\",\n \"premises\": {\n \"addresses\": [\n {\n \"house-number\": 2,\n \"street\": \"Main Street\",\n \"town\": \"Maynooth\",\n \"county\": \"Kildare\"\n },\n {\n \"house-number\": 24,\n \"street\": \"Grafton Street\",\n \"town\": \"Dublin\",\n \"county\": \"Dublin\"\n }\n ]\n },\n \"categories\": [\n {\n \"code\": 1,\n \"name\": \"Children\",\n \"books\": [\n {\n \"title\": \"Matilda\",\n \"lang\": \"English\",\n \"authors\": [\n \"Roald Dahl\"\n ],\n \"editions\": [\n 1988,\n 2000\n ],\n \"price\": 20\n },\n {\n \"title\": \"The Gruffalo\",\n \"lang\": \"English\",\n \"authors\": [\n \"Julia Donaldson\"\n ],\n \"editions\": [\n 1999\n ],\n \"price\": 15\n }\n ]\n },\n {\n \"code\": 2,\n \"name\": \"Thriller\",\n \"books\": [\n {\n \"title\": \"Annihilation\",\n \"lang\": \"English\",\n \"authors\": [\n \"Jeff VanderMeer\"\n ],\n \"editions\": [\n 2014\n ],\n \"price\": 15\n }\n ]\n },\n {\n \"code\": 3,\n \"name\": \"Comedy\",\n \"books\": [\n {\n \"title\": \"Good Omens\",\n \"lang\": \"English\",\n \"authors\": [\n \"Neil Gaiman\",\n \"Terry Pratchett\"\n ],\n \"editions\": [\n 2006\n ],\n \"price\": 13\n },\n {\n \"title\": \"The Colour of Magic\",\n \"lang\": \"English\",\n \"authors\": [\n \"Terry Pratchett\"\n ],\n \"editions\": [\n 1983\n ],\n \"price\": 12\n },\n {\n \"title\": \"The Light Fantastic\",\n \"lang\": \"English\",\n \"authors\": [\n \"Terry Pratchett\"\n ],\n \"editions\": [\n 1986\n ],\n \"price\": 14\n },\n {\n \"title\": \"A Book with No Language\",\n \"lang\": \"\",\n \"authors\": [\n \"Joe Bloggs\"\n ],\n \"editions\": [\n 2023\n ],\n \"price\": 20\n }\n ]\n },\n {\n \"code\": 4,\n \"name\": \"Computing\",\n \"books\": [\n {\n \"title\": \"Debian GNU/Linux\",\n \"lang\": \"German\",\n \"authors\": [\n \"Peter H. Ganten\",\n \"Wulf Alex\"\n ],\n \"editions\": [\n 2007,\n 2013,\n 2021\n ],\n \"price\": 39\n },\n {\n \"title\": \"Logarithm tables\",\n \"lang\": \"N/A\",\n \"authors\": [\n \"Joe Bloggs\"\n ],\n \"editions\": [\n 2009\n ],\n \"price\": 11\n }\n ]\n },\n {\n \"code\": 5,\n \"name\": \"Discount books\",\n \"books\": [\n {\n \"title\": \"Book 1\",\n \"lang\": \"blah\",\n \"authors\": [],\n \"editions\": [],\n \"price\": 1\n },\n {\n \"title\": \"Book 2\",\n \"lang\": \"blah\",\n \"authors\": [],\n \"editions\": [],\n \"price\": 2\n },\n {\n \"title\": \"Book 3\",\n \"lang\": \"blah\",\n \"authors\": [],\n \"editions\": [],\n \"price\": 3\n },\n {\n \"title\": \"Book 4\",\n \"lang\": \"blah\",\n \"authors\": [],\n \"editions\": [],\n \"price\": 4\n },\n {\n \"title\": \"Book 5\",\n \"lang\": \"blah\",\n \"authors\": [],\n \"editions\": [],\n \"price\": 5\n },\n {\n \"title\": \"Book 6\",\n \"lang\": \"blah\",\n \"authors\": [],\n \"editions\": [],\n \"price\": 6\n },\n {\n \"title\": \"Book 7\",\n \"lang\": \"blah\",\n \"authors\": [],\n \"editions\": [],\n \"price\": 7\n },\n {\n \"title\": \"Book 8\",\n \"lang\": \"blah\",\n \"authors\": [],\n \"editions\": [],\n \"price\": 8\n },\n {\n \"title\": \"Book 9\",\n \"lang\": \"blah\",\n \"authors\": [],\n \"editions\": [],\n \"price\": 9\n },\n {\n \"title\": \"Book 10\",\n \"lang\": \"blah\",\n \"authors\": [],\n \"editions\": [],\n \"price\": 10\n }\n ]\n }\n ]\n }\n}", + "raw": "{\n \"bookstore-address\": [\n {\n \"bookstore-name\": \"Easons\",\n \"address\": \"Dublin,Ireland\",\n \"postal-code\": \"D02HA21\"\n }\n ],\n \"bookstore\": {\n \"bookstore-name\": \"Easons\",\n \"premises\": {\n \"addresses\": [\n {\n \"house-number\": 2,\n \"street\": \"Main Street\",\n \"town\": \"Maynooth\",\n \"county\": \"Kildare\"\n },\n {\n \"house-number\": 24,\n \"street\": \"Grafton Street\",\n \"town\": \"Dublin\",\n \"county\": \"Dublin\"\n }\n ]\n },\n \"categories\": [\n {\n \"code\": 1,\n \"name\": \"Children\",\n \"books\" : [\n {\n \"title\": \"Matilda\",\n \"lang\": \"English\",\n \"authors\": [\"Roald Dahl\"],\n \"editions\": [1988, 2000],\n \"price\": 20\n },\n {\n \"title\": \"The Gruffalo\",\n \"lang\": \"English\",\n \"authors\": [\"Julia Donaldson\"],\n \"editions\": [1999],\n \"price\": 15\n }\n ]\n },\n {\n \"code\": 2,\n \"name\": \"Thriller\",\n \"books\" : [\n {\n \"title\": \"Annihilation\",\n \"lang\": \"English\",\n \"authors\": [\"Jeff VanderMeer\"],\n \"editions\": [2014],\n \"price\": 15\n }\n ]\n },\n {\n \"code\": 3,\n \"name\": \"Comedy\",\n \"books\" : [\n {\n \"title\": \"Good Omens\",\n \"lang\": \"English\",\n \"authors\": [\"Neil Gaiman\", \"Terry Pratchett\"],\n \"editions\": [2006],\n \"price\": 13\n },\n {\n \"title\": \"The Colour of Magic\",\n \"lang\": \"English\",\n \"authors\": [\"Terry Pratchett\"],\n \"editions\": [1983],\n \"price\": 12\n },\n {\n \"title\": \"The Light Fantastic\",\n \"lang\": \"English\",\n \"authors\": [\"Terry Pratchett\"],\n \"editions\": [1986],\n \"price\": 14\n },\n {\n \"title\": \"A Book with No Language\",\n \"lang\": \"\",\n \"authors\": [\"Joe Bloggs\"],\n \"editions\": [2023],\n \"price\": 20\n }\n ]\n },\n {\n \"code\": 4,\n \"name\": \"Computing\",\n \"books\" : [\n {\n \"title\": \"Debian GNU/Linux\",\n \"lang\": \"German\",\n \"authors\": [\"Peter H. Ganten\", \"Wulf Alex\"],\n \"editions\": [2007, 2013, 2021],\n \"price\": 39\n },\n {\n \"title\": \"Logarithm tables\",\n \"lang\": \"N/A\",\n \"authors\": [\"Joe Bloggs\"],\n \"editions\": [2009],\n \"price\": 11\n }\n ]\n },\n {\n \"code\": 5,\n \"name\": \"Discount books\",\n \"books\" : [\n {\n \"title\": \"Book 1\",\n \"lang\": \"blah\",\n \"authors\": [],\n \"editions\": [],\n \"price\": 1\n },\n {\n \"title\": \"Book 2\",\n \"lang\": \"blah\",\n \"authors\": [],\n \"editions\": [],\n \"price\": 2\n },\n {\n \"title\": \"Book 3\",\n \"lang\": \"blah\",\n \"authors\": [],\n \"editions\": [],\n \"price\": 3\n },\n {\n \"title\": \"Book 4\",\n \"lang\": \"blah\",\n \"authors\": [],\n \"editions\": [],\n \"price\": 4\n },\n {\n \"title\": \"Book 5\",\n \"lang\": \"blah\",\n \"authors\": [],\n \"editions\": [],\n \"price\": 5\n },\n {\n \"title\": \"Book 6\",\n \"lang\": \"blah\",\n \"authors\": [],\n \"editions\": [],\n \"price\": 6\n },\n {\n \"title\": \"Book 7\",\n \"lang\": \"blah\",\n \"authors\": [],\n \"editions\": [],\n \"price\": 7\n },\n {\n \"title\": \"Book 8\",\n \"lang\": \"blah\",\n \"authors\": [],\n \"editions\": [],\n \"price\": 8\n },\n {\n \"title\": \"Book 9\",\n \"lang\": \"blah\",\n \"authors\": [],\n \"editions\": [],\n \"price\": 9\n },\n {\n \"title\": \"Book 10\",\n \"lang\": \"blah\",\n \"authors\": [],\n \"editions\": [],\n \"price\": 10\n }\n ]\n }\n ]\n }\n}\n", "options": { "raw": { "language": "json" @@ -376,12 +376,12 @@ "response": [] }, { - "name": "Get Node Staff No Descendants", + "name": "Get Node Categories No Descendants", "request": { "method": "GET", "header": [], "url": { - "raw": "http://{{CPS_HOST}}:{{CPS_PORT}}/cps/api/v2/dataspaces/my-store/anchors/bookstore-anchor/node?xpath=/bookstore/staff&descendants=none", + "raw": "http://{{CPS_HOST}}:{{CPS_PORT}}/cps/api/v2/dataspaces/my-store/anchors/bookstore-anchor/node?xpath=/bookstore/categories&descendants=none", "protocol": "http", "host": [ "{{CPS_HOST}}" @@ -400,7 +400,7 @@ "query": [ { "key": "xpath", - "value": "/bookstore/staff" + "value": "/bookstore/categories" }, { "key": "descendants", @@ -412,12 +412,12 @@ "response": [] }, { - "name": "Get Node Inventory All Descendants", + "name": "Get Node Premises All Descendants", "request": { "method": "GET", "header": [], "url": { - "raw": "http://{{CPS_HOST}}:{{CPS_PORT}}/cps/api/v2/dataspaces/my-store/anchors/bookstore-anchor/node?xpath=/bookstore/inventory&descendants=all", + "raw": "http://{{CPS_HOST}}:{{CPS_PORT}}/cps/api/v2/dataspaces/my-store/anchors/bookstore-anchor/node?xpath=/bookstore/premises&descendants=all", "protocol": "http", "host": [ "{{CPS_HOST}}" @@ -436,7 +436,7 @@ "query": [ { "key": "xpath", - "value": "/bookstore/inventory" + "value": "/bookstore/premises" }, { "key": "descendants", @@ -448,12 +448,12 @@ "response": [] }, { - "name": "Get Node Inventory Categories Direct Descendants", + "name": "Get Node Categories with code 2 Direct Descendants", "request": { "method": "GET", "header": [], "url": { - "raw": "http://{{CPS_HOST}}:{{CPS_PORT}}/cps/api/v2/dataspaces/my-store/anchors/bookstore-anchor/node?xpath=/bookstore/inventory/categories[@code='2']&descendants=direct", + "raw": "http://{{CPS_HOST}}:{{CPS_PORT}}/cps/api/v2/dataspaces/my-store/anchors/bookstore-anchor/node?xpath=/bookstore/categories[@code='2']&descendants=direct", "protocol": "http", "host": [ "{{CPS_HOST}}" @@ -472,7 +472,7 @@ "query": [ { "key": "xpath", - "value": "/bookstore/inventory/categories[@code='2']" + "value": "/bookstore/categories[@code='2']" }, { "key": "descendants", @@ -489,7 +489,7 @@ "method": "GET", "header": [], "url": { - "raw": "http://{{CPS_HOST}}:{{CPS_PORT}}/cps/api/v2/dataspaces/my-store/anchors/bookstore-anchor/nodes/query?cps-path=/bookstore/inventory/categories[@numberOfBooks=1]&descendants=-1", + "raw": "http://{{CPS_HOST}}:{{CPS_PORT}}/cps/api/v2/dataspaces/my-store/anchors/bookstore-anchor/nodes/query?cps-path=/bookstore/categories[@name=\"Discount books\"]&descendants=-1", "protocol": "http", "host": [ "{{CPS_HOST}}" @@ -509,7 +509,7 @@ "query": [ { "key": "cps-path", - "value": "/bookstore/inventory/categories[@numberOfBooks=1]" + "value": "/bookstore/categories[@name=\"Discount books\"]" }, { "key": "descendants", @@ -526,7 +526,7 @@ "method": "GET", "header": [], "url": { - "raw": "http://{{CPS_HOST}}:{{CPS_PORT}}/cps/api/v2/dataspaces/my-store/anchors/bookstore-anchor/nodes/query?cps-path=//categories[@code=1]/ancestor::inventory&descendants=0", + "raw": "http://{{CPS_HOST}}:{{CPS_PORT}}/cps/api/v2/dataspaces/my-store/anchors/bookstore-anchor/nodes/query?cps-path=//books[@lang=\"German\"]/ancestor::categories&descendants=0", "protocol": "http", "host": [ "{{CPS_HOST}}" @@ -546,7 +546,7 @@ "query": [ { "key": "cps-path", - "value": "//categories[@code=1]/ancestor::inventory" + "value": "//books[@lang=\"German\"]/ancestor::categories" }, { "key": "descendants", @@ -564,7 +564,48 @@ "header": [], "body": { "mode": "raw", - "raw": "{\r\n \"staff\": {\r\n \"manager\": \"Jane Doe\",\r\n \"members\": [\r\n {\"name\": \"Some Guy\"},\r\n {\"name\": \"Another Person\"}\r\n ]\r\n }\r\n}", + "raw": "{\r\n \"bookstore\": {\r\n \"bookstore-name\": \"Chapters\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://{{CPS_HOST}}:{{CPS_PORT}}/cps/api/v2/dataspaces/my-store/anchors/bookstore-anchor/nodes?xpath=/", + "protocol": "http", + "host": [ + "{{CPS_HOST}}" + ], + "port": "{{CPS_PORT}}", + "path": [ + "cps", + "api", + "v2", + "dataspaces", + "my-store", + "anchors", + "bookstore-anchor", + "nodes" + ], + "query": [ + { + "key": "xpath", + "value": "/" + } + ] + } + }, + "response": [] + }, + { + "name": "Put Nodes", + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "\r\n {\r\n \"premises\": {\r\n \"addresses\": [\r\n {\r\n \"town\": \"Maynooth\",\r\n \"county\": \"Kildare\",\r\n \"street\": \"Main Street\",\r\n \"house-number\": 2\r\n },\r\n {\r\n \"town\": \"Dublin\",\r\n \"county\": \"Dublin\",\r\n \"street\": \"Grafton Street\",\r\n \"house-number\": 24\r\n },\r\n {\r\n \"house-number\": 13,\r\n \"street\": \"Church Street\",\r\n \"town\": \"Athlone\",\r\n \"county\": \"Westmeath\"\r\n }\r\n ]\r\n }\r\n }\r\n", "options": { "raw": { "language": "json" @@ -599,12 +640,12 @@ "response": [] }, { - "name": "Get Node Staff Direct Descendants", + "name": "Get Node Premises Direct Descendants", "request": { "method": "GET", "header": [], "url": { - "raw": "http://{{CPS_HOST}}:{{CPS_PORT}}/cps/api/v2/dataspaces/my-store/anchors/bookstore-anchor/node?xpath=/bookstore/staff&descendants=1", + "raw": "http://{{CPS_HOST}}:{{CPS_PORT}}/cps/api/v2/dataspaces/my-store/anchors/bookstore-anchor/node?xpath=/bookstore/premises&descendants=1", "protocol": "http", "host": [ "{{CPS_HOST}}" @@ -623,7 +664,7 @@ "query": [ { "key": "xpath", - "value": "/bookstore/staff" + "value": "/bookstore/premises" }, { "key": "descendants", diff --git a/releases/3.4.6-container.yaml b/releases/3.4.6-container.yaml new file mode 100644 index 0000000000..72ba08b023 --- /dev/null +++ b/releases/3.4.6-container.yaml @@ -0,0 +1,8 @@ +distribution_type: container +container_release_tag: 3.4.6 +project: cps +log_dir: cps-maven-docker-stage-master/938/ +ref: 4a978d3c66da16bc96b54cba807138fc9b0c79fa +containers: + - name: 'cps-and-ncmp' + version: '3.4.6-20240229T165311Z' diff --git a/releases/3.4.6.yaml b/releases/3.4.6.yaml new file mode 100644 index 0000000000..b3a9a3599b --- /dev/null +++ b/releases/3.4.6.yaml @@ -0,0 +1,4 @@ +distribution_type: maven +log_dir: cps-maven-stage-master/946/ +project: cps +version: 3.4.6
\ No newline at end of file diff --git a/spotbugs/pom.xml b/spotbugs/pom.xml index ef7c2f0f75..bbaf5fe6fb 100644 --- a/spotbugs/pom.xml +++ b/spotbugs/pom.xml @@ -25,7 +25,7 @@ <modelVersion>4.0.0</modelVersion> <groupId>org.onap.cps</groupId> <artifactId>spotbugs</artifactId> - <version>3.4.6-SNAPSHOT</version> + <version>3.4.7-SNAPSHOT</version> <properties> <nexusproxy>https://nexus.onap.org</nexusproxy> diff --git a/version.properties b/version.properties index dbf29f3288..b3ec5707ce 100644 --- a/version.properties +++ b/version.properties @@ -22,7 +22,7 @@ major=3 minor=4 -patch=6 +patch=7 base_version=${major}.${minor}.${patch} |