diff options
author | Niamh Core <niamh.core@est.tech> | 2021-06-29 14:44:23 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@onap.org> | 2021-06-29 14:44:23 +0000 |
commit | 8c3aa37f2da1ac6fbd468aa6df331b3a24febddf (patch) | |
tree | bb094db72a4709e731994f3774708817ba1218e0 | |
parent | 696ab19a41b8168541d083880bef83ac5838fb46 (diff) | |
parent | 55500c3685dbc032c5cb79a727cc588d542e7d15 (diff) |
Merge "create quality params in dmi-plugin"
10 files changed, 429 insertions, 17 deletions
@@ -5,9 +5,7 @@ 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. @@ -15,44 +13,43 @@ limitations under the License. ============LICENSE_END========================================================= --> - <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> - <parent> <groupId>org.onap.oparent</groupId> <artifactId>oparent</artifactId> <version>3.2.0</version> <relativePath/> </parent> - <organization> <name>ONAP - CPS</name> <url>http://www.onap.org/</url> </organization> - <groupId>org.onap.cps</groupId> <artifactId>ncmp-dmi-plugin</artifactId> <version>0.0.1-SNAPSHOT</version> <name>ncmp-dmi-plugin</name> <description>DMI Plugin Service</description> - <properties> <app>org.onap.cps.ncmp.Application</app> + <cps.version>1.1.0-SNAPSHOT</cps.version> + <findbugs.slf4j.version>1.5.0</findbugs.slf4j.version> <groovy.version>3.0.8</groovy.version> + <jacoco.maven.plugin.version>0.8.5</jacoco.maven.plugin.version> + <jacoco.minimum.coverage>0.7</jacoco.minimum.coverage> <java.version>11</java.version> - <oparent.version>3.1.0</oparent.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spock-core.version>2.0-M5-groovy-3.0</spock-core.version> <spock-spring.version>2.0-M5-groovy-3.0</spock-spring.version> + <spotbug.maven.plugin.version>4.1.3</spotbug.maven.plugin.version> <springboot.version>2.5.0</springboot.version> + <springfox.version>3.0.0</springfox.version> <swagger.version>2.1.4</swagger.version> <swagger-annotations-version>1.6.2</swagger-annotations-version> <swagger-codegen-maven-plugin.version>3.0.18</swagger-codegen-maven-plugin.version> </properties> - <dependencyManagement> <dependencies> <dependency> @@ -68,6 +65,11 @@ <version>${swagger-annotations-version}</version> </dependency> <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-boot-starter</artifactId> + <version>${springfox.version}</version> + </dependency> + <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy</artifactId> <version>${groovy.version}</version> @@ -84,7 +86,6 @@ </dependency> </dependencies> </dependencyManagement> - <dependencies> <dependency> <groupId>org.springframework.boot</groupId> @@ -125,8 +126,19 @@ <artifactId>swagger-annotations</artifactId> <version>${swagger-annotations-version}</version> </dependency> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-boot-starter</artifactId> + </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> </dependencies> - <build> <resources> <resource> @@ -209,6 +221,126 @@ </excludes> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-checkstyle-plugin</artifactId> + <executions> + <execution> + <id>cps-java-style</id> + <goals> + <goal>check</goal> + </goals> + <phase>process-sources</phase> + <configuration> + <configLocation>cps-java-style.xml</configLocation> + <sourceDirectories> + <sourceDirectory>${project.build.sourceDirectory}</sourceDirectory> + </sourceDirectories> + <includeResources>true</includeResources> + <includeTestSourceDirectory>true</includeTestSourceDirectory> + <includeTestResources>true</includeTestResources> + <consoleOutput>true</consoleOutput> + <violationSeverity>warning</violationSeverity> + <failOnViolation>true</failOnViolation> + </configuration> + </execution> + </executions> + <dependencies> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>checkstyle</artifactId> + <version>${cps.version}</version> + </dependency> + </dependencies> + </plugin> + <plugin> + <groupId>com.github.spotbugs</groupId> + <artifactId>spotbugs-maven-plugin</artifactId> + <version>${spotbug.maven.plugin.version}</version> + <executions> + <execution> + <id>analyze-compile</id> + <phase>compile</phase> + <goals> + <goal>check</goal> + </goals> + </execution> + </executions> + <dependencies> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>spotbugs</artifactId> + <version>${cps.version}</version> + <scope>compile</scope> + </dependency> + </dependencies> + <configuration> + <plugins> + <plugin> + <groupId>jp.skypencil.findbugs.slf4j</groupId> + <artifactId>bug-pattern</artifactId> + <version>${findbugs.slf4j.version}</version> + </plugin> + </plugins> + <effort>Max</effort> + <threshold>Low</threshold> + <failOnError>true</failOnError> + <excludeFilterFile>spotbugs-exclude.xml</excludeFilterFile> + <xmlOutput>true</xmlOutput> + <xmlOutputDirectory>${basedir}/target/spotbugs</xmlOutputDirectory> + </configuration> + </plugin> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>${jacoco.maven.plugin.version}</version> + <configuration> + <excludes> + <exclude>org/onap/cps/ncmp/rest/model/*</exclude> + </excludes> + </configuration> + <executions> + <execution> + <id>default-prepare-agent</id> + <goals> + <goal>prepare-agent</goal> + </goals> + </execution> + <execution> + <id>coverage-check</id> + <goals> + <goal>check</goal> + </goals> + <configuration> + <dataFile>${basedir}/target/code-coverage/jacoco-ut.exec</dataFile> + <rules> + <rule> + <element>BUNDLE</element> + <limits> + <limit> + <counter>INSTRUCTION</counter> + <value>COVEREDRATIO</value> + <minimum>${jacoco.minimum.coverage}</minimum> + </limit> + </limits> + </rule> + </rules> + </configuration> + </execution> + <execution> + <id>report</id> + <phase>verify</phase> + <goals> + <goal>report-aggregate</goal> + </goals> + <configuration> + <dataFileIncludes> + <fileInclude>**/code-coverage/jacoco-ut.exec</fileInclude> + </dataFileIncludes> + </configuration> + </execution> + </executions> + </plugin> </plugins> </build> </project>
\ No newline at end of file diff --git a/src/main/java/org/onap/cps/ncmp/config/DmiPluginConfig.java b/src/main/java/org/onap/cps/ncmp/config/DmiPluginConfig.java new file mode 100644 index 00000000..427ffe19 --- /dev/null +++ b/src/main/java/org/onap/cps/ncmp/config/DmiPluginConfig.java @@ -0,0 +1,45 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.ncmp.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; + + +@Configuration +public class DmiPluginConfig { + /** + * Swagger-ui configuration. + */ + @Bean("dmi-plugin-docket") + public Docket api() { + return new Docket(DocumentationType.OAS_30) + .groupName("dmi-plugin-docket") + .select() + .apis(RequestHandlerSelectors.any()) + .paths(PathSelectors.any()) + .build(); + } +} + diff --git a/src/main/java/org/onap/cps/ncmp/config/WebSecurityConfig.java b/src/main/java/org/onap/cps/ncmp/config/WebSecurityConfig.java new file mode 100644 index 00000000..34bfae9d --- /dev/null +++ b/src/main/java/org/onap/cps/ncmp/config/WebSecurityConfig.java @@ -0,0 +1,81 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.ncmp.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +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.configuration.WebSecurityConfigurerAdapter; + +/** + * Configuration class to implement application security. + * It enforces Basic Authentication access control. + */ +@Configuration +@EnableWebSecurity +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + 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; + } + + @Override + // The team decided to disable default CSRF Spring protection and not implement CSRF tokens validation. + // ncmp is a stateless REST API that is not as vulnerable to CSRF attacks as web applications running in + // web browsers are. ncmp 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") + protected void configure(final HttpSecurity http) throws Exception { + http + .csrf().disable() + .authorizeRequests() + .antMatchers(permitUris).permitAll() + .anyRequest().authenticated() + .and().httpBasic(); + } + + @Override + protected void configure(final AuthenticationManagerBuilder auth) throws Exception { + auth.inMemoryAuthentication().withUser(username).password("{noop}" + password).roles(USER_ROLE); + } +} diff --git a/src/main/java/org/onap/cps/ncmp/rest/controller/DmiRestController.java b/src/main/java/org/onap/cps/ncmp/rest/controller/DmiRestController.java index 700ca82c..9507c695 100644 --- a/src/main/java/org/onap/cps/ncmp/rest/controller/DmiRestController.java +++ b/src/main/java/org/onap/cps/ncmp/rest/controller/DmiRestController.java @@ -20,6 +20,8 @@ package org.onap.cps.ncmp.rest.controller; import org.onap.cps.ncmp.rest.api.DmiPluginApi; +import org.onap.cps.ncmp.service.DmiService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; @@ -29,9 +31,12 @@ import org.springframework.web.bind.annotation.RestController; @RestController public class DmiRestController implements DmiPluginApi { + @Autowired + private DmiService dmiService; + @Override public ResponseEntity<Object> helloWorld() { - final var helloWorld = "Hello World"; + final var helloWorld = dmiService.getHelloWorld() ; return new ResponseEntity<>(helloWorld, HttpStatus.OK); } diff --git a/src/main/java/org/onap/cps/ncmp/service/DmiServiceImpl.java b/src/main/java/org/onap/cps/ncmp/service/DmiServiceImpl.java index a1cecc3e..b0c140cd 100644 --- a/src/main/java/org/onap/cps/ncmp/service/DmiServiceImpl.java +++ b/src/main/java/org/onap/cps/ncmp/service/DmiServiceImpl.java @@ -19,6 +19,9 @@ package org.onap.cps.ncmp.service; +import org.springframework.stereotype.Service; + +@Service public class DmiServiceImpl implements DmiService { @Override diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 08466681..e506a546 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -26,4 +26,20 @@ security: permit-uri: /manage/health/**,/manage/info,/swagger-ui/**,/swagger-resources/**,/v3/api-docs auth: username: ${CPS_USERNAME} - password: ${CPS_PASSWORD}
\ No newline at end of file + password: ${CPS_PASSWORD} + +# Actuator +management: + endpoints: + web: + base-path: /manage + exposure: + include: info,health,loggers + endpoint: + health: + show-details: always + # kubernetes probes: liveness and readiness + probes: + enabled: true + loggers: + enabled: true diff --git a/src/test/groovy/org/onap/cps/ncmp/rest/controller/ControllerSecuritySpec.groovy b/src/test/groovy/org/onap/cps/ncmp/rest/controller/ControllerSecuritySpec.groovy new file mode 100644 index 00000000..796414bd --- /dev/null +++ b/src/test/groovy/org/onap/cps/ncmp/rest/controller/ControllerSecuritySpec.groovy @@ -0,0 +1,62 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.ncmp.rest.controller + +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.Specification + +@WebMvcTest(controllers = TestController.class) +class ControllerSecuritySpec extends Specification { + + @Autowired + MockMvc mvc + + def testEndpoint = '/test' + + def 'Get request with authentication'() { + when: 'request is sent with authentication' + def response = mvc.perform( + get(testEndpoint).header("Authorization", 'Basic Y3BzdXNlcjpjcHNyMGNrcyE=') + ).andReturn().response + then: 'HTTP OK status code is returned' + assert response.status == HttpStatus.OK.value() + } + + def 'Get request without authentication'() { + when: 'request is sent without authentication' + def response = mvc.perform(get(testEndpoint)).andReturn().response + then: 'HTTP Unauthorized status code is returned' + assert response.status == HttpStatus.UNAUTHORIZED.value() + } + + def 'Get request with invalid authentication'() { + when: 'request is sent with invalid authentication' + def response = mvc.perform( + get(testEndpoint).header("Authorization", 'Basic invalid auth') + ).andReturn().response + then: 'HTTP Unauthorized status code is returned' + assert response.status == HttpStatus.UNAUTHORIZED.value() + } +} diff --git a/src/test/groovy/org/onap/cps/ncmp/rest/controller/DmiRestControllerSpec.groovy b/src/test/groovy/org/onap/cps/ncmp/rest/controller/DmiRestControllerSpec.groovy index 5a7db192..268f0a0d 100644 --- a/src/test/groovy/org/onap/cps/ncmp/rest/controller/DmiRestControllerSpec.groovy +++ b/src/test/groovy/org/onap/cps/ncmp/rest/controller/DmiRestControllerSpec.groovy @@ -19,10 +19,12 @@ package org.onap.cps.ncmp.rest.controller -import org.springframework.http.HttpStatus - import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import org.onap.cps.ncmp.service.DmiService +import org.spockframework.spring.SpringBean +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc +import org.springframework.http.HttpStatus import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Value import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest @@ -30,8 +32,12 @@ import org.springframework.test.web.servlet.MockMvc import spock.lang.Specification @WebMvcTest +@AutoConfigureMockMvc(addFilters = false) class DmiRestControllerSpec extends Specification { + @SpringBean + DmiService mockDmiService = Mock() + @Autowired private MockMvc mvc @@ -43,11 +49,14 @@ class DmiRestControllerSpec extends Specification { def helloWorldEndpoint = "$basePath/v1/helloworld" when: 'get hello world api is invoked' - def response = mvc.perform(get(helloWorldEndpoint)).andReturn().response + def response = mvc.perform( + get(helloWorldEndpoint) + ).andReturn().response then: 'Response Status is OK and contains expected text' response.status == HttpStatus.OK.value() - response.getContentAsString() == 'Hello World' + then: 'the java API was called with the correct parameters' + 1 * mockDmiService.getHelloWorld() } } diff --git a/src/test/java/org/onap/cps/ncmp/rest/controller/TestController.java b/src/test/java/org/onap/cps/ncmp/rest/controller/TestController.java new file mode 100644 index 00000000..a8d87afb --- /dev/null +++ b/src/test/java/org/onap/cps/ncmp/rest/controller/TestController.java @@ -0,0 +1,34 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 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.ncmp.rest.controller; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class TestController { + + @GetMapping("/test") + ResponseEntity<String> test() { + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml new file mode 100644 index 00000000..165d537c --- /dev/null +++ b/src/test/resources/application.yml @@ -0,0 +1,25 @@ +# ============LICENSE_START======================================================= +# Copyright (C) 2021 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========================================================= + +rest: + api: + dmi-base-path: /dmi/api + +security: + auth: + username: cpsuser + password: cpsr0cks!
\ No newline at end of file |