diff --git a/pom.xml b/pom.xml index 2501b81beeff5d2bb455d5250b9b34404e628e0a..a787a9a2f9475b341d586373494fbaedd9c887e4 100644 --- a/pom.xml +++ b/pom.xml @@ -93,6 +93,7 @@ <module>provider/partition-azure</module> <module>provider/partition-aws</module> <module>provider/partition-ibm</module> + <module>provider/partition-gcp</module> </modules> <profiles> diff --git a/provider/partition-gcp/pom.xml b/provider/partition-gcp/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..55437749d141681567c6c81dd2376f10f2f192a3 --- /dev/null +++ b/provider/partition-gcp/pom.xml @@ -0,0 +1,154 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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> + <artifactId>partition</artifactId> + <groupId>org.opengroup.osdu</groupId> + <version>1.0.0</version> + <relativePath>../../pom.xml</relativePath> + </parent> + + <artifactId>partition-gcp</artifactId> + <version>1.0.0</version> + <description>Partition service on GCP</description> + <packaging>jar</packaging> + + <dependencies> + <!-- Internal packages --> + <dependency> + <groupId>org.opengroup.osdu</groupId> + <artifactId>partition-core</artifactId> + <version>1.0.0</version> + </dependency> + + <dependency> + <groupId>org.opengroup.osdu</groupId> + <artifactId>core-lib-gcp</artifactId> + <version>0.3.25</version> + </dependency> + + <!-- Third party Apache 2.0 license packages --> + <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> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-oauth2-client</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-oauth2-jose</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.data</groupId> + <artifactId>spring-data-commons</artifactId> + <version>2.1.10.RELEASE</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>javax.inject</groupId> + <artifactId>javax.inject</artifactId> + <version>1</version> + </dependency> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.cloud</groupId> + <artifactId>spring-cloud-gcp-starter-data-datastore</artifactId> + <version>1.2.5.RELEASE</version> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + <version>2.12.0</version> + </dependency> + <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core --> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-core</artifactId> + <version>2.12.0</version> + </dependency> + <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations --> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-annotations</artifactId> + <version>2.12.0</version> + </dependency> + + <!-- Testing packages --> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>2.25.0</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-module-junit4</artifactId> + <version>2.0.2</version> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-api-mockito2</artifactId> + <version>2.0.2</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <scope>test</scope> + <exclusions> + <exclusion> + <groupId>org.mockito</groupId> + <artifactId>mockito-all</artifactId> + </exclusion> + <exclusion> + <groupId>org.junit.vintage</groupId> + <artifactId>junit-vintage-engine</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-test</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>repackage</goal> + </goals> + <configuration> + <classifier>spring-boot</classifier> + <mainClass>org.opengroup.osdu.partition.provider.gcp.PartitionGcpApplication</mainClass> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file diff --git a/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/PartitionGcpApplication.java b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/PartitionGcpApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..e27739d6051d4fcc0777e18e7393601edfb9f446 --- /dev/null +++ b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/PartitionGcpApplication.java @@ -0,0 +1,35 @@ +/* + Copyright 2002-2021 Google LLC + Copyright 2002-2021 EPAM Systems, Inc + + 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.opengroup.osdu.partition.provider.gcp; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.gcp.data.datastore.repository.config.EnableDatastoreRepositories; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@ComponentScan({"org.opengroup.osdu"}) +@SpringBootApplication +@EnableDatastoreRepositories +@EnableTransactionManagement +public class PartitionGcpApplication { + + public static void main(String[] args) { + SpringApplication.run(PartitionGcpApplication.class, args); + } +} diff --git a/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/cache/CredentialsCache.java b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/cache/CredentialsCache.java new file mode 100644 index 0000000000000000000000000000000000000000..7dfa38d0254a466555649cc34045abcc9972ef4e --- /dev/null +++ b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/cache/CredentialsCache.java @@ -0,0 +1,30 @@ +/* + Copyright 2002-2021 Google LLC + Copyright 2002-2021 EPAM Systems, Inc + + 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.opengroup.osdu.partition.provider.gcp.cache; + +import org.opengroup.osdu.core.common.cache.VmCache; +import org.opengroup.osdu.core.gcp.multitenancy.credentials.GcsCredential; +import org.springframework.stereotype.Component; + +@Component +public class CredentialsCache extends VmCache<String, GcsCredential> { + + public CredentialsCache() { + super(30, 1000); + } +} diff --git a/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/cache/GroupCache.java b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/cache/GroupCache.java new file mode 100644 index 0000000000000000000000000000000000000000..94d417131349b5b8d14f66f3af18e7deb928aabf --- /dev/null +++ b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/cache/GroupCache.java @@ -0,0 +1,30 @@ +/* + Copyright 2002-2021 Google LLC + Copyright 2002-2021 EPAM Systems, Inc + + 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.opengroup.osdu.partition.provider.gcp.cache; + +import org.opengroup.osdu.core.common.cache.VmCache; +import org.opengroup.osdu.core.common.model.entitlements.Groups; +import org.springframework.stereotype.Component; + +@Component +public class GroupCache extends VmCache<String, Groups> { + + public GroupCache() { + super(30, 1000); + } +} diff --git a/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/cache/PartitionListCacheImpl.java b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/cache/PartitionListCacheImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..366bb47ab386d439d07ac41f945966fb59e52b94 --- /dev/null +++ b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/cache/PartitionListCacheImpl.java @@ -0,0 +1,53 @@ +/* + Copyright 2002-2021 Google LLC + Copyright 2002-2021 EPAM Systems, Inc + + 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.opengroup.osdu.partition.provider.gcp.cache; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.opengroup.osdu.core.common.cache.ICache; +import org.opengroup.osdu.partition.provider.interfaces.IPartitionServiceCache; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; + +@Service +@Qualifier("partitionListCache") +@RequiredArgsConstructor +public class PartitionListCacheImpl implements IPartitionServiceCache<String, List<String>> { + + private final ICache<String, List<String>> cache; + + @Override + public void put(String s, List<String> o) { + this.cache.put(s, o); + } + + @Override + public List<String> get(String s) { + return this.cache.get(s); + } + + @Override + public void delete(String s) { + this.cache.delete(s); + } + + @Override + public void clearAll() { + this.cache.clearAll(); + } +} diff --git a/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/cache/PartitionServiceCacheImpl.java b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/cache/PartitionServiceCacheImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..af35fb9431bc5c34932b5ee66b9cdf9be7e99dc0 --- /dev/null +++ b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/cache/PartitionServiceCacheImpl.java @@ -0,0 +1,52 @@ +/* + Copyright 2002-2021 Google LLC + Copyright 2002-2021 EPAM Systems, Inc + + 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.opengroup.osdu.partition.provider.gcp.cache; + +import lombok.RequiredArgsConstructor; +import org.opengroup.osdu.core.common.cache.ICache; +import org.opengroup.osdu.partition.model.PartitionInfo; +import org.opengroup.osdu.partition.provider.interfaces.IPartitionServiceCache; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; + +@Service +@Qualifier("partitionServiceCache") +@RequiredArgsConstructor +public class PartitionServiceCacheImpl implements IPartitionServiceCache<String, PartitionInfo> { + + private final ICache<String, PartitionInfo> cache; + + @Override + public void put(String s, PartitionInfo o) { + this.cache.put(s, o); + } + + @Override + public PartitionInfo get(String s) { + return this.cache.get(s); + } + + @Override + public void delete(String s) { + this.cache.delete(s); + } + + @Override + public void clearAll() { + this.cache.clearAll(); + } +} diff --git a/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/cache/VmCacheConfiguration.java b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/cache/VmCacheConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..362dce796f8d4390c1f7117a1de027ea8ba33013 --- /dev/null +++ b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/cache/VmCacheConfiguration.java @@ -0,0 +1,47 @@ +/* + Copyright 2002-2021 Google LLC + Copyright 2002-2021 EPAM Systems, Inc + + 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.opengroup.osdu.partition.provider.gcp.cache; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.opengroup.osdu.core.common.cache.VmCache; +import org.opengroup.osdu.partition.model.PartitionInfo; +import org.opengroup.osdu.partition.provider.gcp.config.PropertiesConfiguration; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@RequiredArgsConstructor +public class VmCacheConfiguration { + + private final PropertiesConfiguration properties; + + @Bean(name = "partitionListCache") + public VmCache<String, List<String>> partitionListCache() { + return new VmCache<>(this.properties.getCacheExpiration() * 60, + this.properties.getCacheMaxSize()); + } + + @ConfigurationProperties + @Bean(name = "partitionServiceCache") + public VmCache<String, PartitionInfo> partitionServiceCache() { + return new VmCache<>(this.properties.getCacheExpiration() * 60, + this.properties.getCacheMaxSize()); + } +} diff --git a/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/config/PropertiesConfiguration.java b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/config/PropertiesConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..9475913cf2877cae635c911fa3de372df5b90a83 --- /dev/null +++ b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/config/PropertiesConfiguration.java @@ -0,0 +1,36 @@ +/* + Copyright 2002-2021 Google LLC + Copyright 2002-2021 EPAM Systems, Inc + + 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.opengroup.osdu.partition.provider.gcp.config; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties +@Getter +@Setter +public class PropertiesConfiguration { + + private String authorizeApi; + + private int cacheExpiration; + + private int cacheMaxSize; +} diff --git a/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/model/PartitionPropertyEntity.java b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/model/PartitionPropertyEntity.java new file mode 100644 index 0000000000000000000000000000000000000000..ba918e6d3a2ab1ebd6ee165d623beb0ea53ba77c --- /dev/null +++ b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/model/PartitionPropertyEntity.java @@ -0,0 +1,58 @@ +/* + Copyright 2002-2021 Google LLC + Copyright 2002-2021 EPAM Systems, Inc + + 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.opengroup.osdu.partition.provider.gcp.model; + +import com.google.cloud.datastore.Key; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.opengroup.osdu.partition.model.Property; +import org.springframework.cloud.gcp.data.datastore.core.mapping.Entity; +import org.springframework.cloud.gcp.data.datastore.core.mapping.Field; +import org.springframework.data.annotation.Id; + +@Entity(name = "PartitionProperty") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PartitionPropertyEntity { + + @Id + private Key key; + + @Field(name = "partition_id") + private String partitionId; + + private String name; + + private Boolean sensitive; + + private Object value; + + + public PartitionPropertyEntity(String partitionId, String name, Property property) { + this.partitionId = partitionId; + this.name = name; + this.sensitive = property.isSensitive(); + this.value = property.getValue(); + } + + public boolean isSensitive() { + return this.sensitive; + } +} diff --git a/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/repository/PartitionPropertyEntityRepository.java b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/repository/PartitionPropertyEntityRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..cd58c6dd0efeb2883f615274627c34463e3e888e --- /dev/null +++ b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/repository/PartitionPropertyEntityRepository.java @@ -0,0 +1,40 @@ +/* + Copyright 2002-2021 Google LLC + Copyright 2002-2021 EPAM Systems, Inc + + 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.opengroup.osdu.partition.provider.gcp.repository; + +import com.google.cloud.datastore.Key; +import java.util.List; +import java.util.Optional; +import org.opengroup.osdu.partition.provider.gcp.model.PartitionPropertyEntity; +import org.springframework.cloud.gcp.data.datastore.repository.DatastoreRepository; +import org.springframework.cloud.gcp.data.datastore.repository.query.Query; +import org.springframework.stereotype.Repository; + +@Repository +public interface PartitionPropertyEntityRepository extends + DatastoreRepository<PartitionPropertyEntity, Key> { + + Optional<List<PartitionPropertyEntity>> findByPartitionId(String partitionId); + + PartitionPropertyEntity findByPartitionIdAndName(String partitionId, String name); + + void deleteByPartitionId(String partitionId); + + @Query("SELECT DISTINCT partition_id FROM PartitionProperty") + List<String> getAllPartitions(); +} diff --git a/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/security/AuthorizationService.java b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/security/AuthorizationService.java new file mode 100644 index 0000000000000000000000000000000000000000..4ad73ffb75ab467cc370537a80c35fd138bc0b95 --- /dev/null +++ b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/security/AuthorizationService.java @@ -0,0 +1,53 @@ +/* + Copyright 2002-2021 Google LLC + Copyright 2002-2021 EPAM Systems, Inc + + 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.opengroup.osdu.partition.provider.gcp.security; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.opengroup.osdu.core.common.model.http.AppException; +import org.opengroup.osdu.core.common.model.http.DpsHeaders; +import org.opengroup.osdu.partition.provider.interfaces.IAuthorizationService; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; +import org.springframework.web.context.annotation.RequestScope; + +@Slf4j +@Component +@RequestScope +@RequiredArgsConstructor +public class AuthorizationService implements IAuthorizationService { + + private static final String PARTITION_ADMIN_ROLE = "service.partition.admin"; + + private final DpsHeaders headers; + + private final org.opengroup.osdu.core.common.provider.interfaces.IAuthorizationService authorizationService; + + @Override + public boolean isDomainAdminServiceAccount() { + try { + authorizationService.authorizeAny(headers, PARTITION_ADMIN_ROLE); + } catch (AppException e) { + throw e; + } catch (Exception e) { + throw new AppException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Authentication Failure", + e.getMessage(), e); + } + return true; + } +} diff --git a/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/security/EntitlementsClientFactory.java b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/security/EntitlementsClientFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..5e86e5b226f2d2c0201af9af446dac6f96a1897f --- /dev/null +++ b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/security/EntitlementsClientFactory.java @@ -0,0 +1,47 @@ +/* + Copyright 2002-2021 Google LLC + Copyright 2002-2021 EPAM Systems, Inc + + 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.opengroup.osdu.partition.provider.gcp.security; + +import lombok.RequiredArgsConstructor; +import org.opengroup.osdu.core.common.entitlements.EntitlementsAPIConfig; +import org.opengroup.osdu.core.common.entitlements.EntitlementsFactory; +import org.opengroup.osdu.core.common.entitlements.IEntitlementsFactory; +import org.opengroup.osdu.partition.provider.gcp.config.PropertiesConfiguration; +import org.springframework.beans.factory.config.AbstractFactoryBean; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class EntitlementsClientFactory extends AbstractFactoryBean<IEntitlementsFactory> { + + private final PropertiesConfiguration properties; + + @Override + protected IEntitlementsFactory createInstance() throws Exception { + + return new EntitlementsFactory(EntitlementsAPIConfig + .builder() + .rootUrl(properties.getAuthorizeApi()) + .build()); + } + + @Override + public Class<?> getObjectType() { + return IEntitlementsFactory.class; + } +} diff --git a/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/security/SecurityConfigGcp.java b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/security/SecurityConfigGcp.java new file mode 100644 index 0000000000000000000000000000000000000000..483e191c695412c3830b7c742cde856ccb81d7b6 --- /dev/null +++ b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/security/SecurityConfigGcp.java @@ -0,0 +1,44 @@ +/* + Copyright 2002-2021 Google LLC + Copyright 2002-2021 EPAM Systems, Inc + + 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.opengroup.osdu.partition.provider.gcp.security; + +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@EnableWebSecurity +@Configuration +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class SecurityConfigGcp extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.httpBasic().disable() + .csrf().disable(); + } + + @Override + public void configure(WebSecurity web) throws Exception { + web.ignoring().antMatchers("/api-docs") + .antMatchers("/index") + .antMatchers("/swagger"); + } +} diff --git a/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/service/PartitionServiceImpl.java b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/service/PartitionServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..30471f5513bd7299d5728464cc3f518998390ac5 --- /dev/null +++ b/provider/partition-gcp/src/main/java/org/opengroup/osdu/partition/provider/gcp/service/PartitionServiceImpl.java @@ -0,0 +1,161 @@ +/* + Copyright 2002-2021 Google LLC + Copyright 2002-2021 EPAM Systems, Inc + + 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.opengroup.osdu.partition.provider.gcp.service; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import lombok.RequiredArgsConstructor; +import org.apache.http.HttpStatus; +import org.opengroup.osdu.core.common.model.http.AppException; +import org.opengroup.osdu.core.common.provider.interfaces.IKmsClient; +import org.opengroup.osdu.partition.model.PartitionInfo; +import org.opengroup.osdu.partition.model.Property; +import org.opengroup.osdu.partition.provider.gcp.model.PartitionPropertyEntity; +import org.opengroup.osdu.partition.provider.gcp.repository.PartitionPropertyEntityRepository; +import org.opengroup.osdu.partition.provider.interfaces.IPartitionService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +public class PartitionServiceImpl implements IPartitionService { + + private static final String UNKNOWN_ERROR_REASON = "unknown error"; + + + private final PartitionPropertyEntityRepository partitionPropertyEntityRepository; + + private final IKmsClient kmsClient; + + @Override + public PartitionInfo createPartition(String partitionId, PartitionInfo partitionInfo) { + if (this.partitionPropertyEntityRepository.findByPartitionId(partitionId).isPresent()) { + throw new AppException(HttpStatus.SC_CONFLICT, UNKNOWN_ERROR_REASON, + "Partition already exists."); + } + List<PartitionPropertyEntity> partitionProperties = new ArrayList<>(); + for (Map.Entry<String, Property> entry : partitionInfo.getProperties().entrySet()) { + PartitionPropertyEntity entity = new PartitionPropertyEntity(partitionId, + entry.getKey(), entry.getValue()); + encryptPartitionPropertyEntityIfNeeded(entity); + partitionProperties.add(entity); + } + this.partitionPropertyEntityRepository.performTransaction(repository -> { + repository.saveAll(partitionProperties); + return true; + }); + return getEncryptedPartition(partitionId); + } + + private void encryptPartitionPropertyEntityIfNeeded(PartitionPropertyEntity entity) { + if (entity.isSensitive()) { + String propertyValue = entity.getValue().toString(); + try { + entity.setValue(this.kmsClient.encryptString(propertyValue)); + } catch (IOException e) { + throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, UNKNOWN_ERROR_REASON, + e.getMessage()); + } + } + } + + private PartitionInfo getEncryptedPartition(String partitionId) { + List<PartitionPropertyEntity> partitionPropertiesList = this.partitionPropertyEntityRepository + .findByPartitionId(partitionId) + .orElseThrow( + () -> new AppException(HttpStatus.SC_NOT_FOUND, UNKNOWN_ERROR_REASON, + "Partition does not exist.")); + PartitionInfo partitionInfo = new PartitionInfo(); + Map<String, Property> partitionInfoProperties = new HashMap<>(); + for (PartitionPropertyEntity entity : partitionPropertiesList) { + partitionInfoProperties + .put(entity.getName(), new Property(entity.getSensitive(), entity.getValue())); + } + partitionInfo.setProperties(partitionInfoProperties); + + return partitionInfo; + } + + @Transactional + @Override + public PartitionInfo updatePartition(String partitionId, PartitionInfo partitionInfo) { + this.partitionPropertyEntityRepository.findByPartitionId(partitionId) + .orElseThrow( + () -> new AppException(HttpStatus.SC_NOT_FOUND, UNKNOWN_ERROR_REASON, + "An attempt to update not existing partition.")); + List<PartitionPropertyEntity> partitionProperties = new ArrayList<>(); + for (Map.Entry<String, Property> entry : partitionInfo.getProperties().entrySet()) { + PartitionPropertyEntity entity = this.partitionPropertyEntityRepository + .findByPartitionIdAndName(partitionId, entry.getKey()); + if (Objects.nonNull(entity)) { + entity.setSensitive(entry.getValue().isSensitive()); + entity.setValue(entry.getValue().getValue()); + } else { + entity = new PartitionPropertyEntity(partitionId, entry.getKey(), entry.getValue()); + } + encryptPartitionPropertyEntityIfNeeded(entity); + partitionProperties.add(entity); + } + this.partitionPropertyEntityRepository.saveAll(partitionProperties); + return getEncryptedPartition(partitionId); + } + + @Transactional + @Override + public PartitionInfo getPartition(String partitionId) { + PartitionInfo partitionInfo = getEncryptedPartition(partitionId); + for (Property property : partitionInfo.getProperties().values()) { + decryptPartitionPropertyIfNeeded(property); + } + return partitionInfo; + } + + private void decryptPartitionPropertyIfNeeded(Property property) { + if (property.isSensitive()) { + String propertyValue = property.getValue().toString(); + try { + property.setValue(this.kmsClient.decryptString(propertyValue)); + } catch (IOException e) { + throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, UNKNOWN_ERROR_REASON, + e.getMessage()); + } + } + } + + @Transactional + @Override + public boolean deletePartition(String partitionId) { + this.partitionPropertyEntityRepository.findByPartitionId(partitionId) + .orElseThrow( + () -> new AppException(HttpStatus.SC_NOT_FOUND, UNKNOWN_ERROR_REASON, + "An attempt to delete not existing partition.")); + this.partitionPropertyEntityRepository.deleteByPartitionId(partitionId); + return true; + } + + @Transactional + @Override + public List<String> getAllPartitions() { + List<String> allPartitions = this.partitionPropertyEntityRepository.getAllPartitions(); + return (allPartitions.isEmpty() ? null : allPartitions); + } +} diff --git a/provider/partition-gcp/src/main/resources/application.properties b/provider/partition-gcp/src/main/resources/application.properties new file mode 100644 index 0000000000000000000000000000000000000000..971d962852a40cada339c9f1a5b20d60a422add0 --- /dev/null +++ b/provider/partition-gcp/src/main/resources/application.properties @@ -0,0 +1,24 @@ +google-cloud-project=osdu-cicd-epam + +LOG_PREFIX=partition +server.servlet.contextPath=/api/partition/v1 +server.port=8080 +springfox.documentation.swagger.v2.path=/api-docs +authorize-api=https://os-entitlements-gcp-jvmvia5dea-uc.a.run.app/entitlements/v1 +spring.cloud.gcp.datastore.namespace=partitiontest +#ACCEPT_HTTP=true + +cache-expiration=1 +cache-maxSize=1000 + +key-ring=csqp +kms-key=searchService + +KEY_RING=${key-ring} +KMS_KEY=${kms-key} +GOOGLE_CLOUD_PROJECT=${google-cloud-project} + +#logging configuration +logging.level.org.springframework.web=DEBUG +logging.level.org.opengroup.osdu=debug + diff --git a/provider/partition-gcp/src/test/java/org/opengroup/osdu/partition/provider/gcp/service/PartitionServiceImplTest.java b/provider/partition-gcp/src/test/java/org/opengroup/osdu/partition/provider/gcp/service/PartitionServiceImplTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7a8434dbb24156353fbeda7aa1405309ee57b534 --- /dev/null +++ b/provider/partition-gcp/src/test/java/org/opengroup/osdu/partition/provider/gcp/service/PartitionServiceImplTest.java @@ -0,0 +1,175 @@ +/* + Copyright 2002-2021 Google LLC + Copyright 2002-2021 EPAM Systems, Inc + + 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.opengroup.osdu.partition.provider.gcp.service; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.opengroup.osdu.core.common.model.http.AppException; +import org.opengroup.osdu.partition.model.PartitionInfo; +import org.opengroup.osdu.partition.model.Property; +import org.opengroup.osdu.partition.provider.gcp.model.PartitionPropertyEntity; +import org.opengroup.osdu.partition.provider.gcp.repository.PartitionPropertyEntityRepository; + +@RunWith(MockitoJUnitRunner.class) +public class PartitionServiceImplTest { + + private static final String PARTITION_ID = "newPartition"; + private static final boolean SENSITIVE = false; + private static final String NAME = "new-key"; + private static final String VALUE = "new-value"; + + + @Mock + private PartitionPropertyEntityRepository partitionPropertyEntityRepository; + + @InjectMocks + private PartitionServiceImpl partitionServiceImpl; + + private PartitionInfo expectedPartitionInfo; + private PartitionPropertyEntity partitionPropertyEntity; + private Optional<List<PartitionPropertyEntity>> partitionPropertyEntityList; + private Optional<List<PartitionPropertyEntity>> emptyList; + + @Before + public void setup() { + this.expectedPartitionInfo = new PartitionInfo(); + + Property property = new Property(); + property.setSensitive(SENSITIVE); + property.setValue(VALUE); + + Map<String, Property> properties = new HashMap<>(); + properties.put(NAME, property); + + this.expectedPartitionInfo.setProperties(properties); + + partitionPropertyEntity = new PartitionPropertyEntity(); + partitionPropertyEntity.setPartitionId(PARTITION_ID); + partitionPropertyEntity.setName(NAME); + partitionPropertyEntity.setSensitive(SENSITIVE); + partitionPropertyEntity.setValue(VALUE); + + List<PartitionPropertyEntity> entities = new ArrayList<>(); + entities.add(partitionPropertyEntity); + this.partitionPropertyEntityList = Optional.of(entities); + + this.emptyList = Optional.empty(); + } + + @Test + public void should_createPartition_when_partitionDoesNotExist() { + when(this.partitionPropertyEntityRepository.findByPartitionId(PARTITION_ID)) + .thenReturn(this.emptyList, this.partitionPropertyEntityList); + + PartitionInfo actualPartitionInfo = this.partitionServiceImpl + .createPartition(PARTITION_ID, this.expectedPartitionInfo); + + assertEquals(this.expectedPartitionInfo, actualPartitionInfo); + } + + @Test(expected = AppException.class) + public void should_throwAnException_when_createPartitionWhichAlreadyExists() { + when(this.partitionPropertyEntityRepository.findByPartitionId(PARTITION_ID)) + .thenReturn(this.emptyList); + + this.partitionServiceImpl.createPartition(PARTITION_ID, new PartitionInfo()); + } + + @Test + public void should_updatePartition_when_partitionExists() { + when(this.partitionPropertyEntityRepository.findByPartitionId(PARTITION_ID)) + .thenReturn(this.partitionPropertyEntityList); + when(this.partitionPropertyEntityRepository.findByPartitionIdAndName(PARTITION_ID, NAME)) + .thenReturn(null); + when(this.partitionPropertyEntityRepository.save(this.partitionPropertyEntity)) + .thenReturn(this.partitionPropertyEntity); + + PartitionInfo actualPartitionInfo = this.partitionServiceImpl + .updatePartition(PARTITION_ID, this.expectedPartitionInfo); + + assertEquals(this.expectedPartitionInfo, actualPartitionInfo); + } + + @Test(expected = AppException.class) + public void should_throwAnException_when_updatePartitionWhichDoesNotExist() { + when(this.partitionPropertyEntityRepository.findByPartitionId(PARTITION_ID)) + .thenReturn(this.emptyList); + this.partitionServiceImpl.createPartition(PARTITION_ID, new PartitionInfo()); + } + + @Test + public void should_getPartition_when_partitionExists() { + when(this.partitionPropertyEntityRepository.findByPartitionId(PARTITION_ID)) + .thenReturn(this.partitionPropertyEntityList); + + PartitionInfo actualPartitionInfo = this.partitionServiceImpl.getPartition(PARTITION_ID); + + assertEquals(this.expectedPartitionInfo, actualPartitionInfo); + } + + @Test(expected = AppException.class) + public void should_throwAnException_when_getPartitionWhichDoesNotExist() { + when(this.partitionPropertyEntityRepository.findByPartitionId(PARTITION_ID)) + .thenReturn(this.emptyList); + this.partitionServiceImpl.getPartition(PARTITION_ID); + } + + @Test + public void should_deletePartition_when_partitionExists() { + when(this.partitionPropertyEntityRepository.findByPartitionId(PARTITION_ID)) + .thenReturn(this.partitionPropertyEntityList); + doNothing().when(this.partitionPropertyEntityRepository).deleteByPartitionId(PARTITION_ID); + + boolean expected = true; + boolean actual = partitionServiceImpl.deletePartition(PARTITION_ID); + + assertEquals(expected, actual); + } + + @Test(expected = AppException.class) + public void should_throwAnException_when_deletePartitionWhichDoesNotExist() { + when(this.partitionPropertyEntityRepository.findByPartitionId(PARTITION_ID)) + .thenReturn(this.emptyList); + this.partitionServiceImpl.deletePartition(PARTITION_ID); + } + + @Test + public void should_getAllPartitions() { + List<String> expectedPartitions = new ArrayList<>(); + expectedPartitions.add(PARTITION_ID); + + when(this.partitionPropertyEntityRepository.getAllPartitions()).thenReturn(expectedPartitions); + + List<String> actualPartitions = this.partitionServiceImpl.getAllPartitions(); + + assertEquals(expectedPartitions, actualPartitions); + } +} \ No newline at end of file