Commit 89e751c6 authored by Anastasiia Gelmut's avatar Anastasiia Gelmut
Browse files

GONRG-1191 Implement Partition Service

- Connection with Entitlements is done;
- Swagger is done;
- Basic implementation is added.
parent 4d4f9ade
......@@ -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>
......
<?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">
<parent>
<artifactId>partition</artifactId>
<groupId>org.opengroup.osdu</groupId>
<version>1.0.0</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<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>os-core-common</artifactId>
<version>${os-core-common.version}</version>
</dependency> -->
<dependency>
<groupId>org.opengroup.osdu</groupId>
<artifactId>partition-core</artifactId>
<version>1.0.0</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
/*
Copyright 2020 Google LLC
Copyright 2020 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;
@ComponentScan({"org.opengroup.osdu"})
@SpringBootApplication
@EnableDatastoreRepositories
public class PartitionGcpApplication {
public static void main(String[] args) {
SpringApplication.run(PartitionGcpApplication.class, args);
}
}
/*
Copyright 2020 Google LLC
Copyright 2020 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 org.opengroup.osdu.partition.provider.interfaces.IPartitionServiceCache;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
@Qualifier("partitionListCache")
public class PartitionListCacheImpl implements IPartitionServiceCache<String, List<String>> {
@Override
public void put(String s, List<String> o) {
}
@Override
public List<String> get(String s) {
return null;
}
@Override
public void delete(String s) {
}
@Override
public void clearAll() {
}
}
/*
Copyright 2020 Google LLC
Copyright 2020 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.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")
public class PartitionServiceCacheImpl implements IPartitionServiceCache<String, PartitionInfo> {
@Override
public void put(String s, PartitionInfo o) {
}
@Override
public PartitionInfo get(String s) {
return null;
}
@Override
public void delete(String s) {
}
@Override
public void clearAll() {
}
}
/*
Copyright 2020 Google LLC
Copyright 2020 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();
}
}
/*
Copyright 2020 Google LLC
Copyright 2020 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 org.opengroup.osdu.partition.provider.gcp.model.PartitionPropertyEntity;
import org.springframework.cloud.gcp.data.datastore.repository.DatastoreRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface PartitionPropertyEntityRepository extends
DatastoreRepository<PartitionPropertyEntity, Key> {
List<PartitionPropertyEntity> findByPartitionId(String partitionId);
PartitionPropertyEntity findByName(String partitionId, String name);
void deleteByPartitionId(String partitionId);
}
/*
Copyright 2020 Google LLC
Copyright 2020 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.opengroup.osdu.core.common.entitlements.IEntitlementsAndCacheService;
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.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.context.annotation.RequestScope;
@Component
@RequestScope
public class AuthorizationService implements IAuthorizationService {
private static final String PARTITION_ADMIN_ROLE = "service.partition.admin";
@Autowired
private IEntitlementsAndCacheService entitlementsAndCacheService;
@Autowired
private DpsHeaders headers;
@Override
public boolean isDomainAdminServiceAccount() {
try {
return hasRole(PARTITION_ADMIN_ROLE);
} catch (AppException e) {
throw e;
} catch (Exception e) {
throw new AppException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Authentication Failure",
e.getMessage(), e);
}
}
private boolean hasRole(String requiredRole) {
String user = entitlementsAndCacheService.authorize(headers, requiredRole);
headers.put(DpsHeaders.USER_EMAIL, user);
return true;
}
}
/*
Copyright 2020 Google LLC
Copyright 2020 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 java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.http.HttpStatus;
import org.opengroup.osdu.core.common.entitlements.IEntitlementsAndCacheService;
import org.opengroup.osdu.core.common.entitlements.IEntitlementsFactory;
import org.opengroup.osdu.core.common.entitlements.IEntitlementsService;
import org.opengroup.osdu.core.common.http.HttpResponse;
import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
import org.opengroup.osdu.core.common.model.entitlements.Acl;
import org.opengroup.osdu.core.common.model.entitlements.EntitlementsException;
import org.opengroup.osdu.core.common.model.entitlements.Groups;
import org.opengroup.osdu.core.common.model.http.AppException;
import org.opengroup.osdu.core.common.model.http.DpsHeaders;
import org.opengroup.osdu.core.common.model.storage.RecordMetadata;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class EntitlementsAndCacheServiceImpl implements IEntitlementsAndCacheService {
private static final String ERROR_REASON = "Access denied";
private static final String ERROR_MSG = "The user is not authorized to perform this action";
@Autowired
private IEntitlementsFactory factory;
@Autowired
private JaxRsDpsLog logger;
@Override
public String authorize(DpsHeaders headers, String... roles) {
Groups groups = this.getGroups(headers);
if (groups.any(roles)) {
return groups.getDesId();
} else {
throw new AppException(HttpStatus.SC_UNAUTHORIZED, ERROR_REASON, ERROR_MSG);
}
}
@Override
public boolean isValidAcl(DpsHeaders headers, Set<String> acls) {
Groups groups = this.getGroups(headers);
if (groups.getGroups() == null || groups.getGroups().isEmpty()) {
this.logger.error("Error on getting groups for user: " + headers.getUserEmail());
throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "Unknown error",
"Unknown error happened when validating ACL");
}
String email = groups.getGroups().get(0).getEmail();
if (!email.matches(
"^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$")) {
this.logger.error("Email address is invalid for this group: " + groups.getGroups().get(0));
throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "Unknown error",
"Unknown error happened when validating ACL");
}
String domain = email.split("@")[1];
for (String acl : acls) {
if (!acl.split("@")[1].equalsIgnoreCase(domain)) {
return false;
}
}
return true;
}
@Override
public boolean hasOwnerAccess(DpsHeaders headers, String[] ownerList) {
Groups groups = this.getGroups(headers);
Set<String> aclList = new HashSet<>();
for (String owner : ownerList) {
aclList.add(owner.split("@")[0]);
}
String[] acls = new String[aclList.size()];
return groups.any(aclList.toArray(acls));
}
@Override
public List<RecordMetadata> hasValidAccess(List<RecordMetadata> recordsMetadata,
DpsHeaders headers) {
Groups groups = this.getGroups(headers);
List<RecordMetadata> result = new ArrayList<>();
for (RecordMetadata recordMetadata : recordsMetadata) {
Acl storageAcl = recordMetadata.getAcl();
if (hasAccess(storageAcl, groups)) {
result.add(recordMetadata);
} else {
this.logger.warning("Post ACL check fails: " + recordMetadata.getId());
}
}
return result;
}
private boolean hasAccess(Acl storageAcl, Groups groups) {
String[] viewers = storageAcl.getViewers();
String[] owners = storageAcl.getOwners();
Set<String> aclList = new HashSet<>();
for (String viewer : viewers) {