Commit b834d42e authored by Gitlab Runner's avatar Gitlab Runner
Browse files
parents 427993da f92d11bb
......@@ -14,32 +14,84 @@
package org.opengroup.osdu.partition.provider.aws.security;
import org.opengroup.osdu.core.aws.entitlements.RequestKeys;
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.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.context.annotation.RequestScope;
import org.opengroup.osdu.core.aws.entitlements.Authorizer;
import org.opengroup.osdu.core.aws.ssm.SSMUtil;
import javax.annotation.PostConstruct;
import java.util.Map;
@Component
@RequestScope
public class AuthorizationService implements IAuthorizationService {
public static final java.lang.String PARTITION_GROUP = "reserved_aws_admin";
public static final java.lang.String PARTITION_ADMIN_ROLE = "service.partition.admin";
@Autowired
private IEntitlementsAndCacheService entitlementsAndCacheService;
@Autowired
private DpsHeaders headers;
@Value("${aws.dynamodb.region}")
private String awsRegion;
@Value("${aws.environment}")
private String awsEnvironment;
Authorizer authorizer;
String memberEmail=null;
SSMUtil ssmUtil = null;
String spu_email=null;
@PostConstruct
public void init() {
authorizer = new Authorizer(awsRegion, awsEnvironment);
if (ssmUtil == null) {
ssmUtil = new SSMUtil("/osdu/" + awsEnvironment + "/");
}
//get sp email
spu_email = ssmUtil.getSsmParameterAsString("service-principal-user");
}
@Override
public boolean isDomainAdminServiceAccount() {
try {
return hasRole(PARTITION_ADMIN_ROLE);
Map<String, String> dpsheaders = headers.getHeaders();
String authorizationContents = dpsheaders.get(RequestKeys.AUTHORIZATION_HEADER_KEY);
if(authorizationContents == null){
authorizationContents = dpsheaders.get(RequestKeys.AUTHORIZATION_HEADER_KEY.toLowerCase());
}
//no JWT
if(authorizationContents == null)
{
throw AppException.createUnauthorized("No JWT token. Access is Forbidden");
}
memberEmail = authorizer.validateJWT(authorizationContents);
if(memberEmail != null)
{
if(memberEmail.equals(spu_email)){
return true;
}
else{
throw AppException.createUnauthorized("Unauthorized. The user is not Service Principal");
}
}
if(memberEmail == null){
throw AppException.createUnauthorized("Unauthorized. The JWT token could not be validated");
}
}
catch (AppException appE) {
throw appE;
......@@ -47,15 +99,11 @@ public class AuthorizationService implements IAuthorizationService {
catch (Exception e) {
throw new AppException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Authentication Failure", e.getMessage(), e);
}
return false;
}
private boolean hasRole(String requiredRole) {
headers.put(DpsHeaders.DATA_PARTITION_ID, PARTITION_GROUP);
String user = entitlementsAndCacheService.authorize(headers, requiredRole);
headers.put(DpsHeaders.USER_EMAIL, user);
return true;
}
}
// Copyright © 2020 Amazon Web Services
// Copyright 2017-2019, Schlumberger
//
// 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.aws.security;
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.core.common.http.json.HttpResponseBodyMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.stereotype.Component;
import javax.inject.Inject;
@Component
public class EntitlementsClientFactory extends AbstractFactoryBean<IEntitlementsFactory> {
@Value("${AUTHORIZE_API}")
private String AUTHORIZE_API;
@Value("${AUTHORIZE_API_KEY:}")
private String AUTHORIZE_API_KEY;
@Inject
private HttpResponseBodyMapper httpResponseBodyMapper;
@Override
protected IEntitlementsFactory createInstance() {
return new EntitlementsFactory(EntitlementsAPIConfig
.builder()
.rootUrl(AUTHORIZE_API)
.apiKey(AUTHORIZE_API_KEY)
.build(), httpResponseBodyMapper);
}
@Override
public Class<?> getObjectType() {
return IEntitlementsFactory.class;
}
}
\ No newline at end of file
// Copyright © 2020 Amazon Web Services
// Copyright 2017-2019, Schlumberger
//
// 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.aws.service;
import org.apache.http.HttpStatus;
import org.opengroup.osdu.core.common.model.entitlements.Acl;
import org.opengroup.osdu.core.common.model.http.DpsHeaders;
import org.opengroup.osdu.core.common.cache.ICache;
import org.opengroup.osdu.core.common.model.storage.RecordMetadata;
import org.opengroup.osdu.core.common.util.Crc32c;
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.http.HttpResponse;
import org.opengroup.osdu.core.common.entitlements.IEntitlementsFactory;
import org.opengroup.osdu.core.common.entitlements.IEntitlementsService;
import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
import org.opengroup.osdu.core.common.entitlements.IEntitlementsAndCacheService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@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 ICache<String, Groups> cache;
@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_FORBIDDEN, 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) {
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;
}
}
protected Groups getGroups(DpsHeaders headers) {
String cacheKey = this.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) {
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);
}
}
return groups;
}
protected static String getGroupCacheKey(DpsHeaders headers) {
String key = String.format("entitlement-groups:%s:%s", headers.getPartitionIdWithFallbackToAccountId(),
headers.getAuthorization());
return Crc32c.hashToBase64EncodedString(key);
}
}
......@@ -14,24 +14,10 @@
package org.opengroup.osdu.partition.provider.aws.util;
import java.net.URI;
import java.util.*;
import java.util.stream.Collectors;
import javax.inject.Inject;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagement;
import com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagementClientBuilder;
import com.amazonaws.services.simplesystemsmanagement.model.DeleteParametersRequest;
import com.amazonaws.services.simplesystemsmanagement.model.DeleteParametersResult;
import com.amazonaws.services.simplesystemsmanagement.model.GetParametersByPathRequest;
import com.amazonaws.services.simplesystemsmanagement.model.GetParametersByPathResult;
import com.amazonaws.services.simplesystemsmanagement.model.ParameterType;
import com.amazonaws.services.simplesystemsmanagement.model.PutParameterRequest;
import com.amazonaws.services.simplesystemsmanagement.model.PutParameterResult;
import com.amazonaws.services.simplesystemsmanagement.model.Parameter;
import com.amazonaws.services.simplesystemsmanagement.model.*;
import org.opengroup.osdu.core.aws.iam.IAMConfig;
import org.opengroup.osdu.partition.model.Property;
import org.opengroup.osdu.partition.provider.aws.AwsServiceConfig;
......@@ -39,10 +25,7 @@ import org.springframework.stereotype.Component;
import javax.inject.Inject;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
@Component
......@@ -57,8 +40,8 @@ public final class SSMHelper {
public SSMHelper() {
amazonAWSCredentials = IAMConfig.amazonAWSCredentials();
ssmManager = AWSSimpleSystemsManagementClientBuilder.standard()
.withCredentials(amazonAWSCredentials)
.build();
.withCredentials(amazonAWSCredentials)
.build();
}
// public boolean secretExists(String secretName) {
......@@ -90,10 +73,10 @@ public final class SSMHelper {
do {
GetParametersByPathRequest request = new GetParametersByPathRequest()
.withPath(ssmPath)
.withRecursive(true)
.withNextToken(nextToken)
.withWithDecryption(true);
.withPath(ssmPath)
.withRecursive(true)
.withNextToken(nextToken)
.withWithDecryption(true);
GetParametersByPathResult result = ssmManager.getParametersByPath(request);
nextToken = result.getNextToken();
......@@ -123,9 +106,9 @@ public final class SSMHelper {
do {
GetParametersByPathRequest request = new GetParametersByPathRequest()
.withPath(ssmPath)
.withRecursive(true)
.withNextToken(nextToken);
.withPath(ssmPath)
.withRecursive(true)
.withNextToken(nextToken);
GetParametersByPathResult result = ssmManager.getParametersByPath(request);
nextToken = result.getNextToken();
......@@ -161,10 +144,10 @@ public final class SSMHelper {
String ssmPath = getSsmPathForPartititionSecret(partitionName, secretName);
PutParameterRequest request = new PutParameterRequest()
.withName(ssmPath)
.withType(ParameterType.SecureString)
.withOverwrite(true)
.withValue(String.valueOf(secretValue));
.withName(ssmPath)
.withType(ParameterType.SecureString)
.withOverwrite(true)
.withValue(String.valueOf(secretValue));
PutParameterResult result = ssmManager.putParameter(request);
......@@ -190,7 +173,7 @@ public final class SSMHelper {
ssmParamPaths = ssmParamPaths.subList(subListCount, ssmParamPaths.size());
DeleteParametersRequest request = new DeleteParametersRequest()
.withNames(paramsToDelete);
.withNames(paramsToDelete);
DeleteParametersResult result = ssmManager.deleteParameters(request);
......@@ -218,22 +201,22 @@ public final class SSMHelper {
.withRecursive(true)
.withNextToken(nextToken);
result = ssmManager.getParametersByPath(request);
result = ssmManager.getParametersByPath(request);
for(Parameter p: result.getParameters())
{
String dp = (p.getName().substring(ssmPath.length()).split("/")[0]);
uniquePartitions.add(dp);
}
nextToken = result.getNextToken();
}
while (nextToken != null);
for(Parameter p: result.getParameters())
{
String dp = (p.getName().substring(ssmPath.length()).split("/")[0]);
uniquePartitions.add(dp);
}
partitions.addAll(uniquePartitions);
partitions.addAll(uniquePartitions);
return partitions;
......
......@@ -34,6 +34,9 @@ aws.dynamodb.table.prefix=${ENVIRONMENT}-
aws.dynamodb.region=${AWS_REGION}
aws.dynamodb.endpoint=dynamodb.${AWS_REGION}.amazonaws.com
aws.environment=${ENVIRONMENT}
## AWS ElastiCache configuration
aws.elasticache.cluster.endpoint=${CACHE_CLUSTER_ENDPOINT}
aws.elasticache.cluster.port=${CACHE_CLUSTER_PORT}
......
......@@ -28,21 +28,10 @@ echo "$SCRIPT_SOURCE_DIR"
(cd "$SCRIPT_SOURCE_DIR"/../bin && ./install-deps.sh)
#### ADD REQUIRED ENVIRONMENT VARIABLES HERE ###############################################
# The following variables are automatically populated from the environment during integration testing
# see os-deploy-aws/build-aws/integration-test-env-variables.py for an updated list
# AWS_COGNITO_CLIENT_ID
# PARTITION_URL
export AWS_COGNITO_AUTH_FLOW=USER_PASSWORD_AUTH
export AWS_COGNITO_AUTH_PARAMS_PASSWORD=$ADMIN_PASSWORD
export AWS_COGNITO_AUTH_PARAMS_USER=$ADMIN_USER
export AWS_COGNITO_AUTH_PARAMS_USER_NO_ACCESS=$USER_NO_ACCESS
export AWS_COGNITO_CLIENT_ID=$AWS_COGNITO_CLIENT_ID
export DOMAIN=testing.com
export PARTITION_BASE_URL=$PARTITION_BASE_URL
export CLIENT_TENANT=common
export MY_TENANT=opendes
export ENVIRONMENT=$RESOURCE_PREFIX
export RESOURCE_PREFIX=$RESOURCE_PREFIX
#### RUN INTEGRATION TEST #########################################################################
......
......@@ -71,7 +71,7 @@
<dependency>
<groupId>org.opengroup.osdu.core.aws</groupId>
<artifactId>os-core-lib-aws</artifactId>
<version>0.3.16</version>
<version>0.3.17</version>
</dependency>
<dependency>
......
......@@ -16,39 +16,78 @@
package org.opengroup.osdu.partition.util;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagement;
import com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagementClientBuilder;
import com.amazonaws.services.simplesystemsmanagement.model.GetParameterRequest;
import com.amazonaws.services.simplesystemsmanagement.model.GetParameterResult;
import com.google.common.base.Strings;
import org.opengroup.osdu.core.aws.cognito.AWSCognitoClient;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.opengroup.osdu.core.aws.entitlements.ServicePrincipal;
import org.opengroup.osdu.core.aws.iam.IAMConfig;
import org.opengroup.osdu.core.aws.secrets.SecretsManager;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;
import java.security.*;
import java.util.Date;
public class AwsTestUtils extends TestUtils {
private AWSCognitoClient cognitoClient;
public AwsTestUtils() {
cognitoClient = new AWSCognitoClient();
}
String client_credentials_secret;
String client_credentials_clientid;
ServicePrincipal sp;
private String awsOauthCustomScope;
private final static String ENVIRONMENT = "RESOURCE_PREFIX";
private final static String REGION = "AWS_REGION";
private AWSCredentialsProvider amazonAWSCredentials;
private AWSSimpleSystemsManagement ssmManager;
String sptoken=null;
@Override
public synchronized String getAccessToken() throws Exception {