Commit 7a373a8a authored by Anastasiia Gelmut's avatar Anastasiia Gelmut
Browse files

GONRG-1191 Implement Partition Service

-PartitionService implementation is done;
-PartitionServiceImplTest is done.
parent cd26d831
<?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">
<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>
......@@ -13,7 +11,6 @@
<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>
......@@ -21,17 +18,17 @@
<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>
<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>
......
/*
Copyright 2020 Google LLC
Copyright 2020 EPAM Systems, Inc
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.
......@@ -21,10 +21,12 @@ 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) {
......
/*
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);
}
}
/*
Copyright 2020 Google LLC
Copyright 2020 EPAM Systems, Inc
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.
......
/*
Copyright 2020 Google LLC
Copyright 2020 EPAM Systems, Inc
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.
......@@ -50,5 +50,4 @@ public class PartitionListCacheImpl implements IPartitionServiceCache<String, Li
public void clearAll() {
this.cache.clearAll();
}
}
/*
Copyright 2020 Google LLC
Copyright 2020 EPAM Systems, Inc
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.
......@@ -14,7 +14,6 @@
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;
......
/*
Copyright 2020 Google LLC
Copyright 2020 EPAM Systems, Inc
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.
......@@ -18,27 +18,30 @@
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 int cacheExpiration;
private int cacheMaxSize;
private final PropertiesConfiguration properties;
@Bean(name = "partitionListCache")
public VmCache<String, List<String>> partitionListCache() {
return new VmCache<>(cacheExpiration * 60, cacheMaxSize);
return new VmCache<>(this.properties.getCacheExpiration() * 60,
this.properties.getCacheMaxSize());
}
@ConfigurationProperties
@Bean(name = "partitionServiceCache")
public VmCache<String, PartitionInfo> partitionServiceCache() {
return new VmCache<>(cacheExpiration * 60, cacheMaxSize);
return new VmCache<>(this.properties.getCacheExpiration() * 60,
this.properties.getCacheMaxSize());
}
}
/*
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;
......@@ -13,8 +30,6 @@ public class PropertiesConfiguration {
private String authorizeApi;
private String authorizeApiKey;
private int cacheExpiration;
private int cacheMaxSize;
......
/*
Copyright 2020 Google LLC
Copyright 2020 EPAM Systems, Inc
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.
......@@ -44,10 +44,15 @@ public class PartitionPropertyEntity {
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;
}
}
/*
Copyright 2020 Google LLC
Copyright 2020 EPAM Systems, Inc
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.
......@@ -19,18 +19,22 @@ 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> {
List<PartitionPropertyEntity> findByPartitionId(String partitionId);
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();
}
/*
Copyright 2020 Google LLC
Copyright 2020 EPAM Systems, Inc
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.
......@@ -48,12 +48,11 @@ public class AuthorizationService implements IAuthorizationService {
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);
String user = this.entitlementsAndCacheService.authorize(headers, requiredRole);
this.headers.put(DpsHeaders.USER_EMAIL, user);
return true;
}
}
/*
Copyright 2020 Google LLC
Copyright 2020 EPAM Systems, Inc
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.
......@@ -17,36 +17,36 @@
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 lombok.RequiredArgsConstructor;
import org.apache.http.HttpStatus;
import org.opengroup.osdu.core.common.cache.ICache;
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.opengroup.osdu.core.common.util.Crc32c;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
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;
private final IEntitlementsFactory factory;
@Autowired
private JaxRsDpsLog logger;
private final ICache<String, Groups> cache;
private final JaxRsDpsLog logger;
@Override
public String authorize(DpsHeaders headers, String... roles) {
......@@ -60,94 +60,45 @@ public class EntitlementsAndCacheServiceImpl implements IEntitlementsAndCacheSer
@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;
return false;
}
@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));
return false;
}
@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) {
aclList.add(viewer.split("@")[0]);
}
for (String owner : owners) {
aclList.add(owner.split("@")[0]);
}
String[] acls = new String[aclList.size()];
if (groups.any(aclList.toArray(acls))) {
return true;
} else {
return false;
}
return null;
}
protected Groups getGroups(DpsHeaders headers) {
IEntitlementsService service = this.factory.create(headers);
Groups groups = null;
try {
groups = service.getGroups();
} catch (EntitlementsException e) {
e.printStackTrace();
HttpResponse response = e.getHttpResponse();
this.logger.error(String.format("Error requesting entitlements service %s", response));
throw new AppException(e.getHttpResponse().getResponseCode(), ERROR_REASON, ERROR_MSG, e);
String cacheKey = getGroupCacheKey(headers);
Groups groups = this.cache.get(cacheKey);
if (groups == null) {
IEntitlementsService service = this.factory.create(headers);
try {
groups = service.getGroups();
this.cache.put(cacheKey, groups);
this.logger.info("Entitlements cache miss");
} catch (EntitlementsException e) {
HttpResponse response = e.getHttpResponse();
this.logger.error(String.format("Error requesting entitlements service %s", response));
throw new AppException(e.getHttpResponse().getResponseCode(), ERROR_REASON, ERROR_MSG, e);
}
}
return groups;
}
protected static String getGroupCacheKey(DpsHeaders headers) {
String key = String
.format("entitlement-groups:%s:%s", headers.getPartitionIdWithFallbackToAccountId(),
headers.getAuthorization());
return Crc32c.hashToBase64EncodedString(key);
}
}
/*
Copyright 2020 Google LLC
Copyright 2020 EPAM Systems, Inc
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.
......@@ -17,26 +17,26 @@
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 String authorizeApi;
private String authorizeApiKey;
private final PropertiesConfiguration properties;
@Override
protected IEntitlementsFactory createInstance() throws Exception {
return new EntitlementsFactory(EntitlementsAPIConfig
.builder()
.rootUrl(authorizeApi)
.apiKey(authorizeApiKey)
.rootUrl(properties.getAuthorizeApi())
.build());
}
......
/*
Copyright 2020 Google LLC
Copyright 2020 EPAM Systems, Inc
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.
......@@ -31,10 +31,8 @@ public class SecurityConfigGcp extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().disable()
.csrf().disable(); //disable default authN. AuthN handled by endpoints proxy
.csrf().disable();
}
@Override
......
/*
Copyright 2020 Google LLC
Copyright 2020 EPAM Systems, Inc
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.
......@@ -17,20 +17,22 @@
package org.opengroup.osdu.partition.provider.gcp.service;
import java.util.ArrayList;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
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;