From a3a3668cbf474d74876509d133b4b8ba191440bd Mon Sep 17 00:00:00 2001 From: Matt Wise <wsmatth@amazon.com> Date: Thu, 24 Sep 2020 18:08:24 +0000 Subject: [PATCH] AWS Implementation of Partition Service commit 1b1c1971 Author: Matt Wise <wsmatth@amazon.com> Date: Thu Sep 24 2020 12:59:53 GMT-0500 (Central Daylight Time) code review feedback commit 1f30b0d9 Author: Matt Wise <wsmatth@amazon.com> Date: Thu Sep 24 2020 11:52:45 GMT-0500 (Central Daylight Time) add handler for ssm parameter async put. make sure response isn't returned until ssm params all exist commit f0b23b95 Author: Matt Wise <wsmatth@amazon.com> Date: Wed Sep 23 2020 15:54:15 GMT-0500 (Central Daylight Time) create bad jwt for no-access tests commit a3df6cea Author: Matt Wise <wsmatth@amazon.com> Date: Wed Sep 23 2020 15:23:07 GMT-0500 (Central Daylight Time) add entitlement support for partition commit 2ec6d558 Author: Matt Wise <wsmatth@amazon.com> Date: Tue Sep 22 2020 14:32:06 GMT-0500 (Central Daylight Time) update int tests commit ba6979a6 Author: Matt Wise <wsmatth@amazon.com> Date: Mon Sep 21 2020 21:39:40 GMT-0500 (Central Daylight Time) add springboot actuator health check commit 541c3b87 Author: Matt Wise <wsmatth@amazon.com> Date: Mon Sep 21 2020 15:23:24 GMT-0500 (Central Daylight Time) fix import for AWSCognitoClient commit 1c249655 Author: Matt Wise <wsmatth@amazon.com> Date: Mon Sep 21 2020 14:36:16 GMT-0500 (Central Daylight Time) Work on integration tests commit c45e1435 Author: Matt Wise <wsmatth@amazon.com> Date: Mon Sep 21 2020 12:16:21 GMT-0500 (Central Daylight Time) Add copyright commit bd71cc33 Author: Matt Wise <wsmatth@amazon.com> Date: Mon Sep 21 2020 12:16:08 GMT-0500 (Central Daylight Time) Add dummy cache implementation commit 63f035ee Author: Matt Wise <wsmatth@amazon.com> Date: Mon Sep 21 2020 09:33:23 GMT-0500 (Central Daylight Time) for now, use basic auth. service should be protected by keeping it in a private subnet commit d575c5b3 Author: Matt Wise <wsmatth@amazon.com> Date: Mon Sep 21 2020 09:16:19 GMT-0500 (Central Daylight Time) surround environment var with braces commit a9deff7e Author: Matt Wise <wsmatth@amazon.com> Date: Wed Sep 09 2020 15:55:19 GMT-0500 (Central Daylight Time) add basic properties commit bf7fbc00 Author: Matt Wise <wsmatth@amazon.com> Date: Wed Sep 09 2020 15:48:19 GMT-0500 (Central Daylight Time) work on delete implementation merging common code commit 7364962a Author: Matt Wise <wsmatth@amazon.com> Date: Tue Sep 08 2020 17:36:28 GMT-0500 (Central Daylight Time) work on SSM implementation for partition commit 02f133a7 Author: Matt Wise <wsmatth@amazon.com> Date: Fri Sep 04 2020 16:38:05 GMT-0500 (Central Daylight Time) boilerplate implementation of AWS Partition Service commit b740ef22 Author: Matt Wise <wsmatth@amazon.com> Date: Fri Sep 04 2020 15:28:52 GMT-0500 (Central Daylight Time) start partition implementation --- .gitignore | 4 + pom.xml | 13 ++ provider/partition-aws/build-aws/Dockerfile | 22 ++ .../partition-aws/build-aws/build-info.py | 88 ++++++++ .../partition-aws/build-aws/buildspec.yaml | 84 ++++++++ provider/partition-aws/maven/settings.xml | 76 +++++++ provider/partition-aws/pom.xml | 191 ++++++++++++++++++ .../provider/aws/AwsServiceConfig.java | 34 ++++ .../provider/aws/PartitionApplication.java | 28 +++ .../provider/aws/cache/GroupCache.java | 40 ++++ .../security/AuthenticationRequestFilter.java | 96 +++++++++ .../aws/security/AuthorizationService.java | 50 +++++ .../aws/security/BasicAuthSecurityConfig.java | 30 +++ .../security/EntitlementsClientFactory.java | 48 +++++ .../EntitlementsAndCacheServiceImpl.java | 165 +++++++++++++++ .../PartitionServiceDummyCacheImpl.java | 49 +++++ .../aws/service/PartitionServiceImpl.java | 126 ++++++++++++ .../provider/aws/util/SSMHelper.java | 168 +++++++++++++++ .../src/main/resources/application.properties | 39 ++++ .../aws/service/PartitionServiceImplTest.java | 164 +++++++++++++++ .../org.mockito.plugins.MockMaker | 1 + .../build-aws/prepare-dist.sh | 48 +++++ .../partition-test-aws/build-aws/run-tests.sh | 61 ++++++ testing/partition-test-aws/pom.xml | 108 ++++++++++ .../partition/api/TestCreatePartition.java | 41 ++++ .../partition/api/TestDeletePartition.java | 41 ++++ .../partition/api/TestGetPartitionById.java | 40 ++++ .../osdu/partition/util/AwsTestUtils.java | 90 +++++++++ testing/pom.xml | 1 + 29 files changed, 1946 insertions(+) create mode 100644 provider/partition-aws/build-aws/Dockerfile create mode 100644 provider/partition-aws/build-aws/build-info.py create mode 100644 provider/partition-aws/build-aws/buildspec.yaml create mode 100644 provider/partition-aws/maven/settings.xml create mode 100644 provider/partition-aws/pom.xml create mode 100644 provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/AwsServiceConfig.java create mode 100644 provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/PartitionApplication.java create mode 100644 provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/cache/GroupCache.java create mode 100644 provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/security/AuthenticationRequestFilter.java create mode 100644 provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/security/AuthorizationService.java create mode 100644 provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/security/BasicAuthSecurityConfig.java create mode 100644 provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/security/EntitlementsClientFactory.java create mode 100644 provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/service/EntitlementsAndCacheServiceImpl.java create mode 100644 provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/service/PartitionServiceDummyCacheImpl.java create mode 100644 provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/service/PartitionServiceImpl.java create mode 100644 provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/util/SSMHelper.java create mode 100644 provider/partition-aws/src/main/resources/application.properties create mode 100644 provider/partition-aws/src/test/java/org/opengroup/osdu/partition/provider/aws/service/PartitionServiceImplTest.java create mode 100644 provider/partition-aws/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker create mode 100755 testing/partition-test-aws/build-aws/prepare-dist.sh create mode 100755 testing/partition-test-aws/build-aws/run-tests.sh create mode 100644 testing/partition-test-aws/pom.xml create mode 100644 testing/partition-test-aws/src/test/java/org/opengroup/osdu/partition/api/TestCreatePartition.java create mode 100644 testing/partition-test-aws/src/test/java/org/opengroup/osdu/partition/api/TestDeletePartition.java create mode 100644 testing/partition-test-aws/src/test/java/org/opengroup/osdu/partition/api/TestGetPartitionById.java create mode 100644 testing/partition-test-aws/src/test/java/org/opengroup/osdu/partition/util/AwsTestUtils.java diff --git a/.gitignore b/.gitignore index 07cd1b613..1a1358c15 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,7 @@ load-tests/*.pyc # VSCode .vscode/ + +.DS_STORE + +dist/ \ No newline at end of file diff --git a/pom.xml b/pom.xml index 4dd71ad62..681fed9ba 100644 --- a/pom.xml +++ b/pom.xml @@ -86,6 +86,7 @@ <modules> <module>partition-core</module> <module>provider/partition-azure</module> + <module>provider/partition-aws</module> </modules> <distributionManagement> @@ -128,5 +129,17 @@ <module>provider/partition-azure</module> </modules> </profile> + <profile> + <id>partition-aws</id> + <activation> + <property> + <name>env</name> + <value>partition-aws</value> + </property> + </activation> + <modules> + <module>provider/partition-aws</module> + </modules> + </profile> </profiles> </project> diff --git a/provider/partition-aws/build-aws/Dockerfile b/provider/partition-aws/build-aws/Dockerfile new file mode 100644 index 000000000..40a867437 --- /dev/null +++ b/provider/partition-aws/build-aws/Dockerfile @@ -0,0 +1,22 @@ +# Copyright © 2020 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. + +# https://docs.spring.io/spring-boot/docs/current/reference/html/deployment.html +FROM amazoncorretto:8 + +ARG JAR_FILE=provider/partition-aws/target/*spring-boot.jar +WORKDIR / +COPY ${JAR_FILE} app.jar +EXPOSE 8080 +ENTRYPOINT java $JAVA_OPTS -jar /app.jar diff --git a/provider/partition-aws/build-aws/build-info.py b/provider/partition-aws/build-aws/build-info.py new file mode 100644 index 000000000..1ea9b54bd --- /dev/null +++ b/provider/partition-aws/build-aws/build-info.py @@ -0,0 +1,88 @@ +# Copyright © 2020 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. +import boto3 +import json +import os +import argparse + +# Create the build-info.json +parser = argparse.ArgumentParser(description="") + +# env - CODEBUILD_SOURCE_VERSION +parser.add_argument("--branch", type=str, help="") + +# env - CODEBUILD_RESOLVED_SOURCE_VERSION +parser.add_argument("--commit", type=str, help="") + +# env - CODEBUILD_BUILD_ID +parser.add_argument("--buildid", type=str, help="") + +# env - CODEBUILD_BUILD_NUMBER +parser.add_argument("--buildnumber", type=str, help="") + +# Get from directory name +parser.add_argument("--reponame", type=str, help="") + +# env OUTPUT_DIR +parser.add_argument("--outdir", type=str, help="") + +# full ecr image and tag, and any other artifacts +parser.add_argument("--artifact", type=str, action="append", help="") + + + +args = parser.parse_args() + +branch = args.branch +commitId = args.commit +buildId = args.buildid +buildNumber = args.buildnumber +repoName = args.reponame +outputDir = args.outdir +artifacts = args.artifact + +buildInfoFilePath = os.path.join(".", outputDir, "build-info.json") + +print(buildInfoFilePath) + +commitArgs = { + "repositoryName": repoName, + "commitId": commitId +} + +commitDetail = { + "commit": "" +} + +# get the commit detail +try: + codecommit = boto3.client("codecommit") + commitDetail = codecommit.get_commit(**commitArgs) +except Exception as e: + print("Getting commit information from codecommit failed") + +buildInfo = { + "branch": branch, + "build-id": buildId, + "build-number": buildNumber, + "repo": repoName, + "artifacts": artifacts, + "commit": commitDetail["commit"] +} +print(json.dumps(buildInfo, sort_keys=True, indent=4)) + +# write the build.json file to dist +f = open(buildInfoFilePath, "w") +f.write(json.dumps(buildInfo, sort_keys=True, indent=4)) +f.close() diff --git a/provider/partition-aws/build-aws/buildspec.yaml b/provider/partition-aws/build-aws/buildspec.yaml new file mode 100644 index 000000000..a85e849bd --- /dev/null +++ b/provider/partition-aws/build-aws/buildspec.yaml @@ -0,0 +1,84 @@ +# Copyright © 2020 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. + +# https://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html + +# https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html +version: 0.2 + +phases: + install: + runtime-versions: + java: corretto8 + commands: + - if [ $(echo $CODEBUILD_SOURCE_VERSION | grep -c ^refs/heads.*) -eq 1 ]; then echo "Branch name found"; else echo "This build only supports branch builds" && exit 1; fi + - apt-get update -y + - apt-get install -y maven + - java -version + - mvn -version + - mkdir -p /root/.m2 + - cp ./provider/partition-aws/maven/settings.xml /root/.m2/settings.xml # copy the AWS-specific settings.xml to the CodeBuild instance's .m2 folder + - export AWS_ACCOUNT_ID=`aws sts get-caller-identity | grep Account | cut -d':' -f 2 | cut -d'"' -f 2` + - export AWS_OSDU_DEV_MAVEN_AUTH_TOKEN=`aws codeartifact get-authorization-token --domain $AWS_OSDU_DEV_MAVEN_DOMAIN --domain-owner $AWS_ACCOUNT_ID --query authorizationToken --output text` + pre_build: + commands: + - echo "Logging in to Amazon ECR..." + - $(aws ecr get-login --no-include-email --region $AWS_REGION) # authenticate with ECR via the AWS CLI + build: + commands: + - export REPO_NAME=${PWD##*/} + - export OUTPUT_DIR="dist" + - export BRANCH_NAME=`echo ${CODEBUILD_SOURCE_VERSION} | awk '{gsub("refs/heads/","");gsub("\\.","-");gsub("[[:space:]]","-")}1' | sed 's/\//-/g' | awk '{print tolower($0)}'` + - export ECR_TAG=`echo build.${BRANCH_NAME}.${CODEBUILD_BUILD_NUMBER}.${CODEBUILD_RESOLVED_SOURCE_VERSION} | cut -c 1-120` + - export ECR_IMAGE=${ECR_REGISTRY}:${ECR_TAG} + - export ECR_IMAGE_BRANCH_LATEST=${ECR_REGISTRY}:${BRANCH_NAME} + - export INTEGRATION_TEST_OUTPUT=${OUTPUT_DIR}/testing/integration + - export INTEGRATION_TEST_OUTPUT_BIN=${INTEGRATION_TEST_OUTPUT}/bin + - mkdir -p ${OUTPUT_DIR}/bin + - mkdir -p ${OUTPUT_DIR}/testing && mkdir -p ${INTEGRATION_TEST_OUTPUT} && mkdir -p ${INTEGRATION_TEST_OUTPUT}/bin + - echo "Placeholder" >> ${OUTPUT_DIR}/build-info.json # touched so that the output directory has some content incase the build fails so that testing reports are uploaded + - printenv + + - echo "Building primary service assemblies..." + - mvn -B test install -pl partition-core,provider/partition-aws -Ddeployment.environment=prod + + - echo "Building integration testing assemblies and gathering artifacts..." + - ./testing/partition-test-aws/build-aws/prepare-dist.sh + + - echo "Building docker image..." + - docker build -f provider/partition-aws/build-aws/Dockerfile -t ${ECR_IMAGE} . + - docker tag ${ECR_IMAGE} ${ECR_IMAGE_BRANCH_LATEST} + - echo "Pushing docker image..." + - docker push ${ECR_IMAGE} + - docker push ${ECR_IMAGE_BRANCH_LATEST} + + - echo "Generate build-info.json" + - | + python provider/partition-aws/build-aws/build-info.py --branch ${CODEBUILD_SOURCE_VERSION} --commit ${CODEBUILD_RESOLVED_SOURCE_VERSION} \ + --buildid ${CODEBUILD_BUILD_ID} --buildnumber ${CODEBUILD_BUILD_NUMBER} --reponame ${REPO_NAME} --outdir ${OUTPUT_DIR} \ + --artifact ${ECR_IMAGE} +reports: + SurefireReports: # CodeBuild will create a report group called "SurefireReports". + files: #Store all of the files + - "partition-core/target/surefire-reports/**/*" + - "provider/partition-aws/target/surefire-reports/**/*" + base-directory: "." # Location of the reports +artifacts: + files: + - "**/*" + base-directory: "dist" + name: ${REPO_NAME}_${BRANCH_NAME}_$(date +%F)_${CODEBUILD_BUILD_NUMBER}.zip +cache: + paths: + - "/root/.m2/**/*" \ No newline at end of file diff --git a/provider/partition-aws/maven/settings.xml b/provider/partition-aws/maven/settings.xml new file mode 100644 index 000000000..b8192246c --- /dev/null +++ b/provider/partition-aws/maven/settings.xml @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright © 2020 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. +--> + +<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"> + + <profiles> + <profile> + <id>aws-osdu-dev-maven</id> + <activation> + <activeByDefault>true</activeByDefault> + </activation> + <repositories> + <repository> + <id>aws-osdu-dev-maven</id> + <url>${env.AWS_OSDU_DEV_MAVEN_URL}</url> + </repository> + <repository> + <id>gitlab-os-core-common-maven</id> + <url>https://community.opengroup.org/api/v4/projects/67/packages/maven</url> + </repository> + </repositories> + </profile> + <profile> + <id>credentialsConfiguration</id> + <activation> + <activeByDefault>true</activeByDefault> + </activation> + <properties> + <deployment.environment>dev</deployment.environment> + <aws.accessKeyId>no-default</aws.accessKeyId> + <aws.secretKey>no-default</aws.secretKey> + <azure.devops.username>Another-Access-Token-2021</azure.devops.username> + <azure.devops.token>no-default</azure.devops.token> + </properties> + </profile> + </profiles> + + <servers> + <server> + <id>aws-osdu-dev-maven</id> + <username>aws</username> + <password>${env.AWS_OSDU_DEV_MAVEN_AUTH_TOKEN}</password> + </server> + </servers> + + <!-- CodeArtifact doesn't support external repos yet that aren't Maven Central. ETA Q4 2020. --> + <!-- <mirrors> --> + <!-- <mirror> --> + <!-- <id>aws-osdu-dev-maven</id> --> + <!-- <name>aws-osdu-dev-maven</name> --> + <!-- <url>https://osdu-dev-888733619319.d.codeartifact.us-east-1.amazonaws.com/maven/osdu-maven/</url> --> + <!-- <mirrorOf>*,!gitlab-os-core-common-maven</mirrorOf> --> + <!-- </mirror> --> + <!-- </mirrors> --> + + <activeProfiles> + <activeProfile>credentialsConfiguration</activeProfile> + </activeProfiles> + +</settings> \ No newline at end of file diff --git a/provider/partition-aws/pom.xml b/provider/partition-aws/pom.xml new file mode 100644 index 000000000..f6b201832 --- /dev/null +++ b/provider/partition-aws/pom.xml @@ -0,0 +1,191 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + Copyright © 2020 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. + --> + +<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>../../</relativePath> + </parent> + + <modelVersion>4.0.0</modelVersion> + <artifactId>partition-aws</artifactId> + <version>1.0.0</version> + <description>Partition service on AWS</description> + <packaging>jar</packaging> + + <properties> + <aws.version>1.11.637</aws.version> + <deployment.environment>dev</deployment.environment> + </properties> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>com.amazonaws</groupId> + <artifactId>aws-java-sdk-bom</artifactId> + <version>${aws.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <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.core.aws</groupId> + <artifactId>os-core-lib-aws</artifactId> + <version>0.3.7</version> + </dependency> + <dependency> + <groupId>org.opengroup.osdu</groupId> + <artifactId>partition-core</artifactId> + <version>1.0.0</version> + </dependency> + + <!-- AWS managed packages --> + <dependency> + <groupId>com.amazonaws</groupId> + <artifactId>aws-java-sdk</artifactId> + <version>${aws.version}</version> + </dependency> + <dependency> + <groupId>com.amazonaws</groupId> + <artifactId>aws-java-sdk-dynamodb</artifactId> + </dependency> + <dependency> + <groupId>com.amazonaws</groupId> + <artifactId>aws-java-sdk-s3</artifactId> + </dependency> + <dependency> + <groupId>com.amazonaws</groupId> + <artifactId>aws-java-sdk-sns</artifactId> + </dependency> + <dependency> + <groupId>com.amazonaws</groupId> + <artifactId>aws-java-sdk-cognitoidentity</artifactId> + </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> + + <!-- 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.aws.PartitionApplication</mainClass> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> diff --git a/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/AwsServiceConfig.java b/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/AwsServiceConfig.java new file mode 100644 index 000000000..005231193 --- /dev/null +++ b/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/AwsServiceConfig.java @@ -0,0 +1,34 @@ +// Copyright © 2020, 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 org.opengroup.osdu.partition.provider.aws; + +import javax.annotation.PostConstruct; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class AwsServiceConfig { + + @Value("${aws.resource.prefix}") + public String environment; + + public String ssmPartitionPrefix; + + @PostConstruct + public void init() { + ssmPartitionPrefix = "/osdu/" + environment + "/partition/partitions/"; + } +} diff --git a/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/PartitionApplication.java b/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/PartitionApplication.java new file mode 100644 index 000000000..1a36bf2ec --- /dev/null +++ b/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/PartitionApplication.java @@ -0,0 +1,28 @@ +// Copyright © 2020 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 org.opengroup.osdu.partition.provider.aws; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +@ComponentScan({"org.opengroup.osdu"}) +@SpringBootApplication +public class PartitionApplication { + + public static void main(String[] args) { + SpringApplication.run(PartitionApplication.class, args); + } +} \ No newline at end of file diff --git a/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/cache/GroupCache.java b/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/cache/GroupCache.java new file mode 100644 index 000000000..497363457 --- /dev/null +++ b/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/cache/GroupCache.java @@ -0,0 +1,40 @@ +// Copyright © 2020 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 org.opengroup.osdu.partition.provider.aws.cache; + +import org.opengroup.osdu.core.common.model.http.DpsHeaders; +import org.opengroup.osdu.core.common.model.entitlements.Groups; +import org.opengroup.osdu.core.common.cache.RedisCache; +import org.opengroup.osdu.core.common.util.Crc32c; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class GroupCache extends RedisCache<String, Groups> { + public GroupCache(@Value("${aws.elasticache.cluster.endpoint}") final String REDIS_GROUP_HOST, @Value("${aws.elasticache.cluster.port}") final String REDIS_GROUP_PORT) { + super(REDIS_GROUP_HOST, Integer.parseInt(REDIS_GROUP_PORT), 30, String.class, Groups.class); + } + + public static String getGroupCacheKey(DpsHeaders headers) { + String key = String.format("entitlement-groups:%s:%s", headers.getPartitionIdWithFallbackToAccountId(), + headers.getAuthorization()); + return Crc32c.hashToBase64EncodedString(key); + } + + public static String getPartitionGroupsCacheKey(String dataPartitionId) { + String key = String.format("entitlement-groups:data-partition:%s", dataPartitionId); + return Crc32c.hashToBase64EncodedString(key); + } +} diff --git a/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/security/AuthenticationRequestFilter.java b/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/security/AuthenticationRequestFilter.java new file mode 100644 index 000000000..891dae938 --- /dev/null +++ b/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/security/AuthenticationRequestFilter.java @@ -0,0 +1,96 @@ +// Copyright © 2020 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 org.opengroup.osdu.partition.provider.aws.security; + +// import java.io.IOException; +// import java.util.Collections; +// import java.util.function.Function; +// import java.util.logging.Logger; +// import java.util.stream.Collectors; + +// import javax.servlet.FilterChain; +// import javax.servlet.ServletException; +// import javax.servlet.http.HttpServletRequest; +// import javax.servlet.http.HttpServletResponse; + +// import org.opengroup.osdu.core.common.model.http.AppException; +// import org.opengroup.osdu.core.common.model.http.DpsHeaders; +// import org.springframework.http.HttpHeaders; +// import org.springframework.lang.NonNull; +// import org.springframework.security.authentication.AnonymousAuthenticationToken; +// import org.springframework.security.core.context.SecurityContextHolder; +// import org.springframework.util.MultiValueMap; +// import org.springframework.web.filter.OncePerRequestFilter; +// import org.springframework.web.servlet.HandlerExceptionResolver; +// import org.opengroup.osdu.core.common.model.entitlements.Groups; + +// public class AuthenticationRequestFilter extends OncePerRequestFilter { + +// private static Logger logger = Logger.getLogger(AuthenticationRequestFilter.class.getName()); + +// private final HandlerExceptionResolver handlerExceptionResolver; + +// public AuthenticationRequestFilter(HandlerExceptionResolver handlerExceptionResolver) { +// this.handlerExceptionResolver = handlerExceptionResolver; +// } + +// @Override +// protected void doFilterInternal(@NonNull HttpServletRequest httpServletRequest, +// @NonNull HttpServletResponse httpServletResponse, +// @NonNull FilterChain filterChain) throws ServletException, IOException { +// MultiValueMap<String, String> requestHeaders = httpHeaders(httpServletRequest); +// DpsHeaders dpsHeaders = DpsHeaders.createFromEntrySet(requestHeaders.entrySet()); +// dpsHeaders.addCorrelationIdIfMissing(); + +// try { + +// // String message = String.format("User authenticated | User: %s", groups.getMemberEmail()); +// authenticate(null); +// // logger.info(message); +// filterChain.doFilter(httpServletRequest, httpServletResponse); +// } +// // catch (EntitlementsException e) { +// // String message = String.format("User not authenticated. Response: %s", e.getHttpResponse()); +// // logger.warning(message); +// // AppException unauthorized = AppException.createUnauthorized("Error: " + e.getMessage()); +// // handlerExceptionResolver.resolveException(httpServletRequest, httpServletResponse, null, unauthorized); +// // } +// catch (NullPointerException e) { +// String message = String.format("User not authenticated. Null pointer exception: %s", e.getMessage()); +// logger.warning(message); +// AppException unauthorized = AppException.createUnauthorized("Error: " + e.getMessage()); +// handlerExceptionResolver.resolveException(httpServletRequest, httpServletResponse, null, unauthorized); +// } + +// } + +// private void authenticate(Groups groups) { +// OsduAuthentication authentication = new OsduAuthentication(groups, emptyList()); +// authentication.setAuthenticated(true); +// SecurityContextHolder.getContext().setAuthentication(authentication); +// } + +// private HttpHeaders httpHeaders(@NonNull HttpServletRequest httpRequest) { +// return Collections +// .list(httpRequest.getHeaderNames()) +// .stream() +// .collect(Collectors.toMap( +// Function.identity(), +// h -> Collections.list(httpRequest.getHeaders(h)), +// (oldValue, newValue) -> newValue, +// HttpHeaders::new +// )); +// } +// } diff --git a/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/security/AuthorizationService.java b/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/security/AuthorizationService.java new file mode 100644 index 000000000..b88e2e042 --- /dev/null +++ b/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/security/AuthorizationService.java @@ -0,0 +1,50 @@ +// Copyright © 2020 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 org.opengroup.osdu.partition.provider.aws.security; + +import org.opengroup.osdu.core.common.entitlements.IEntitlementsAndCacheService; +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.stereotype.Component; +import org.springframework.web.context.annotation.RequestScope; + +@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; + + @Override + public boolean isDomainAdminServiceAccount() { + return hasRole(PARTITION_ADMIN_ROLE); + } + + 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; + } + +} + diff --git a/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/security/BasicAuthSecurityConfig.java b/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/security/BasicAuthSecurityConfig.java new file mode 100644 index 000000000..7193321fc --- /dev/null +++ b/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/security/BasicAuthSecurityConfig.java @@ -0,0 +1,30 @@ +// Copyright © 2020 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 org.opengroup.osdu.partition.provider.aws.security; + +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class BasicAuthSecurityConfig extends WebSecurityConfigurerAdapter { + protected void configure(HttpSecurity http) throws Exception { + ((HttpSecurity)http.httpBasic().disable()) + .csrf().disable(); + } +} diff --git a/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/security/EntitlementsClientFactory.java b/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/security/EntitlementsClientFactory.java new file mode 100644 index 000000000..8420ca502 --- /dev/null +++ b/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/security/EntitlementsClientFactory.java @@ -0,0 +1,48 @@ +// 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.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.config.AbstractFactoryBean; +import org.springframework.stereotype.Component; + +@Component +public class EntitlementsClientFactory extends AbstractFactoryBean<IEntitlementsFactory> { + + @Value("${AUTHORIZE_API}") + private String AUTHORIZE_API; + + @Value("${AUTHORIZE_API_KEY:}") + private String AUTHORIZE_API_KEY; + + @Override + protected IEntitlementsFactory createInstance() throws Exception { + + return new EntitlementsFactory(EntitlementsAPIConfig + .builder() + .rootUrl(AUTHORIZE_API) + .apiKey(AUTHORIZE_API_KEY) + .build()); + } + + @Override + public Class<?> getObjectType() { + return IEntitlementsFactory.class; + } +} \ No newline at end of file diff --git a/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/service/EntitlementsAndCacheServiceImpl.java b/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/service/EntitlementsAndCacheServiceImpl.java new file mode 100644 index 000000000..4c62bbf80 --- /dev/null +++ b/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/service/EntitlementsAndCacheServiceImpl.java @@ -0,0 +1,165 @@ +// 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); + } +} diff --git a/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/service/PartitionServiceDummyCacheImpl.java b/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/service/PartitionServiceDummyCacheImpl.java new file mode 100644 index 000000000..a5f93dda6 --- /dev/null +++ b/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/service/PartitionServiceDummyCacheImpl.java @@ -0,0 +1,49 @@ +// Copyright © 2020 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 org.opengroup.osdu.partition.provider.aws.service; + +import org.opengroup.osdu.partition.model.PartitionInfo; +import org.opengroup.osdu.partition.provider.interfaces.IPartitionServiceCache; +import org.springframework.stereotype.Service; + +/*** + * We don't want to use cache. Implement a dummy service to always return a cache miss. + */ +@Service +public class PartitionServiceDummyCacheImpl implements IPartitionServiceCache { + public PartitionServiceDummyCacheImpl() { + + } + + @Override + public void clearAll() { + return; + } + + @Override + public void delete(String arg0) { + return; + } + + @Override + public PartitionInfo get(String arg0) { + return null; + } + + @Override + public void put(String arg0, PartitionInfo arg1) { + return; + } +} diff --git a/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/service/PartitionServiceImpl.java b/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/service/PartitionServiceImpl.java new file mode 100644 index 000000000..d6fbb17c1 --- /dev/null +++ b/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/service/PartitionServiceImpl.java @@ -0,0 +1,126 @@ +// Copyright © 2020 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 org.opengroup.osdu.partition.provider.aws.service; + +import java.util.Map; + +import com.amazonaws.partitions.model.Partition; + +import org.apache.http.HttpStatus; +import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; +import org.opengroup.osdu.core.common.model.http.AppException; +import org.opengroup.osdu.partition.model.PartitionInfo; +import org.opengroup.osdu.partition.provider.aws.util.SSMHelper; +import org.opengroup.osdu.partition.provider.interfaces.IPartitionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class PartitionServiceImpl implements IPartitionService { + + @Autowired + private JaxRsDpsLog logger; + + @Autowired + private SSMHelper ssmHelper; + + public PartitionServiceImpl() { + + } + + @Override + public PartitionInfo createPartition(String partitionId, PartitionInfo partitionInfo) { + + if (ssmHelper.partitionExists(partitionId)) { + throw new AppException(HttpStatus.SC_CONFLICT, "partition exist", "Partition with same id exist"); + } + + try { + for (Map.Entry<String, Object> entry : partitionInfo.getProperties().entrySet()) { + ssmHelper.createOrUpdateSecret(partitionId, entry.getKey(), entry.getValue()); + } + + /** + * SSM parameters are not immediately available after pushing to System Manager. + * This API is expected to return a 200 response meaning that the parameters should be available immediately. + * This logic is added to validate when the parameters become available before returning the 200 response. + * The performance hit is acceptable because partitions are only created as an early operation and shouldn't affect + * the performance of runtime workflows + */ + int retryCount = 5; + boolean partitionReady = false; + while (!partitionReady && retryCount > 0) { + retryCount--; + Map<String, Object> partitionCheck = ssmHelper.getPartitionSecrets(partitionId); + if (partitionCheck.size() == partitionInfo.getProperties().size()) + partitionReady = true; + else + Thread.sleep(250); + } + + if (!partitionReady) { + try { + this.deletePartition(partitionId); + } + catch (Exception e){ + + } + + throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "Partition Creation Failed", "One or more secrets couldn't be stored within the timeout limit"); + + } + } + catch (Exception e) { + + try { + Thread.sleep(2000); //wait for any existing ssm parameters that got added to normalize + this.deletePartition(partitionId); + } + catch (Exception deleteE) { + //if the partition didnt get created at all deletePartition will throw an exception. Eat it so we return the creation exception. + } + + logger.error("Failed to create partition due to key creation failure in ssm", e.getMessage()); + throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "Partition Creation Failure", e.getMessage(), e); + } + + return partitionInfo; + } + + @Override + public PartitionInfo getPartition(String partitionId) { + + Map<String,Object> secrets = ssmHelper.getPartitionSecrets(partitionId); + + + //throw error if partition doesn't exist + if (secrets.size() <= 0) { + throw new AppException(HttpStatus.SC_NOT_FOUND, "partition not found", String.format("%s partition not found", partitionId)); + } + + return PartitionInfo.builder().properties(secrets).build(); + } + + @Override + public boolean deletePartition(String partitionId) { + + if (!ssmHelper.partitionExists(partitionId)) { + throw new AppException(HttpStatus.SC_NOT_FOUND, "partition not found", String.format("%s partition not found", partitionId)); + } + + return ssmHelper.deletePartitionSecrets(partitionId); + } + +} diff --git a/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/util/SSMHelper.java b/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/util/SSMHelper.java new file mode 100644 index 000000000..a76bb6f54 --- /dev/null +++ b/provider/partition-aws/src/main/java/org/opengroup/osdu/partition/provider/aws/util/SSMHelper.java @@ -0,0 +1,168 @@ +// Copyright © 2020 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 org.opengroup.osdu.partition.provider.aws.util; + +import java.net.URI; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +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 org.opengroup.osdu.core.aws.iam.IAMConfig; +import org.opengroup.osdu.partition.provider.aws.AwsServiceConfig; +import org.springframework.stereotype.Component; + +@Component +public final class SSMHelper { + + @Inject + private AwsServiceConfig awsServiceConfig; + + private AWSCredentialsProvider amazonAWSCredentials; + private AWSSimpleSystemsManagement ssmManager; + + public SSMHelper() { + amazonAWSCredentials = IAMConfig.amazonAWSCredentials(); + ssmManager = AWSSimpleSystemsManagementClientBuilder.standard() + .withCredentials(amazonAWSCredentials) + .build(); + } + + // public boolean secretExists(String secretName) { + // GetParameterRequest request = new GetParameterRequest().withName(secretName); + // GetParameterResult result = ssmManager.getParameter(request); + + // return result.getParameter() != null; + // } + + private String getSsmPathForPartitition(String partitionName) { + return URI.create(getTenantPrefix() + '/' + partitionName + '/').normalize().toString(); + } + + private String getSsmPathForPartititionSecret(String partitionName, String secretName) { + return URI.create(getSsmPathForPartitition(partitionName) + '/' + secretName).normalize().toString(); + } + + private List<Parameter> getSsmParamsForPartition(String partitionName) { + + String ssmPath = getSsmPathForPartitition(partitionName); + + GetParametersByPathRequest request = new GetParametersByPathRequest() + .withPath(ssmPath) + .withRecursive(true) + .withWithDecryption(true); + + GetParametersByPathResult result = ssmManager.getParametersByPath(request); + + return result.getParameters(); + } + + public List<String> getSsmParamsPathsForPartition(String partitionName) { + + String ssmPath = getSsmPathForPartitition(partitionName); + + GetParametersByPathRequest request = new GetParametersByPathRequest() + .withPath(ssmPath) + .withRecursive(true) + .withWithDecryption(true); + + GetParametersByPathResult result = ssmManager.getParametersByPath(request); + + List<String> ssmParamNames = result.getParameters().stream().map(Parameter::getName).collect(Collectors.toList()); + + return ssmParamNames; + } + + public boolean partitionExists(String partitionName) { + + String ssmPath = getSsmPathForPartitition(partitionName); + + GetParametersByPathRequest request = new GetParametersByPathRequest() + .withPath(ssmPath) + .withRecursive(true) + .withMaxResults(1); + + GetParametersByPathResult result = ssmManager.getParametersByPath(request); + + return result.getParameters().size() > 0; + } + + public Map<String, Object> getPartitionSecrets(String partitionName) { + + List<Parameter> partitionSsmParameters = getSsmParamsForPartition(partitionName); + + String ssmPath = getSsmPathForPartitition(partitionName); + + Map<String,Object> kvMap = new HashMap<>(); + + for (Parameter parameter : partitionSsmParameters) { + + String shortName = parameter.getName().substring(ssmPath.length()); + + kvMap.put(shortName, parameter.getValue()); + } + + return kvMap; + } + + public boolean createOrUpdateSecret(String partitionName, String secretName, Object secretValue) { + + String ssmPath = getSsmPathForPartititionSecret(partitionName, secretName); + + PutParameterRequest request = new PutParameterRequest() + .withName(ssmPath) + .withType(ParameterType.SecureString) + .withValue(String.valueOf(secretValue)); + + + PutParameterResult result = ssmManager.putParameter(request); + + //secret creation throws an exception if there's an error so we wont hit here + return true; + + } + + public boolean deletePartitionSecrets(String partitionName) { + + List<String> ssmParamPaths = getSsmParamsPathsForPartition(partitionName); + + DeleteParametersRequest request = new DeleteParametersRequest() + .withNames(ssmParamPaths); + + DeleteParametersResult result = ssmManager.deleteParameters(request); + + return result.getDeletedParameters().size() > 0; + + } + + private String getTenantPrefix() { + return awsServiceConfig.ssmPartitionPrefix; + } +} diff --git a/provider/partition-aws/src/main/resources/application.properties b/provider/partition-aws/src/main/resources/application.properties new file mode 100644 index 000000000..ebf7995d7 --- /dev/null +++ b/provider/partition-aws/src/main/resources/application.properties @@ -0,0 +1,39 @@ +# Copyright © 2020 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. + +LOG_PREFIX=partition +server.servlet.contextPath=/api/partition/v1 +logging.level.org.springframework.web=${LOG_LEVEL:INFO} +JAVA_OPTS=-Dserver.port=80 +server.port=8080 +spring.data.redis.repositories.enabled=false +springfox.documentation.swagger.v2.path=/api-docs + +AUTHORIZE_API=${ENTITLEMENTS_BASE_URL}/api/entitlements/v1 + +#logging configuration +logging.transaction.enabled=true +logging.slf4jlogger.enabled=true + +aws.resource.prefix=${ENVIRONMENT} + +## AWS DynamoDB configuration +## These are not used right now by partition service, but core-lib tenantfactory crashes if they're not set +aws.dynamodb.key=id +aws.dynamodb.table.prefix=${ENVIRONMENT}- +aws.dynamodb.region=${AWS_REGION} +aws.dynamodb.endpoint=dynamodb.${AWS_REGION}.amazonaws.com + +## AWS ElastiCache configuration +aws.elasticache.cluster.endpoint=${CACHE_CLUSTER_ENDPOINT} +aws.elasticache.cluster.port=${CACHE_CLUSTER_PORT} \ No newline at end of file diff --git a/provider/partition-aws/src/test/java/org/opengroup/osdu/partition/provider/aws/service/PartitionServiceImplTest.java b/provider/partition-aws/src/test/java/org/opengroup/osdu/partition/provider/aws/service/PartitionServiceImplTest.java new file mode 100644 index 000000000..6b9c468ba --- /dev/null +++ b/provider/partition-aws/src/test/java/org/opengroup/osdu/partition/provider/aws/service/PartitionServiceImplTest.java @@ -0,0 +1,164 @@ +// Copyright © 2020 Amazon Web Services +// Copyright 2017-2020, 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.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; +import org.opengroup.osdu.core.common.model.http.AppException; +import org.opengroup.osdu.partition.model.PartitionInfo; +import org.opengroup.osdu.partition.provider.aws.util.SSMHelper; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executors; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.powermock.api.mockito.PowerMockito.mockStatic; + +@RunWith(PowerMockRunner.class) +public class PartitionServiceImplTest { + + @Mock + private SSMHelper ssmHelper; + + @InjectMocks + private PartitionServiceImpl partService; + + private PartitionInfo partitionInfo = new PartitionInfo(); + + private Map<String,Object> partitionSecretMap = new HashMap<>(); + + @Before + public void setup() { + + partitionSecretMap.put("id", "my-tenant"); + partitionSecretMap.put("storageAccount", "storage-account"); + partitionSecretMap.put("complianceRuleSet", "compliance-rule-set"); + partitionInfo.setProperties(partitionSecretMap); + + } + + @Test + public void should_ThrowConflictError_when_createPartition_whenPartitionExists() { + when(ssmHelper.partitionExists(any())).thenReturn(true); + + try { + partService.createPartition(this.partitionInfo.getProperties().get("id").toString(), this.partitionInfo); + //we should never hit this code because create partition should end in an error + assertTrue("Expected partService.createPartition to throw an exception, but passed",false); + } catch (AppException e) { + assertTrue(e.getError().getCode() == 409); + assertTrue(e.getError().getReason().equalsIgnoreCase("partition exist")); + assertTrue(e.getError().getMessage().equalsIgnoreCase("Partition with same id exist")); + } + } + + @Test + public void should_returnPartitionInfo_when_createPartition_whenPartitionDoesntExist() { + + when(ssmHelper.partitionExists(any())).thenReturn(false); + when(ssmHelper.createOrUpdateSecret(any(), any(), any())).thenReturn(true); + when(ssmHelper.getPartitionSecrets(any())).thenReturn(this.partitionInfo.getProperties()); + + PartitionInfo partInfo = partService.createPartition(this.partitionInfo.getProperties().get("id").toString(), this.partitionInfo); + assertTrue(partInfo.getProperties().size() == 3); + assertTrue(partInfo.getProperties().containsKey("id")); + assertTrue(partInfo.getProperties().containsKey("complianceRuleSet")); + assertTrue(partInfo.getProperties().containsKey("storageAccount")); + } + + @Test + public void should_returnPartition_when_partitionExists() { + + String Key1 = "my-tenant-id"; + String Key2 = "my-tenant-groups"; + String Key3 = "my-tenant-complianceRuleSet"; + + HashMap<String,Object> propertiesMap = new HashMap<>(); + propertiesMap.put("id", this.partitionInfo.getProperties().get("id").toString()); + propertiesMap.put(Key1, null); + propertiesMap.put(Key2, null); + propertiesMap.put(Key3, null); + + + when(ssmHelper.getPartitionSecrets(any())).thenReturn(propertiesMap); + + PartitionInfo partitionInfo = this.partService.getPartition(this.partitionInfo.getProperties().get("id").toString()); + assertTrue(partitionInfo.getProperties().containsKey(Key1)); + assertTrue(partitionInfo.getProperties().containsKey(Key2)); + assertTrue(partitionInfo.getProperties().containsKey(Key3)); + assertTrue(partitionInfo.getProperties().containsKey("id")); + } + + @Test + public void should_throwNotFoundException_when_partitionDoesntExist() { + + try { + partService.getPartition(this.partitionInfo.getProperties().get("id").toString()); + //we should never hit this code because get partition should end in an error + assertTrue("Expected partService.getPartition to throw an exception, but passed",false); + } catch (AppException e) { + assertTrue(e.getError().getCode() == 404); + assertTrue(e.getError().getReason().equalsIgnoreCase("partition not found")); + assertTrue(e.getError().getMessage().equalsIgnoreCase("my-tenant partition not found")); + } + } + + @Test + public void should_returnTrue_when_successfullyDeletingSecretes() { + + when(ssmHelper.partitionExists(any())).thenReturn(true); + when(ssmHelper.getSsmParamsPathsForPartition(any())).thenReturn(Arrays.asList("/my-tenant/partition/partitions/dummy-param")); + when(ssmHelper.deletePartitionSecrets(any())).thenReturn(true); + + assertTrue(this.partService.deletePartition("test-partition")); + } + + @Test + public void should_throwException_when_deletingNonExistentPartition() { + + + try { + this.partService.deletePartition("some-invalid-partition"); + //we should never hit this code because delete partition should end in an error + assertTrue("Expected partService.deletePartition to throw an exception, but passed",false); + } catch (AppException ae) { + assertTrue(ae.getError().getCode() == 404); + assertEquals("some-invalid-partition partition not found", ae.getError().getMessage()); + } + } + + @Test(expected = AppException.class) + public void should_throwException_when_deletingInvalidPartition() { + + this.partService.deletePartition(null); + } +} \ No newline at end of file diff --git a/provider/partition-aws/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/provider/partition-aws/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 000000000..ca6ee9cea --- /dev/null +++ b/provider/partition-aws/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1 @@ +mock-maker-inline \ No newline at end of file diff --git a/testing/partition-test-aws/build-aws/prepare-dist.sh b/testing/partition-test-aws/build-aws/prepare-dist.sh new file mode 100755 index 000000000..6f3f4ff18 --- /dev/null +++ b/testing/partition-test-aws/build-aws/prepare-dist.sh @@ -0,0 +1,48 @@ +# Copyright © 2020 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. + +# This script prepares the dist directory for the integration tests. +# Must be run from the root of the repostiory + +# This script prepares the dist directory for the integration tests. +# Must be run from the root of the repostiory + +set -e + +OUTPUT_DIR="${OUTPUT_DIR:-dist}" + +INTEGRATION_TEST_OUTPUT_DIR=${INTEGRATION_TEST_OUTPUT_DIR:-$OUTPUT_DIR}/testing/integration +INTEGRATION_TEST_OUTPUT_BIN_DIR=${INTEGRATION_TEST_OUTPUT_DIR:-$INTEGRATION_TEST_OUTPUT_DIR}/bin +INTEGRATION_TEST_SOURCE_DIR=testing +INTEGRATION_TEST_SOURCE_DIR_AWS="$INTEGRATION_TEST_SOURCE_DIR"/partition-test-aws +INTEGRATION_TEST_SOURCE_DIR_CORE="$INTEGRATION_TEST_SOURCE_DIR"/partition-test-core +echo "--Source directories variables--" +echo $INTEGRATION_TEST_SOURCE_DIR_AWS +echo $INTEGRATION_TEST_SOURCE_DIR_CORE +echo "--Output directories variables--" +echo $OUTPUT_DIR +echo $INTEGRATION_TEST_OUTPUT_DIR +echo $INTEGRATION_TEST_OUTPUT_BIN_DIR + +rm -rf "$INTEGRATION_TEST_OUTPUT_DIR" +mkdir -p "$INTEGRATION_TEST_OUTPUT_DIR" && mkdir -p "$INTEGRATION_TEST_OUTPUT_BIN_DIR" +echo "Building integration testing assemblies and gathering artifacts..." +mvn install -f "$INTEGRATION_TEST_SOURCE_DIR_CORE"/pom.xml +mvn install dependency:copy-dependencies -DskipTests -f "$INTEGRATION_TEST_SOURCE_DIR_AWS"/pom.xml -DincludeGroupIds=org.opengroup.osdu -Dmdep.copyPom +cp "$INTEGRATION_TEST_SOURCE_DIR_AWS"/target/dependency/* "${INTEGRATION_TEST_OUTPUT_BIN_DIR}" +(cd "${INTEGRATION_TEST_OUTPUT_BIN_DIR}" && ls *.jar | sed -e 's/\.jar$//' | xargs -I {} echo mvn install:install-file -Dfile={}.jar -DpomFile={}.pom >> install-deps.sh) +chmod +x "${INTEGRATION_TEST_OUTPUT_BIN_DIR}"/install-deps.sh +mvn clean -f "$INTEGRATION_TEST_SOURCE_DIR_AWS"/pom.xml +cp -R "$INTEGRATION_TEST_SOURCE_DIR_AWS"/* "${INTEGRATION_TEST_OUTPUT_DIR}"/ + diff --git a/testing/partition-test-aws/build-aws/run-tests.sh b/testing/partition-test-aws/build-aws/run-tests.sh new file mode 100755 index 000000000..ee4b21fc0 --- /dev/null +++ b/testing/partition-test-aws/build-aws/run-tests.sh @@ -0,0 +1,61 @@ +# Copyright © 2020 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. + +# This script prepares the dist directory for the integration tests. +# Must be run from the root of the repostiory + +# This script executes the test and copies reports to the provided output directory +# To call this script from the service working directory +# ./dist/testing/integration/build-aws/run-tests.sh "./reports/" + +echo "### Running Partition Service Integration Tests... ###" + + +SCRIPT_SOURCE_DIR=$(dirname "$0") +echo "Script source location" +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 + +#### RUN INTEGRATION TEST ######################################################################### + +mvn test -f "$SCRIPT_SOURCE_DIR"/../pom.xml +TEST_EXIT_CODE=$? + +#### COPY TEST REPORTS ######################################################################### + +if [ -n "$1" ] + then + mkdir -p "$1" + cp -R "$SCRIPT_SOURCE_DIR"/../target/surefire-reports "$1" +fi + +echo "### Partition Service Integration Tests Finished ###" + +exit $TEST_EXIT_CODE \ No newline at end of file diff --git a/testing/partition-test-aws/pom.xml b/testing/partition-test-aws/pom.xml new file mode 100644 index 000000000..ebded165c --- /dev/null +++ b/testing/partition-test-aws/pom.xml @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright 2020 © 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. +--> +<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> + <groupId>org.opengroup.osdu.partition</groupId> + <artifactId>partition-test-aws</artifactId> + <version>0.0.1-SNAPSHOT</version> + <packaging>jar</packaging> + + <properties> + <java.version>1.8</java.version> + <maven.compiler.target>1.8</maven.compiler.target> + <maven.compiler.source>1.8</maven.compiler.source> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencies> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>1.18.8</version> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-client</artifactId> + <version>1.19.4</version> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + </dependency> + + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>2.8.5</version> + </dependency> + + <dependency> + <groupId>org.opengroup.osdu.partition</groupId> + <artifactId>partition-test-core</artifactId> + <version>0.0.1-SNAPSHOT</version> + </dependency> + + <dependency> + <groupId>org.opengroup.osdu.core.aws</groupId> + <artifactId>os-core-lib-aws</artifactId> + <version>0.3.7</version> + </dependency> + + <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + <version>27.1-jre</version> + </dependency> + + <dependency> + <groupId>io.jsonwebtoken</groupId> + <artifactId>jjwt</artifactId> + <version>0.9.1</version> + <exclusions> + <exclusion> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + </exclusion> + </exclusions> + </dependency> + + </dependencies> + <repositories> + <repository> + <id>${gitlab-server}</id> + <url>https://community.opengroup.org/api/v4/groups/17/-/packages/maven</url> + </repository> + </repositories> + + <distributionManagement> + <repository> + <id>${gitlab-server}</id> + <url>https://community.opengroup.org/api/v4/projects/221/packages/maven</url> + </repository> + <snapshotRepository> + <id>${gitlab-server}</id> + <url>https://community.opengroup.org/api/v4/projects/221/packages/maven</url> + </snapshotRepository> + </distributionManagement> + +</project> diff --git a/testing/partition-test-aws/src/test/java/org/opengroup/osdu/partition/api/TestCreatePartition.java b/testing/partition-test-aws/src/test/java/org/opengroup/osdu/partition/api/TestCreatePartition.java new file mode 100644 index 000000000..9288b19e5 --- /dev/null +++ b/testing/partition-test-aws/src/test/java/org/opengroup/osdu/partition/api/TestCreatePartition.java @@ -0,0 +1,41 @@ +// Copyright © 2020 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 org.opengroup.osdu.partition.api; + +import org.junit.After; +import org.junit.Before; +import org.opengroup.osdu.partition.util.AwsTestUtils; + +public class TestCreatePartition extends CreatePartitionTest { + + @Before + @Override + public void setup() { + this.testUtils = new AwsTestUtils(); + } + + @After + @Override + public void tearDown() { + try { + this.deleteResource(); + } + catch (Exception e) { + + } + this.testUtils = null; + } + +} diff --git a/testing/partition-test-aws/src/test/java/org/opengroup/osdu/partition/api/TestDeletePartition.java b/testing/partition-test-aws/src/test/java/org/opengroup/osdu/partition/api/TestDeletePartition.java new file mode 100644 index 000000000..6a8ff15de --- /dev/null +++ b/testing/partition-test-aws/src/test/java/org/opengroup/osdu/partition/api/TestDeletePartition.java @@ -0,0 +1,41 @@ +// Copyright © 2020 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 org.opengroup.osdu.partition.api; + +import org.junit.After; +import org.junit.Before; +import org.opengroup.osdu.partition.util.AwsTestUtils; + +public class TestDeletePartition extends DeletePartitionTest { + + @Before + @Override + public void setup() { + this.testUtils = new AwsTestUtils(); + } + + @After + @Override + public void tearDown() { + + try { + this.deleteResource(); + } + catch (Exception e) { + + } + this.testUtils = null; + } +} diff --git a/testing/partition-test-aws/src/test/java/org/opengroup/osdu/partition/api/TestGetPartitionById.java b/testing/partition-test-aws/src/test/java/org/opengroup/osdu/partition/api/TestGetPartitionById.java new file mode 100644 index 000000000..48c2eb4ce --- /dev/null +++ b/testing/partition-test-aws/src/test/java/org/opengroup/osdu/partition/api/TestGetPartitionById.java @@ -0,0 +1,40 @@ +// Copyright © 2020 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 org.opengroup.osdu.partition.api; + +import org.junit.After; +import org.junit.Before; +import org.opengroup.osdu.partition.util.AwsTestUtils; + +public class TestGetPartitionById extends GetPartitionByIdApitTest { + + @Before + @Override + public void setup() { + this.testUtils = new AwsTestUtils(); + } + + @After + @Override + public void tearDown() { + try { + this.deleteResource(); + } + catch (Exception e) { + + } + this.testUtils = null; + } +} diff --git a/testing/partition-test-aws/src/test/java/org/opengroup/osdu/partition/util/AwsTestUtils.java b/testing/partition-test-aws/src/test/java/org/opengroup/osdu/partition/util/AwsTestUtils.java new file mode 100644 index 000000000..902225e02 --- /dev/null +++ b/testing/partition-test-aws/src/test/java/org/opengroup/osdu/partition/util/AwsTestUtils.java @@ -0,0 +1,90 @@ +/* + * Copyright © 2020 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 org.opengroup.osdu.partition.util; + +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 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.util.Date; + +public class AwsTestUtils extends TestUtils { + + private AWSCognitoClient cognitoClient; + + public AwsTestUtils() { + cognitoClient = new AWSCognitoClient(); + } + + @Override + public synchronized String getAccessToken() throws Exception { + if (Strings.isNullOrEmpty(token)) { + token = cognitoClient.getTokenForUserWithAccess(); + } + + return "Bearer " + token; + } + + @Override + public synchronized String getNoAccessToken() throws Exception { + if (Strings.isNullOrEmpty(noAccessToken)) { + + noAccessToken = createInvalidToken("baduser@example.com"); + } + return "Bearer " + noAccessToken; + } + + private static String createInvalidToken(String username) { + + try { + KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("RSA"); + keyGenerator.initialize(2048); + + + + KeyPair kp = keyGenerator.genKeyPair(); + PublicKey publicKey = (PublicKey) kp.getPublic(); + PrivateKey privateKey = (PrivateKey) kp.getPrivate(); + + + String token = Jwts.builder() + .setSubject(username) + .setExpiration(new Date()) + .setIssuer("info@example.com") + // RS256 with privateKey + .signWith(SignatureAlgorithm.RS256, privateKey) + .compact(); + + return token; + } + catch (NoSuchAlgorithmException ex) { + return null; + } + + + } +} \ No newline at end of file diff --git a/testing/pom.xml b/testing/pom.xml index e768a3f79..22ac051d0 100644 --- a/testing/pom.xml +++ b/testing/pom.xml @@ -34,6 +34,7 @@ <modules> <module>partition-test-core</module> <module>partition-test-azure</module> + <module>partition-test-aws</module> </modules> <repositories> -- GitLab