Add gRPC & REST basic auth support 73/79673/6
authorAlexis de Talhouët <adetalhouet89@gmail.com>
Tue, 5 Mar 2019 02:37:27 +0000 (21:37 -0500)
committerAlexis de Talhouët <adetalhouet89@gmail.com>
Tue, 5 Mar 2019 14:23:52 +0000 (14:23 +0000)
Change-Id: Iaa187a8288a9c84aa80b596a14e66de10a9b7501
Issue-ID: CCSDK-1055
Signed-off-by: Alexis de Talhouët <adetalhouet89@gmail.com>
16 files changed:
ms/blueprintsprocessor/application/pom.xml
ms/blueprintsprocessor/application/src/main/java/org/onap/ccsdk/apps/blueprintsprocessor/BlueprintGRPCServer.java
ms/blueprintsprocessor/application/src/main/java/org/onap/ccsdk/apps/blueprintsprocessor/BlueprintHttpServer.java
ms/blueprintsprocessor/application/src/main/java/org/onap/ccsdk/apps/blueprintsprocessor/BlueprintProcessorApplication.java
ms/blueprintsprocessor/application/src/main/java/org/onap/ccsdk/apps/blueprintsprocessor/WebConfig.java
ms/blueprintsprocessor/application/src/main/java/org/onap/ccsdk/apps/blueprintsprocessor/security/AuthenticationManager.java [new file with mode: 0644]
ms/blueprintsprocessor/application/src/main/java/org/onap/ccsdk/apps/blueprintsprocessor/security/BasicAuthServerInterceptor.java [new file with mode: 0644]
ms/blueprintsprocessor/application/src/main/java/org/onap/ccsdk/apps/blueprintsprocessor/security/SecurityConfiguration.java [new file with mode: 0644]
ms/blueprintsprocessor/application/src/main/java/org/onap/ccsdk/apps/blueprintsprocessor/security/SecurityContextRepository.java [new file with mode: 0644]
ms/blueprintsprocessor/application/src/main/resources/application.properties
ms/blueprintsprocessor/application/src/test/resources/application.properties
ms/blueprintsprocessor/modules/inbounds/selfservice-api/pom.xml
ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/BluePrintManagementGRPCHandler.kt
ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/BluePrintProcessingGRPCHandler.kt
ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/ExecutionServiceController.kt
ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/ExecutionServiceHandlerTest.kt

index 83dc706..f42cdfa 100755 (executable)
@@ -17,7 +17,8 @@
   ~  See the License for the specific language governing permissions and
   ~  limitations under the License.
   -->
-<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>org.onap.ccsdk.apps.blueprintsprocessor</groupId>
             <artifactId>spring-boot-devtools</artifactId>
             <scope>runtime</scope>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-security</artifactId>
+        </dependency>
+
         <!-- North Bound -->
         <dependency>
             <groupId>org.onap.ccsdk.apps.blueprintsprocessor</groupId>
index 86fdccd..3ac1a6e 100644 (file)
@@ -18,6 +18,7 @@ package org.onap.ccsdk.apps.blueprintsprocessor;
 
 import io.grpc.Server;
 import io.grpc.ServerBuilder;
+import org.onap.ccsdk.apps.blueprintsprocessor.security.BasicAuthServerInterceptor;
 import org.onap.ccsdk.apps.blueprintsprocessor.selfservice.api.BluePrintManagementGRPCHandler;
 import org.onap.ccsdk.apps.blueprintsprocessor.selfservice.api.BluePrintProcessingGRPCHandler;
 import org.slf4j.Logger;
@@ -37,9 +38,10 @@ public class BlueprintGRPCServer implements ApplicationListener<ContextRefreshed
 
     @Autowired
     private BluePrintProcessingGRPCHandler bluePrintProcessingGRPCHandler;
-
     @Autowired
     private BluePrintManagementGRPCHandler bluePrintManagementGRPCHandler;
+    @Autowired
+    private BasicAuthServerInterceptor authInterceptor;
 
     @Value("${blueprintsprocessor.grpcPort}")
     private Integer grpcPort;
@@ -49,10 +51,11 @@ public class BlueprintGRPCServer implements ApplicationListener<ContextRefreshed
         try {
             log.info("Starting Blueprint Processor GRPC Starting..");
             Server server = ServerBuilder
-                    .forPort(grpcPort)
-                    .addService(bluePrintProcessingGRPCHandler)
-                    .addService(bluePrintManagementGRPCHandler)
-                    .build();
+                .forPort(grpcPort)
+                .intercept(authInterceptor)
+                .addService(bluePrintProcessingGRPCHandler)
+                .addService(bluePrintManagementGRPCHandler)
+                .build();
 
             server.start();
             log.info("Blueprint Processor GRPC server started and ready to serve on port({})...", server.getPort());
index b00c462..9561b78 100644 (file)
 
 package org.onap.ccsdk.apps.blueprintsprocessor;
 
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
 import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory;
 import org.springframework.boot.web.server.WebServer;
 import org.springframework.http.server.reactive.HttpHandler;
 import org.springframework.stereotype.Component;
 
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-
-@ConditionalOnProperty(name = "blueprintsprocessor.grpcEnable", havingValue = "true")
 @Component
 public class BlueprintHttpServer {
+
     private static Logger log = LoggerFactory.getLogger(BlueprintHttpServer.class);
 
     @Value("${blueprintsprocessor.httpPort}")
index 241d920..3f8dc37 100644 (file)
@@ -21,7 +21,6 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.boot.autoconfigure.SpringBootApplication;\r
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;\r
 import org.springframework.context.annotation.ComponentScan;\r
-import org.springframework.web.reactive.config.EnableWebFlux;\r
 \r
 /**\r
  * BlueprintProcessorApplication\r
@@ -30,10 +29,10 @@ import org.springframework.web.reactive.config.EnableWebFlux;
  */\r
 @SpringBootApplication\r
 @EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})\r
-@EnableWebFlux\r
 @ComponentScan(basePackages = {"org.onap.ccsdk.apps.controllerblueprints",\r
-        "org.onap.ccsdk.apps.blueprintsprocessor"})\r
+    "org.onap.ccsdk.apps.blueprintsprocessor"})\r
 public class BlueprintProcessorApplication {\r
+\r
     public static void main(String[] args) {\r
         SpringApplication.run(BlueprintProcessorApplication.class, args);\r
     }\r
index 796a2d7..47c7b72 100644 (file)
 \r
 package org.onap.ccsdk.apps.blueprintsprocessor;\r
 \r
+import org.onap.ccsdk.apps.blueprintsprocessor.security.AuthenticationManager;\r
+import org.onap.ccsdk.apps.blueprintsprocessor.security.SecurityContextRepository;\r
+import org.springframework.beans.factory.annotation.Autowired;\r
+import org.springframework.context.annotation.Bean;\r
 import org.springframework.context.annotation.Configuration;\r
-import org.springframework.web.reactive.config.*;\r
+import org.springframework.http.HttpMethod;\r
+import org.springframework.security.config.web.server.ServerHttpSecurity;\r
+import org.springframework.security.web.server.SecurityWebFilterChain;\r
+import org.springframework.web.reactive.config.CorsRegistry;\r
+import org.springframework.web.reactive.config.ResourceHandlerRegistry;\r
+import org.springframework.web.reactive.config.WebFluxConfigurationSupport;\r
 \r
 /**\r
  * WebConfig\r
@@ -27,21 +36,43 @@ import org.springframework.web.reactive.config.*;
  */\r
 @Configuration\r
 public class WebConfig extends WebFluxConfigurationSupport {\r
-       @Override\r
+\r
+    @Autowired\r
+    private AuthenticationManager authenticationManager;\r
+\r
+    @Autowired\r
+    private SecurityContextRepository securityContextRepository;\r
+\r
+    @Override\r
     public void addResourceHandlers(ResourceHandlerRegistry registry) {\r
         registry.addResourceHandler("swagger-ui.html")\r
-                .addResourceLocations("classpath:/META-INF/resources/");\r
+            .addResourceLocations("classpath:/META-INF/resources/");\r
 \r
         registry.addResourceHandler("/webjars/**")\r
-                .addResourceLocations("classpath:/META-INF/resources/webjars/");\r
+            .addResourceLocations("classpath:/META-INF/resources/webjars/");\r
     }\r
 \r
     @Override\r
     public void addCorsMappings(CorsRegistry corsRegistry) {\r
         corsRegistry.addMapping("/**")\r
-                .allowedOrigins("*")\r
-                .allowedMethods("*")\r
-                .allowedHeaders("DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range")\r
-                .maxAge(3600);\r
+            .allowedOrigins("*")\r
+            .allowedMethods("*")\r
+            .allowedHeaders("*")\r
+            .maxAge(3600);\r
+    }\r
+\r
+\r
+    @Bean\r
+    public SecurityWebFilterChain securitygWebFilterChain(ServerHttpSecurity http) {\r
+        return http.csrf().disable()\r
+            .formLogin().disable()\r
+            .httpBasic().disable()\r
+            .authenticationManager(authenticationManager)\r
+            .securityContextRepository(securityContextRepository)\r
+            .authorizeExchange()\r
+            .pathMatchers(HttpMethod.OPTIONS).permitAll()\r
+            .anyExchange().authenticated()\r
+            .and().build();\r
+\r
     }\r
 }\r
diff --git a/ms/blueprintsprocessor/application/src/main/java/org/onap/ccsdk/apps/blueprintsprocessor/security/AuthenticationManager.java b/ms/blueprintsprocessor/application/src/main/java/org/onap/ccsdk/apps/blueprintsprocessor/security/AuthenticationManager.java
new file mode 100644 (file)
index 0000000..726be2c
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 Bell Canada.
+ *
+ * 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.
+ */
+package org.onap.ccsdk.apps.blueprintsprocessor.security;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.authentication.ReactiveAuthenticationManager;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import reactor.core.publisher.Mono;
+
+@Configuration
+public class AuthenticationManager implements ReactiveAuthenticationManager {
+
+    @Autowired
+    private AuthenticationProvider authenticationProvider;
+
+    @Override
+    public Mono<Authentication> authenticate(Authentication authentication) {
+        try {
+            return Mono.just(authenticationProvider.authenticate(authentication));
+        } catch (AuthenticationException e) {
+            return Mono.error(e);
+        }
+    }
+}
\ No newline at end of file
diff --git a/ms/blueprintsprocessor/application/src/main/java/org/onap/ccsdk/apps/blueprintsprocessor/security/BasicAuthServerInterceptor.java b/ms/blueprintsprocessor/application/src/main/java/org/onap/ccsdk/apps/blueprintsprocessor/security/BasicAuthServerInterceptor.java
new file mode 100644 (file)
index 0000000..db0bfce
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2019 Bell Canada.
+ *
+ * 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.
+ */
+package org.onap.ccsdk.apps.blueprintsprocessor.security;
+
+import com.google.common.base.Strings;
+import io.grpc.Metadata;
+import io.grpc.ServerCall;
+import io.grpc.ServerCallHandler;
+import io.grpc.ServerInterceptor;
+import io.grpc.Status;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Component;
+
+@Component
+public class BasicAuthServerInterceptor implements ServerInterceptor {
+
+    private static Logger log = LoggerFactory.getLogger(BasicAuthServerInterceptor.class);
+
+    @Autowired
+    private AuthenticationManager authenticationManager;
+
+
+    @Override
+    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
+        ServerCall<ReqT, RespT> call,
+        Metadata headers,
+        ServerCallHandler<ReqT, RespT> next) {
+        String authHeader = headers.get(Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER));
+
+        if (Strings.isNullOrEmpty(authHeader)) {
+            throw Status.UNAUTHENTICATED.withDescription("Missing required authentication").asRuntimeException();
+
+        }
+
+        try {
+            String[] tokens = decodeBasicAuth(authHeader);
+            String username = tokens[0];
+
+            log.info("Basic Authentication Authorization header found for user: {}", username);
+
+            Authentication authRequest = new UsernamePasswordAuthenticationToken(username, tokens[1]);
+            Authentication authResult = authenticationManager.authenticate(authRequest).block();
+
+            log.info("Authentication success: {}", authResult);
+
+            SecurityContextHolder.getContext().setAuthentication(authResult);
+
+        } catch (AuthenticationException e) {
+            SecurityContextHolder.clearContext();
+
+            log.info("Authentication request failed: {}", e.getMessage());
+
+            throw Status.UNAUTHENTICATED.withDescription(e.getMessage()).withCause(e).asRuntimeException();
+        }
+
+        return next.startCall(call, headers);
+    }
+
+    private String[] decodeBasicAuth(String authHeader) {
+        String basicAuth;
+        try {
+            basicAuth = new String(Base64.getDecoder().decode(authHeader.substring(6).getBytes(StandardCharsets.UTF_8)),
+                StandardCharsets.UTF_8);
+        } catch (IllegalArgumentException | IndexOutOfBoundsException e) {
+            throw new BadCredentialsException("Failed to decode basic authentication token");
+        }
+
+        int delim = basicAuth.indexOf(':');
+        if (delim == -1) {
+            throw new BadCredentialsException("Failed to decode basic authentication token");
+        }
+
+        return new String[]{basicAuth.substring(0, delim), basicAuth.substring(delim + 1)};
+    }
+}
\ No newline at end of file
diff --git a/ms/blueprintsprocessor/application/src/main/java/org/onap/ccsdk/apps/blueprintsprocessor/security/SecurityConfiguration.java b/ms/blueprintsprocessor/application/src/main/java/org/onap/ccsdk/apps/blueprintsprocessor/security/SecurityConfiguration.java
new file mode 100644 (file)
index 0000000..7ddc42c
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 Bell Canada.
+ *
+ * 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.
+ */
+package org.onap.ccsdk.apps.blueprintsprocessor.security;
+
+import java.util.Collections;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.provisioning.InMemoryUserDetailsManager;
+
+@Configuration
+public class SecurityConfiguration {
+
+    @Value("${security.user.name}")
+    private String username;
+
+    @Value("${security.user.password}")
+    private String password;
+
+    @Bean
+    public UserDetailsService inMemoryUserService() {
+        UserDetails user = new User(username, password,
+            Collections.singletonList(new SimpleGrantedAuthority("USER")));
+        return new InMemoryUserDetailsManager(user);
+    }
+
+    @Bean
+    public PasswordEncoder passwordEncoder() {
+        return new BCryptPasswordEncoder();
+    }
+
+    @Bean
+    public AuthenticationProvider inMemoryAuthenticationProvider() {
+        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
+        provider.setUserDetailsService(inMemoryUserService());
+        return provider;
+    }
+}
\ No newline at end of file
diff --git a/ms/blueprintsprocessor/application/src/main/java/org/onap/ccsdk/apps/blueprintsprocessor/security/SecurityContextRepository.java b/ms/blueprintsprocessor/application/src/main/java/org/onap/ccsdk/apps/blueprintsprocessor/security/SecurityContextRepository.java
new file mode 100644 (file)
index 0000000..f9e184a
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 Bell Canada.
+ *
+ * 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.
+ */
+package org.onap.ccsdk.apps.blueprintsprocessor.security;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextImpl;
+import org.springframework.security.web.server.context.ServerSecurityContextRepository;
+import org.springframework.stereotype.Component;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+@Component
+public class SecurityContextRepository implements ServerSecurityContextRepository {
+
+    @Autowired
+    private AuthenticationManager authenticationManager;
+
+    @Override
+    public Mono<Void> save(ServerWebExchange swe, SecurityContext sc) {
+        throw new UnsupportedOperationException("Not supported.");
+    }
+
+    @Override
+    public Mono<SecurityContext> load(ServerWebExchange swe) {
+        ServerHttpRequest request = swe.getRequest();
+        String authHeader = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
+        if (authHeader != null && authHeader.startsWith("Basic")) {
+            String[] tokens = decodeBasicAuth(authHeader);
+            String username = tokens[0];
+            String password = tokens[1];
+            Authentication auth = new UsernamePasswordAuthenticationToken(username, password);
+            return this.authenticationManager.authenticate(auth).map(SecurityContextImpl::new);
+        } else {
+            return Mono.empty();
+        }
+    }
+
+    private String[] decodeBasicAuth(String authHeader) {
+        String basicAuth;
+        try {
+            basicAuth = new String(Base64.getDecoder().decode(authHeader.substring(6).getBytes(StandardCharsets.UTF_8)),
+                StandardCharsets.UTF_8);
+        } catch (IllegalArgumentException | IndexOutOfBoundsException e) {
+            throw new BadCredentialsException("Failed to decode basic authentication token");
+        }
+
+        int delim = basicAuth.indexOf(':');
+        if (delim == -1) {
+            throw new BadCredentialsException("Failed to decode basic authentication token");
+        }
+
+        return new String[]{basicAuth.substring(0, delim), basicAuth.substring(delim + 1)};
+    }
+}
\ No newline at end of file
index cfef4f8..e955c97 100755 (executable)
@@ -36,3 +36,6 @@ blueprintsprocessor.db.primary.hibernateDialect=org.hibernate.dialect.MySQL5Inno
 # Python executor
 blueprints.processor.functions.python.executor.executionPath=/opt/app/onap/scripts/jython/ccsdk_blueprints
 blueprints.processor.functions.python.executor.modulePaths=/opt/app/onap/scripts/jython/ccsdk_blueprints,/opt/app/onap/scripts/jython/ccsdk_netconf
+
+security.user.password: {bcrypt}$2a$10$duaUzVUVW0YPQCSIbGEkQOXwafZGwQ/b32/Ys4R1iwSSawFgz7QNu
+security.user.name: ccsdkapps
index 2b5bea1..3930245 100644 (file)
@@ -17,6 +17,9 @@
 #
 # Web server config
 server.port=8080
+blueprintsprocessor.grpcEnable=false
+blueprintsprocessor.httpPort=8080
+blueprintsprocessor.grpcPort=9111
 # Blueprint Processor File Execution and Handling Properties
 blueprintsprocessor.blueprintDeployPath=/opt/app/onap/blueprints/deploy
 blueprintsprocessor.blueprintArchivePath=/opt/app/onap/blueprints/archive
@@ -32,3 +35,6 @@ blueprintsprocessor.db.primary.hibernateDialect=org.hibernate.dialect.H2Dialect
 # Python executor
 blueprints.processor.functions.python.executor.executionPath=/opt/app/onap/scripts/jython
 blueprints.processor.functions.python.executor.modulePaths=/opt/app/onap/scripts/jython
+
+security.user.password: {bcrypt}$2a$10$duaUzVUVW0YPQCSIbGEkQOXwafZGwQ/b32/Ys4R1iwSSawFgz7QNu
+security.user.name: ccsdkapps
index c05b84a..f538a15 100755 (executable)
     <description>Blueprints Processor Selfservice API</description>
 
     <dependencies>
+
+        <dependency>
+            <groupId>org.springframework.security</groupId>
+            <artifactId>spring-security-core</artifactId>
+        </dependency>
+
         <dependency>
             <groupId>org.onap.ccsdk.apps.components</groupId>
             <artifactId>proto-definition</artifactId>
index fb0bc56..d689187 100644 (file)
@@ -28,16 +28,18 @@ import org.onap.ccsdk.apps.controllerblueprints.management.api.BluePrintManageme
 import org.onap.ccsdk.apps.controllerblueprints.management.api.BluePrintManagementOutput
 import org.onap.ccsdk.apps.controllerblueprints.management.api.BluePrintManagementServiceGrpc
 import org.slf4j.LoggerFactory
+import org.springframework.security.access.prepost.PreAuthorize
 import org.springframework.stereotype.Service
 import java.io.File
 
 @Service
-class BluePrintManagementGRPCHandler(private val bluePrintCoreConfiguration: BluePrintCoreConfiguration,
+open class BluePrintManagementGRPCHandler(private val bluePrintCoreConfiguration: BluePrintCoreConfiguration,
                                      private val bluePrintCatalogService: BluePrintCatalogService)
     : BluePrintManagementServiceGrpc.BluePrintManagementServiceImplBase() {
 
     private val log = LoggerFactory.getLogger(BluePrintManagementGRPCHandler::class.java)
 
+    @PreAuthorize("hasRole('USER')")
     override fun uploadBlueprint(request: BluePrintManagementInput, responseObserver: StreamObserver<BluePrintManagementOutput>) {
         val blueprintName = request.blueprintName
         val blueprintVersion = request.blueprintVersion
@@ -61,6 +63,7 @@ class BluePrintManagementGRPCHandler(private val bluePrintCoreConfiguration: Blu
         }
     }
 
+    @PreAuthorize("hasRole('USER')")
     override fun removeBlueprint(request: BluePrintManagementInput, responseObserver: StreamObserver<BluePrintManagementOutput>) {
         val blueprintName = request.blueprintName
         val blueprintVersion = request.blueprintVersion
index edb1d31..aadbec8 100644 (file)
@@ -23,14 +23,16 @@ import org.onap.ccsdk.apps.controllerblueprints.processing.api.BluePrintProcessi
 import org.onap.ccsdk.apps.controllerblueprints.processing.api.ExecutionServiceInput
 import org.onap.ccsdk.apps.controllerblueprints.processing.api.ExecutionServiceOutput
 import org.slf4j.LoggerFactory
+import org.springframework.security.access.prepost.PreAuthorize
 import org.springframework.stereotype.Service
 
 @Service
-class BluePrintProcessingGRPCHandler(private val bluePrintCoreConfiguration: BluePrintCoreConfiguration,
+open class BluePrintProcessingGRPCHandler(private val bluePrintCoreConfiguration: BluePrintCoreConfiguration,
                                      private val executionServiceHandler: ExecutionServiceHandler)
     : BluePrintProcessingServiceGrpc.BluePrintProcessingServiceImplBase() {
     private val log = LoggerFactory.getLogger(BluePrintProcessingGRPCHandler::class.java)
 
+    @PreAuthorize("hasRole('USER')")
     override fun process(
         responseObserver: StreamObserver<ExecutionServiceOutput>): StreamObserver<ExecutionServiceInput> {
 
index 6477c06..16f0fa8 100644 (file)
@@ -23,6 +23,7 @@ import org.onap.ccsdk.apps.blueprintsprocessor.core.api.data.ExecutionServiceOut
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.http.MediaType
 import org.springframework.http.codec.multipart.FilePart
+import org.springframework.security.access.prepost.PreAuthorize
 import org.springframework.web.bind.annotation.PostMapping
 import org.springframework.web.bind.annotation.RequestBody
 import org.springframework.web.bind.annotation.RequestMapping
@@ -34,7 +35,7 @@ import reactor.core.publisher.Mono
 
 @RestController
 @RequestMapping("/api/v1/execution-service")
-class ExecutionServiceController {
+open class ExecutionServiceController {
 
     @Autowired
     lateinit var executionServiceHandler: ExecutionServiceHandler
@@ -48,6 +49,7 @@ class ExecutionServiceController {
     @PostMapping(path = ["/upload"], consumes = [MediaType.MULTIPART_FORM_DATA_VALUE])
     @ApiOperation(value = "Upload CBA", notes = "Takes a File and load it in the runtime database")
     @ResponseBody
+    @PreAuthorize("hasRole('USER')")
     fun upload(@RequestPart("file") parts: Mono<FilePart>): Mono<String> {
         return parts
             .filter { it is FilePart }
@@ -59,6 +61,7 @@ class ExecutionServiceController {
     @ApiOperation(value = "Resolve Resource Mappings",
         notes = "Takes the blueprint information and process as per the payload")
     @ResponseBody
+    @PreAuthorize("hasRole('USER')")
     fun process(@RequestBody executionServiceInput: ExecutionServiceInput): ExecutionServiceOutput {
         if (executionServiceInput.actionIdentifiers.mode == ACTION_MODE_ASYNC) {
             throw IllegalStateException("Can't process async request through the REST endpoint. Use gRPC for async processing.")
index de12014..b730472 100644 (file)
@@ -24,6 +24,7 @@ import org.onap.ccsdk.apps.blueprintsprocessor.core.api.data.ExecutionServiceInp
 import org.onap.ccsdk.apps.controllerblueprints.core.interfaces.BluePrintCatalogService
 import org.onap.ccsdk.apps.controllerblueprints.core.utils.JacksonUtils
 import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.autoconfigure.security.SecurityProperties
 import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest
 import org.springframework.context.annotation.ComponentScan
 import org.springframework.core.io.ByteArrayResource
@@ -39,7 +40,7 @@ import kotlin.test.assertTrue
 
 @RunWith(SpringRunner::class)
 @WebFluxTest
-@ContextConfiguration(classes = [ExecutionServiceHandler::class, BluePrintCoreConfiguration::class, BluePrintCatalogService::class])
+@ContextConfiguration(classes = [ExecutionServiceHandler::class, BluePrintCoreConfiguration::class, BluePrintCatalogService::class, SecurityProperties::class])
 @ComponentScan(basePackages = ["org.onap.ccsdk.apps.blueprintsprocessor", "org.onap.ccsdk.apps.controllerblueprints"])
 @TestPropertySource(locations = ["classpath:application-test.properties"])
 class ExecutionServiceHandlerTest {