Commit 305986ad authored by Matt Wise's avatar Matt Wise
Browse files

AWS Entitlements - Use ECS instead of Lambda, Update API

commit 83f2a9a77b4d74f2cc8ec35ec4e00fb928613ce5
Author: Matt Wise <wsmatth@amazon.com>
Date:   Mon Aug 17 14:49:15 2020 -0500

    import Random

commit 54b6fe5becf4e411fdcd14cddfc382afed9df0b2
Author: Matt Wise <wsmatth@amazon.com>
Date:   Mon Aug 17 14:41:30 2020 -0500

    Squashed commit of the following:

    commit 2a66b605d914bbd97db1660bb810ead51cfbd54c
    Author: Matt Wise <wsmatth@amazon.com>
    Date:   Mon Aug 17 13:12:48 2020 -0500

        Use JWT generator rather than hardcoded expired JWT

    commit 1eac420c1294f26e0d5826b7b9a9fdd3eb122122
    Author: Matt Wise <wsmatth@amazon.com>
    Date:   Mon Aug 17 09:26:00 2020 -0500

        Update CI/CD for GL

    commit 8a2bd8953860b5c71de4337b5dae2001e5d49c1e
    Author: Rucha Deshpande <deshruch@amazon.com>
    Date:   Thu Aug 13 20:57:28 2020 +0000

        Ecs impl changes

        commit a6cd7422
        Author: Matt Wise <wsmatth@amazon.com>
        Date: Thu Aug 13 2020 15:56:43 GMT-0500 (Central Daylight Time)

            Remove whitespace at end of file

        commit e4fc842f
        Author: Matt Wise <wsmatth@amazon.com>
        Date: Thu Aug 13 2020 15:56:09 GMT-0500 (Central Daylight Time)

            Add license/copyright

        commit a28b1f14
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Thu Aug 13 2020 15:44:55 GMT-0500 (Central Daylight Time)

            Adding copyright

        commit 1a616bd2
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Thu Aug 13 2020 15:42:04 GMT-0500 (Central Daylight Time)

            Adding copyright

        commit 79d770f8
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Thu Aug 13 2020 12:02:40 GMT-0500 (Central Daylight Time)

            Merge branch 'feat/ecs-impl-rebase' of https://git-codecommit.us-east-1.amazonaws.com/v1/repos/os-entitlements-aws into feat/ecs-impl-rebase

        commit 26d5263b
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Thu Aug 13 2020 12:00:56 GMT-0500 (Central Daylight Time)

            Adding appropriate copyright statements

        commit 87104a42
        Author: Matt Wise <wsmatth@amazon.com>
        Date: Tue Aug 11 2020 15:26:38 GMT-0500 (Central Daylight Time)

            Merge remote-tracking branch 'origin/dev' into feat/ecs-impl-rebase

        commit 461c4d7e
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Fri Aug 07 2020 16:50:05 GMT-0500 (Central Daylight Time)

            update core-lib-aws to 0.3.7

        commit 6803e98b
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Fri Aug 07 2020 14:44:50 GMT-0500 (Central Daylight Time)

            Updating os-core-lib-aws to 0.3.6 release version

        commit 6d490fd0
        Author: Matt Wise <wsmatth@amazon.com>
        Date: Fri Aug 07 2020 10:19:33 GMT-0500 (Central Daylight Time)

            update test pom to use 0.3.6-SNAPSHOT

        commit 34c1bfab
        Author: Matt Wise <wsmatth@amazon.com>
        Date: Fri Aug 07 2020 10:14:48 GMT-0500 (Central Daylight Time)

            use corretto8 as jdk version for build

        commit 16898129
        Author: Matt Wise <wsmatth@amazon.com>
        Date: Fri Aug 07 2020 10:08:28 GMT-0500 (Central Daylight Time)

            Update to use 0.3.6 core-common and 0.3.6-SNAPSHOT core-lib-aws.  Switch off of S3 and start using CodeArtifact for maven packages.  Use gitlab for core-common packages

        commit 66b079be
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Thu Aug 06 2020 09:15:05 GMT-0500 (Central Daylight Time)

            fixing  the package registry path

        commit 8d5c44b5
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Thu Aug 06 2020 08:55:42 GMT-0500 (Central Daylight Time)

            update os-corelib--aws version  to 0.3.6

        commit 590f6e54
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Thu Jul 30 2020 11:51:06 GMT-0500 (Central Daylight Time)

            added chmod for prepare-dist.sh

        commit caf348a3
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Thu Jul 30 2020 11:40:09 GMT-0500 (Central Daylight Time)

            removing ./maven/settings cp step

        commit 739ed353
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Thu Jul 30 2020 11:36:54 GMT-0500 (Central Daylight Time)

            updated int test steps

        commit dda14729
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Thu Jul 30 2020 11:35:04 GMT-0500 (Central Daylight Time)

            Int tests updates

        commit 9c452b4d
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Thu Jul 30 2020 11:34:45 GMT-0500 (Central Daylight Time)

            int tests

        commit fd12b61b
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Thu Jul 30 2020 11:34:09 GMT-0500 (Central Daylight Time)

            modified for integration test

        commit 077be858
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Wed Jul 29 2020 16:30:01 GMT-0500 (Central Daylight Time)

            Renaming the class

        commit bb588223
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Wed Jul 29 2020 15:36:43 GMT-0500 (Central Daylight Time)

            Uncommented integration test build steps

        commit b75d2699
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Wed Jul 29 2020 15:35:08 GMT-0500 (Central Daylight Time)

            Adding relevant variables

        commit afb66463
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Wed Jul 29 2020 15:32:46 GMT-0500 (Central Daylight Time)

            Int tests

        commit 66a6816b
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Wed Jul 29 2020 11:25:32 GMT-0500 (Central Daylight Time)

            changed m2 path/ removed commented dependencies

        commit 76b8dd23
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Wed Jul 29 2020 11:00:51 GMT-0500 (Central Daylight Time)

            updated os-core-lib-aws version to 0.3.5 and os-core-common to 0.3.4

        commit 4b07db8f
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Wed Jul 29 2020 11:00:12 GMT-0500 (Central Daylight Time)

            updated os-core-lic-aws version to 0.3.5

        commit 3605686a
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Wed Jul 29 2020 10:59:23 GMT-0500 (Central Daylight Time)

            Added some defaults

        commit f57b5ae0
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Wed Jul 29 2020 10:58:48 GMT-0500 (Central Daylight Time)

            uncommented int test env create/cleanup code

        commit 30e29930
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Wed Jul 29 2020 10:57:50 GMT-0500 (Central Daylight Time)

            Corrected error codes

        commit ae85ccb7
        Author: Rucha deshpande <deshruch@amazon.com>
        Date: Tue Jul 28 2020 16:55:10 GMT-0500 (Central Daylight Time)

            Adding ExceptionHandler for AppException

        commit cc3380d7
        Author: Matt Wise <wsmatth@amazon.com>
        Date: Tue Jul 28 2020 16:16:01 GMT-0500 (Central Daylight Time)

            rebase ecs impl changes on top of GL history
parent ca6cbacb
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;
}