Commit 67c8b679 authored by Srihari Prabaharan's avatar Srihari Prabaharan
Browse files

Merge branch 'feat/aws-entitlements' into 'master'

Feat/aws entitlements

See merge request !6
parents ca6cbacb f654c84d
Pipeline #5938 failed with stages
in 9 minutes and 21 seconds
variables:
AWS_BUILD_SUBDIR: ./
AWS_TEST_SUBDIR: ./
AWS_BUILD_SUBDIR: build-aws
AWS_TEST_SUBDIR: testing/entitlements-test-aws
AWS_SERVICE: entitlements
AWS_ENVIRONMENT: dev
AWS_REGION: us-east-1
include:
- project: "osdu/platform/ci-cd-pipelines"
file: "standard-setup.yml"
- project: "osdu/platform/ci-cd-pipelines"
file: "build/maven.yml"
- project: "osdu/platform/ci-cd-pipelines"
file: "scanners/fossa.yml"
- project: 'osdu/platform/ci-cd-pipelines'
file: 'cloud-providers/aws.yml'
- project: "osdu/platform/ci-cd-pipelines"
file: "scanners/gitlab-ultimate.yml"
# disable the eslint scanner
# I think this is being generated from the presence of an HTML file, but there
# is no javascript to scan, so the job isn't helpful and just gets in the way
eslint-sast:
rules:
- when: never
// Copyright © Amazon Web Services
//
// 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 com.amazonaws.osdu.entitlements;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.HttpStatus;
import org.opengroup.osdu.core.aws.dynamodb.DynamoDBQueryHelper;
import org.opengroup.osdu.core.aws.entitlements.*;
import org.opengroup.osdu.core.aws.lambda.HttpLambdaUtil;
import org.opengroup.osdu.core.aws.lambda.HttpMethods;
import org.opengroup.osdu.core.aws.lambda.HttpStatusCodes;
import org.opengroup.osdu.core.aws.lambda.LambdaLogger;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DeleteMember implements RequestStreamHandler {
HttpLambdaUtil httpLambdaUtil = new HttpLambdaUtil();
Authorizer authorizer = new Authorizer();
DynamoDBQueryHelper dynamoDBQueryHelper;
/**
* Constructor that sets up the ability to interact with Dynamo
*/
public DeleteMember(){
this(
System.getenv("dynamoDBEndpoint"),
System.getenv("dynamoDBRegion"),
System.getenv("groupsTablePrefix")
);
}
/**
* Constructor used for unit testing
* @param amazonDynamoDBEndpoint
* @param amazonDynamoDBRegion
* @param tablePrefix
*/
public DeleteMember(String amazonDynamoDBEndpoint, String amazonDynamoDBRegion, String tablePrefix) {
dynamoDBQueryHelper = new DynamoDBQueryHelper(amazonDynamoDBEndpoint, amazonDynamoDBRegion, tablePrefix);
}
/**
* Method that gets called by API Gateway. Parses the request into usuable objects and then does all the checks
* @param inputStream
* @param outputStream
* @param context
* @throws IOException
*/
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)
throws IOException {
ObjectMapper mapper = new ObjectMapper();
// initialize values filled by each check;
int httpStatusCode = HttpStatusCodes.UNASSIGNED;
Exception exception = new Exception();
String respBody = "";
Map<String, String> respHeaders = new HashMap<>();
Map<String, String> headers = new HashMap<>();
String[] path = new String[0];
String httpMethod = "";
try{
Map<String, Object> request = mapper.readValue(inputStream, Map.class);
path = ((String) request.get(RequestKeys.PATH_REQUEST_KEY)).split("/");
httpMethod = (String) request.get(RequestKeys.HTTP_METHOD_REQUEST_KEY);
headers = (HashMap<String, String>) request.get(RequestKeys.HEADERS_REQUEST_KEY);
httpLambdaUtil.logHeaders(headers);
} catch (ClassCastException e){
LambdaLogger.logException("Casting exception in parsing request, headers, httpMethod.", e);
httpStatusCode = HttpStatusCodes.INTERNAL_SERVER_ERROR;
exception = e;
} catch (IOException e){
LambdaLogger.logException("IO exception in parsing request, headers, httpMethod.", e);
httpStatusCode = HttpStatusCodes.INTERNAL_SERVER_ERROR;
exception = e;
} catch (Exception e){
LambdaLogger.logException("General exception in parsing request, headers, httpMethod.", e);
httpStatusCode = HttpStatusCodes.INTERNAL_SERVER_ERROR;
exception = e;
}
// get groupEmail from path
String groupEmail = "";
String memberEmail = "";
try {
groupEmail = path[2];
memberEmail = path[4];
} catch(IndexOutOfBoundsException e){
httpStatusCode = HttpStatusCodes.INTERNAL_SERVER_ERROR;
exception = e;
}
// check for valid http method
if(httpMethod == null && httpMethod.equals(HttpMethods.GET) == false){
httpStatusCode = HttpStatusCodes.METHOD_NOT_ALLOWED;
}
// authorization header is lowercase in osdu services but standard is uppercase first letter
// check for valid JWT
String authorizationContents = headers.get(RequestKeys.AUTHORIZATION_HEADER_KEY);
if(authorizationContents == null){
authorizationContents = headers.get(RequestKeys.AUTHORIZATION_HEADER_KEY.toLowerCase());
}
String callerEmail = authorizer.validateJWT(authorizationContents);
if (httpStatusCode == HttpStatusCodes.UNASSIGNED && callerEmail == null) {
httpStatusCode = HttpStatusCodes.UNAUTHORIZED;
}
// check if user is owner of group
if(httpStatusCode == HttpStatusCodes.UNASSIGNED){
try {
if (isUserOwnerOfGroup(dynamoDBQueryHelper, headers.get(RequestKeys.DATA_PARTITION_ID_HEADER_KEY),
callerEmail, groupEmail) == false) {
httpStatusCode = HttpStatusCodes.UNAUTHORIZED;
}
} catch(Exception e){
httpStatusCode = HttpStatusCodes.INTERNAL_SERVER_ERROR;
exception = e;
}
}
// perform action
if(httpStatusCode == HttpStatusCodes.UNASSIGNED) {
try {
handleDeleteMember(groupEmail, headers.get("data-partition-id"), memberEmail);
respBody = String.format("%s removed from group %s", memberEmail, groupEmail);
httpStatusCode = HttpStatusCodes.OK;
} catch (NullPointerException e){
httpStatusCode = HttpStatus.SC_NOT_FOUND;
exception = e;
respBody = String.format("%s is not found in group %s", memberEmail, groupEmail);
}catch (Exception e) {
httpStatusCode = HttpStatus.SC_INTERNAL_SERVER_ERROR;
exception = e;
}
}
// return a response based on what the status code is
httpLambdaUtil.writeResponseBasedOnStatus(httpStatusCode, outputStream, respBody, respHeaders, exception);
}
/**
* Handles the actual action of deleting a member
* @param groupEmail
* @param dataPartitionId
* @param memberEmail
*/
private void handleDeleteMember(String groupEmail, String dataPartitionId, String memberEmail) {
dynamoDBQueryHelper.deleteByPrimaryKey(GroupsDoc.class, String.format("%s:%s:%s", dataPartitionId,
groupEmail, memberEmail));
}
/**
* Checks if calling user is an owner of the group which is required for the calling user to delete a member from the
* group
* @param dynamoDBQueryHelper
* @param dataPartitionId
* @param memberEmail
* @param groupEmail
* @return
* @throws IOException
*/
private boolean isUserOwnerOfGroup(DynamoDBQueryHelper dynamoDBQueryHelper, String dataPartitionId, String memberEmail,
String groupEmail) throws IOException {
boolean inGroup = false;
List<GroupsDoc> groups = GroupsUtil.getGroupsDocs(dynamoDBQueryHelper, dataPartitionId, memberEmail, groupEmail);
for(GroupsDoc group : groups){
if(group.getRole().equals(GroupRoles.OWNER.name())){
inGroup = true;
break;
}
}
return inGroup;
}
}
// Copyright © Amazon Web Services
//
// 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 com.amazonaws.osdu.entitlements;
import java.io.*;
import java.util.*;
import com.amazonaws.Request;
import com.amazonaws.services.xray.model.Http;
import com.fasterxml.jackson.core.JsonParseException;
import org.opengroup.osdu.core.aws.dynamodb.DynamoDBQueryHelper;
import org.opengroup.osdu.core.aws.entitlements.*;
import org.opengroup.osdu.core.aws.lambda.HttpLambdaUtil;
import org.opengroup.osdu.core.aws.lambda.HttpMethods;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.opengroup.osdu.core.aws.lambda.HttpStatusCodes;
import org.opengroup.osdu.core.aws.lambda.LambdaLogger;
public class GetGroups implements RequestStreamHandler {
HttpLambdaUtil httpLambdaUtil = new HttpLambdaUtil();
Authorizer authorizer = new Authorizer();
DynamoDBQueryHelper dynamoDBQueryHelper;
/**
* Constructor that sets up the ability to interact with Dynamo
*/
public GetGroups(){
this(
System.getenv("dynamoDBEndpoint"),
System.getenv("dynamoDBRegion"),
System.getenv("groupsTablePrefix")
);
}
/**
* Constructor used for unit testing
* @param amazonDynamoDBEndpoint
* @param amazonDynamoDBRegion
* @param tablePrefix
*/
public GetGroups(String amazonDynamoDBEndpoint, String amazonDynamoDBRegion, String tablePrefix) {
dynamoDBQueryHelper = new DynamoDBQueryHelper(amazonDynamoDBEndpoint, amazonDynamoDBRegion, tablePrefix);
}
/**
* The method that gets picked up after being called from the API gateway. GetGroups is the simplest
* of the entitlements lambdas. It calls to a static method in the util lib to get groups. This is in
* the util lib because it gets called by other lambdas too
* @param inputStream
* @param outputStream
* @param context
* @throws IOException
*/
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)
throws IOException {
ObjectMapper mapper = new ObjectMapper();
// initialize values filled by each check;
int httpStatusCode = HttpStatusCodes.UNASSIGNED;
Exception exception = new Exception();
String respBody = "";
Map<String, String> respHeaders = new HashMap<>();
Map<String, String> headers = new HashMap<>();
String httpMethod = "";
try{
Map<String, Object> request = mapper.readValue(inputStream, Map.class);
headers = (HashMap<String, String>) request.get(RequestKeys.HEADERS_REQUEST_KEY);
httpMethod = (String) request.get(RequestKeys.HTTP_METHOD_REQUEST_KEY);
httpLambdaUtil.logHeaders(headers);
} catch (ClassCastException e){
LambdaLogger.logException("Casting exception in parsing request, headers, httpMethod.", e);
httpStatusCode = HttpStatusCodes.INTERNAL_SERVER_ERROR;
exception = e;
} catch (IOException e){
LambdaLogger.logException("IO exception in parsing request, headers, httpMethod.", e);
httpStatusCode = HttpStatusCodes.INTERNAL_SERVER_ERROR;
exception = e;
} catch (Exception e){
LambdaLogger.logException("General exception in parsing request, headers, httpMethod.", e);
httpStatusCode = HttpStatusCodes.INTERNAL_SERVER_ERROR;
exception = e;
}
// check for valid http method
if(httpMethod == null && httpMethod.equals(HttpMethods.GET) == false){
httpStatusCode = HttpStatusCodes.METHOD_NOT_ALLOWED;
}
// check for valid JWT
// authorization header is lowercase in osdu services but standard is uppercase first letter
String authorizationContents = headers.get(RequestKeys.AUTHORIZATION_HEADER_KEY);
if(authorizationContents == null){
authorizationContents = headers.get(RequestKeys.AUTHORIZATION_HEADER_KEY.toLowerCase());
}
String memberEmail = authorizer.validateJWT(authorizationContents);
respHeaders.put(RequestKeys.USER_HEADER_KEY, memberEmail);
if (httpStatusCode == HttpStatusCodes.UNASSIGNED && memberEmail == null) {
httpStatusCode = HttpStatusCodes.UNAUTHORIZED;
}
// perform action
if (httpStatusCode == HttpStatusCodes.UNASSIGNED){
try {
String memberEmailAndDataPartitionId = GroupsUtil.GetMemberEmailAndDataPartitionId(memberEmail, headers);
List<GroupInfoRaw> groups = GroupsUtil.handleGetGroups(dynamoDBQueryHelper, memberEmailAndDataPartitionId);
respBody = mapper.writeValueAsString(groups);
httpStatusCode = HttpStatusCodes.OK;
} catch (Exception e) {
httpStatusCode = HttpStatusCodes.INTERNAL_SERVER_ERROR;
exception = e;
}
}
httpLambdaUtil.writeResponseBasedOnStatus(httpStatusCode, outputStream, respBody, respHeaders, exception);
}
}
// Copyright © Amazon Web Services
//
// 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 com.amazonaws.osdu.entitlements;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.opengroup.osdu.core.aws.dynamodb.DynamoDBQueryHelper;
import org.opengroup.osdu.core.aws.dynamodb.QueryPageResult;
import org.opengroup.osdu.core.aws.entitlements.*;
import org.opengroup.osdu.core.aws.lambda.HttpLambdaUtil;
import org.opengroup.osdu.core.aws.lambda.HttpMethods;
import org.opengroup.osdu.core.aws.lambda.HttpStatusCodes;
import org.opengroup.osdu.core.aws.lambda.LambdaLogger;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class GroupsGetMembers implements RequestStreamHandler {
private final static String limitQueryParamName = "limit";
private final static String cursorQueryParamName = "cursor";
private final static String roleQueryParamName = "role";
HttpLambdaUtil httpLambdaUtil = new HttpLambdaUtil();
Authorizer authorizer = new Authorizer();
DynamoDBQueryHelper dynamoDBQueryHelper;
String defaultRole;
String defaultLimitAmount;
/**
* Constructor that sets up the ability to interact with Dynamo
*/
public GroupsGetMembers(){
this(
System.getenv("dynamoDBEndpoint"),
System.getenv("dynamoDBRegion"),
System.getenv("groupsTablePrefix"),
System.getenv("defaultRole"),
System.getenv("defaultLimitAmount")
);
}
public GroupsGetMembers(String amazonDynamoDBEndpoint,
String amazonDynamoDBRegion,
String tablePrefix,
String defaultRole,
String defaultLimitAmount){
dynamoDBQueryHelper = new DynamoDBQueryHelper(amazonDynamoDBEndpoint, amazonDynamoDBRegion, tablePrefix);
this.defaultRole = defaultRole;
this.defaultLimitAmount = defaultLimitAmount;
}
/**
* Method that gets called by API Gateway. Parses the request into usuable objects and then does all the checks
* @param inputStream
* @param outputStream
* @param context
* @throws IOException
*/
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)
throws IOException {
ObjectMapper mapper = new ObjectMapper();
// initialize values filled by each check;
int httpStatusCode = HttpStatusCodes.UNASSIGNED;
Exception exception = new Exception();
String respBody = "";
Map<String, String> respHeaders = new HashMap<>();
String httpMethod = "";
Map<String, String> headers = new HashMap<>();
String path = "";
String[] pathSplit = new String[0];
Map<String, String> queryParameters = new HashMap<>();
try{
Map<String, Object> request = mapper.readValue(inputStream, Map.class);
httpMethod = (String) request.get(RequestKeys.HTTP_METHOD_REQUEST_KEY);
headers = (HashMap<String, String>) request.get(RequestKeys.HEADERS_REQUEST_KEY);
path = (String) request.get(RequestKeys.PATH_REQUEST_KEY);
pathSplit = (path).split("/");
queryParameters = (HashMap<String, String>) request.get(RequestKeys.QUERY_PARAMETERS_REQUEST_KEY);
if(queryParameters == null){
queryParameters = new HashMap<>();
}
httpLambdaUtil.logHeaders(headers);
} catch (ClassCastException e){
LambdaLogger.logException("Casting exception in parsing request, headers, httpMethod.", e);
httpStatusCode = HttpStatusCodes.INTERNAL_SERVER_ERROR;
exception = e;
} catch (IOException e){
LambdaLogger.logException("IO exception in parsing request, headers, httpMethod.", e);
httpStatusCode = HttpStatusCodes.INTERNAL_SERVER_ERROR;
exception = e;
} catch (Exception e){
LambdaLogger.logException("General exception in parsing request, headers, httpMethod.", e);
httpStatusCode = HttpStatusCodes.INTERNAL_SERVER_ERROR;
exception = e;
}
// get groupEmail from path
String groupEmail = "";
try {
groupEmail = pathSplit[2];
} catch(IndexOutOfBoundsException e){
httpStatusCode = HttpStatusCodes.INTERNAL_SERVER_ERROR;
exception = e;
}
// check for valid http method
if(httpMethod == null && httpMethod.equals(HttpMethods.GET) == false){
httpStatusCode = HttpStatusCodes.METHOD_NOT_ALLOWED;
}
// authorization header is lowercase in osdu services but standard is uppercase first letter
// check for valid JWT
String authorizationContents = headers.get(RequestKeys.AUTHORIZATION_HEADER_KEY);
if(authorizationContents == null){
authorizationContents = headers.get(RequestKeys.AUTHORIZATION_HEADER_KEY.toLowerCase());
}
String memberEmail = authorizer.validateJWT(authorizationContents);
if (httpStatusCode == HttpStatusCodes.UNASSIGNED && memberEmail == null) {
httpStatusCode = HttpStatusCodes.UNAUTHORIZED;
}
// check if user is member or owner of group
if(httpStatusCode == HttpStatusCodes.UNASSIGNED){
try {
if (isUserMemberOfGroup(dynamoDBQueryHelper, headers.get(RequestKeys.DATA_PARTITION_ID_HEADER_KEY),
memberEmail, groupEmail) == false) {
httpStatusCode = HttpStatusCodes.UNAUTHORIZED;
}
} catch(Exception e){
httpStatusCode = HttpStatusCodes.INTERNAL_SERVER_ERROR;
exception = e;
}
}
// perform action
if (httpStatusCode == HttpStatusCodes.UNASSIGNED){
try {
respBody = handleGetMembers(groupEmail, queryParameters);
httpStatusCode = HttpStatusCodes.OK;
} catch (Exception e) {
httpStatusCode = HttpStatusCodes.INTERNAL_SERVER_ERROR;
exception = e;
}
}
httpLambdaUtil.writeResponseBasedOnStatus(httpStatusCode, outputStream, respBody, respHeaders, exception);
}
/**
* Checks if calling user is member of the group that it's trying to get a list of members for
* @param dynamoDBQueryHelper
* @param dataPartitionId
* @param memberEmail
* @param groupEmail
* @return
* @throws IOException
*/
private boolean isUserMemberOfGroup(DynamoDBQueryHelper dynamoDBQueryHelper, String dataPartitionId, String memberEmail,
String groupEmail) throws IOException {
boolean inGroup = false;
List<GroupsDoc> groups = GroupsUtil.getGroupsDocs(dynamoDBQueryHelper, dataPartitionId, memberEmail, groupEmail);
for(GroupsDoc group : groups){
if(group.getRole().equals(GroupRoles.MEMBER.name()) || group.getRole().equals(GroupRoles.VIEWER.name())
|| group.getRole().equals(GroupRoles.OWNER.name())){
inGroup = true;
break;
}
}
return inGroup;
}
/**