diff --git a/.github/workflows/main.yml b/.github/workflows/all-ci.yml similarity index 60% rename from .github/workflows/main.yml rename to .github/workflows/all-ci.yml index d53b9dca..c65364b7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/all-ci.yml @@ -1,8 +1,8 @@ -name: Main Workflow +name: All CI on: push: - branches: [ main, fireegg-test-servers ] + branches: [ main, staging ] pull_request: workflow_dispatch: inputs: @@ -13,33 +13,35 @@ on: type: string jobs: - lint: + python-lint: name: Lint uses: ./.github/workflows/lint.yml - run-tests: + run-test-server: permissions: id-token: write contents: read - name: Run Tests - uses: ./.github/workflows/test.yml + name: Run TestServer Tests + uses: ./.github/workflows/test-server.yml with: python-version: ${{ inputs.python-version || '3.11' }} secrets: inherit - run-duvet: + python-integ: permissions: id-token: write contents: read - pages: write - name: Run Duvet - uses: ./.github/workflows/duvet.yml + name: Python Integration Tests + uses: ./.github/workflows/python-integ.yml + with: + python-version: ${{ inputs.python-version || '3.11' }} secrets: inherit - run-examples: + run-duvet-test-server: permissions: id-token: write contents: read - name: Run Examples - uses: ./.github/workflows/examples.yml + pages: write + name: Run Duvet + uses: ./.github/workflows/duvet-test-server.yml secrets: inherit diff --git a/.github/workflows/duvet.yml b/.github/workflows/duvet-test-server.yml similarity index 84% rename from .github/workflows/duvet.yml rename to .github/workflows/duvet-test-server.yml index 529be19d..f4bac5a8 100644 --- a/.github/workflows/duvet.yml +++ b/.github/workflows/duvet-test-server.yml @@ -1,11 +1,11 @@ -name: Run Tests +name: Generate Duvet Report for TestServer on: workflow_call: # Optional inputs that can be provided when calling this workflow jobs: - test: + duvet: runs-on: macos-latest permissions: id-token: write @@ -17,15 +17,14 @@ jobs: uses: actions/checkout@v5 with: submodules: true - token: ${{ secrets.PAT_FOR_PRIVATE_RUBY }} + token: ${{ secrets.PAT_FOR_SPEC }} - name: Checkout CPP code cpp-v3 uses: actions/checkout@v5 with: submodules: recursive - token: ${{ secrets.PAT_FOR_CPP }} - repository: awslabs/aws-sdk-cpp-staging - ref: fire-egg-dev + repository: aws/aws-sdk-cpp + ref: main path: test-server/cpp-v3-server/aws-sdk-cpp/ - name: Setup Rust toolchain @@ -91,15 +90,15 @@ jobs: test-server/index.html - name: Setup Pages - if: always() && github.ref == 'refs/heads/fireegg-test-servers' && github.event_name == 'push' + if: always() && (github.ref == 'refs/heads/staging' || github.ref == 'refs/heads/fireegg-test-servers') && github.event_name == 'push' uses: actions/configure-pages@v5 - name: Upload Pages artifact - if: always() && github.ref == 'refs/heads/fireegg-test-servers' && github.event_name == 'push' + if: always() && (github.ref == 'refs/heads/staging' || github.ref == 'refs/heads/fireegg-test-servers') && github.event_name == 'push' uses: actions/upload-pages-artifact@v3 with: path: test-server/ - name: Deploy to GitHub Pages - if: always() && github.ref == 'refs/heads/fireegg-test-servers' && github.event_name == 'push' + if: always() && (github.ref == 'refs/heads/staging' || github.ref == 'refs/heads/fireegg-test-servers') && github.event_name == 'push' uses: actions/deploy-pages@v4 diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml deleted file mode 100644 index 4b1cde5a..00000000 --- a/.github/workflows/examples.yml +++ /dev/null @@ -1,90 +0,0 @@ -name: Run Examples - -on: - workflow_call: - -jobs: - run-examples: - runs-on: macos-14-large - permissions: - id-token: write - contents: read - - steps: - - name: Checkout code - uses: actions/checkout@v5 - with: - submodules: true - token: ${{ secrets.PAT_FOR_PRIVATE_RUBY }} - - - name: Checkout CPP code cpp-examples - uses: actions/checkout@v5 - with: - submodules: recursive - token: ${{ secrets.PAT_FOR_CPP }} - repository: awslabs/aws-sdk-cpp-staging - ref: fire-egg-dev - path: all-examples/cpp/aws-sdk-cpp/ - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.11" - - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - with: - ruby-version: "3.4" - - - name: Set up PHP with Composer - uses: shivammathur/setup-php@verbose - with: - php-version: "8.1" - - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version: 1.24 - - # Cache uv dependencies - - name: Cache uv dependencies - uses: actions/cache@v3 - with: - path: ~/.cache/uv - key: ${{ runner.os }}-uv-${{ hashFiles('./test-server/python-v3-server/**/pyproject.toml') }} - restore-keys: | - ${{ runner.os }}-uv- - - - name: Install Uv - run: pip install uv - - # Cache Gradle dependencies and build outputs - - name: Cache Gradle packages - uses: actions/cache@v4 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - test-server/java-v3-server/.gradle - test-server/java-tests/.gradle - key: ${{ runner.os }}-gradle-${{ hashFiles('test-server/java-v3-server/**/*.gradle*', 'test-server/java-tests/**/gradle-wrapper.properties', 'test-server/java-tests/**/*.gradle*', 'test-server/java-v3-server/**/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle- - - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - role-to-assume: arn:aws:iam::370957321024:role/S3EC-Python-Github-test-role - aws-region: us-west-2 - - - name: Install dependencies for all examples - working-directory: ./all-examples - run: make install - - - name: Run all examples - working-directory: ./all-examples - run: make run - env: - AWS_REGION: us-west-2 - BUCKET_NAME: ${{ vars.TEST_SERVER_S3_BUCKET }} - KMS_KEY_ID: ${{ vars.TEST_SERVER_KMS_KEY_ARN }} diff --git a/.github/workflows/python-integ.yml b/.github/workflows/python-integ.yml new file mode 100644 index 00000000..9e5ae818 --- /dev/null +++ b/.github/workflows/python-integ.yml @@ -0,0 +1,57 @@ +name: Python Integration Tests + +on: + workflow_call: + inputs: + python-version: + description: "Python version to use" + default: "3.11" + required: false + type: string + +jobs: + python-integ: + runs-on: macos-14-large + permissions: + id-token: write + contents: read + + steps: + - name: Checkout code + uses: actions/checkout@v5 + with: + submodules: false + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ inputs.python-version || '3.11' }} + + - name: Cache uv dependencies + uses: actions/cache@v4 + with: + path: ~/.cache/uv + key: ${{ runner.os }}-uv-${{ hashFiles('./test-server/python-v3-server/**/pyproject.toml') }} + restore-keys: | + ${{ runner.os }}-uv- + + - name: Install Uv + run: pip install uv + + - name: Install dependencies + run: make install + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: arn:aws:iam::370957321024:role/S3EC-Python-Github-test-role + aws-region: us-west-2 + + - name: Run unit tests + run: make test-unit + + - name: Run integration tests + run: make test-integration + env: + CI_S3_BUCKET: ${{ vars.CI_S3_BUCKET }} + CI_KMS_KEY_ALIAS: ${{ vars.CI_KMS_KEY_ALIAS }} diff --git a/.github/workflows/test.yml b/.github/workflows/test-server.yml similarity index 69% rename from .github/workflows/test.yml rename to .github/workflows/test-server.yml index 182b7f47..4fa10666 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test-server.yml @@ -1,4 +1,4 @@ -name: Run Tests +name: Run TestServer Tests on: workflow_call: @@ -11,7 +11,7 @@ on: type: string jobs: - test: + test-server: runs-on: macos-14-large permissions: id-token: write @@ -22,10 +22,7 @@ jobs: uses: actions/checkout@v5 with: submodules: false - # This is Ryan Emery's (seebees) PAT. - # To grant this workflow access to a new private repo, - # ask Ryan to edit this PAT's permissions to add access to a new private repo. - token: ${{ secrets.PAT_FOR_PRIVATE_RUBY }} + token: ${{ secrets.PAT_FOR_SPEC }} # There are a lot of submodules here # This initializes the checkouts in parallel (--jobs) @@ -39,7 +36,7 @@ jobs: run: | git config --global url."https://github.com/".insteadOf "git@github.com:" git config --global credential.helper store - echo "https://x-token-auth:${{ secrets.PAT_FOR_PRIVATE_RUBY }}@github.com" > ~/.git-credentials + echo "https://x-token-auth:${{ secrets.PAT_FOR_SPEC }}@github.com" > ~/.git-credentials - name: Optimize git for performance run: | @@ -58,24 +55,19 @@ jobs: --jobs ${{ steps.cpu-count.outputs.count }} \ --force \ test-server/cpp-v2-transition-server/aws-sdk-cpp \ - test-server/cpp-v3-server/aws-sdk-cpp \ - test-server/cpp-v2-server/aws-sdk-cpp + test-server/cpp-v3-server/aws-sdk-cpp - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: "3.4" + ruby-version: "3.4.7" + bundler-cache: true - name: Set up PHP with Composer uses: shivammathur/setup-php@verbose with: php-version: "8.1" - - name: Install PHP V2 dependencies - working-directory: ./test-server/php-v2-server - shell: bash - run: composer install - - name: Install PHP V2 Transition dependencies working-directory: ./test-server/php-v2-transition-server shell: bash @@ -95,36 +87,6 @@ jobs: run: | brew install libmicrohttpd nlohmann-json ossp-uuid - # Legacy Python tests: - # - name: Set up Python - # uses: actions/setup-python@v5 - # with: - # python-version: ${{ inputs.python-version || '3.11' }} - # - # # Cache uv dependencies - # - name: Cache uv dependencies - # uses: actions/cache@v3 - # with: - # path: ~/.cache/uv - # key: ${{ runner.os }}-uv-${{ hashFiles('./test-server/python-v3-server/**/pyproject.toml') }} - # restore-keys: | - # ${{ runner.os }}-uv- - - # - name: Install Uv - # run: pip install uv - - # - name: Install dependencies - # run: make install - - # - name: Run unit tests - # run: make test-unit - - # - name: Run integration tests - # run: make test-integration - # env: - # CI_S3_BUCKET: ${{ vars.CI_S3_BUCKET }} - # CI_KMS_KEY_ALIAS: ${{ vars.CI_KMS_KEY_ALIAS }} - # Cache Gradle dependencies and build outputs - name: Cache Gradle packages uses: actions/cache@v4 @@ -132,9 +94,8 @@ jobs: path: | ~/.gradle/caches ~/.gradle/wrapper - test-server/java-v3-server/.gradle test-server/java-tests/.gradle - key: ${{ runner.os }}-gradle-${{ hashFiles('test-server/java-v3-server/**/*.gradle*', 'test-server/java-tests/**/gradle-wrapper.properties', 'test-server/java-tests/**/*.gradle*', 'test-server/java-v3-server/**/gradle-wrapper.properties') }} + key: ${{ runner.os }}-gradle-${{ hashFiles('test-server/java-tests/**/gradle-wrapper.properties', 'test-server/java-tests/**/*.gradle*') }} restore-keys: | ${{ runner.os }}-gradle- @@ -163,7 +124,7 @@ jobs: MAKEFLAGS: -j${{ steps.cpu-count.outputs.count }} - name: Run run-tests - run: cd test-server && make run-tests + run: cd test-server && make test-servers-run-tests env: AWS_REGION: us-west-2 TEST_SERVER_S3_BUCKET: ${{ vars.TEST_SERVER_S3_BUCKET }} @@ -177,11 +138,9 @@ jobs: name: server-logs path: | test-server/*/server.log - test-server/*/net-v2-server.log - test-server/*/net-v3-server.log - name: Stop the servers - run: cd test-server && make stop-servers + run: cd test-server && make test-servers-stop - name: Upload results if: always() diff --git a/.gitmodules b/.gitmodules index a88a83f9..75e91f99 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,60 +1,48 @@ [submodule "test-server/ruby-v2-server/local-ruby-sdk"] path = test-server/ruby-v2-server/local-ruby-sdk - url = git@github.com:aws/aws-sdk-ruby-staging.git + url = git@github.com:aws/aws-sdk-ruby.git + branch = version-3 [submodule "test-server/ruby-v3-server/local-ruby-sdk"] path = test-server/ruby-v3-server/local-ruby-sdk - url = git@github.com:aws/aws-sdk-ruby-staging.git -[submodule "test-server/php-v2-server/local-php-sdk"] - path = test-server/php-v2-server/local-php-sdk - url = git@github.com:aws/private-aws-sdk-php-staging.git - branch = master + url = git@github.com:aws/aws-sdk-ruby.git + branch = version-3 [submodule "test-server/php-v3-server/local-php-sdk"] path = test-server/php-v3-server/local-php-sdk - url = git@github.com:aws/private-aws-sdk-php-staging.git - branch = s3ec/improved + url = git@github.com:aws/aws-sdk-php.git + branch = master [submodule "test-server/go-v4-server/local-go-s3ec"] path = test-server/go-v4-server/local-go-s3ec - url = https://github.com/aws/private-amazon-s3-encryption-client-go-staging + url = https://github.com/aws/amazon-s3-encryption-client-go + branch = main [submodule "test-server/java-v3-transition-server/s3ec-staging"] path = test-server/java-v3-transition-server/s3ec-staging - url = git@github.com:aws/private-amazon-s3-encryption-client-java-staging.git - branch = imabhichow/transition-read-kc + url = git@github.com:aws/amazon-s3-encryption-client-java.git + branch = main-3.x [submodule "test-server/java-v4-server/s3ec-staging"] path = test-server/java-v4-server/s3ec-staging - url = git@github.com:aws/private-amazon-s3-encryption-client-java-staging.git - branch = imabhichow/add-kc + url = git@github.com:aws/amazon-s3-encryption-client-java.git + branch = main [submodule "test-server/specification"] path = test-server/specification url = git@github.com:awslabs/private-aws-encryption-sdk-specification-staging.git branch = fire-egg-staging -[submodule "test-server/net-v2-v3-server/s3ec-net-v2"] - path = test-server/net-v2-v3-server/s3ec-net-v2 - url = https://github.com/aws/private-amazon-s3-encryption-client-dotnet-staging.git - branch = v3sdk-development -[submodule "test-server/net-v2-v3-server/s3ec-net-v3"] - path = test-server/net-v2-v3-server/s3ec-net-v3 - url = https://github.com/aws/private-amazon-s3-encryption-client-dotnet-staging.git - branch = s3ec-v3 [submodule "test-server/net-v4-server/s3ec-net-v4-improved"] - path = test-server/net-v4-server/s3ec-net-v4-improved - url = https://github.com/aws/private-amazon-s3-encryption-client-dotnet-staging.git - branch = s3ec-v4-WIP + path = test-server/net-v4-server/s3ec-net-v4-improved + url = https://github.com/aws/amazon-s3-encryption-client-dotnet.git + branch = main [submodule "test-server/go-v3-transition-server/local-go-s3ec"] path = test-server/go-v3-transition-server/local-go-s3ec - url = https://github.com/aws/private-amazon-s3-encryption-client-go-staging - branch = v3-strip + url = https://github.com/aws/amazon-s3-encryption-client-go + branch = main [submodule "test-server/net-v3-transition-server/s3ec-v3-transition-branch"] path = test-server/net-v3-transition-server/s3ec-v3-transition-branch - url = https://github.com/aws/private-amazon-s3-encryption-client-dotnet-staging.git - branch = rishav/key-commitment + url = https://github.com/aws/amazon-s3-encryption-client-dotnet.git + branch = v4sdk-development [submodule "test-server/cpp-v2-transition-server/aws-sdk-cpp"] path = test-server/cpp-v2-transition-server/aws-sdk-cpp - url = git@github.com:awslabs/aws-sdk-cpp-staging.git - branch = fire-egg-dev + url = git@github.com:aws/aws-sdk-cpp.git + branch = main [submodule "test-server/cpp-v3-server/aws-sdk-cpp"] path = test-server/cpp-v3-server/aws-sdk-cpp - url = git@github.com:awslabs/aws-sdk-cpp-staging.git - branch = fire-egg-dev -[submodule "test-server/cpp-v2-server/aws-sdk-cpp"] - path = test-server/cpp-v2-server/aws-sdk-cpp - url = git@github.com:awslabs/aws-sdk-cpp-staging.git + url = git@github.com:aws/aws-sdk-cpp.git + branch = main diff --git a/README.md b/README.md index c24d1796..edcfd4ff 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ This library provides an S3 client that supports client-side encryption. ### Prerequisites - Python 3.11 or higher -- [Poetry](https://python-poetry.org/) for dependency management +- [uv](https://github.com/astral-sh/uv) for package and project management ### Setup @@ -73,3 +73,13 @@ Common Flake8 issues in the codebase include: - **Code complexity** (C901): Refactor complex functions When contributing to this project, please try to fix linting issues in the files you modify. + +### Pull Request Command +While this project is in development, +it is useful to use `gh pr` to create the pull-requests, +so they can be associated with the GitHub project. + +```sh +gh pr create -B staging -p "S3EC-Python" -f +``` + diff --git a/all-examples/Makefile b/all-examples/Makefile deleted file mode 100644 index eeb0949b..00000000 --- a/all-examples/Makefile +++ /dev/null @@ -1,110 +0,0 @@ -# Makefile for S3 Encryption Client Examples -# Runs make commands across all language/version directories - -# Default target -.PHONY: all install clean run help list-examples - -# Find all directories with Makefiles -EXAMPLE_DIRS := $(shell find . -name Makefile -not -path "./Makefile" -not -path "./cpp/aws-sdk-cpp/**" -not -path "./cpp/build/**" | xargs dirname | sed 's|^\./||' | $(if $(FILTER),grep -E "$$(echo '$(FILTER)' | sed 's/,/|/g')",cat) | sort) - -all: install - -# Install dependencies for all examples -install: - @echo "Installing dependencies for all examples..." - @failed=0; \ - for dir in $(EXAMPLE_DIRS); do \ - echo ""; \ - echo "=== Installing dependencies in $$dir ==="; \ - if (cd $$dir && $(MAKE) install); then \ - echo "✓ Successfully installed dependencies in $$dir"; \ - else \ - echo "✗ Failed to install dependencies in $$dir"; \ - failed=$$((failed + 1)); \ - fi; \ - done; \ - echo ""; \ - if [ $$failed -eq 0 ]; then \ - echo "All dependencies installed successfully!"; \ - else \ - echo "$$failed example(s) failed to install dependencies"; \ - exit 1; \ - fi - -# Clean all examples -clean: - @echo "Cleaning all examples..." - @failed=0; \ - for dir in $(EXAMPLE_DIRS); do \ - echo ""; \ - echo "=== Cleaning $$dir ==="; \ - if (cd $$dir && $(MAKE) clean); then \ - echo "✓ Successfully cleaned $$dir"; \ - else \ - echo "✗ Failed to clean $$dir"; \ - failed=$$((failed + 1)); \ - fi; \ - done; \ - echo ""; \ - if [ $$failed -eq 0 ]; then \ - echo "All examples cleaned successfully!"; \ - else \ - echo "$$failed example(s) failed to clean"; \ - exit 1; \ - fi - -# Run all examples with default parameters -run: - @echo "Running all examples with default parameters..." - @failed=0; \ - for dir in $(EXAMPLE_DIRS); do \ - echo ""; \ - echo "=== Running example in $$dir ==="; \ - if (cd $$dir && $(MAKE) run); then \ - echo "✓ Successfully ran example in $$dir"; \ - else \ - echo "✗ Failed to run example in $$dir"; \ - failed=$$((failed + 1)); \ - fi; \ - done; \ - echo ""; \ - if [ $$failed -eq 0 ]; then \ - echo "All examples completed successfully!"; \ - else \ - echo "$$failed example(s) failed to run"; \ - exit 1; \ - fi - -# List all available examples -list-examples: - @echo "Available S3 Encryption Client examples:" - @for dir in $(EXAMPLE_DIRS); do \ - echo " $$dir"; \ - done - -# Show help -help: - @echo "S3 Encryption Client Examples Makefile" - @echo "" - @echo "Available targets:" - @echo " install - Install dependencies for all examples" - @echo " run - Run all examples with default parameters" - @echo " clean - Clean all examples" - @echo " list-examples - List all available example directories" - @echo " help - Show this help message" - @echo "" - @echo "Filtering examples:" - @echo " Use FILTER to run commands on specific examples:" - @echo " make install FILTER=go # Only Go examples" - @echo " make run FILTER=v4 # Only v4 examples" - @echo " make clean FILTER=go/v3,ruby # Go v3 and Ruby examples" - @echo "" - @echo "Individual example usage:" - @echo " To work with a specific example, cd into its directory and use its Makefile:" - @echo " cd go/v4 && make run" - @echo " cd ruby/v2 && make install" - @echo "" - @echo "Available examples:" - @for dir in $(EXAMPLE_DIRS); do \ - echo " $$dir"; \ - done diff --git a/all-examples/README.md b/all-examples/README.md deleted file mode 100644 index 8472de78..00000000 --- a/all-examples/README.md +++ /dev/null @@ -1,74 +0,0 @@ -# S3 Encryption Client Examples - -This directory contains example projects for the Amazon S3 Encryption Client across different programming languages and major versions. - -## Directory Structure - -Each language has subdirectories for different major versions of the S3 Encryption Client: - -- `cpp/` - C++ examples - - `v2/` - S3EC C++ v2 example (transitional) - - `v3/` - S3EC C++ v3 example (improved) -- `net/` - .NET examples - - `v3/` - S3EC .NET v3 example (transitional) - - `v4/` - S3EC .NET v4 example (improved) -- `go/` - Go examples - - `v3/` - S3EC Go v3 example (transitional) - - `v4/` - S3EC Go v4 example (improved) -- `java/` - Java examples - - `v3/` - S3EC Java v3 example (transitional) - - `v4/` - S3EC Java v4 example (improved) -- `php/` - PHP examples - - `v2/` - S3EC PHP v2 example (transitional) - - `v3/` - S3EC PHP v3 example (improved) -- `ruby/` - Ruby examples - - `v2/` - S3EC Ruby v2 example (transitional) - - `v3/` - S3EC Ruby v3 example (improved) - -## Setup Instructions - -### Prerequisites - -1. **Git Submodules**: Some examples depend on staging versions of the S3EC libraries that are included as git submodules. Initialize and update submodules: - - ```bash - git submodule update --init --recursive - ``` - -2. **AWS Credentials**: Configure your AWS credentials using one of the following methods: - - AWS CLI: `aws configure` - - Environment variables: `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` - - IAM roles (for EC2 instances) - -3. **KMS Key**: Use "arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01" by default, or create a KMS key in your AWS account and note the key ID for use in examples. - -### Language-Specific Setup - -Each language directory contains specific setup instructions in its README file. Generally: - -- **Java**: Requires JDK 11+ and Gradle -- **Go**: Requires Go 1.21+ -- **.NET**: Requires .NET 8.0+ -- **PHP**: Requires PHP 7.4+ and Composer -- **Ruby**: Requires Ruby 3.0+ and Bundler -- **C++**: Requires CMake 3.16+ and C++17 compiler - -## Usage - -Each example directory contains: - -- Build configuration files (e.g., `build.gradle.kts`, `go.mod`, `composer.json`) -- Source code demonstrating basic S3EC usage -- README with specific setup and run instructions - -## Dependencies - -Examples use different dependency sources based on version: - -- **Released versions**: Use public package repositories (Maven Central, npm, etc.) -- **Staging versions**: Use git submodules pointing to staging repositories -- **Local versions**: Reference locally built libraries - -## Support - -For issues with specific examples, refer to the individual README files in each language/version directory. diff --git a/all-examples/cpp/CMakeLists.txt b/all-examples/cpp/CMakeLists.txt deleted file mode 100644 index 906951b8..00000000 --- a/all-examples/cpp/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -cmake_minimum_required(VERSION 3.16) -project(s3ec-test) - -set(CMAKE_CXX_STANDARD 14) - -# Configure AWS SDK build options -set(BUILD_ONLY "kms;s3;s3-encryption" CACHE STRING "Build only KMS, S3, and S3-encryption components") -set(ENABLE_TESTING OFF CACHE BOOL "Disable testing") -set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build static libraries") - -# Add AWS SDK as subdirectory -add_subdirectory(aws-sdk-cpp) - -find_package(PkgConfig REQUIRED) - -add_executable(s3ec-test main.cpp) - -target_link_libraries(s3ec-test - aws-cpp-sdk-core - aws-cpp-sdk-kms - aws-cpp-sdk-s3 - aws-cpp-sdk-s3-encryption -) diff --git a/all-examples/cpp/Makefile b/all-examples/cpp/Makefile deleted file mode 100644 index 64550528..00000000 --- a/all-examples/cpp/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# Makefile for S3 Encryption Client C++ Example - -.PHONY: all install clean run help - -# Default arguments for running the example -# Override these when calling make run -VERSION ?= V3 -BUCKET_NAME ?= avp-21638 -OBJECT_KEY ?= s3ec-cpp-test -KMS_KEY_ID ?= arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 -AWS_REGION ?= us-east-2 - -all: run - -install: build/s3ec-test - -aws-sdk-cpp: - git clone --recurse-submodules -b fire-egg-dev https://github.com/awslabs/aws-sdk-cpp-staging.git aws-sdk-cpp - -build/s3ec-test: aws-sdk-cpp - mkdir -p build && cd build && cmake .. && make - -clean: - rm -rf build - -# Run the example with default arguments -run: build/s3ec-test - @echo "Running S3 Encryption Client C++ example..." - @echo "Version: $(VERSION)" - @echo "Bucket: $(BUCKET_NAME)" - @echo "Object Key: $(OBJECT_KEY)" - @echo "KMS Key ID: $(KMS_KEY_ID)" - @echo "Region: $(AWS_REGION)" - @echo "" - ./build/s3ec-test $(VERSION) $(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION) - -# Show help -help: - @echo "S3 Encryption Client C++ Example Makefile" - @echo "" - @echo "Available targets:" - @echo " install - Install Go dependencies using Go modules" - @echo " run - Install dependencies and run the example" - @echo " clean - Remove C++ artifacts" - @echo " help - Show this help message" - @echo "" - @echo "Default parameters:" - @echo " VERSION = $(VERSION) (must be V2 or V3)" - @echo " BUCKET_NAME = $(BUCKET_NAME)" - @echo " OBJECT_KEY = $(OBJECT_KEY)" - @echo " KMS_KEY_ID = $(KMS_KEY_ID)" - @echo " AWS_REGION = $(AWS_REGION)" - @echo "" - @echo "To run with custom parameters:" - @echo " make run VERSION=your-version BUCKET_NAME=your-bucket OBJECT_KEY=your-key KMS_KEY_ID=your-kms-key AWS_REGION=your-region" - @echo "" - @echo "Prerequisites:" - @echo " - Read access to https://github.com/awslabs/aws-sdk-cpp-staging.git" - @echo " - AWS credentials configured (AWS CLI, environment variables, or IAM role)" - @echo " - Valid S3 bucket and KMS key with appropriate permissions" diff --git a/all-examples/cpp/README.md b/all-examples/cpp/README.md deleted file mode 100644 index 8875fb07..00000000 --- a/all-examples/cpp/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# C++ S3 Encryption Test - -Minimal C++ use of S3 Encryption - -## Build - -```bash -make install -``` - -## Run - -```bash -make run -``` diff --git a/all-examples/cpp/main.cpp b/all-examples/cpp/main.cpp deleted file mode 100644 index 30cb2b8d..00000000 --- a/all-examples/cpp/main.cpp +++ /dev/null @@ -1,245 +0,0 @@ -#include -#include -#include -#include - -using namespace Aws::S3Encryption; -using Aws::S3Encryption::Materials::KMSWithContextEncryptionMaterials; - -static Aws::Map get_encryption_context(const char * version) -{ - return { - {"purpose", "example"}, - {"version", version}, - {"language", "c++"} - }; -} - -static int test_migration(const char *bucket, const char *object, const char *kms_key_id, const char *region) -{ - Aws::Client::ClientConfiguration s3ClientConfig; - s3ClientConfig.region = region; - - auto materials = std::make_shared(kms_key_id, s3ClientConfig); - CryptoConfigurationV3 config(materials); - - // STEP 1: Upgrade to V3 client to prepare to read messages with commitment. - // You want to update your readers before you update your writers - config.SetCommitmentPolicy(CommitmentPolicy::FORBID_ENCRYPT_ALLOW_DECRYPT); - auto client = std::make_shared(config, s3ClientConfig); - - auto encryption_context = get_encryption_context("V3"); - - // Put Object - writes objects WITHOUT commitment - Aws::S3::Model::PutObjectRequest put_request; - put_request.SetBucket(bucket); - put_request.SetKey(object); - - auto data = std::string("This is the sample content."); - - auto stream = std::make_shared(data); - put_request.SetBody(stream); - - // Put Object - writes objects WITHOUT commitment - auto put_outcome = client->PutObject(put_request, encryption_context); - assert(put_outcome.IsSuccess()); - - Aws::S3::Model::GetObjectRequest get_request; - get_request.SetBucket(bucket); - get_request.SetKey(object); - - // Get Object - can read objects with or without commitment - auto get_outcome = client->GetObject(get_request, encryption_context); - assert(get_outcome.IsSuccess()); - - // STEP 2: If all of the readers can read with or without commitment - // you can upgrade the commitment policy to write objects with commitment - config.SetCommitmentPolicy(CommitmentPolicy::REQUIRE_ENCRYPT_ALLOW_DECRYPT); - client = std::make_shared(config, s3ClientConfig); - - stream = std::make_shared(data); - put_request.SetBody(stream); - - // Put Object - writes objects WITH commitment - put_outcome = client->PutObject(put_request, encryption_context); - assert(put_outcome.IsSuccess()); - - // Get Object - can read objects with or without commitment - get_outcome = client->GetObject(get_request, encryption_context); - assert(get_outcome.IsSuccess()); - - // STEP 3: Once your system no longer has to read messages without commitment, - // you may update your client to only read messages written with key commitment - config.SetCommitmentPolicy(CommitmentPolicy::REQUIRE_ENCRYPT_REQUIRE_DECRYPT); - client = std::make_shared(config, s3ClientConfig); - - stream = std::make_shared(data); - put_request.SetBody(stream); - - // Put Object - writes objects WITH commitment - put_outcome = client->PutObject(put_request, encryption_context); - assert(put_outcome.IsSuccess()); - - // Get Object - can only read objects with commitment - get_outcome = client->GetObject(get_request, encryption_context); - assert(get_outcome.IsSuccess()); - - return 0; -} - -static int test_v3(const char *bucket, const char *object, const char *kms_key_id, const char *region) -{ - Aws::Client::ClientConfiguration s3ClientConfig; - s3ClientConfig.region = region; - - auto materials = std::make_shared(kms_key_id, s3ClientConfig); - CryptoConfigurationV3 config(materials); - // config.AllowLegacy(); - // config.SetStorageMethod(StorageMethod::INSTRUCTION_FILE); - // config.SetCommitmentPolicy(CommitmentPolicy::FORBID_ENCRYPT_ALLOW_DECRYPT); - - - auto client = std::make_shared(config, s3ClientConfig); - - auto encryption_context = get_encryption_context("V3"); - - Aws::S3::Model::PutObjectRequest put_request; - put_request.SetBucket(bucket); - put_request.SetKey(object); - - auto data = std::string("This is the sample content."); - - auto stream = std::make_shared(data); - put_request.SetBody(stream); - - auto put_outcome = client->PutObject(put_request, encryption_context); - if (put_outcome.IsSuccess()) - { - fprintf(stderr, "PutObject V3 Successful.\n"); - } - else - { - fprintf(stderr, "PutObject V3 Failed : %s\n", put_outcome.GetError().GetMessage().c_str()); - return 1; - } - - Aws::S3::Model::GetObjectRequest get_request; - get_request.SetBucket(bucket); - get_request.SetKey(object); - auto get_outcome = client->GetObject(get_request, encryption_context); - if (get_outcome.IsSuccess()) - { - fprintf(stderr, "GetObject V3 Successful.\n"); - Aws::StringStream response_stream; - response_stream << get_outcome.GetResult().GetBody().rdbuf(); - if (response_stream.str() != data) - { - fprintf(stderr, "GetObject V3 returned the wrong data.\n"); - return 1; - } - } - else - { - fprintf(stderr, "GetObject V3 Failed : %s\n", put_outcome.GetError().GetMessage().c_str()); - return 1; - } - return 0; -} - -static int test_v2(const char *bucket, const char *object, const char *kms_key_id, const char *region) -{ - Aws::Client::ClientConfiguration s3ClientConfig; - s3ClientConfig.region = region; - - auto materials = std::make_shared(kms_key_id, s3ClientConfig); - CryptoConfigurationV2 config(materials); - // config.SetSecurityProfile(SecurityProfile::V2_AND_LEGACY); - // config.SetStorageMethod(StorageMethod::INSTRUCTION_FILE); - - - auto client = std::make_shared(config, s3ClientConfig); - - auto encryption_context = get_encryption_context("V2"); - - Aws::S3::Model::PutObjectRequest put_request; - put_request.SetBucket(bucket); - put_request.SetKey(object); - - auto data = std::string("This is the sample content."); - - auto stream = std::make_shared(data); - put_request.SetBody(stream); - - auto put_outcome = client->PutObject(put_request, encryption_context); - if (put_outcome.IsSuccess()) - { - fprintf(stderr, "PutObject V2 Successful.\n"); - } - else - { - fprintf(stderr, "PutObject V2 Failed : %s\n", put_outcome.GetError().GetMessage().c_str()); - return 1; - } - - Aws::S3::Model::GetObjectRequest get_request; - get_request.SetBucket(bucket); - get_request.SetKey(object); - auto get_outcome = client->GetObject(get_request, encryption_context); - if (get_outcome.IsSuccess()) - { - fprintf(stderr, "GetObject V2 Successful.\n"); - Aws::StringStream response_stream; - response_stream << get_outcome.GetResult().GetBody().rdbuf(); - if (response_stream.str() != data) - { - fprintf(stderr, "GetObject V2 returned the wrong data.\n"); - return 1; - } - } - else - { - fprintf(stderr, "GetObject V2 Failed : %s\n", put_outcome.GetError().GetMessage().c_str()); - return 1; - } - return 0; -} - -int main(int argc, char **argv) -{ - if (argc != 6) - { - fprintf(stderr, "USAGE : s3ec-test version bucket object key_id region"); - return 1; - } - - auto version_str = argv[1]; - auto bucket = argv[2]; - auto object = argv[3]; - auto kms_key_id = argv[4]; - auto region = argv[5]; - - bool is_v3; - if (strcasecmp(version_str, "v3") == 0) - { - is_v3 = true; - } - else if (strcasecmp(version_str, "v2") == 0) - { - is_v3 = false; - } - else - { - fprintf(stderr, "Version was <%s> must be V2 or V3\n", version_str); - return 1; - } - - Aws::SDKOptions options; - Aws::InitAPI(options); - - if (is_v3) - test_v3(bucket, object, kms_key_id, region); - else - test_v2(bucket, object, kms_key_id, region); - - Aws::ShutdownAPI(options); -} diff --git a/all-examples/go/v3/Makefile b/all-examples/go/v3/Makefile deleted file mode 100644 index d7285fe9..00000000 --- a/all-examples/go/v3/Makefile +++ /dev/null @@ -1,69 +0,0 @@ -# Makefile for S3 Encryption Client Go v3 Example - -# Default target -.PHONY: all install clean run help - -# Variables -SCRIPT = main.go - -# Default arguments for running the example -# Override these when calling make run -BUCKET_NAME ?= avp-21638 -OBJECT_KEY ?= s3ec-go-v3 -KMS_KEY_ID ?= arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 -AWS_REGION ?= us-east-2 - -all: install - -# Install dependencies using Go modules -install: - @echo "Installing Go dependencies..." - @go mod tidy - @echo "Dependencies installed successfully!" - -# Clean Go artifacts -clean: - @echo "Cleaning Go artifacts..." - @go clean - @echo "Clean completed!" - -# Run the example with default arguments -run: install - @echo "Running S3 Encryption Client v3 Go example..." - @echo "Bucket: $(BUCKET_NAME)" - @echo "Object Key: $(OBJECT_KEY)" - @echo "KMS Key ID: $(KMS_KEY_ID)" - @echo "Region: $(AWS_REGION)" - @echo "" - @go run $(SCRIPT) $(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION) - -# Run with custom arguments -# Usage: make run-custom BUCKET_NAME=my-bucket OBJECT_KEY=my-key KMS_KEY_ID=my-kms-key AWS_REGION=my-region -run-custom: install - @go run $(SCRIPT) $(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION) - -# Show help -help: - @echo "S3 Encryption Client Go v3 Example Makefile" - @echo "" - @echo "Available targets:" - @echo " install - Install Go dependencies using Go modules" - @echo " run - Install dependencies and run the example with default parameters" - @echo " run-custom - Install dependencies and run with custom parameters" - @echo " clean - Remove Go artifacts" - @echo " help - Show this help message" - @echo "" - @echo "Default parameters:" - @echo " BUCKET_NAME = $(BUCKET_NAME)" - @echo " OBJECT_KEY = $(OBJECT_KEY)" - @echo " KMS_KEY_ID = $(KMS_KEY_ID)" - @echo " AWS_REGION = $(AWS_REGION)" - @echo "" - @echo "To run with custom parameters:" - @echo " make run BUCKET_NAME=your-bucket OBJECT_KEY=your-key KMS_KEY_ID=your-kms-key AWS_REGION=your-region" - @echo "" - @echo "Prerequisites:" - @echo " - Go 1.24+ installed on the system" - @echo " - AWS credentials configured (AWS CLI, environment variables, or IAM role)" - @echo " - Valid S3 bucket and KMS key with appropriate permissions" - @echo " - S3 Encryption Client v3 Go SDK (included in local-go-s3ec)" diff --git a/all-examples/go/v3/README.md b/all-examples/go/v3/README.md deleted file mode 100644 index 519dfc36..00000000 --- a/all-examples/go/v3/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# S3 Encryption Client Go v3 Example - -This example demonstrates how to use the Amazon S3 Encryption Client v3 for Go to perform client-side encryption and decryption of objects. - -## Prerequisites - -1. **Go**: Requires Go 1.24 or later -2. **AWS Credentials**: Configure your AWS credentials using one of the following methods: - - AWS CLI: `aws configure` - - Environment variables: `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` - - IAM roles (for EC2 instances) -3. **KMS Key**: You'll need a KMS key ID or ARN. You can use the default example key: `arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01` -4. **S3 Bucket**: An existing S3 bucket where you have read/write permissions - -## Setup - -1. Initialize submodules and download dependencies: - ```bash - make install - ``` - - Or manually: - ```bash - go mod tidy - ``` - - **Note**: This example uses a local submodule for the S3EC Go v3 library via the `replace` directive in `go.mod`. - -## Usage - -### Using Make (Recommended) - -Run the example with default parameters: -```bash -make run -``` - -Run with custom parameters: -```bash -make run BUCKET_NAME=my-bucket OBJECT_KEY=my-key KMS_KEY_ID=my-kms-key AWS_REGION=my-region -``` - -### Manual Usage - -Run the example with the following command: - -```bash -go run main.go -``` - -### Example: - -```bash -go run main.go my-test-bucket s3ec-go-v3-test arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 us-east-2 -``` diff --git a/all-examples/go/v3/go.mod b/all-examples/go/v3/go.mod deleted file mode 100644 index 1821569a..00000000 --- a/all-examples/go/v3/go.mod +++ /dev/null @@ -1,32 +0,0 @@ -module github.com/aws/amazon-s3-encryption-client-python/all-examples/go/v3 - -go 1.24 - -require ( - github.com/aws/amazon-s3-encryption-client-go/v3 v3.1.0 - github.com/aws/aws-sdk-go-v2 v1.24.0 - github.com/aws/aws-sdk-go-v2/config v1.26.1 - github.com/aws/aws-sdk-go-v2/service/kms v1.27.4 - github.com/aws/aws-sdk-go-v2/service/s3 v1.47.5 -) - -require ( - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.16.12 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.9 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.9 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 // indirect - github.com/aws/smithy-go v1.19.0 // indirect -) - -// S3EC Go V3 uses a local submodule for development -replace github.com/aws/amazon-s3-encryption-client-go/v3 => ./local-go-s3ec/v3 diff --git a/all-examples/go/v3/go.sum b/all-examples/go/v3/go.sum deleted file mode 100644 index 244c8814..00000000 --- a/all-examples/go/v3/go.sum +++ /dev/null @@ -1,40 +0,0 @@ -github.com/aws/aws-sdk-go-v2 v1.24.0 h1:890+mqQ+hTpNuw0gGP6/4akolQkSToDJgHfQE7AwGuk= -github.com/aws/aws-sdk-go-v2 v1.24.0/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 h1:OCs21ST2LrepDfD3lwlQiOqIGp6JiEUqG84GzTDoyJs= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4/go.mod h1:usURWEKSNNAcAZuzRn/9ZYPT8aZQkR7xcCtunK/LkJo= -github.com/aws/aws-sdk-go-v2/config v1.26.1 h1:z6DqMxclFGL3Zfo+4Q0rLnAZ6yVkzCRxhRMsiRQnD1o= -github.com/aws/aws-sdk-go-v2/config v1.26.1/go.mod h1:ZB+CuKHRbb5v5F0oJtGdhFTelmrxd4iWO1lf0rQwSAg= -github.com/aws/aws-sdk-go-v2/credentials v1.16.12 h1:v/WgB8NxprNvr5inKIiVVrXPuuTegM+K8nncFkr1usU= -github.com/aws/aws-sdk-go-v2/credentials v1.16.12/go.mod h1:X21k0FjEJe+/pauud82HYiQbEr9jRKY3kXEIQ4hXeTQ= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 h1:w98BT5w+ao1/r5sUuiH6JkVzjowOKeOJRHERyy1vh58= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10/go.mod h1:K2WGI7vUvkIv1HoNbfBA1bvIZ+9kL3YVmWxeKuLQsiw= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 h1:v+HbZaCGmOwnTTVS86Fleq0vPzOd7tnJGbFhP0stNLs= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9/go.mod h1:Xjqy+Nyj7VDLBtCMkQYOw1QYfAEZCVLrfI0ezve8wd4= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 h1:N94sVhRACtXyVcjXxrwK1SKFIJrA9pOJ5yu2eSHnmls= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9/go.mod h1:hqamLz7g1/4EJP+GH5NBhcUMLjW+gKLQabgyz6/7WAU= -github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 h1:GrSw8s0Gs/5zZ0SX+gX4zQjRnRsMJDJ2sLur1gRBhEM= -github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9 h1:ugD6qzjYtB7zM5PN/ZIeaAIyefPaD82G8+SJopgvUpw= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9/go.mod h1:YD0aYBWCrPENpHolhKw2XDlTIWae2GKXT1T4o6N6hiM= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.9 h1:/90OR2XbSYfXucBMJ4U14wrjlfleq/0SB6dZDPncgmo= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.9/go.mod h1:dN/Of9/fNZet7UrQQ6kTDo/VSwKPIq94vjlU16bRARc= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9 h1:Nf2sHxjMJR8CSImIVCONRi4g0Su3J+TSTbS7G0pUeMU= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9/go.mod h1:idky4TER38YIjr2cADF1/ugFMKvZV7p//pVeV5LZbF0= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.9 h1:iEAeF6YC3l4FzlJPP9H3Ko1TXpdjdqWffxXjp8SY6uk= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.9/go.mod h1:kjsXoK23q9Z/tLBrckZLLyvjhZoS+AGrzqzUfEClvMM= -github.com/aws/aws-sdk-go-v2/service/kms v1.27.4 h1:c75pHGBV3h6WOsIjbJhLyOnlCPXzap45nbiP2Z5jk5M= -github.com/aws/aws-sdk-go-v2/service/kms v1.27.4/go.mod h1:D9FVDkZjkZnnFHymJ3fPVz0zOUlNSd0xcIIVmmrAac8= -github.com/aws/aws-sdk-go-v2/service/s3 v1.47.5 h1:Keso8lIOS+IzI2MkPZyK6G0LYcK3My2LQ+T5bxghEAY= -github.com/aws/aws-sdk-go-v2/service/s3 v1.47.5/go.mod h1:vADO6Jn+Rq4nDtfwNjhgR84qkZwiC6FqCaXdw/kYwjA= -github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 h1:ldSFWz9tEHAwHNmjx2Cvy1MjP5/L9kNoR0skc6wyOOM= -github.com/aws/aws-sdk-go-v2/service/sso v1.18.5/go.mod h1:CaFfXLYL376jgbP7VKC96uFcU8Rlavak0UlAwk1Dlhc= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 h1:2k9KmFawS63euAkY4/ixVNsYYwrwnd5fIvgEKkfZFNM= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5/go.mod h1:W+nd4wWDVkSUIox9bacmkBP5NMFQeTJ/xqNabpzSR38= -github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 h1:5UYvv8JUvllZsRnfrcMQ+hJ9jNICmcgKPAO1CER25Wg= -github.com/aws/aws-sdk-go-v2/service/sts v1.26.5/go.mod h1:XX5gh4CB7wAs4KhcF46G6C8a2i7eupU19dcAAE+EydU= -github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM= -github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= diff --git a/all-examples/go/v3/local-go-s3ec b/all-examples/go/v3/local-go-s3ec deleted file mode 120000 index 7e5e770c..00000000 --- a/all-examples/go/v3/local-go-s3ec +++ /dev/null @@ -1 +0,0 @@ -../../../test-server/go-v3-transition-server/local-go-s3ec \ No newline at end of file diff --git a/all-examples/go/v3/main.go b/all-examples/go/v3/main.go deleted file mode 100644 index 22732bc8..00000000 --- a/all-examples/go/v3/main.go +++ /dev/null @@ -1,171 +0,0 @@ -package main - -import ( - "context" - "fmt" - "io" - "os" - "strings" - - "github.com/aws/amazon-s3-encryption-client-go/v3/client" - "github.com/aws/amazon-s3-encryption-client-go/v3/commitment" - "github.com/aws/amazon-s3-encryption-client-go/v3/materials" - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/config" - "github.com/aws/aws-sdk-go-v2/service/kms" - "github.com/aws/aws-sdk-go-v2/service/s3" -) - -func main() { - // Check command line arguments - if len(os.Args) != 5 { - fmt.Printf("Usage: %s \n", os.Args[0]) - fmt.Printf("Example: %s avp-21638 s3ec-go-v3 arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 us-east-2\n", os.Args[0]) - os.Exit(1) - } - - bucketName := os.Args[1] - objectKey := os.Args[2] - kmsKeyID := os.Args[3] - region := os.Args[4] - - fmt.Println("=== S3 Encryption Client v3 Example (Go) ===") - fmt.Printf("Bucket: %s\n", bucketName) - fmt.Printf("Object Key: %s\n", objectKey) - fmt.Printf("KMS Key ID: %s\n", kmsKeyID) - fmt.Printf("Region: %s\n", region) - fmt.Println() - - // Test data for encryption - testData := "Hello, World! This is a test message for S3 encryption client v3 in Go." - fmt.Printf("Original data: %s\n", testData) - fmt.Printf("Data length: %d bytes\n", len(testData)) - fmt.Println() - - fmt.Println("--- Initialize S3 Encryption Client v3 ---") - - // Create regular S3 client - cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion(region)) - if err != nil { - fmt.Printf("Error loading AWS config: %v\n", err) - os.Exit(1) - } - s3Client := s3.NewFromConfig(cfg) - - // Create KMS client - kmsClient := kms.NewFromConfig(cfg) - - // Create KMS keyring - keyring := materials.NewKmsKeyring(kmsClient, kmsKeyID) - - // Create Cryptographic Materials Manager - cmm, err := materials.NewCryptographicMaterialsManager(keyring) - if err != nil { - fmt.Printf("Error creating CMM: %v\n", err) - os.Exit(1) - } - - // Create S3 Encryption Client v3 - encryptionClient, err := client.New(s3Client, cmm, func(options *client.EncryptionClientOptions) { - options.CommitmentPolicy = commitment.FORBID_ENCRYPT_ALLOW_DECRYPT - }) - if err != nil { - fmt.Printf("Error creating S3 Encryption Client: %v\n", err) - os.Exit(1) - } - - fmt.Println("Successfully initialized S3 Encryption Client v3") - fmt.Println("--- Encrypt and Upload Object to S3 ---") - - // Add encryption context - encryptionContext := map[string]string{ - "purpose": "example", - "version": "v3", - "language": "go", - } - - // Create context with encryption context - ctx := context.WithValue(context.Background(), "EncryptionContext", encryptionContext) - - // Upload encrypted object using S3 Encryption Client - putInput := &s3.PutObjectInput{ - Bucket: aws.String(bucketName), - Key: aws.String(objectKey), - Body: strings.NewReader(testData), - } - - _, err = encryptionClient.PutObject(ctx, putInput) - if err != nil { - if strings.Contains(err.Error(), "NoSuchBucket") { - fmt.Printf("Error: S3 bucket '%s' does not exist or is not accessible\n", bucketName) - } else if strings.Contains(err.Error(), "NotFoundException") { - fmt.Printf("Error: KMS key '%s' not found or not accessible\n", kmsKeyID) - } else { - fmt.Printf("Error uploading encrypted object: %v\n", err) - } - os.Exit(1) - } - - fmt.Println("Successfully uploaded encrypted object to S3!") - fmt.Printf(" Bucket: %s\n", bucketName) - fmt.Printf(" Key: %s\n", objectKey) - fmt.Printf(" Encryption Context: %v\n", encryptionContext) - fmt.Println() - - fmt.Println("--- Download and Decrypt Object from S3 ---") - - // Download and decrypt object using S3 Encryption Client - getInput := &s3.GetObjectInput{ - Bucket: aws.String(bucketName), - Key: aws.String(objectKey), - } - - getResponse, err := encryptionClient.GetObject(ctx, getInput) - if err != nil { - fmt.Printf("Error downloading and decrypting object: %v\n", err) - os.Exit(1) - } - defer getResponse.Body.Close() - - // Read the decrypted data - decryptedData, err := io.ReadAll(getResponse.Body) - if err != nil { - fmt.Printf("Error reading decrypted data: %v\n", err) - os.Exit(1) - } - - fmt.Println("Successfully downloaded and decrypted object from S3!") - fmt.Printf(" Object size: %d bytes\n", len(decryptedData)) - fmt.Printf(" Decrypted data: %s\n", string(decryptedData)) - fmt.Println() - - fmt.Println("--- Verify Roundtrip Success ---") - - // Verify the roundtrip was successful - if string(decryptedData) == testData { - fmt.Println("SUCCESS: Roundtrip encryption/decryption completed successfully!") - fmt.Println(" Original data matches decrypted data") - fmt.Println(" Data integrity verified") - } else { - fmt.Println("ERROR: Roundtrip failed - data mismatch") - fmt.Printf(" Original: %s\n", testData) - fmt.Printf(" Decrypted: %s\n", string(decryptedData)) - os.Exit(1) - } - - // Optionally Delete the Object - //fmt.Println("--- Cleanup ---") - // Clean up the test object using regular S3 client - // _, err = s3Client.DeleteObject(context.TODO(), &s3.DeleteObjectInput{ - // Bucket: aws.String(bucketName), - // Key: aws.String(objectKey), - // }) - // if err != nil { - // fmt.Printf("Error deleting test object: %v\n", err) - // } else { - // fmt.Println("Test object deleted from S3") - // } - - fmt.Println() - fmt.Println("=== Example completed successfully! ===") -} diff --git a/all-examples/go/v4/Makefile b/all-examples/go/v4/Makefile deleted file mode 100644 index 1e8307e7..00000000 --- a/all-examples/go/v4/Makefile +++ /dev/null @@ -1,69 +0,0 @@ -# Makefile for S3 Encryption Client Go v4 Example - -# Default target -.PHONY: all install clean run help - -# Variables -SCRIPT = main.go - -# Default arguments for running the example -# Override these when calling make run -BUCKET_NAME ?= avp-21638 -OBJECT_KEY ?= s3ec-go-v4 -KMS_KEY_ID ?= arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 -AWS_REGION ?= us-east-2 - -all: install - -# Install dependencies using Go modules -install: - @echo "Installing Go dependencies..." - @go mod tidy - @echo "Dependencies installed successfully!" - -# Clean Go artifacts -clean: - @echo "Cleaning Go artifacts..." - @go clean - @echo "Clean completed!" - -# Run the example with default arguments -run: install - @echo "Running S3 Encryption Client v4 Go example..." - @echo "Bucket: $(BUCKET_NAME)" - @echo "Object Key: $(OBJECT_KEY)" - @echo "KMS Key ID: $(KMS_KEY_ID)" - @echo "Region: $(AWS_REGION)" - @echo "" - @go run $(SCRIPT) $(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION) - -# Run with custom arguments -# Usage: make run-custom BUCKET_NAME=my-bucket OBJECT_KEY=my-key KMS_KEY_ID=my-kms-key AWS_REGION=my-region -run-custom: install - @go run $(SCRIPT) $(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION) - -# Show help -help: - @echo "S3 Encryption Client Go v4 Example Makefile" - @echo "" - @echo "Available targets:" - @echo " install - Install Go dependencies using Go modules" - @echo " run - Install dependencies and run the example with default parameters" - @echo " run-custom - Install dependencies and run with custom parameters" - @echo " clean - Remove Go artifacts" - @echo " help - Show this help message" - @echo "" - @echo "Default parameters:" - @echo " BUCKET_NAME = $(BUCKET_NAME)" - @echo " OBJECT_KEY = $(OBJECT_KEY)" - @echo " KMS_KEY_ID = $(KMS_KEY_ID)" - @echo " AWS_REGION = $(AWS_REGION)" - @echo "" - @echo "To run with custom parameters:" - @echo " make run BUCKET_NAME=your-bucket OBJECT_KEY=your-key KMS_KEY_ID=your-kms-key AWS_REGION=your-region" - @echo "" - @echo "Prerequisites:" - @echo " - Go 1.24+ installed on the system" - @echo " - AWS credentials configured (AWS CLI, environment variables, or IAM role)" - @echo " - Valid S3 bucket and KMS key with appropriate permissions" - @echo " - S3 Encryption Client v4 Go SDK (included in local-go-s3ec)" diff --git a/all-examples/go/v4/README.md b/all-examples/go/v4/README.md deleted file mode 100644 index b6972f26..00000000 --- a/all-examples/go/v4/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# S3 Encryption Client Go v4 Example - -This example demonstrates how to use the Amazon S3 Encryption Client v4 for Go to perform client-side encryption and decryption of objects. - -## Prerequisites - -1. **Go**: Requires Go 1.24 or later -2. **AWS Credentials**: Configure your AWS credentials using one of the following methods: - - AWS CLI: `aws configure` - - Environment variables: `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` - - IAM roles (for EC2 instances) -3. **KMS Key**: You'll need a KMS key ID or ARN. You can use the default example key: `arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01` -4. **S3 Bucket**: An existing S3 bucket where you have read/write permissions - -## Setup - -1. Initialize submodules and download dependencies: - ```bash - make install - ``` - - Or manually: - ```bash - go mod tidy - ``` - - **Note**: This example uses a local submodule for the S3EC Go v4 library via the `replace` directive in `go.mod`. - -## Usage - -### Using Make (Recommended) - -Run the example with default parameters: -```bash -make run -``` - -Run with custom parameters: -```bash -make run BUCKET_NAME=my-bucket OBJECT_KEY=my-key KMS_KEY_ID=my-kms-key AWS_REGION=my-region -``` - -### Manual Usage - -Run the example with the following command: - -```bash -go run main.go -``` - -### Example: - -```bash -go run main.go my-test-bucket s3ec-go-v4-test arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 us-east-2 -``` diff --git a/all-examples/go/v4/go.mod b/all-examples/go/v4/go.mod deleted file mode 100644 index 48bea56e..00000000 --- a/all-examples/go/v4/go.mod +++ /dev/null @@ -1,32 +0,0 @@ -module github.com/aws/amazon-s3-encryption-client-python/all-examples/go/v4 - -go 1.24 - -require ( - github.com/aws/amazon-s3-encryption-client-go/v4 v4.0.0 - github.com/aws/aws-sdk-go-v2 v1.24.0 - github.com/aws/aws-sdk-go-v2/config v1.26.1 - github.com/aws/aws-sdk-go-v2/service/kms v1.27.4 - github.com/aws/aws-sdk-go-v2/service/s3 v1.47.5 -) - -require ( - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.16.12 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.9 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.9 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 // indirect - github.com/aws/smithy-go v1.19.0 // indirect -) - -// S3EC Go V4 uses a local submodule for development -replace github.com/aws/amazon-s3-encryption-client-go/v4 => ./local-go-s3ec/v4 diff --git a/all-examples/go/v4/go.sum b/all-examples/go/v4/go.sum deleted file mode 100644 index 244c8814..00000000 --- a/all-examples/go/v4/go.sum +++ /dev/null @@ -1,40 +0,0 @@ -github.com/aws/aws-sdk-go-v2 v1.24.0 h1:890+mqQ+hTpNuw0gGP6/4akolQkSToDJgHfQE7AwGuk= -github.com/aws/aws-sdk-go-v2 v1.24.0/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 h1:OCs21ST2LrepDfD3lwlQiOqIGp6JiEUqG84GzTDoyJs= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4/go.mod h1:usURWEKSNNAcAZuzRn/9ZYPT8aZQkR7xcCtunK/LkJo= -github.com/aws/aws-sdk-go-v2/config v1.26.1 h1:z6DqMxclFGL3Zfo+4Q0rLnAZ6yVkzCRxhRMsiRQnD1o= -github.com/aws/aws-sdk-go-v2/config v1.26.1/go.mod h1:ZB+CuKHRbb5v5F0oJtGdhFTelmrxd4iWO1lf0rQwSAg= -github.com/aws/aws-sdk-go-v2/credentials v1.16.12 h1:v/WgB8NxprNvr5inKIiVVrXPuuTegM+K8nncFkr1usU= -github.com/aws/aws-sdk-go-v2/credentials v1.16.12/go.mod h1:X21k0FjEJe+/pauud82HYiQbEr9jRKY3kXEIQ4hXeTQ= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 h1:w98BT5w+ao1/r5sUuiH6JkVzjowOKeOJRHERyy1vh58= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10/go.mod h1:K2WGI7vUvkIv1HoNbfBA1bvIZ+9kL3YVmWxeKuLQsiw= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 h1:v+HbZaCGmOwnTTVS86Fleq0vPzOd7tnJGbFhP0stNLs= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9/go.mod h1:Xjqy+Nyj7VDLBtCMkQYOw1QYfAEZCVLrfI0ezve8wd4= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 h1:N94sVhRACtXyVcjXxrwK1SKFIJrA9pOJ5yu2eSHnmls= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9/go.mod h1:hqamLz7g1/4EJP+GH5NBhcUMLjW+gKLQabgyz6/7WAU= -github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 h1:GrSw8s0Gs/5zZ0SX+gX4zQjRnRsMJDJ2sLur1gRBhEM= -github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9 h1:ugD6qzjYtB7zM5PN/ZIeaAIyefPaD82G8+SJopgvUpw= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9/go.mod h1:YD0aYBWCrPENpHolhKw2XDlTIWae2GKXT1T4o6N6hiM= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.9 h1:/90OR2XbSYfXucBMJ4U14wrjlfleq/0SB6dZDPncgmo= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.9/go.mod h1:dN/Of9/fNZet7UrQQ6kTDo/VSwKPIq94vjlU16bRARc= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9 h1:Nf2sHxjMJR8CSImIVCONRi4g0Su3J+TSTbS7G0pUeMU= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9/go.mod h1:idky4TER38YIjr2cADF1/ugFMKvZV7p//pVeV5LZbF0= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.9 h1:iEAeF6YC3l4FzlJPP9H3Ko1TXpdjdqWffxXjp8SY6uk= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.9/go.mod h1:kjsXoK23q9Z/tLBrckZLLyvjhZoS+AGrzqzUfEClvMM= -github.com/aws/aws-sdk-go-v2/service/kms v1.27.4 h1:c75pHGBV3h6WOsIjbJhLyOnlCPXzap45nbiP2Z5jk5M= -github.com/aws/aws-sdk-go-v2/service/kms v1.27.4/go.mod h1:D9FVDkZjkZnnFHymJ3fPVz0zOUlNSd0xcIIVmmrAac8= -github.com/aws/aws-sdk-go-v2/service/s3 v1.47.5 h1:Keso8lIOS+IzI2MkPZyK6G0LYcK3My2LQ+T5bxghEAY= -github.com/aws/aws-sdk-go-v2/service/s3 v1.47.5/go.mod h1:vADO6Jn+Rq4nDtfwNjhgR84qkZwiC6FqCaXdw/kYwjA= -github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 h1:ldSFWz9tEHAwHNmjx2Cvy1MjP5/L9kNoR0skc6wyOOM= -github.com/aws/aws-sdk-go-v2/service/sso v1.18.5/go.mod h1:CaFfXLYL376jgbP7VKC96uFcU8Rlavak0UlAwk1Dlhc= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 h1:2k9KmFawS63euAkY4/ixVNsYYwrwnd5fIvgEKkfZFNM= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5/go.mod h1:W+nd4wWDVkSUIox9bacmkBP5NMFQeTJ/xqNabpzSR38= -github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 h1:5UYvv8JUvllZsRnfrcMQ+hJ9jNICmcgKPAO1CER25Wg= -github.com/aws/aws-sdk-go-v2/service/sts v1.26.5/go.mod h1:XX5gh4CB7wAs4KhcF46G6C8a2i7eupU19dcAAE+EydU= -github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM= -github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= diff --git a/all-examples/go/v4/local-go-s3ec b/all-examples/go/v4/local-go-s3ec deleted file mode 120000 index d06737d9..00000000 --- a/all-examples/go/v4/local-go-s3ec +++ /dev/null @@ -1 +0,0 @@ -../../../test-server/go-v4-server/local-go-s3ec \ No newline at end of file diff --git a/all-examples/go/v4/main.go b/all-examples/go/v4/main.go deleted file mode 100644 index a1227790..00000000 --- a/all-examples/go/v4/main.go +++ /dev/null @@ -1,171 +0,0 @@ -package main - -import ( - "context" - "fmt" - "io" - "os" - "strings" - - "github.com/aws/amazon-s3-encryption-client-go/v4/client" - "github.com/aws/amazon-s3-encryption-client-go/v4/commitment" - "github.com/aws/amazon-s3-encryption-client-go/v4/materials" - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/config" - "github.com/aws/aws-sdk-go-v2/service/kms" - "github.com/aws/aws-sdk-go-v2/service/s3" -) - -func main() { - // Check command line arguments - if len(os.Args) != 5 { - fmt.Printf("Usage: %s \n", os.Args[0]) - fmt.Printf("Example: %s avp-21638 s3ec-go-v4 arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 us-east-2\n", os.Args[0]) - os.Exit(1) - } - - bucketName := os.Args[1] - objectKey := os.Args[2] - kmsKeyID := os.Args[3] - region := os.Args[4] - - fmt.Println("=== S3 Encryption Client v4 Example (Go) ===") - fmt.Printf("Bucket: %s\n", bucketName) - fmt.Printf("Object Key: %s\n", objectKey) - fmt.Printf("KMS Key ID: %s\n", kmsKeyID) - fmt.Printf("Region: %s\n", region) - fmt.Println() - - // Test data for encryption - testData := "Hello, World! This is a test message for S3 encryption client v4 in Go." - fmt.Printf("Original data: %s\n", testData) - fmt.Printf("Data length: %d bytes\n", len(testData)) - fmt.Println() - - fmt.Println("--- Initialize S3 Encryption Client v4 ---") - - // Create regular S3 client - cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion(region)) - if err != nil { - fmt.Printf("Error loading AWS config: %v\n", err) - os.Exit(1) - } - s3Client := s3.NewFromConfig(cfg) - - // Create KMS client - kmsClient := kms.NewFromConfig(cfg) - - // Create KMS keyring - keyring := materials.NewKmsKeyring(kmsClient, kmsKeyID) - - // Create Cryptographic Materials Manager - cmm, err := materials.NewCryptographicMaterialsManager(keyring) - if err != nil { - fmt.Printf("Error creating CMM: %v\n", err) - os.Exit(1) - } - - // Create S3 Encryption Client v4 - encryptionClient, err := client.New(s3Client, cmm, func(options *client.EncryptionClientOptions) { - options.CommitmentPolicy = commitment.REQUIRE_ENCRYPT_ALLOW_DECRYPT - }) - if err != nil { - fmt.Printf("Error creating S3 Encryption Client: %v\n", err) - os.Exit(1) - } - - fmt.Println("Successfully initialized S3 Encryption Client v4") - fmt.Println("--- Encrypt and Upload Object to S3 ---") - - // Add encryption context - encryptionContext := map[string]string{ - "purpose": "example", - "version": "v4", - "language": "go", - } - - // Create context with encryption context - ctx := context.WithValue(context.Background(), "EncryptionContext", encryptionContext) - - // Upload encrypted object using S3 Encryption Client - putInput := &s3.PutObjectInput{ - Bucket: aws.String(bucketName), - Key: aws.String(objectKey), - Body: strings.NewReader(testData), - } - - _, err = encryptionClient.PutObject(ctx, putInput) - if err != nil { - if strings.Contains(err.Error(), "NoSuchBucket") { - fmt.Printf("Error: S3 bucket '%s' does not exist or is not accessible\n", bucketName) - } else if strings.Contains(err.Error(), "NotFoundException") { - fmt.Printf("Error: KMS key '%s' not found or not accessible\n", kmsKeyID) - } else { - fmt.Printf("Error uploading encrypted object: %v\n", err) - } - os.Exit(1) - } - - fmt.Println("Successfully uploaded encrypted object to S3!") - fmt.Printf(" Bucket: %s\n", bucketName) - fmt.Printf(" Key: %s\n", objectKey) - fmt.Printf(" Encryption Context: %v\n", encryptionContext) - fmt.Println() - - fmt.Println("--- Download and Decrypt Object from S3 ---") - - // Download and decrypt object using S3 Encryption Client - getInput := &s3.GetObjectInput{ - Bucket: aws.String(bucketName), - Key: aws.String(objectKey), - } - - getResponse, err := encryptionClient.GetObject(ctx, getInput) - if err != nil { - fmt.Printf("Error downloading and decrypting object: %v\n", err) - os.Exit(1) - } - defer getResponse.Body.Close() - - // Read the decrypted data - decryptedData, err := io.ReadAll(getResponse.Body) - if err != nil { - fmt.Printf("Error reading decrypted data: %v\n", err) - os.Exit(1) - } - - fmt.Println("Successfully downloaded and decrypted object from S3!") - fmt.Printf(" Object size: %d bytes\n", len(decryptedData)) - fmt.Printf(" Decrypted data: %s\n", string(decryptedData)) - fmt.Println() - - fmt.Println("--- Verify Roundtrip Success ---") - - // Verify the roundtrip was successful - if string(decryptedData) == testData { - fmt.Println("SUCCESS: Roundtrip encryption/decryption completed successfully!") - fmt.Println(" Original data matches decrypted data") - fmt.Println(" Data integrity verified") - } else { - fmt.Println("ERROR: Roundtrip failed - data mismatch") - fmt.Printf(" Original: %s\n", testData) - fmt.Printf(" Decrypted: %s\n", string(decryptedData)) - os.Exit(1) - } - - // Optionally Delete the Object - //fmt.Println("--- Cleanup ---") - // Clean up the test object using regular S3 client - // _, err = s3Client.DeleteObject(context.TODO(), &s3.DeleteObjectInput{ - // Bucket: aws.String(bucketName), - // Key: aws.String(objectKey), - // }) - // if err != nil { - // fmt.Printf("Error deleting test object: %v\n", err) - // } else { - // fmt.Println("Test object deleted from S3") - // } - - fmt.Println() - fmt.Println("=== Example completed successfully! ===") -} diff --git a/all-examples/java/v3/Makefile b/all-examples/java/v3/Makefile deleted file mode 100644 index 81e4228d..00000000 --- a/all-examples/java/v3/Makefile +++ /dev/null @@ -1,75 +0,0 @@ -# Makefile for S3 Encryption Client Java v3 Example - -# Default target -.PHONY: all install clean run help s3ec-staging - -# Default arguments for running the example -# Override these when calling make run -BUCKET_NAME ?= avp-21638 -OBJECT_KEY ?= s3ec-java-v3 -KMS_KEY_ID ?= arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 -AWS_REGION ?= us-east-2 - -all: install - -# Install S3 Encryption Client library from source -s3ec-staging: - @echo "[JAVA V3] Installing S3 Encryption Client library from source..." - @cd s3ec-staging && mvn -B -ntp install -DskipTests - @echo "[JAVA V3] S3 Encryption Client library installed successfully!" - -# Install dependencies using Gradle -install: s3ec-staging - @echo "[JAVA V3] Installing Java dependencies..." - @chmod +x ./gradlew - @./gradlew build - @echo "[JAVA V3] Dependencies installed successfully!" - -# Clean Gradle artifacts -clean: - @echo "[JAVA V3] Cleaning Gradle artifacts..." - @./gradlew clean - @echo "[JAVA V3] Clean completed!" - -# Run the example with default arguments -run: install - @echo "[JAVA V3] Running S3 Encryption Client v3 Java example..." - @echo "[JAVA V3] Bucket: $(BUCKET_NAME)" - @echo "[JAVA V3] Object Key: $(OBJECT_KEY)" - @echo "[JAVA V3] KMS Key ID: $(KMS_KEY_ID)" - @echo "[JAVA V3] Region: $(AWS_REGION)" - @echo "" - @./gradlew run --args="$(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION)" - -# Run with custom arguments -# Usage: make run-custom BUCKET_NAME=my-bucket OBJECT_KEY=my-key KMS_KEY_ID=my-kms-key AWS_REGION=my-region -run-custom: install - @./gradlew run --args="$(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION)" - -# Show help -help: - @echo "S3 Encryption Client Java v3 Example Makefile" - @echo "" - @echo "Available targets:" - @echo " s3ec-staging - Install S3 Encryption Client library from source" - @echo " install - Install Java dependencies using Gradle" - @echo " run - Install dependencies and run the example with default parameters" - @echo " run-custom - Install dependencies and run with custom parameters" - @echo " clean - Remove Gradle artifacts" - @echo " help - Show this help message" - @echo "" - @echo "Default parameters:" - @echo " BUCKET_NAME = $(BUCKET_NAME)" - @echo " OBJECT_KEY = $(OBJECT_KEY)" - @echo " KMS_KEY_ID = $(KMS_KEY_ID)" - @echo " AWS_REGION = $(AWS_REGION)" - @echo "" - @echo "To run with custom parameters:" - @echo " make run BUCKET_NAME=your-bucket OBJECT_KEY=your-key KMS_KEY_ID=your-kms-key AWS_REGION=your-region" - @echo "" - @echo "Prerequisites:" - @echo " - Java 11+ installed on the system" - @echo " - AWS credentials configured (AWS CLI, environment variables, or IAM role)" - @echo " - Valid S3 bucket and KMS key with appropriate permissions" - @echo " - S3 Encryption Client v3 library installed in local Maven repository" - @echo " (Install by running: cd s3ec-staging && mvn install)" diff --git a/all-examples/java/v3/README.md b/all-examples/java/v3/README.md deleted file mode 100644 index 50e67684..00000000 --- a/all-examples/java/v3/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# S3 Encryption Client Java v3 Example - -This example demonstrates how to use the Amazon S3 Encryption Client v3 for Java to perform client-side encryption and decryption of objects. - -## Prerequisites - -1. **Java**: Requires Java 11 or later -2. **Gradle**: The project uses Gradle wrapper (included - `./gradlew`) -3. **Maven**: Required to install the S3 Encryption Client library from source -4. **AWS Credentials**: Configure your AWS credentials using one of the following methods: - - AWS CLI: `aws configure` - - Environment variables: `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` - - IAM roles (for EC2 instances) -5. **KMS Key**: You'll need a KMS key ID or ARN. You can use the default example key: `arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01` -6. **S3 Bucket**: An existing S3 bucket where you have read/write permissions - -## Setup - -Install dependencies and build (this automatically installs the S3 Encryption Client library from source): -```bash -make install -``` - -Or manually: -```bash -cd s3ec-staging && mvn clean install && cd - -./gradlew build -``` - -**Note**: This example uses a local library installed in Maven local repository via the symbolic link `s3ec-staging`. - -## Usage - -### Using Make (Recommended) - -Run the example with default parameters: -```bash -make run -``` - -Run with custom parameters: -```bash -make run BUCKET_NAME=my-bucket OBJECT_KEY=my-key KMS_KEY_ID=my-kms-key AWS_REGION=my-region -``` - -### Manual Usage - -Run the example with the following command: - -```bash -./gradlew run --args=" " -``` - -### Example: - -```bash -./gradlew run --args="my-test-bucket s3ec-java-v3-test arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 us-east-2" diff --git a/all-examples/java/v3/build.gradle.kts b/all-examples/java/v3/build.gradle.kts deleted file mode 100644 index f0748625..00000000 --- a/all-examples/java/v3/build.gradle.kts +++ /dev/null @@ -1,47 +0,0 @@ -plugins { - java - application -} - -group = "software.amazon.encryption.s3.example" -version = "1.0.0" - -repositories { - mavenLocal() - mavenCentral() -} - -dependencies { - // AWS SDK v2 dependencies - implementation(platform("software.amazon.awssdk:bom:2.20.0")) - implementation("software.amazon.awssdk:s3") - implementation("software.amazon.awssdk:kms") - implementation("software.amazon.awssdk:auth") - - // S3 Encryption Client v3 from local Maven repository - implementation("software.amazon.encryption.s3:amazon-s3-encryption-client-java:3.4.0-read-kc") -} - -application { - mainClass.set("software.amazon.encryption.s3.example.Main") -} - -java { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 -} - -tasks.jar { - manifest { - attributes["Main-Class"] = "software.amazon.encryption.s3.example.Main" - } - - // Create a fat jar with all dependencies - from(configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) }) - duplicatesStrategy = DuplicatesStrategy.EXCLUDE - archiveBaseName.set("s3ec-java-v3-example") -} - -tasks.named("run") { - standardInput = System.`in` -} diff --git a/all-examples/java/v3/gradle/wrapper/gradle-wrapper.jar b/all-examples/java/v3/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index e6441136..00000000 Binary files a/all-examples/java/v3/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/all-examples/java/v3/gradle/wrapper/gradle-wrapper.properties b/all-examples/java/v3/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index a4413138..00000000 --- a/all-examples/java/v3/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/all-examples/java/v3/gradlew b/all-examples/java/v3/gradlew deleted file mode 100755 index b740cf13..00000000 --- a/all-examples/java/v3/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# 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 -# -# https://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. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/all-examples/java/v3/gradlew.bat b/all-examples/java/v3/gradlew.bat deleted file mode 100644 index 25da30db..00000000 --- a/all-examples/java/v3/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/all-examples/java/v3/s3ec-staging b/all-examples/java/v3/s3ec-staging deleted file mode 120000 index 1a52a7b9..00000000 --- a/all-examples/java/v3/s3ec-staging +++ /dev/null @@ -1 +0,0 @@ -../../../test-server/java-v3-transition-server/s3ec-staging \ No newline at end of file diff --git a/all-examples/java/v3/settings.gradle.kts b/all-examples/java/v3/settings.gradle.kts deleted file mode 100644 index a4dcbbae..00000000 --- a/all-examples/java/v3/settings.gradle.kts +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = "s3ec-java-v3-example" diff --git a/all-examples/java/v3/src/main/java/software/amazon/encryption/s3/example/Main.java b/all-examples/java/v3/src/main/java/software/amazon/encryption/s3/example/Main.java deleted file mode 100644 index b0d9c112..00000000 --- a/all-examples/java/v3/src/main/java/software/amazon/encryption/s3/example/Main.java +++ /dev/null @@ -1,161 +0,0 @@ -package software.amazon.encryption.s3.example; - -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; - -import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; -import software.amazon.awssdk.core.sync.RequestBody; -import software.amazon.awssdk.regions.Region; -import software.amazon.awssdk.services.kms.KmsClient; -import software.amazon.awssdk.services.s3.S3Client; -import software.amazon.awssdk.services.s3.model.GetObjectRequest; -import software.amazon.awssdk.services.s3.model.PutObjectRequest; -import software.amazon.encryption.s3.CommitmentPolicy; -import software.amazon.encryption.s3.S3EncryptionClient; -import software.amazon.encryption.s3.algorithms.AlgorithmSuite; -import software.amazon.encryption.s3.materials.CryptographicMaterialsManager; -import software.amazon.encryption.s3.materials.DefaultCryptoMaterialsManager; -import software.amazon.encryption.s3.materials.KmsKeyring; - -/** - * Example demonstrating the use of Amazon S3 Encryption Client v3 for Java. - * - * This example shows how to: - * 1. Initialize the S3 Encryption Client with KMS keyring - * 2. Encrypt and upload an object to S3 - * 3. Download and decrypt the object - * 4. Verify the roundtrip encryption/decryption - */ -public class Main { - - public static void main(String[] args) { - // Check command line arguments - if (args.length != 4) { - System.out.println("Usage: ./gradlew run --args=\" \""); - System.out.println("Example: ./gradlew run --args=\"avp-21638 s3ec-java-v3 arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 us-east-2\""); - System.exit(1); - } - - String bucketName = args[0]; - String objectKey = args[1]; - String kmsKeyId = args[2]; - String region = args[3]; - - System.out.println("=== S3 Encryption Client v3 Example (Java) ==="); - System.out.println("Bucket: " + bucketName); - System.out.println("Object Key: " + objectKey); - System.out.println("KMS Key ID: " + kmsKeyId); - System.out.println("Region: " + region); - System.out.println(); - - // Test data for encryption - String testData = "Hello, World! This is a test message for S3 encryption client v3 in Java."; - System.out.println("Original data: " + testData); - System.out.println("Data length: " + testData.length() + " bytes"); - System.out.println(); - - try { - System.out.println("--- Initialize S3 Encryption Client v3 ---"); - - // Create standard S3 client - S3Client s3Client = S3Client.builder() - .region(Region.of(region)) - .credentialsProvider(DefaultCredentialsProvider.create()) - .build(); - - // Create KMS client - KmsClient kmsClient = KmsClient.builder() - .region(Region.of(region)) - .credentialsProvider(DefaultCredentialsProvider.create()) - .build(); - - // Create KMS keyring - KmsKeyring keyring = KmsKeyring.builder() - .kmsClient(kmsClient) - .wrappingKeyId(kmsKeyId) - .build(); - - // Create Cryptographic Materials Manager - CryptographicMaterialsManager cmm = DefaultCryptoMaterialsManager.builder() - .keyring(keyring) - .build(); - - // Create S3 Encryption Client v3 - S3EncryptionClient encryptionClient = S3EncryptionClient.builder() - .commitmentPolicy(CommitmentPolicy.FORBID_ENCRYPT_ALLOW_DECRYPT) - .encryptionAlgorithm(AlgorithmSuite.ALG_AES_256_GCM_IV12_TAG16_NO_KDF) - .wrappedClient(s3Client) - .cryptoMaterialsManager(cmm) - .enableLegacyUnauthenticatedModes(true) - .enableLegacyWrappingAlgorithms(true) - .build(); - - System.out.println("Successfully initialized S3 Encryption Client v3"); - System.out.println("--- Encrypt and Upload Object to S3 ---"); - - // Add encryption context - Map encryptionContext = new HashMap<>(); - encryptionContext.put("purpose", "example"); - encryptionContext.put("version", "v3"); - encryptionContext.put("language", "java"); - - // Upload encrypted object using S3 Encryption Client - PutObjectRequest putRequest = PutObjectRequest.builder() - .bucket(bucketName) - .key(objectKey) - .build(); - - encryptionClient.putObject(putRequest, RequestBody.fromString(testData)); - - System.out.println("Successfully uploaded encrypted object to S3!"); - System.out.println(" Bucket: " + bucketName); - System.out.println(" Key: " + objectKey); - System.out.println(" Encryption Context: " + encryptionContext); - System.out.println(); - - System.out.println("--- Download and Decrypt Object from S3 ---"); - - // Download and decrypt object using S3 Encryption Client - GetObjectRequest getRequest = GetObjectRequest.builder() - .bucket(bucketName) - .key(objectKey) - .build(); - - String decryptedData = encryptionClient.getObjectAsBytes(getRequest) - .asString(StandardCharsets.UTF_8); - - System.out.println("Successfully downloaded and decrypted object from S3!"); - System.out.println(" Object size: " + decryptedData.length() + " bytes"); - System.out.println(" Decrypted data: " + decryptedData); - System.out.println(); - - System.out.println("--- Verify Roundtrip Success ---"); - - // Verify the roundtrip was successful - if (decryptedData.equals(testData)) { - System.out.println("SUCCESS: Roundtrip encryption/decryption completed successfully!"); - System.out.println(" Original data matches decrypted data"); - System.out.println(" Data integrity verified"); - } else { - System.out.println("ERROR: Roundtrip failed - data mismatch"); - System.out.println(" Original: " + testData); - System.out.println(" Decrypted: " + decryptedData); - System.exit(1); - } - - System.out.println(); - System.out.println("=== Example completed successfully! ==="); - - // Clean up clients - encryptionClient.close(); - s3Client.close(); - kmsClient.close(); - - } catch (Exception e) { - System.err.println("Error: " + e.getMessage()); - e.printStackTrace(); - System.exit(1); - } - } -} diff --git a/all-examples/java/v4/Makefile b/all-examples/java/v4/Makefile deleted file mode 100644 index 3390c5e4..00000000 --- a/all-examples/java/v4/Makefile +++ /dev/null @@ -1,75 +0,0 @@ -# Makefile for S3 Encryption Client Java v4 Example - -# Default target -.PHONY: all install clean run help s3ec-staging - -# Default arguments for running the example -# Override these when calling make run -BUCKET_NAME ?= avp-21638 -OBJECT_KEY ?= s3ec-java-v4 -KMS_KEY_ID ?= arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 -AWS_REGION ?= us-east-2 - -all: install - -# Install S3 Encryption Client library from source -s3ec-staging: - @echo "[JAVA V4] Installing S3 Encryption Client library from source..." - @cd s3ec-staging && mvn -B -ntp install -DskipTests - @echo "[JAVA V4] S3 Encryption Client library installed successfully!" - -# Install dependencies using Gradle -install: s3ec-staging - @echo "[JAVA V4] Installing Java dependencies..." - @chmod +x ./gradlew - @./gradlew build - @echo "[JAVA V4] Dependencies installed successfully!" - -# Clean Gradle artifacts -clean: - @echo "[JAVA V4] Cleaning Gradle artifacts..." - @./gradlew clean - @echo "[JAVA V4] Clean completed!" - -# Run the example with default arguments -run: install - @echo "[JAVA V4] Running S3 Encryption Client v4 Java example..." - @echo "[JAVA V4] Bucket: $(BUCKET_NAME)" - @echo "[JAVA V4] Object Key: $(OBJECT_KEY)" - @echo "[JAVA V4] KMS Key ID: $(KMS_KEY_ID)" - @echo "[JAVA V4] Region: $(AWS_REGION)" - @echo "" - @./gradlew run --args="$(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION)" - -# Run with custom arguments -# Usage: make run-custom BUCKET_NAME=my-bucket OBJECT_KEY=my-key KMS_KEY_ID=my-kms-key AWS_REGION=my-region -run-custom: install - @./gradlew run --args="$(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION)" - -# Show help -help: - @echo "S3 Encryption Client Java v4 Example Makefile" - @echo "" - @echo "Available targets:" - @echo " s3ec-staging - Install S3 Encryption Client library from source" - @echo " install - Install Java dependencies using Gradle" - @echo " run - Install dependencies and run the example with default parameters" - @echo " run-custom - Install dependencies and run with custom parameters" - @echo " clean - Remove Gradle artifacts" - @echo " help - Show this help message" - @echo "" - @echo "Default parameters:" - @echo " BUCKET_NAME = $(BUCKET_NAME)" - @echo " OBJECT_KEY = $(OBJECT_KEY)" - @echo " KMS_KEY_ID = $(KMS_KEY_ID)" - @echo " AWS_REGION = $(AWS_REGION)" - @echo "" - @echo "To run with custom parameters:" - @echo " make run BUCKET_NAME=your-bucket OBJECT_KEY=your-key KMS_KEY_ID=your-kms-key AWS_REGION=your-region" - @echo "" - @echo "Prerequisites:" - @echo " - Java 11+ installed on the system" - @echo " - AWS credentials configured (AWS CLI, environment variables, or IAM role)" - @echo " - Valid S3 bucket and KMS key with appropriate permissions" - @echo " - S3 Encryption Client v4 library installed." - @echo " (Install by running: cd s3ec-staging && mvn install)" diff --git a/all-examples/java/v4/README.md b/all-examples/java/v4/README.md deleted file mode 100644 index deedec94..00000000 --- a/all-examples/java/v4/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# S3 Encryption Client Java v4 Example - -This example demonstrates how to use the Amazon S3 Encryption Client v4 for Java to perform client-side encryption and decryption of objects with **key commitment** enabled for enhanced security. - -## Prerequisites - -1. **Java**: Requires Java 11 or later -2. **Gradle**: The example project uses Gradle wrapper (included - `./gradlew`) -3. **Maven**: Required to install the S3 Encryption Client library from source -4. **AWS Credentials**: Configure your AWS credentials using one of the following methods: - - AWS CLI: `aws configure` - - Environment variables: `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` - - IAM roles (for EC2 instances) -5. **KMS Key**: You'll need a KMS key ID or ARN. You can use the default example key: `arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01` -6. **S3 Bucket**: An existing S3 bucket where you have read/write permissions - -## Setup - -Install dependencies and build (this automatically installs the S3 Encryption Client library from source): -```bash -make install -``` - -Or manually: -```bash -cd s3ec-staging && mvn clean install && cd .. -./gradlew build -``` - -**Note**: This example uses a local library installed in Maven local repository via the symbolic link `s3ec-staging`. - -## Usage - -### Using Make (Recommended) - -Run the example with default parameters: -```bash -make run -``` - -Run with custom parameters: -```bash -make run BUCKET_NAME=my-bucket OBJECT_KEY=my-key KMS_KEY_ID=my-kms-key AWS_REGION=my-region -``` - -### Manual Usage - -Run the example with the following command: - -```bash -./gradlew run --args=" " -``` - -### Example: - -```bash -./gradlew run --args="my-test-bucket s3ec-java-v4-test arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 us-east-2" diff --git a/all-examples/java/v4/build.gradle.kts b/all-examples/java/v4/build.gradle.kts deleted file mode 100644 index 56b02b97..00000000 --- a/all-examples/java/v4/build.gradle.kts +++ /dev/null @@ -1,47 +0,0 @@ -plugins { - java - application -} - -group = "software.amazon.encryption.s3.example" -version = "1.0.0" - -repositories { - mavenLocal() - mavenCentral() -} - -dependencies { - // AWS SDK v2 dependencies - implementation(platform("software.amazon.awssdk:bom:2.20.0")) - implementation("software.amazon.awssdk:s3") - implementation("software.amazon.awssdk:kms") - implementation("software.amazon.awssdk:auth") - - // S3 Encryption Client v4 from local Maven repository - implementation("software.amazon.encryption.s3:amazon-s3-encryption-client-java:3.4.0-add-kc") -} - -application { - mainClass.set("software.amazon.encryption.s3.example.Main") -} - -java { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 -} - -tasks.jar { - manifest { - attributes["Main-Class"] = "software.amazon.encryption.s3.example.Main" - } - - // Create a fat jar with all dependencies - from(configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) }) - duplicatesStrategy = DuplicatesStrategy.EXCLUDE - archiveBaseName.set("s3ec-java-v4-example") -} - -tasks.named("run") { - standardInput = System.`in` -} diff --git a/all-examples/java/v4/gradle/wrapper/gradle-wrapper.jar b/all-examples/java/v4/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index e6441136..00000000 Binary files a/all-examples/java/v4/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/all-examples/java/v4/gradle/wrapper/gradle-wrapper.properties b/all-examples/java/v4/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index a4413138..00000000 --- a/all-examples/java/v4/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/all-examples/java/v4/gradlew b/all-examples/java/v4/gradlew deleted file mode 100755 index b740cf13..00000000 --- a/all-examples/java/v4/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# 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 -# -# https://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. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/all-examples/java/v4/gradlew.bat b/all-examples/java/v4/gradlew.bat deleted file mode 100644 index 25da30db..00000000 --- a/all-examples/java/v4/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/all-examples/java/v4/s3ec-staging b/all-examples/java/v4/s3ec-staging deleted file mode 120000 index 970f5de7..00000000 --- a/all-examples/java/v4/s3ec-staging +++ /dev/null @@ -1 +0,0 @@ -../../../test-server/java-v4-server/s3ec-staging \ No newline at end of file diff --git a/all-examples/java/v4/settings.gradle.kts b/all-examples/java/v4/settings.gradle.kts deleted file mode 100644 index e20b5a12..00000000 --- a/all-examples/java/v4/settings.gradle.kts +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = "s3ec-java-v4-example" diff --git a/all-examples/java/v4/src/main/java/software/amazon/encryption/s3/example/Main.java b/all-examples/java/v4/src/main/java/software/amazon/encryption/s3/example/Main.java deleted file mode 100644 index 4ec8fd9b..00000000 --- a/all-examples/java/v4/src/main/java/software/amazon/encryption/s3/example/Main.java +++ /dev/null @@ -1,160 +0,0 @@ -package software.amazon.encryption.s3.example; - -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; - -import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; -import software.amazon.awssdk.core.sync.RequestBody; -import software.amazon.awssdk.regions.Region; -import software.amazon.awssdk.services.kms.KmsClient; -import software.amazon.awssdk.services.s3.S3Client; -import software.amazon.awssdk.services.s3.model.GetObjectRequest; -import software.amazon.awssdk.services.s3.model.PutObjectRequest; -import software.amazon.encryption.s3.S3EncryptionClient; -import software.amazon.encryption.s3.materials.CryptographicMaterialsManager; -import software.amazon.encryption.s3.materials.DefaultCryptoMaterialsManager; -import software.amazon.encryption.s3.materials.KmsKeyring; - -/** - * Example demonstrating the use of Amazon S3 Encryption Client v4 for Java. - * - * This example shows how to: - * 1. Initialize the S3 Encryption Client with KMS keyring and key commitment - * 2. Encrypt and upload an object to S3 with key commitment - * 3. Download and decrypt the object - * 4. Verify the roundtrip encryption/decryption - */ -public class Main { - - public static void main(String[] args) { - // Check command line arguments - if (args.length != 4) { - System.out.println("Usage: ./gradlew run --args=\" \""); - System.out.println("Example: ./gradlew run --args=\"avp-21638 s3ec-java-v4 arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 us-east-2\""); - System.exit(1); - } - - String bucketName = args[0]; - String objectKey = args[1]; - String kmsKeyId = args[2]; - String region = args[3]; - - System.out.println("=== S3 Encryption Client v4 Example (Java) ==="); - System.out.println("Bucket: " + bucketName); - System.out.println("Object Key: " + objectKey); - System.out.println("KMS Key ID: " + kmsKeyId); - System.out.println("Region: " + region); - System.out.println(); - - // Test data for encryption - String testData = "Hello, World! This is a test message for S3 encryption client v4 in Java."; - System.out.println("Original data: " + testData); - System.out.println("Data length: " + testData.length() + " bytes"); - System.out.println(); - - try { - System.out.println("--- Initialize S3 Encryption Client v4 ---"); - - // Create standard S3 client - S3Client s3Client = S3Client.builder() - .region(Region.of(region)) - .credentialsProvider(DefaultCredentialsProvider.create()) - .build(); - - // Create KMS client - KmsClient kmsClient = KmsClient.builder() - .region(Region.of(region)) - .credentialsProvider(DefaultCredentialsProvider.create()) - .build(); - - // Create KMS keyring - KmsKeyring keyring = KmsKeyring.builder() - .kmsClient(kmsClient) - .wrappingKeyId(kmsKeyId) - .build(); - - // Create Cryptographic Materials Manager - CryptographicMaterialsManager cmm = DefaultCryptoMaterialsManager.builder() - .keyring(keyring) - .build(); - - // Create S3 Encryption Client v4 with key commitment enabled (Defaults to REQUIRE_ENCRYPT_REQUIRE_DECRYPT) - S3EncryptionClient encryptionClient = S3EncryptionClient.builderV4() - .wrappedClient(s3Client) - .cryptoMaterialsManager(cmm) - .enableLegacyUnauthenticatedModes(false) - .enableLegacyWrappingAlgorithms(false) - .build(); - - System.out.println("Successfully initialized S3 Encryption Client v4"); - System.out.println("Key commitment: ENABLED"); - System.out.println("--- Encrypt and Upload Object to S3 ---"); - - // Add encryption context - Map encryptionContext = new HashMap<>(); - encryptionContext.put("purpose", "example"); - encryptionContext.put("version", "v4"); - encryptionContext.put("language", "java"); - - // Upload encrypted object using S3 Encryption Client - PutObjectRequest putRequest = PutObjectRequest.builder() - .bucket(bucketName) - .key(objectKey) - .build(); - - encryptionClient.putObject(putRequest, RequestBody.fromString(testData)); - - System.out.println("Successfully uploaded encrypted object to S3!"); - System.out.println(" Bucket: " + bucketName); - System.out.println(" Key: " + objectKey); - System.out.println(" Encryption Context: " + encryptionContext); - System.out.println(" Key Commitment: ENABLED"); - System.out.println(); - - System.out.println("--- Download and Decrypt Object from S3 ---"); - - // Download and decrypt object using S3 Encryption Client - GetObjectRequest getRequest = GetObjectRequest.builder() - .bucket(bucketName) - .key(objectKey) - .build(); - - String decryptedData = encryptionClient.getObjectAsBytes(getRequest) - .asString(StandardCharsets.UTF_8); - - System.out.println("Successfully downloaded and decrypted object from S3!"); - System.out.println(" Object size: " + decryptedData.length() + " bytes"); - System.out.println(" Decrypted data: " + decryptedData); - System.out.println(); - - System.out.println("--- Verify Roundtrip Success ---"); - - // Verify the roundtrip was successful - if (decryptedData.equals(testData)) { - System.out.println("SUCCESS: Roundtrip encryption/decryption completed successfully!"); - System.out.println(" Original data matches decrypted data"); - System.out.println(" Data integrity verified"); - System.out.println(" Key commitment verified"); - } else { - System.out.println("ERROR: Roundtrip failed - data mismatch"); - System.out.println(" Original: " + testData); - System.out.println(" Decrypted: " + decryptedData); - System.exit(1); - } - - System.out.println(); - System.out.println("=== Example completed successfully! ==="); - - // Clean up clients - encryptionClient.close(); - s3Client.close(); - kmsClient.close(); - - } catch (Exception e) { - System.err.println("Error: " + e.getMessage()); - e.printStackTrace(); - System.exit(1); - } - } -} diff --git a/all-examples/net/.gitignore b/all-examples/net/.gitignore deleted file mode 100644 index c6a52ab1..00000000 --- a/all-examples/net/.gitignore +++ /dev/null @@ -1,19 +0,0 @@ -# Build results -bin/ -obj/ - -# User-specific files -*.user -*.suo -*.userosscache -*.sln.docstates - -# Visual Studio -.vs/ - -# Rider -.idea/ - -# NuGet packages -packages/ -*.nupkg diff --git a/all-examples/net/v3/Makefile b/all-examples/net/v3/Makefile deleted file mode 100644 index c375acc7..00000000 --- a/all-examples/net/v3/Makefile +++ /dev/null @@ -1,66 +0,0 @@ -# Makefile for S3 Encryption Client .NET v3 Example - -# Default target -.PHONY: all install clean run help - -# Default arguments for running the example -# Override these when calling make run -BUCKET_NAME ?= avp-21638 -OBJECT_KEY ?= s3ec-dotnet-v3 -KMS_KEY_ID ?= arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 -AWS_REGION ?= us-east-2 - -all: install - -# Install dependencies using .NET modules -install: - @echo "[NET V3] Installing .NET dependencies..." - dotnet restore - @echo "[NET V3] Dependencies installed successfully!" - -# Clean .NET artifacts -clean: - @echo "[NET V3] Cleaning .NET artifacts..." - dotnet clean - @echo "[NET V3] Clean completed!" - -# Run the example with default arguments -run: install - @echo "[NET V3] Running S3 Encryption Client v3 .NET example..." - @echo "[NET V3] Bucket: $(BUCKET_NAME)" - @echo "[NET V3] Object Key: $(OBJECT_KEY)" - @echo "[NET V3] KMS Key ID: $(KMS_KEY_ID)" - @echo "[NET V3] Region: $(AWS_REGION)" - @echo "" - @dotnet run -- $(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION) - -# Run with custom arguments -# Usage: make run-custom BUCKET_NAME=my-bucket OBJECT_KEY=my-key KMS_KEY_ID=my-kms-key AWS_REGION=my-region -run-custom: install - @dotnet run -- $(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION) - -# Show help -help: - @echo "S3 Encryption Client .NET v3 Example Makefile" - @echo "" - @echo "Available targets:" - @echo " install - Install .NET dependencies using .NET modules" - @echo " run - Install dependencies and run the example with default parameters" - @echo " run-custom - Install dependencies and run with custom parameters" - @echo " clean - Remove .NET artifacts" - @echo " help - Show this help message" - @echo "" - @echo "Default parameters:" - @echo " BUCKET_NAME = $(BUCKET_NAME)" - @echo " OBJECT_KEY = $(OBJECT_KEY)" - @echo " KMS_KEY_ID = $(KMS_KEY_ID)" - @echo " AWS_REGION = $(AWS_REGION)" - @echo "" - @echo "To run with custom parameters:" - @echo " make run BUCKET_NAME=your-bucket OBJECT_KEY=your-key KMS_KEY_ID=your-kms-key AWS_REGION=your-region" - @echo "" - @echo "Prerequisites:" - @echo " - Supported .NET framework installed on the system. See https://www.nuget.org/packages/Amazon.Extensions.S3.Encryption for supported one." - @echo " - AWS credentials configured (AWS CLI, environment variables, or IAM role)" - @echo " - Valid S3 bucket and KMS key with appropriate permissions" - @echo " - S3 Encryption Client v3 .NET SDK (included in s3ec-v3-local)" \ No newline at end of file diff --git a/all-examples/net/v3/Program.cs b/all-examples/net/v3/Program.cs deleted file mode 100644 index 6c1336f6..00000000 --- a/all-examples/net/v3/Program.cs +++ /dev/null @@ -1,76 +0,0 @@ -using Amazon; -using Amazon.Extensions.S3.Encryption; -using Amazon.Extensions.S3.Encryption.Primitives; -using Amazon.S3; -using Amazon.S3.Model; - -using Amazon.Extensions.S3.Encryption; -using Amazon.Extensions.S3.Encryption.Primitives; -using Amazon.S3; -using Amazon.S3.Model; - -namespace S3EncryptionClientV3Example -{ - class Program - { - static async Task Main(string[] args) - { - if (args.Length != 4) - { - Console.WriteLine("[NET V3] Usage: dotnet run "); - Environment.Exit(1); - } - - var (bucketName, objectKey, kmsKeyId, region) = (args[0], args[1], args[2], args[3]); - var testData = "Hello, World! This is a test message for S3 encryption client v3 in .NET."; - - Console.WriteLine("=== S3 Encryption Client v3 Example (.NET) ==="); - - try - { - var s3Client = CreateS3ECWithKms(kmsKeyId, region); - - await s3Client.PutObjectAsync(new PutObjectRequest - { - BucketName = bucketName, - Key = objectKey, - ContentBody = testData - }); - - var getResponse = await s3Client.GetObjectAsync(bucketName, objectKey); - using var reader = new StreamReader(getResponse.ResponseStream); - var decryptedData = await reader.ReadToEndAsync(); - - if (decryptedData != testData) - { - Console.WriteLine("[NET V3] ERROR: Roundtrip failed - data mismatch"); - Environment.Exit(1); - } - - Console.WriteLine("[NET V3] SUCCESS: Roundtrip encryption/decryption completed successfully!"); - } - catch (Exception ex) - { - Console.WriteLine($"[NET V3] Error: {ex.Message}"); - Environment.Exit(1); - } - } - - private static AmazonS3Client CreateS3ECWithKms(string kmsKeyId, string region) - { - var encryptionContextPerClient = new Dictionary - { - ["purpose"] = "example", - ["version"] = "v3", - ["language"] = "dotnet" - }; - - var encryptionMaterial = new EncryptionMaterialsV2(kmsKeyId, KmsType.KmsContext, encryptionContextPerClient); - var configuration = new AmazonS3CryptoConfigurationV2(SecurityProfile.V2, CommitmentPolicy.ForbidEncryptAllowDecrypt, ContentEncryptionAlgorithm.AesGcm) - { - RegionEndpoint = RegionEndpoint.GetBySystemName(region) - }; - return new AmazonS3EncryptionClientV2(configuration, encryptionMaterial); - } - } -} diff --git a/all-examples/net/v3/s3ec-v3-local b/all-examples/net/v3/s3ec-v3-local deleted file mode 120000 index a2d8df44..00000000 --- a/all-examples/net/v3/s3ec-v3-local +++ /dev/null @@ -1 +0,0 @@ -../../../test-server/net-v3-transition-server/s3ec-v3-transition-branch \ No newline at end of file diff --git a/all-examples/net/v3/v3.csproj b/all-examples/net/v3/v3.csproj deleted file mode 100644 index cfb74fad..00000000 --- a/all-examples/net/v3/v3.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - Exe - net8.0 - enable - enable - false - - - - - - - - - - - diff --git a/all-examples/net/v4/Makefile b/all-examples/net/v4/Makefile deleted file mode 100644 index f45fbdfd..00000000 --- a/all-examples/net/v4/Makefile +++ /dev/null @@ -1,66 +0,0 @@ -# Makefile for S3 Encryption Client .NET v4 Example - -# Default target -.PHONY: all install clean run help - -# Default arguments for running the example -# Override these when calling make run -BUCKET_NAME ?= avp-21638 -OBJECT_KEY ?= s3ec-dotnet-v4 -KMS_KEY_ID ?= arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 -AWS_REGION ?= us-east-2 - -all: install - -# Install dependencies using .NET modules -install: - @echo "[NET V4] Installing .NET dependencies..." - dotnet restore - @echo "[NET V4] Dependencies installed successfully!" - -# Clean .NET artifacts -clean: - @echo "[NET V4] Cleaning .NET artifacts..." - dotnet clean - @echo "[NET V4] Clean completed!" - -# Run the example with default arguments -run: install - @echo "[NET V4] Running S3 Encryption Client v4 .NET example..." - @echo "[NET V4] Bucket: $(BUCKET_NAME)" - @echo "[NET V4] Object Key: $(OBJECT_KEY)" - @echo "[NET V4] KMS Key ID: $(KMS_KEY_ID)" - @echo "[NET V4] Region: $(AWS_REGION)" - @echo "" - @dotnet run -- $(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION) - -# Run with custom arguments -# Usage: make run-custom BUCKET_NAME=my-bucket OBJECT_KEY=my-key KMS_KEY_ID=my-kms-key AWS_REGION=my-region -run-custom: install - @dotnet run -- $(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION) - -# Show help -help: - @echo "S3 Encryption Client .NET v4 Example Makefile" - @echo "" - @echo "Available targets:" - @echo " install - Install .NET dependencies using .NET modules" - @echo " run - Install dependencies and run the example with default parameters" - @echo " run-custom - Install dependencies and run with custom parameters" - @echo " clean - Remove .NET artifacts" - @echo " help - Show this help message" - @echo "" - @echo "Default parameters:" - @echo " BUCKET_NAME = $(BUCKET_NAME)" - @echo " OBJECT_KEY = $(OBJECT_KEY)" - @echo " KMS_KEY_ID = $(KMS_KEY_ID)" - @echo " AWS_REGION = $(AWS_REGION)" - @echo "" - @echo "To run with custom parameters:" - @echo " make run BUCKET_NAME=your-bucket OBJECT_KEY=your-key KMS_KEY_ID=your-kms-key AWS_REGION=your-region" - @echo "" - @echo "Prerequisites:" - @echo " - Supported .NET framework installed on the system. See https://www.nuget.org/packages/Amazon.Extensions.S3.Encryption for supported one." - @echo " - AWS credentials configured (AWS CLI, environment variables, or IAM role)" - @echo " - Valid S3 bucket and KMS key with appropriate permissions" - @echo " - S3 Encryption Client v4 .NET SDK (included in s3ec-v4-local)" \ No newline at end of file diff --git a/all-examples/net/v4/Program.cs b/all-examples/net/v4/Program.cs deleted file mode 100644 index a8c799a6..00000000 --- a/all-examples/net/v4/Program.cs +++ /dev/null @@ -1,76 +0,0 @@ -using Amazon; -using Amazon.Extensions.S3.Encryption; -using Amazon.Extensions.S3.Encryption.Primitives; -using Amazon.S3; -using Amazon.S3.Model; - -using Amazon.Extensions.S3.Encryption; -using Amazon.Extensions.S3.Encryption.Primitives; -using Amazon.S3; -using Amazon.S3.Model; - -namespace S3EncryptionClientV4Example -{ - class Program - { - static async Task Main(string[] args) - { - if (args.Length != 4) - { - Console.WriteLine("[NET V4] Usage: dotnet run "); - Environment.Exit(1); - } - - var (bucketName, objectKey, kmsKeyId, region) = (args[0], args[1], args[2], args[3]); - var testData = "Hello, World! This is a test message for S3 encryption client v4 in .NET."; - - Console.WriteLine("=== S3 Encryption Client v4 Example (.NET) ==="); - - try - { - var s3Client = CreateS3ECWithKms(kmsKeyId, region); - - await s3Client.PutObjectAsync(new PutObjectRequest - { - BucketName = bucketName, - Key = objectKey, - ContentBody = testData - }); - - var getResponse = await s3Client.GetObjectAsync(bucketName, objectKey); - using var reader = new StreamReader(getResponse.ResponseStream); - var decryptedData = await reader.ReadToEndAsync(); - - if (decryptedData != testData) - { - Console.WriteLine("[NET V4] ERROR: Roundtrip failed - data mismatch"); - Environment.Exit(1); - } - - Console.WriteLine("[NET V4] SUCCESS: Roundtrip encryption/decryption completed successfully!"); - } - catch (Exception ex) - { - Console.WriteLine($"[NET V4] Error: {ex.Message}"); - Environment.Exit(1); - } - } - - private static AmazonS3Client CreateS3ECWithKms(string kmsKeyId, string region) - { - var encryptionContextPerClient = new Dictionary - { - ["purpose"] = "example", - ["version"] = "v4", - ["language"] = "dotnet" - }; - - var encryptionMaterial = new EncryptionMaterialsV4(kmsKeyId, KmsType.KmsContext, encryptionContextPerClient); - var configuration = new AmazonS3CryptoConfigurationV4(SecurityProfile.V4, CommitmentPolicy.RequireEncryptRequireDecrypt, ContentEncryptionAlgorithm.AesGcmWithCommitment) - { - RegionEndpoint = RegionEndpoint.GetBySystemName(region) - }; - return new AmazonS3EncryptionClientV4(configuration, encryptionMaterial); - } - } -} diff --git a/all-examples/net/v4/s3ec-v4-local b/all-examples/net/v4/s3ec-v4-local deleted file mode 120000 index 371b1a90..00000000 --- a/all-examples/net/v4/s3ec-v4-local +++ /dev/null @@ -1 +0,0 @@ -../../../test-server/net-v4-server/s3ec-net-v4-improved \ No newline at end of file diff --git a/all-examples/net/v4/v4.csproj b/all-examples/net/v4/v4.csproj deleted file mode 100644 index 6d223a92..00000000 --- a/all-examples/net/v4/v4.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - Exe - net8.0 - enable - enable - false - - - - - - - - - - - diff --git a/all-examples/php/v2/.gitignore b/all-examples/php/v2/.gitignore deleted file mode 100644 index 07108589..00000000 --- a/all-examples/php/v2/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -vendor/* -cookies.txt -server.pid -composer.lock \ No newline at end of file diff --git a/all-examples/php/v2/Makefile b/all-examples/php/v2/Makefile deleted file mode 100644 index 0747d7b8..00000000 --- a/all-examples/php/v2/Makefile +++ /dev/null @@ -1,71 +0,0 @@ -# Makefile for S3 Encryption Client PHP v2 Example - -# Default target -.PHONY: all install clean run help - -# Variables -SCRIPT = main.php - -# Default arguments for running the example -# Override these when calling make run -BUCKET_NAME ?= avp-21638 -OBJECT_KEY ?= s3ec-php-v2 -KMS_KEY_ID ?= arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 -AWS_REGION ?= us-east-2 - -all: install - -# Install dependencies using Composer -install: - @echo "Installing PHP dependencies..." - @composer install --no-dev --optimize-autoloader - @echo "Dependencies installed successfully!" - -# Clean composer artifacts -clean: - @echo "Cleaning composer artifacts..." - @rm -rf vendor/ - @rm -f composer.lock - @echo "Clean completed!" - -# Run the example with default arguments -run: install - @echo "Running S3 Encryption Client v2 PHP example..." - @echo "Bucket: $(BUCKET_NAME)" - @echo "Object Key: $(OBJECT_KEY)" - @echo "KMS Key ID: $(KMS_KEY_ID)" - @echo "Region: $(AWS_REGION)" - @echo "" - @php $(SCRIPT) $(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION) - -# Run with custom arguments -# Usage: make run-custom BUCKET_NAME=my-bucket OBJECT_KEY=my-key KMS_KEY_ID=my-kms-key AWS_REGION=my-region -run-custom: install - @php $(SCRIPT) $(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION) - -# Show help -help: - @echo "S3 Encryption Client PHP v2 Example Makefile" - @echo "" - @echo "Available targets:" - @echo " install - Install PHP dependencies using Composer" - @echo " run - Install dependencies and run the example with default parameters" - @echo " run-custom - Install dependencies and run with custom parameters" - @echo " clean - Remove composer artifacts (vendor/, composer.lock)" - @echo " help - Show this help message" - @echo "" - @echo "Default parameters:" - @echo " BUCKET_NAME = $(BUCKET_NAME)" - @echo " OBJECT_KEY = $(OBJECT_KEY)" - @echo " KMS_KEY_ID = $(KMS_KEY_ID)" - @echo " AWS_REGION = $(AWS_REGION)" - @echo "" - @echo "To run with custom parameters:" - @echo " make run BUCKET_NAME=your-bucket OBJECT_KEY=your-key KMS_KEY_ID=your-kms-key AWS_REGION=your-region" - @echo "" - @echo "Prerequisites:" - @echo " - PHP 7.4+ installed on the system" - @echo " - Composer installed (https://getcomposer.org/)" - @echo " - AWS credentials configured (AWS CLI, environment variables, or IAM role)" - @echo " - Valid S3 bucket and KMS key with appropriate permissions" - @echo " - S3 Encryption Client v2 PHP SDK (included in local-php-sdk)" diff --git a/all-examples/php/v2/composer.json b/all-examples/php/v2/composer.json deleted file mode 100644 index 914bf900..00000000 --- a/all-examples/php/v2/composer.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "aws/s3ec-php-v2-example", - "description": "PHP v2 example for Amazon S3 Encryption Client", - "type": "project", - "license": "Apache-2.0", - "repositories": [ - { - "type": "path", - "url": "./local-php-sdk", - "options": { - "symlink": true - } - } - ], - "require": { - "php": ">=7.4", - "aws/aws-sdk-php": "@dev", - "ramsey/uuid": "^4.9" - }, - "autoload": { - "psr-4": { - "AWS\\S3EC\\Example\\": "src/" - } - }, - "config": { - "optimize-autoloader": true, - "platform": { - "php": "8.1" - } - }, - "minimum-stability": "dev", - "prefer-stable": true -} diff --git a/all-examples/php/v2/local-php-sdk b/all-examples/php/v2/local-php-sdk deleted file mode 120000 index 04ad0cf7..00000000 --- a/all-examples/php/v2/local-php-sdk +++ /dev/null @@ -1 +0,0 @@ -../../../test-server/php-v2-transition-server/local-php-sdk \ No newline at end of file diff --git a/all-examples/php/v2/main.php b/all-examples/php/v2/main.php deleted file mode 100755 index df2fdd32..00000000 --- a/all-examples/php/v2/main.php +++ /dev/null @@ -1,161 +0,0 @@ -#!/usr/bin/env php - \n"; - echo "Example: {$GLOBALS['argv'][0]} avp-21638 s3ec-php-v2 arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 us-east-2\n"; - exit(1); - } - - $bucketName = $GLOBALS['argv'][1]; - $objectKey = $GLOBALS['argv'][2]; - $kmsKeyId = $GLOBALS['argv'][3]; - $region = $GLOBALS['argv'][4]; - - echo "=== S3 Encryption Client v2 Example (PHP) ===\n"; - echo "Bucket: {$bucketName}\n"; - echo "Object Key: {$objectKey}\n"; - echo "KMS Key ID: {$kmsKeyId}\n"; - echo "Region: {$region}\n"; - echo "\n"; - - try { - // Test data for encryption - $testData = "Hello, World! This is a test message for S3 encryption client v2 in PHP."; - echo "Original data: {$testData}\n"; - echo "Data length: " . strlen($testData) . " bytes\n"; - echo "\n"; - - echo "--- Initialize S3 Encryption Client v2 ---\n"; - - // Create regular S3 client - $s3Client = new S3Client([ - 'region' => $region, - 'version' => 'latest' - ]); - - // Create KMS client - $kmsClient = new KmsClient([ - 'region' => $region, - 'version' => 'latest' - ]); - - // Create S3 Encryption Client v2 - $encryptionClient = new S3EncryptionClientV2($s3Client); - $materialsProvider = new KmsMaterialsProviderV2($kmsClient, $kmsKeyId); - - echo "Successfully initialized S3 Encryption Client v2\n"; - echo "--- Encrypt and Upload Object to S3 ---\n"; - - // Add encryption context - $encryptionContext = [ - 'purpose' => 'example', - 'version' => 'v2', - 'language' => 'php' - ]; - - $cipherOptions = [ - 'Cipher' => 'gcm', - 'KeySize' => 256, - ]; - - // Upload encrypted object using S3 Encryption Client - $putResponse = $encryptionClient->putObject([ - 'Bucket' => $bucketName, - 'Key' => $objectKey, - 'Body' => $testData, - '@MaterialsProvider' => $materialsProvider, - '@KmsEncryptionContext' => $encryptionContext, - '@CipherOptions' => $cipherOptions, - ]); - - echo "Successfully uploaded encrypted object to S3!\n"; - echo " Bucket: {$bucketName}\n"; - echo " Key: {$objectKey}\n"; - echo " Encryption Context: " . json_encode($encryptionContext) . "\n"; - echo "\n"; - - echo "--- Download and Decrypt Object from S3 ---\n"; - - // Download and decrypt object using S3 Encryption Client - $getResponse = $encryptionClient->getObject([ - 'Bucket' => $bucketName, - 'Key' => $objectKey, - '@KmsEncryptionContext' => $encryptionContext, - '@MaterialsProvider' => $materialsProvider, - '@CommitmentPolicy' => 'FORBID_ENCRYPT_ALLOW_DECRYPT', - '@SecurityProfile' => 'V2' - ]); - - // Read the decrypted data - $decryptedData = (string) $getResponse['Body']; - - echo "Successfully downloaded and decrypted object from S3!\n"; - echo " Object size: " . strlen($decryptedData) . " bytes\n"; - echo " Decrypted data: {$decryptedData}\n"; - echo "\n"; - - echo "--- Verify Roundtrip Success ---\n"; - - // Verify the roundtrip was successful - if ($decryptedData === $testData) { - echo "SUCCESS: Roundtrip encryption/decryption completed successfully!\n"; - echo " Original data matches decrypted data\n"; - echo " Data integrity verified\n"; - } else { - echo "ERROR: Roundtrip failed - data mismatch\n"; - echo " Original: {$testData}\n"; - echo " Decrypted: {$decryptedData}\n"; - exit(1); - } - - // Optionally Delete the Object - // echo "--- Cleanup ---\n"; - // Clean up the test object using regular S3 client - // $s3Client->deleteObject([ - // 'Bucket' => $bucketName, - // 'Key' => $objectKey - // ]); - // echo "Test object deleted from S3\n"; - - echo "\n"; - echo "=== Example completed successfully! ===\n"; - - } catch (AwsException $e) { - $errorCode = $e->getAwsErrorCode(); - $errorMessage = $e->getMessage(); - - if (strpos($errorCode, 'NoSuchBucket') !== false) { - echo "Error: S3 bucket '{$bucketName}' does not exist or is not accessible\n"; - echo " {$errorMessage}\n"; - } elseif (strpos($errorCode, 'NotFoundException') !== false) { - echo "Error: KMS key '{$kmsKeyId}' not found or not accessible\n"; - echo " {$errorMessage}\n"; - } elseif (strpos($errorMessage, 'encryption') !== false) { - echo "S3 Encryption Error: {$errorMessage}\n"; - } else { - echo "AWS Service Error: {$errorMessage}\n"; - echo " Error Code: {$errorCode}\n"; - } - exit(1); - } catch (Exception $e) { - echo "Unexpected error: {$e->getMessage()}\n"; - echo " File: {$e->getFile()}:{$e->getLine()}\n"; - exit(1); - } -} - -// Run the main function if this script is executed directly -if (php_sapi_name() === 'cli' && isset($GLOBALS['argv']) && basename($GLOBALS['argv'][0]) === basename(__FILE__)) { - main(); -} diff --git a/all-examples/php/v3/.gitignore b/all-examples/php/v3/.gitignore deleted file mode 100644 index 07108589..00000000 --- a/all-examples/php/v3/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -vendor/* -cookies.txt -server.pid -composer.lock \ No newline at end of file diff --git a/all-examples/php/v3/Makefile b/all-examples/php/v3/Makefile deleted file mode 100644 index 328a901a..00000000 --- a/all-examples/php/v3/Makefile +++ /dev/null @@ -1,71 +0,0 @@ -# Makefile for S3 Encryption Client PHP v3 Example - -# Default target -.PHONY: all install clean run help - -# Variables -SCRIPT = main.php - -# Default arguments for running the example -# Override these when calling make run -BUCKET_NAME ?= avp-21638 -OBJECT_KEY ?= s3ec-php-v3 -KMS_KEY_ID ?= arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 -AWS_REGION ?= us-east-2 - -all: install - -# Install dependencies using Composer -install: - @echo "Installing PHP dependencies..." - @composer install --no-dev --optimize-autoloader - @echo "Dependencies installed successfully!" - -# Clean composer artifacts -clean: - @echo "Cleaning composer artifacts..." - @rm -rf vendor/ - @rm -f composer.lock - @echo "Clean completed!" - -# Run the example with default arguments -run: install - @echo "Running S3 Encryption Client v3 PHP example..." - @echo "Bucket: $(BUCKET_NAME)" - @echo "Object Key: $(OBJECT_KEY)" - @echo "KMS Key ID: $(KMS_KEY_ID)" - @echo "Region: $(AWS_REGION)" - @echo "" - @php $(SCRIPT) $(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION) - -# Run with custom arguments -# Usage: make run-custom BUCKET_NAME=my-bucket OBJECT_KEY=my-key KMS_KEY_ID=my-kms-key AWS_REGION=my-region -run-custom: install - @php $(SCRIPT) $(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION) - -# Show help -help: - @echo "S3 Encryption Client PHP v3 Example Makefile" - @echo "" - @echo "Available targets:" - @echo " install - Install PHP dependencies using Composer" - @echo " run - Install dependencies and run the example with default parameters" - @echo " run-custom - Install dependencies and run with custom parameters" - @echo " clean - Remove composer artifacts (vendor/, composer.lock)" - @echo " help - Show this help message" - @echo "" - @echo "Default parameters:" - @echo " BUCKET_NAME = $(BUCKET_NAME)" - @echo " OBJECT_KEY = $(OBJECT_KEY)" - @echo " KMS_KEY_ID = $(KMS_KEY_ID)" - @echo " AWS_REGION = $(AWS_REGION)" - @echo "" - @echo "To run with custom parameters:" - @echo " make run BUCKET_NAME=your-bucket OBJECT_KEY=your-key KMS_KEY_ID=your-kms-key AWS_REGION=your-region" - @echo "" - @echo "Prerequisites:" - @echo " - PHP 7.4+ installed on the system" - @echo " - Composer installed (https://getcomposer.org/)" - @echo " - AWS credentials configured (AWS CLI, environment variables, or IAM role)" - @echo " - Valid S3 bucket and KMS key with appropriate permissions" - @echo " - S3 Encryption Client v3 PHP SDK (included in local-php-sdk)" diff --git a/all-examples/php/v3/composer.json b/all-examples/php/v3/composer.json deleted file mode 100644 index 2ad2469a..00000000 --- a/all-examples/php/v3/composer.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "aws/s3ec-php-v3-example", - "description": "PHP v3 example for Amazon S3 Encryption Client", - "type": "project", - "license": "Apache-2.0", - "repositories": [ - { - "type": "path", - "url": "./local-php-sdk", - "options": { - "symlink": true - } - } - ], - "require": { - "php": ">=7.4", - "aws/aws-sdk-php": "@dev", - "ramsey/uuid": "^4.9" - }, - "autoload": { - "psr-4": { - "AWS\\S3EC\\Example\\": "src/" - } - }, - "config": { - "optimize-autoloader": true, - "platform": { - "php": "8.1" - } - }, - "minimum-stability": "dev", - "prefer-stable": true -} diff --git a/all-examples/php/v3/local-php-sdk b/all-examples/php/v3/local-php-sdk deleted file mode 120000 index 3b9b4cd7..00000000 --- a/all-examples/php/v3/local-php-sdk +++ /dev/null @@ -1 +0,0 @@ -../../../test-server/php-v3-server/local-php-sdk \ No newline at end of file diff --git a/all-examples/php/v3/main.php b/all-examples/php/v3/main.php deleted file mode 100755 index 949a0ce1..00000000 --- a/all-examples/php/v3/main.php +++ /dev/null @@ -1,508 +0,0 @@ -#!/usr/bin/env php - \n"; - echo "Example: {$GLOBALS['argv'][0]} avp-21638 s3ec-php-v3 arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 us-east-2\n"; - exit(1); - } - - $bucketName = $GLOBALS['argv'][1]; - $objectKey = $GLOBALS['argv'][2]; - $kmsKeyId = $GLOBALS['argv'][3]; - $region = $GLOBALS['argv'][4]; - - echo "=== S3 Encryption Client v3 Example (PHP) ===\n"; - echo "Bucket: {$bucketName}\n"; - echo "Object Key: {$objectKey}\n"; - echo "KMS Key ID: {$kmsKeyId}\n"; - echo "Region: {$region}\n"; - echo "\n"; - - try { - // Test data for encryption - $testData = "Hello, World! This is a test message for S3 encryption client v3 in PHP."; - echo "Original data: {$testData}\n"; - echo "Data length: " . strlen($testData) . " bytes\n"; - echo "\n"; - - echo "--- Initialize S3 Encryption Client v3 ---\n"; - - // Create regular S3 client - $s3Client = new S3Client([ - 'region' => $region, - 'version' => 'latest' - ]); - - // Create KMS client - $kmsClient = new KmsClient([ - 'region' => $region, - 'version' => 'latest' - ]); - - // Create S3 Encryption Client v3 - // Create S3 Encryption Client v2 - $encryptionClient = new S3EncryptionClientV3($s3Client); - $materialsProvider = new KmsMaterialsProviderV3($kmsClient, $kmsKeyId); - - echo "Successfully initialized S3 Encryption Client v3\n"; - echo "--- Encrypt and Upload Object to S3 ---\n"; - - // Add encryption context - $encryptionContext = [ - 'purpose' => 'example', - 'version' => 'v3', - 'language' => 'php' - ]; - - $cipherOptions = [ - 'Cipher' => 'gcm', - 'KeySize' => 256, - ]; - - // Upload encrypted object using S3 Encryption Client - $putResponse = $encryptionClient->putObject([ - 'Bucket' => $bucketName, - 'Key' => $objectKey, - 'Body' => $testData, - '@MaterialsProvider' => $materialsProvider, - '@KmsEncryptionContext' => $encryptionContext, - '@CommitmentPolicy' => "REQUIRE_ENCRYPT_REQUIRE_DECRYPT", - '@CipherOptions' => $cipherOptions, - ]); - - echo "Successfully uploaded encrypted object to S3!\n"; - echo " Bucket: {$bucketName}\n"; - echo " Key: {$objectKey}\n"; - echo " Encryption Context: " . json_encode($encryptionContext) . "\n"; - echo "\n"; - - echo "--- Download and Decrypt Object from S3 ---\n"; - - // Download and decrypt object using S3 Encryption Client - $getResponse = $encryptionClient->getObject([ - 'Bucket' => $bucketName, - 'Key' => $objectKey, - '@KmsEncryptionContext' => $encryptionContext, - '@MaterialsProvider' => $materialsProvider, - '@CommitmentPolicy' => "REQUIRE_ENCRYPT_REQUIRE_DECRYPT", - '@SecurityProfile' => 'V3' - ]); - - // Read the decrypted data - $decryptedData = (string) $getResponse['Body']; - - echo "Successfully downloaded and decrypted object from S3!\n"; - echo " Object size: " . strlen($decryptedData) . " bytes\n"; - echo " Decrypted data: {$decryptedData}\n"; - echo "\n"; - - echo "--- Verify Roundtrip Success ---\n"; - - // Verify the roundtrip was successful - if ($decryptedData === $testData) { - echo "SUCCESS: Roundtrip encryption/decryption completed successfully!\n"; - echo " Original data matches decrypted data\n"; - echo " Data integrity verified\n"; - } else { - echo "ERROR: Roundtrip failed - data mismatch\n"; - echo " Original: {$testData}\n"; - echo " Decrypted: {$decryptedData}\n"; - exit(1); - } - - // Optionally Delete the Object - // echo "--- Cleanup ---\n"; - // Clean up the test object using regular S3 client - // $s3Client->deleteObject([ - // 'Bucket' => $bucketName, - // 'Key' => $objectKey - // ]); - // echo "Test object deleted from S3\n"; - - echo "\n"; - echo "=== Example completed successfully! ===\n"; - - } catch (AwsException $e) { - $errorCode = $e->getAwsErrorCode(); - $errorMessage = $e->getMessage(); - - if (strpos($errorCode, 'NoSuchBucket') !== false) { - echo "Error: S3 bucket '{$bucketName}' does not exist or is not accessible\n"; - echo " {$errorMessage}\n"; - } elseif (strpos($errorCode, 'NotFoundException') !== false) { - echo "Error: KMS key '{$kmsKeyId}' not found or not accessible\n"; - echo " {$errorMessage}\n"; - } elseif (strpos($errorMessage, 'encryption') !== false) { - echo "S3 Encryption Error: {$errorMessage}\n"; - } else { - echo "AWS Service Error: {$errorMessage}\n"; - echo " Error Code: {$errorCode}\n"; - } - exit(1); - } catch (Exception $e) { - echo "Unexpected error: {$e->getMessage()}\n"; - echo " File: {$e->getFile()}:{$e->getLine()}\n"; - exit(1); - } -} - -function testMigration(): void { - if (count($GLOBALS['argv']) !== 5) { - echo "Usage: {$GLOBALS['argv'][0]} \n"; - echo "Example: {$GLOBALS['argv'][0]} avp-21638 s3ec-php-v3 arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 us-east-2\n"; - exit(1); - } - - $bucketName = $GLOBALS['argv'][1]; - $objectKey = $GLOBALS['argv'][2]; - $kmsKeyId = $GLOBALS['argv'][3]; - $region = $GLOBALS['argv'][4]; - - echo "=== S3 Encryption Client Pre-migration (V2) Example ===\n"; - echo "Bucket: {$bucketName}\n"; - echo "Object Key: {$objectKey}\n"; - echo "KMS Key ID: {$kmsKeyId}\n"; - echo "Region: {$region}\n"; - echo "\n"; - - try { - $testData = "Hello, World! This is a test message for S3 encryption client Pre-migration (V2) in PHP."; - echo "Original data: {$testData}\n"; - echo "Data length: " . strlen($testData) . " bytes\n"; - echo "\n"; - - $v2EncryptionClient = new S3EncryptionClientV2( - new S3Client([ - 'region' => $region, - 'version' => 'latest', - ]) - ); - - $materialsProviderV2 = new KmsMaterialsProviderV2( - new KmsClient([ - 'region' => $region, - 'version' => 'latest', - ]), - $kmsKeyId - ); - - $cipherOptions = [ - 'Cipher' => 'gcm', - 'KeySize' => 256, - ]; - - $v2EncryptionClient->putObject([ - '@MaterialsProvider' => $materialsProviderV2, - '@CipherOptions' => $cipherOptions, - '@KmsEncryptionContext' => ['context-key' => 'context-value'], - 'Bucket' => $bucketName, - 'Key' => $objectKey, - 'Body' => $testData, - ]); - - $getResponse = $v2EncryptionClient->getObject([ - '@KmsAllowDecryptWithAnyCmk' => true, - '@SecurityProfile' => 'V2_AND_LEGACY', - '@CommitmentPolicy' => 'FORBID_ENCRYPT_ALLOW_DECRYPT', - '@MaterialsProvider' => $materialsProviderV2, - '@CipherOptions' => $cipherOptions, - 'Bucket' => $bucketName, - 'Key' => $objectKey, - ]); - - // Read the decrypted data - $decryptedData = (string) $getResponse['Body']; - - echo "Successfully downloaded and decrypted object from S3!\n"; - echo " Object size: " . strlen($decryptedData) . " bytes\n"; - echo " Decrypted data: {$decryptedData}\n"; - echo "\n"; - - echo "--- Verify Roundtrip Success ---\n"; - - // Verify the roundtrip was successful - if ($decryptedData === $testData) { - echo "SUCCESS: Roundtrip encryption/decryption completed successfully!\n"; - echo " Original data matches decrypted data\n"; - echo " Data integrity verified\n"; - } else { - echo "ERROR: Roundtrip failed - data mismatch\n"; - echo " Original: {$testData}\n"; - echo " Decrypted: {$decryptedData}\n"; - exit(1); - } - - // Optionally Delete the Object - // echo "--- Cleanup ---\n"; - // Clean up the test object using regular S3 client - // $s3Client->deleteObject([ - // 'Bucket' => $bucketName, - // 'Key' => $objectKey - // ]); - // echo "Test object deleted from S3\n"; - - echo "\n"; - echo "=== Example completed successfully! ===\n"; - - } catch (AwsException $e) { - $errorCode = $e->getAwsErrorCode(); - $errorMessage = $e->getMessage(); - - if (strpos($errorCode, 'NoSuchBucket') !== false) { - echo "Error: S3 bucket '{$bucketName}' does not exist or is not accessible\n"; - echo " {$errorMessage}\n"; - } elseif (strpos($errorCode, 'NotFoundException') !== false) { - echo "Error: KMS key '{$kmsKeyId}' not found or not accessible\n"; - echo " {$errorMessage}\n"; - } elseif (strpos($errorMessage, 'encryption') !== false) { - echo "S3 Encryption Error: {$errorMessage}\n"; - } else { - echo "AWS Service Error: {$errorMessage}\n"; - echo " Error Code: {$errorCode}\n"; - } - exit(1); - } catch (Exception $e) { - echo "Unexpected error: {$e->getMessage()}\n"; - echo " File: {$e->getFile()}:{$e->getLine()}\n"; - exit(1); - } - - echo "=== S3 Encryption Client during migration (V3 with backward compatibility) Example ===\n"; - echo "Bucket: {$bucketName}\n"; - echo "Object Key: {$objectKey}\n"; - echo "KMS Key ID: {$kmsKeyId}\n"; - echo "Region: {$region}\n"; - echo "\n"; - - try { - $testData = "Hello, World! This is a test message for S3 encryption client during migration (V3 with backward compatibility) in PHP."; - echo "Original data: {$testData}\n"; - echo "Data length: " . strlen($testData) . " bytes\n"; - echo "\n"; - - $v3EncryptionClient = new S3EncryptionClientV3( - new S3Client([ - 'region' => $region, - 'version' => 'latest', - ]) - ); - - $materialsProviderV3 = new KmsMaterialsProviderV3( - new KmsClient([ - 'region' => $region, - 'version' => 'latest', - ]), - $kmsKeyId - ); - - $cipherOptions = [ - 'Cipher' => 'gcm', - 'KeySize' => 256, - ]; - - $v3EncryptionClient->putObject([ - '@MaterialsProvider' => $materialsProviderV3, - '@CipherOptions' => $cipherOptions, - '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_ALLOW_DECRYPT', - '@KmsEncryptionContext' => ['context-key' => 'context-value'], - 'Bucket' => $bucketName, - 'Key' => $objectKey, - 'Body' => $testData, - ]); - - $getResponse = $v3EncryptionClient->getObject([ - '@KmsAllowDecryptWithAnyCmk' => true, - '@SecurityProfile' => 'V3_AND_LEGACY', - '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_ALLOW_DECRYPT', - '@MaterialsProvider' => $materialsProviderV3, - '@CipherOptions' => $cipherOptions, - 'Bucket' => $bucketName, - 'Key' => $objectKey, - ]); - - // Read the decrypted data - $decryptedData = (string) $getResponse['Body']; - - echo "Successfully downloaded and decrypted object from S3!\n"; - echo " Object size: " . strlen($decryptedData) . " bytes\n"; - echo " Decrypted data: {$decryptedData}\n"; - echo "\n"; - - echo "--- Verify Roundtrip Success ---\n"; - - // Verify the roundtrip was successful - if ($decryptedData === $testData) { - echo "SUCCESS: Roundtrip encryption/decryption completed successfully!\n"; - echo " Original data matches decrypted data\n"; - echo " Data integrity verified\n"; - } else { - echo "ERROR: Roundtrip failed - data mismatch\n"; - echo " Original: {$testData}\n"; - echo " Decrypted: {$decryptedData}\n"; - exit(1); - } - - // Optionally Delete the Object - // echo "--- Cleanup ---\n"; - // Clean up the test object using regular S3 client - // $s3Client->deleteObject([ - // 'Bucket' => $bucketName, - // 'Key' => $objectKey - // ]); - // echo "Test object deleted from S3\n"; - - echo "\n"; - echo "=== Example completed successfully! ===\n"; - - } catch (AwsException $e) { - $errorCode = $e->getAwsErrorCode(); - $errorMessage = $e->getMessage(); - - if (strpos($errorCode, 'NoSuchBucket') !== false) { - echo "Error: S3 bucket '{$bucketName}' does not exist or is not accessible\n"; - echo " {$errorMessage}\n"; - } elseif (strpos($errorCode, 'NotFoundException') !== false) { - echo "Error: KMS key '{$kmsKeyId}' not found or not accessible\n"; - echo " {$errorMessage}\n"; - } elseif (strpos($errorMessage, 'encryption') !== false) { - echo "S3 Encryption Error: {$errorMessage}\n"; - } else { - echo "AWS Service Error: {$errorMessage}\n"; - echo " Error Code: {$errorCode}\n"; - } - exit(1); - } catch (Exception $e) { - echo "Unexpected error: {$e->getMessage()}\n"; - echo " File: {$e->getFile()}:{$e->getLine()}\n"; - exit(1); - } - - echo "=== S3 Encryption Client post-migration (V3 with key commitment) Example ===\n"; - echo "Bucket: {$bucketName}\n"; - echo "Object Key: {$objectKey}\n"; - echo "KMS Key ID: {$kmsKeyId}\n"; - echo "Region: {$region}\n"; - echo "\n"; - - try { - $testData = "Hello, World! This is a test message for S3 encryption client post-migration (V3 with key commitment) in PHP."; - echo "Original data: {$testData}\n"; - echo "Data length: " . strlen($testData) . " bytes\n"; - echo "\n"; - - $v3EncryptionClient = new S3EncryptionClientV3( - new S3Client([ - 'region' => $region, - 'version' => 'latest', - ]) - ); - - $materialsProviderV3 = new KmsMaterialsProviderV3( - new KmsClient([ - 'region' => $region, - 'version' => 'latest', - ]), - $kmsKeyId - ); - - $cipherOptions = [ - 'Cipher' => 'gcm', - 'KeySize' => 256, - ]; - - $v3EncryptionClient->putObject([ - '@MaterialsProvider' => $materialsProviderV3, - '@CipherOptions' => $cipherOptions, - '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT', - '@KmsEncryptionContext' => ['context-key' => 'context-value'], - 'Bucket' => $bucketName, - 'Key' => $objectKey, - 'Body' => $testData, - ]); - - $getResponse = $v3EncryptionClient->getObject([ - '@KmsAllowDecryptWithAnyCmk' => true, - '@SecurityProfile' => 'V3', - '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT', - '@MaterialsProvider' => $materialsProviderV3, - '@CipherOptions' => $cipherOptions, - 'Bucket' => $bucketName, - 'Key' => $objectKey, - ]); - - // Read the decrypted data - $decryptedData = (string) $getResponse['Body']; - - echo "Successfully downloaded and decrypted object from S3!\n"; - echo " Object size: " . strlen($decryptedData) . " bytes\n"; - echo " Decrypted data: {$decryptedData}\n"; - echo "\n"; - - echo "--- Verify Roundtrip Success ---\n"; - - // Verify the roundtrip was successful - if ($decryptedData === $testData) { - echo "SUCCESS: Roundtrip encryption/decryption completed successfully!\n"; - echo " Original data matches decrypted data\n"; - echo " Data integrity verified\n"; - } else { - echo "ERROR: Roundtrip failed - data mismatch\n"; - echo " Original: {$testData}\n"; - echo " Decrypted: {$decryptedData}\n"; - exit(1); - } - - // Optionally Delete the Object - // echo "--- Cleanup ---\n"; - // Clean up the test object using regular S3 client - // $s3Client->deleteObject([ - // 'Bucket' => $bucketName, - // 'Key' => $objectKey - // ]); - // echo "Test object deleted from S3\n"; - - echo "\n"; - echo "=== Example completed successfully! ===\n"; - - } catch (AwsException $e) { - $errorCode = $e->getAwsErrorCode(); - $errorMessage = $e->getMessage(); - - if (strpos($errorCode, 'NoSuchBucket') !== false) { - echo "Error: S3 bucket '{$bucketName}' does not exist or is not accessible\n"; - echo " {$errorMessage}\n"; - } elseif (strpos($errorCode, 'NotFoundException') !== false) { - echo "Error: KMS key '{$kmsKeyId}' not found or not accessible\n"; - echo " {$errorMessage}\n"; - } elseif (strpos($errorMessage, 'encryption') !== false) { - echo "S3 Encryption Error: {$errorMessage}\n"; - } else { - echo "AWS Service Error: {$errorMessage}\n"; - echo " Error Code: {$errorCode}\n"; - } - exit(1); - } catch (Exception $e) { - echo "Unexpected error: {$e->getMessage()}\n"; - echo " File: {$e->getFile()}:{$e->getLine()}\n"; - exit(1); - } -} - -// Run the main function if this script is executed directly -if (php_sapi_name() === 'cli' && isset($GLOBALS['argv']) && basename($GLOBALS['argv'][0]) === basename(__FILE__)) { - main(); - testMigration(); -} diff --git a/all-examples/ruby/v2/Gemfile b/all-examples/ruby/v2/Gemfile deleted file mode 100644 index 5f51bf18..00000000 --- a/all-examples/ruby/v2/Gemfile +++ /dev/null @@ -1,12 +0,0 @@ -source 'https://rubygems.org' - -ruby '>= 2.7.0' - -gem 'aws-sdk-s3', path: 'local-ruby-sdk/gems/aws-sdk-s3' -gem 'aws-sdk-kms', path: 'local-ruby-sdk/gems/aws-sdk-kms' -gem 'json', '~> 2.0' -gem 'rexml', '~> 3.0' - -group :development do - gem 'rubocop', '~> 1.0' -end diff --git a/all-examples/ruby/v2/Gemfile.lock b/all-examples/ruby/v2/Gemfile.lock deleted file mode 100644 index 7c4a32c4..00000000 --- a/all-examples/ruby/v2/Gemfile.lock +++ /dev/null @@ -1,82 +0,0 @@ -PATH - remote: local-ruby-sdk/gems/aws-sdk-kms - specs: - aws-sdk-kms (1.115.0) - aws-sdk-core (~> 3, >= 3.234.0) - aws-sigv4 (~> 1.5) - -PATH - remote: local-ruby-sdk/gems/aws-sdk-s3 - specs: - aws-sdk-s3 (1.201.0) - aws-sdk-core (~> 3, >= 3.234.0) - aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.5) - -GEM - remote: https://rubygems.org/ - specs: - ast (2.4.3) - aws-eventstream (1.4.0) - aws-partitions (1.1177.0) - aws-sdk-core (3.235.0) - aws-eventstream (~> 1, >= 1.3.0) - aws-partitions (~> 1, >= 1.992.0) - aws-sigv4 (~> 1.9) - base64 - bigdecimal - jmespath (~> 1, >= 1.6.1) - logger - aws-sigv4 (1.12.1) - aws-eventstream (~> 1, >= 1.0.2) - base64 (0.3.0) - bigdecimal (3.3.1) - jmespath (1.6.2) - json (2.15.2) - language_server-protocol (3.17.0.5) - lint_roller (1.1.0) - logger (1.7.0) - parallel (1.27.0) - parser (3.3.10.0) - ast (~> 2.4.1) - racc - prism (1.6.0) - racc (1.8.1) - rainbow (3.1.1) - regexp_parser (2.11.3) - rexml (3.4.4) - rubocop (1.81.6) - json (~> 2.3) - language_server-protocol (~> 3.17.0.2) - lint_roller (~> 1.1.0) - parallel (~> 1.10) - parser (>= 3.3.0.2) - rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 2.9.3, < 3.0) - rubocop-ast (>= 1.47.1, < 2.0) - ruby-progressbar (~> 1.7) - unicode-display_width (>= 2.4.0, < 4.0) - rubocop-ast (1.47.1) - parser (>= 3.3.7.2) - prism (~> 1.4) - ruby-progressbar (1.13.0) - unicode-display_width (3.2.0) - unicode-emoji (~> 4.1) - unicode-emoji (4.1.0) - -PLATFORMS - arm64-darwin-24 - ruby - -DEPENDENCIES - aws-sdk-kms! - aws-sdk-s3! - json (~> 2.0) - rexml (~> 3.0) - rubocop (~> 1.0) - -RUBY VERSION - ruby 3.4.7p58 - -BUNDLED WITH - 2.7.2 diff --git a/all-examples/ruby/v2/Makefile b/all-examples/ruby/v2/Makefile deleted file mode 100644 index cfa1adef..00000000 --- a/all-examples/ruby/v2/Makefile +++ /dev/null @@ -1,70 +0,0 @@ -# Makefile for S3 Encryption Client Ruby v2 Example - -# Default target -.PHONY: all install clean run help - -# Variables -SCRIPT = main.rb - -# Default arguments for running the example -# Override these when calling make run -BUCKET_NAME ?= avp-21638 -OBJECT_KEY ?= s3ec-ruby-v2 -KMS_KEY_ID ?= arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 -AWS_REGION ?= us-east-2 - -all: install - -# Install dependencies using Bundler -install: - @echo "Installing Ruby dependencies..." - @bundle install - @echo "Dependencies installed successfully!" - -# Clean bundle artifacts -clean: - @echo "Cleaning bundle artifacts..." - @bundle clean --force - @echo "Clean completed!" - -# Run the example with default arguments -run: install - @echo "Running S3 Encryption Client v2 Ruby example..." - @echo "Bucket: $(BUCKET_NAME)" - @echo "Object Key: $(OBJECT_KEY)" - @echo "KMS Key ID: $(KMS_KEY_ID)" - @echo "Region: $(AWS_REGION)" - @echo "" - @bundle exec ruby $(SCRIPT) $(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION) - -# Run with custom arguments -# Usage: make run-custom BUCKET_NAME=my-bucket OBJECT_KEY=my-key KMS_KEY_ID=my-kms-key AWS_REGION=my-region -run-custom: install - @bundle exec ruby $(SCRIPT) $(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION) - -# Show help -help: - @echo "S3 Encryption Client Ruby v2 Example Makefile" - @echo "" - @echo "Available targets:" - @echo " install - Install Ruby dependencies using Bundler" - @echo " run - Install dependencies and run the example with default parameters" - @echo " run-custom - Install dependencies and run with custom parameters" - @echo " clean - Remove bundle artifacts" - @echo " help - Show this help message" - @echo "" - @echo "Default parameters:" - @echo " BUCKET_NAME = $(BUCKET_NAME)" - @echo " OBJECT_KEY = $(OBJECT_KEY)" - @echo " KMS_KEY_ID = $(KMS_KEY_ID)" - @echo " AWS_REGION = $(AWS_REGION)" - @echo "" - @echo "To run with custom parameters:" - @echo " make run BUCKET_NAME=your-bucket OBJECT_KEY=your-key KMS_KEY_ID=your-kms-key AWS_REGION=your-region" - @echo "" - @echo "Prerequisites:" - @echo " - Ruby 3.0+ installed on the system" - @echo " - Bundler gem installed (gem install bundler)" - @echo " - AWS credentials configured (AWS CLI, environment variables, or IAM role)" - @echo " - Valid S3 bucket and KMS key with appropriate permissions" - @echo " - S3 Encryption Client v2 Ruby SDK (included in local-ruby-sdk)" diff --git a/all-examples/ruby/v2/local-ruby-sdk b/all-examples/ruby/v2/local-ruby-sdk deleted file mode 120000 index 7abd378c..00000000 --- a/all-examples/ruby/v2/local-ruby-sdk +++ /dev/null @@ -1 +0,0 @@ -../../../test-server/ruby-v2-server/local-ruby-sdk \ No newline at end of file diff --git a/all-examples/ruby/v2/main.rb b/all-examples/ruby/v2/main.rb deleted file mode 100644 index 3fc86f7c..00000000 --- a/all-examples/ruby/v2/main.rb +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env ruby - -require 'aws-sdk-s3' -require 'aws-sdk-kms' -require 'json' - -# See: https://github.com/ruby/openssl/issues/949 -Aws.use_bundled_cert! - -def main - # Check command line arguments - if ARGV.length != 4 - puts "Usage: #{$0} " - puts "Example: #{$0} avp-21638 s3ec-ruby-v2 arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 us-east-2" - exit 1 - end - - bucket_name = ARGV[0] - object_key = ARGV[1] - kms_key_id = ARGV[2] - region = ARGV[3] - - puts "=== S3 Encryption Client v2 Example (Ruby) ===" - puts "Bucket: #{bucket_name}" - puts "Object Key: #{object_key}" - puts "KMS Key ID: #{kms_key_id}" - puts "Region: #{region}" - puts - - begin - # Test data for encryption - test_data = "Hello, World! This is a test message for S3 encryption client v2 in Ruby." - puts "Original data: #{test_data}" - puts "Data length: #{test_data.length} bytes" - puts - - puts "--- Initialize S3 Encryption Client v2 ---" - - # Create regular S3 client - s3_client = Aws::S3::Client.new(region: region) - - # Create KMS client - kms_client = Aws::KMS::Client.new(region: region) - - # Create S3 Encryption Client v2 - encryption_client = Aws::S3::EncryptionV2::Client.new( - client: s3_client, - kms_key_id: kms_key_id, - kms_client: kms_client, - key_wrap_schema: :kms_context, - content_encryption_schema: :aes_gcm_no_padding, - security_profile: :v2 - ) - - puts "Successfully initialized S3 Encryption Client v2" - puts "--- Encrypt and Upload Object to S3 ---" - - # Add encryption context - encryption_context = { - 'purpose' => 'example', - 'version' => 'v2', - 'language' => 'ruby' - } - - # Upload encrypted object using S3 Encryption Client - put_response = encryption_client.put_object({ - bucket: bucket_name, - key: object_key, - body: test_data, - kms_encryption_context: encryption_context - }) - - puts "Successfully uploaded encrypted object to S3!" - puts " Bucket: #{bucket_name}" - puts " Key: #{object_key}" - puts " Encryption Context: #{encryption_context}" - puts - - puts "--- Download and Decrypt Object from S3 ---" - - # Download and decrypt object using S3 Encryption Client - get_response = encryption_client.get_object({ - bucket: bucket_name, - key: object_key, - kms_encryption_context: encryption_context - }) - - # Read the decrypted data - decrypted_data = get_response.body.read - - puts "Successfully downloaded and decrypted object from S3!" - puts " Object size: #{decrypted_data.length} bytes" - puts " Decrypted data: #{decrypted_data}" - puts - - puts "--- Verify Roundtrip Success ---" - - # Verify the roundtrip was successful - if decrypted_data == test_data - puts "SUCCESS: Roundtrip encryption/decryption completed successfully!" - puts " Original data matches decrypted data" - puts " Data integrity verified" - else - puts "ERROR: Roundtrip failed - data mismatch" - puts " Original: #{test_data}" - puts " Decrypted: #{decrypted_data}" - exit 1 - end - - # Optionally Delete the Object - #puts "--- Cleanup ---" - # Clean up the test object using regular S3 client - # s3_client.delete_object({ - # bucket: bucket_name, - # key: object_key - # }) - # puts "Test object deleted from S3" - - puts - puts "=== Example completed successfully! ===" - - rescue Aws::S3::Errors::NoSuchBucket => e - puts "Error: S3 bucket '#{bucket_name}' does not exist or is not accessible" - puts " #{e.message}" - exit 1 - rescue Aws::KMS::Errors::NotFoundException => e - puts "Error: KMS key '#{kms_key_id}' not found or not accessible" - puts " #{e.message}" - exit 1 - rescue Aws::S3::EncryptionV2::Errors::EncryptionError => e - puts "S3 Encryption Error: #{e.message}" - exit 1 - rescue Aws::S3::EncryptionV2::Errors::DecryptionError => e - puts "S3 Decryption Error: #{e.message}" - exit 1 - rescue Aws::Errors::ServiceError => e - puts "AWS Service Error: #{e.message}" - puts " Error Code: #{e.code}" if e.respond_to?(:code) - exit 1 - rescue StandardError => e - puts "Unexpected error: #{e.message}" - puts e.backtrace.first(5) - exit 1 - end -end - -# Run the main function if this script is executed directly -if __FILE__ == $0 - main -end diff --git a/all-examples/ruby/v3/Gemfile b/all-examples/ruby/v3/Gemfile deleted file mode 100644 index 5f51bf18..00000000 --- a/all-examples/ruby/v3/Gemfile +++ /dev/null @@ -1,12 +0,0 @@ -source 'https://rubygems.org' - -ruby '>= 2.7.0' - -gem 'aws-sdk-s3', path: 'local-ruby-sdk/gems/aws-sdk-s3' -gem 'aws-sdk-kms', path: 'local-ruby-sdk/gems/aws-sdk-kms' -gem 'json', '~> 2.0' -gem 'rexml', '~> 3.0' - -group :development do - gem 'rubocop', '~> 1.0' -end diff --git a/all-examples/ruby/v3/Makefile b/all-examples/ruby/v3/Makefile deleted file mode 100644 index b27bf29f..00000000 --- a/all-examples/ruby/v3/Makefile +++ /dev/null @@ -1,70 +0,0 @@ -# Makefile for S3 Encryption Client Ruby v3 Example - -# Default target -.PHONY: all install clean run help - -# Variables -SCRIPT = main.rb - -# Default arguments for running the example -# Override these when calling make run -BUCKET_NAME ?= avp-21638 -OBJECT_KEY ?= s3ec-ruby-v3 -KMS_KEY_ID ?= arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 -AWS_REGION ?= us-east-2 - -all: install - -# Install dependencies using Bundler -install: - @echo "Installing Ruby dependencies..." - @bundle install - @echo "Dependencies installed successfully!" - -# Clean bundle artifacts -clean: - @echo "Cleaning bundle artifacts..." - @bundle clean --force - @echo "Clean completed!" - -# Run the example with default arguments -run: install - @echo "Running S3 Encryption Client v3 Ruby example..." - @echo "Bucket: $(BUCKET_NAME)" - @echo "Object Key: $(OBJECT_KEY)" - @echo "KMS Key ID: $(KMS_KEY_ID)" - @echo "Region: $(AWS_REGION)" - @echo "" - @bundle exec ruby $(SCRIPT) $(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION) - -# Run with custom arguments -# Usage: make run-custom BUCKET_NAME=my-bucket OBJECT_KEY=my-key KMS_KEY_ID=my-kms-key AWS_REGION=my-region -run-custom: install - @bundle exec ruby $(SCRIPT) $(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION) - -# Show help -help: - @echo "S3 Encryption Client Ruby v3 Example Makefile" - @echo "" - @echo "Available targets:" - @echo " install - Install Ruby dependencies using Bundler" - @echo " run - Install dependencies and run the example with default parameters" - @echo " run-custom - Install dependencies and run with custom parameters" - @echo " clean - Remove bundle artifacts" - @echo " help - Show this help message" - @echo "" - @echo "Default parameters:" - @echo " BUCKET_NAME = $(BUCKET_NAME)" - @echo " OBJECT_KEY = $(OBJECT_KEY)" - @echo " KMS_KEY_ID = $(KMS_KEY_ID)" - @echo " AWS_REGION = $(AWS_REGION)" - @echo "" - @echo "To run with custom parameters:" - @echo " make run BUCKET_NAME=your-bucket OBJECT_KEY=your-key KMS_KEY_ID=your-kms-key AWS_REGION=your-region" - @echo "" - @echo "Prerequisites:" - @echo " - Ruby 3.0+ installed on the system" - @echo " - Bundler gem installed (gem install bundler)" - @echo " - AWS credentials configured (AWS CLI, environment variables, or IAM role)" - @echo " - Valid S3 bucket and KMS key with appropriate permissions" - @echo " - S3 Encryption Client v3 Ruby SDK (included in local-ruby-sdk)" diff --git a/all-examples/ruby/v3/local-ruby-sdk b/all-examples/ruby/v3/local-ruby-sdk deleted file mode 120000 index 49be2657..00000000 --- a/all-examples/ruby/v3/local-ruby-sdk +++ /dev/null @@ -1 +0,0 @@ -../../../test-server/ruby-v3-server/local-ruby-sdk \ No newline at end of file diff --git a/all-examples/ruby/v3/main.rb b/all-examples/ruby/v3/main.rb deleted file mode 100644 index 59743515..00000000 --- a/all-examples/ruby/v3/main.rb +++ /dev/null @@ -1,148 +0,0 @@ -#!/usr/bin/env ruby - -require 'aws-sdk-s3' -require 'aws-sdk-kms' -require 'json' - -# See: https://github.com/ruby/openssl/issues/949 -Aws.use_bundled_cert! - -def main - # Check command line arguments - if ARGV.length != 4 - puts "Usage: #{$0} " - puts "Example: #{$0} avp-21638 s3ec-ruby-v3 arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 us-east-2" - exit 1 - end - - bucket_name = ARGV[0] - object_key = ARGV[1] - kms_key_id = ARGV[2] - region = ARGV[3] - - puts "=== S3 Encryption Client v3 Example (Ruby) ===" - puts "Bucket: #{bucket_name}" - puts "Object Key: #{object_key}" - puts "KMS Key ID: #{kms_key_id}" - puts "Region: #{region}" - puts - - begin - # Test data for encryption - test_data = "Hello, World! This is a test message for S3 encryption client v3 in Ruby." - puts "Original data: #{test_data}" - puts "Data length: #{test_data.length} bytes" - puts - - puts "--- Initialize S3 Encryption Client v3 ---" - - # Create regular S3 client - s3_client = Aws::S3::Client.new(region: region) - - # Create KMS client - kms_client = Aws::KMS::Client.new(region: region) - - # Create S3 Encryption Client v3 - encryption_client = Aws::S3::EncryptionV3::Client.new( - client: s3_client, - kms_key_id: kms_key_id, - kms_client: kms_client, - key_wrap_schema: :kms_context - ) - - puts "Successfully initialized S3 Encryption Client v3" - puts "--- Encrypt and Upload Object to S3 ---" - - # Add encryption context - encryption_context = { - 'purpose' => 'example', - 'version' => 'v3', - 'language' => 'ruby' - } - - # Upload encrypted object using S3 Encryption Client - put_response = encryption_client.put_object({ - bucket: bucket_name, - key: object_key, - body: test_data, - kms_encryption_context: encryption_context - }) - - puts "Successfully uploaded encrypted object to S3!" - puts " Bucket: #{bucket_name}" - puts " Key: #{object_key}" - puts " Encryption Context: #{encryption_context}" - puts - - puts "--- Download and Decrypt Object from S3 ---" - - # Download and decrypt object using S3 Encryption Client - get_response = encryption_client.get_object({ - bucket: bucket_name, - key: object_key, - kms_encryption_context: encryption_context - }) - - # Read the decrypted data - decrypted_data = get_response.body.read - - puts "Successfully downloaded and decrypted object from S3!" - puts " Object size: #{decrypted_data.length} bytes" - puts " Decrypted data: #{decrypted_data}" - puts - - puts "--- Verify Roundtrip Success ---" - - # Verify the roundtrip was successful - if decrypted_data == test_data - puts "SUCCESS: Roundtrip encryption/decryption completed successfully!" - puts " Original data matches decrypted data" - puts " Data integrity verified" - else - puts "ERROR: Roundtrip failed - data mismatch" - puts " Original: #{test_data}" - puts " Decrypted: #{decrypted_data}" - exit 1 - end - - # Optionally Delete the Object - #puts "--- Cleanup ---" - # Clean up the test object using regular S3 client - # s3_client.delete_object({ - # bucket: bucket_name, - # key: object_key - # }) - # puts "Test object deleted from S3" - - puts - puts "=== Example completed successfully! ===" - - rescue Aws::S3::Errors::NoSuchBucket => e - puts "Error: S3 bucket '#{bucket_name}' does not exist or is not accessible" - puts " #{e.message}" - exit 1 - rescue Aws::KMS::Errors::NotFoundException => e - puts "Error: KMS key '#{kms_key_id}' not found or not accessible" - puts " #{e.message}" - exit 1 - rescue Aws::S3::EncryptionV3::Errors::EncryptionError => e - puts "S3 Encryption Error: #{e.message}" - exit 1 - rescue Aws::S3::EncryptionV3::Errors::DecryptionError => e - puts "S3 Decryption Error: #{e.message}" - exit 1 - rescue Aws::Errors::ServiceError => e - puts "AWS Service Error: #{e.message}" - puts " Error Code: #{e.code}" if e.respond_to?(:code) - exit 1 - rescue StandardError => e - puts "Unexpected error: #{e.message}" - puts e.backtrace.first(5) - exit 1 - end -end - -# Run the main function if this script is executed directly -if __FILE__ == $0 - main -end diff --git a/pyproject.toml b/pyproject.toml index 883b6914..b05f22aa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,7 @@ test = [ "pytest>=8.4.1", ] dev = [ - "black>=24.3.0", + "black>=24.3.0,<27.0.0", "ruff>=0.3.0", ] @@ -52,3 +52,6 @@ max-complexity = 10 [tool.ruff.lint.isort] known-first-party = ["s3_encryption"] + +[tool.ruff.lint.per-file-ignores] +"test/**/*.py" = ["D100", "D101", "D102", "D103", "D104", "E501"] diff --git a/src/s3_encryption/__init__.py b/src/s3_encryption/__init__.py index adfb6886..46cdbdd1 100644 --- a/src/s3_encryption/__init__.py +++ b/src/s3_encryption/__init__.py @@ -1,6 +1,7 @@ # Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 """Top-level S3 Encryption Client v3 for Python package.""" + import io from attrs import define, field diff --git a/src/s3_encryption/exceptions.py b/src/s3_encryption/exceptions.py index 748075fc..463a180d 100644 --- a/src/s3_encryption/exceptions.py +++ b/src/s3_encryption/exceptions.py @@ -5,6 +5,24 @@ This module contains custom exception classes used throughout the S3 Encryption Client. """ +from botocore.exceptions import BotoCoreError -class S3EncryptionClientError(Exception): - """Exception class for S3 Encryption Client errors.""" + +class S3EncryptionClientError(BotoCoreError): + """Exception class for non-Security S3 Encryption Client errors.""" + + fmt = "{msg}" + + def __init__(self, message="An unspecified S3 Encryption Client error occurred"): + """Initialize the exception with a message.""" + super().__init__(msg=message) + + +class S3EncryptionClientSecurityError(BotoCoreError): + """Security Exceptions for S3 Encryption Client errors.""" + + fmt = "{msg}" + + def __init__(self, message="An unspecified S3 Encryption Client Security error occurred"): + """Initialize the exception with a message.""" + super().__init__(msg=message) diff --git a/src/s3_encryption/materials/encrypted_data_key.py b/src/s3_encryption/materials/encrypted_data_key.py index 28401b40..b2c2359a 100644 --- a/src/s3_encryption/materials/encrypted_data_key.py +++ b/src/s3_encryption/materials/encrypted_data_key.py @@ -5,6 +5,7 @@ This module provides the EncryptedDataKey class which represents an encrypted data key used in the S3 encryption process. """ + from attrs import define diff --git a/src/s3_encryption/materials/materials.py b/src/s3_encryption/materials/materials.py index 9f72ab91..3966e17c 100644 --- a/src/s3_encryption/materials/materials.py +++ b/src/s3_encryption/materials/materials.py @@ -6,6 +6,7 @@ which contain the cryptographic materials needed for S3 object encryption and decryption operations. """ + from typing import Any from attrs import define, field diff --git a/src/s3_encryption/metadata.py b/src/s3_encryption/metadata.py index b4378990..f42feadb 100644 --- a/src/s3_encryption/metadata.py +++ b/src/s3_encryption/metadata.py @@ -5,6 +5,7 @@ This module provides classes and utilities for managing encryption metadata for S3 objects, including serialization and deserialization of metadata. """ + import json from typing import Any diff --git a/src/s3_encryption/pipelines.py b/src/s3_encryption/pipelines.py index 6046fb3a..37093803 100644 --- a/src/s3_encryption/pipelines.py +++ b/src/s3_encryption/pipelines.py @@ -5,6 +5,7 @@ This module provides pipelines for encrypting objects before they are put into S3 and decrypting objects after they are retrieved from S3. """ + import base64 import os diff --git a/test-server/Makefile b/test-server/Makefile index 94a76b3f..21b5c98b 100644 --- a/test-server/Makefile +++ b/test-server/Makefile @@ -1,14 +1,14 @@ # Makefile for S3 Encryption Client Testing -.PHONY: all start-servers run-tests stop-servers clean ci check-env help +.PHONY: test-servers-all test-servers-start test-servers-run-tests test-servers-stop test-servers-clean test-servers-ci test-servers-check-env test-servers-help # CI target for GitHub Actions -ci: +test-servers-ci: $(MAKE) build-all-servers $(MAKE) start-all-servers $(MAKE) wait-all-servers - $(MAKE) run-tests - $(MAKE) stop-servers + $(MAKE) test-servers-run-tests + $(MAKE) test-servers-stop SERVER_DIRS := $(shell find . -maxdepth 1 -type d -name '*-server' | sed 's|^\./||' | $(if $(FILTER),grep -E "$$(echo '$(FILTER)' | sed 's/,/|/g')",cat) | sort) @@ -36,7 +36,7 @@ $(BUILD_SERVER_TARGETS): build-%: fi # Build and start all servers -start-servers: +test-servers-start: @echo "Building all servers..." $(MAKE) build-all-servers @echo "Starting all servers..." @@ -75,7 +75,7 @@ $(WAIT_SERVER_TARGETS): wait-%: # Run the Java tests -run-tests: +test-servers-run-tests: @echo "Running Java tests..." @echo "Exporting environment variables from servers to tests..." @# Extract AWS environment variables from the current shell and pass them to the tests @@ -90,7 +90,7 @@ run-tests: @echo "Tests completed successfully" # Stop the servers -stop-servers: +test-servers-stop: @echo "Stopping servers..." @for dir in $(SERVER_DIRS); do \ echo "Stopping server in $$dir..."; \ @@ -99,18 +99,18 @@ stop-servers: @echo "Servers stopped" # Help target -help: +test-servers-help: @echo "Available targets:" - @echo " all : Start servers and run tests (default, output to stdout)" - @echo " ci : Run in CI mode (start servers, run tests, stop servers)" - @echo " start-servers : Start all servers in parallel" - @echo " run-tests : Run Java tests" - @echo " stop-servers : Stop running servers" - @echo " check-env : Check if required environment variables are set" - @echo " help : Show this help message" + @echo " test-servers-all : Start servers and run tests (default, output to stdout)" + @echo " test-servers-ci : Run in CI mode (start servers, run tests, stop servers)" + @echo " test-servers-start : Start all servers in parallel" + @echo " test-servers-run-tests : Run Java tests" + @echo " test-servers-stop : Stop running servers" + @echo " test-servers-check-env : Check if required environment variables are set" + @echo " test-servers-help : Show this help message" # Check if required environment variables are set -check-env: +test-servers-check-env: @echo "Checking required environment variables..." @if [ -z "$$AWS_ACCESS_KEY_ID" ]; then echo "AWS_ACCESS_KEY_ID is not set"; else echo "AWS_ACCESS_KEY_ID is set"; fi @if [ -z "$$AWS_SECRET_ACCESS_KEY" ]; then echo "AWS_SECRET_ACCESS_KEY is not set"; else echo "AWS_SECRET_ACCESS_KEY is set"; fi diff --git a/test-server/README.md b/test-server/README.md index 818e8ded..48187fc3 100644 --- a/test-server/README.md +++ b/test-server/README.md @@ -31,12 +31,6 @@ make start-servers # Start only the Python S3EC V3 server make start-python-v3-server -# Start only the Java S3EC V3 server -make start-java-v3-server - -# Start only the Go S3EC V3 server -make start-go-v3-server - # Run Java tests make run-tests @@ -83,7 +77,6 @@ You can adjust the source pattern or comment style as needed. Examples: - `ruby-v2-server/.duvet/config.toml` -- `php-v2-server/.duvet/config.toml` There are Makefile targets, but you can just run `make duvet` or `duvet report` inside a server directory to run the report. diff --git a/test-server/cpp-v2-server/.duvet/.gitignore b/test-server/cpp-v2-server/.duvet/.gitignore deleted file mode 100644 index 93956e36..00000000 --- a/test-server/cpp-v2-server/.duvet/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -reports/ -requirements/ -specification/ \ No newline at end of file diff --git a/test-server/cpp-v2-server/CMakeLists.txt b/test-server/cpp-v2-server/CMakeLists.txt deleted file mode 100644 index b282dbc4..00000000 --- a/test-server/cpp-v2-server/CMakeLists.txt +++ /dev/null @@ -1,39 +0,0 @@ -cmake_minimum_required(VERSION 3.16) -project(s3ec-cpp-v2-server) - -set(CMAKE_CXX_STANDARD 17) - -# Configure AWS SDK build options -set(BUILD_ONLY "kms;s3;s3-encryption" CACHE STRING "Build only KMS, S3, and S3-encryption components") -set(ENABLE_TESTING OFF CACHE BOOL "Disable testing") -set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build static libraries") - -# Add AWS SDK as subdirectory -add_subdirectory(aws-sdk-cpp) - -find_package(PkgConfig REQUIRED) -pkg_check_modules(LIBMICROHTTPD REQUIRED libmicrohttpd) - -find_package(nlohmann_json REQUIRED) - -add_executable(s3ec-server main.cpp) - -target_include_directories(s3ec-server PRIVATE - ${LIBMICROHTTPD_INCLUDE_DIRS} - /opt/homebrew/include -) - -target_link_directories(s3ec-server PRIVATE - ${LIBMICROHTTPD_LIBRARY_DIRS} - /opt/homebrew/lib -) - -target_link_libraries(s3ec-server - ${LIBMICROHTTPD_LIBRARIES} - aws-cpp-sdk-core - aws-cpp-sdk-kms - aws-cpp-sdk-s3 - aws-cpp-sdk-s3-encryption - nlohmann_json::nlohmann_json - uuid -) \ No newline at end of file diff --git a/test-server/cpp-v2-server/Makefile b/test-server/cpp-v2-server/Makefile deleted file mode 100644 index 2d0a4b55..00000000 --- a/test-server/cpp-v2-server/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -# Makefile for S3 Encryption Client Testing - -.PHONY: build-server start-server stop-server wait-for-server - -PID_FILE := server.pid -PORT := 8085 - -build/s3ec-server: - cd aws-sdk-cpp - mkdir -p build && cd build && cmake .. - -build-server: | build/s3ec-server - @echo "Building Cpp V2 server..." - cd build && $(MAKE) - -start-server: - @echo "Starting Cpp V2 server..." - cd build && \ - AWS_ACCESS_KEY_ID="$$AWS_ACCESS_KEY_ID" \ - AWS_SECRET_ACCESS_KEY="$$AWS_SECRET_ACCESS_KEY" \ - AWS_SESSION_TOKEN="$$AWS_SESSION_TOKEN" \ - AWS_REGION="us-west-2" \ - ./s3ec-server > ../server.log 2>&1 & echo $$! > ../$(PID_FILE) - @echo "Cpp V2 server starting..." - -stop-server: - @echo "Stopping server on port $(PORT)..." - @lsof -ti:$(PORT) | xargs kill -9 2>/dev/null || true - @if [ -f $(PID_FILE) ]; then \ - pkill -P $$(cat $(PID_FILE)) 2>/dev/null || true; \ - kill -9 $$(cat $(PID_FILE)) 2>/dev/null || true; \ - rm -f $(PID_FILE); \ - fi - @rm -f server.log - @echo "Server stopped" - -wait-for-server: - $(MAKE) -C .. wait-for-port PORT=$(PORT) diff --git a/test-server/cpp-v2-server/README.md b/test-server/cpp-v2-server/README.md deleted file mode 100644 index 8e77feda..00000000 --- a/test-server/cpp-v2-server/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# C++ S3 Encryption Test Server - -Minimal C++ implementation of the S3 Encryption test server. - -## Dependencies - -- libmicrohttpd -- AWS SDK for C++ -- nlohmann/json -- uuid - -On MacOS you can -```bash -brew install libmicrohttpd nlohmann-json ossp-uuid -``` - -## Build - -```bash -mkdir build && cd build -cmake .. -make -``` - -## Run - -```bash -./s3ec-server -``` - -Server runs on localhost:8085 - -## API Endpoints - -- `POST /client` - Create S3 encryption client -- `GET /object/{bucket}/{key}` - Get encrypted object -- `PUT /object/{bucket}/{key}` - Put encrypted object \ No newline at end of file diff --git a/test-server/cpp-v2-server/aws-sdk-cpp b/test-server/cpp-v2-server/aws-sdk-cpp deleted file mode 160000 index 994384ca..00000000 --- a/test-server/cpp-v2-server/aws-sdk-cpp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 994384ca8b9defe2ae60b5d3447ec5f47f7ec19f diff --git a/test-server/cpp-v2-server/main.cpp b/test-server/cpp-v2-server/main.cpp deleted file mode 100644 index e8ffe770..00000000 --- a/test-server/cpp-v2-server/main.cpp +++ /dev/null @@ -1,668 +0,0 @@ -/* - * S3 Encryption Test Server - C++ V2 - * - * CONCURRENCY AND SYNCHRONIZATION DESIGN: - * - * 1. Threading Model: - * - Uses MHD_USE_POLL_INTERNALLY with fixed thread pool - * - Thread pool size = CPU cores * 2 (auto-detected at startup) - * - Threads are reused across connections for efficiency - * - I/O multiplexing (poll) distributes connections across thread pool - * - All S3 operations are SYNCHRONOUS - server waits for S3 completion before responding - * - POLL mechanism avoids FD_SETSIZE=1024 limitation of select() - * - * 2. Resource Scaling: - * - All limits automatically scale with detected CPU count: - * * Thread pool size = num_cores * 2 - * * Connection limit = num_cores * 2 - * * S3 client maxConnections = num_cores * 2 - * - Multiplier of 2 accounts for I/O blocking without starving throughput - * - Ensures optimal resource usage on any hardware configuration - * - * 3. Client Cache (client_cache_secret): - * - Protected by std::shared_mutex for efficient concurrent access - * - get_client() uses shared_lock (multiple threads can read simultaneously) - * - set_client() uses unique_lock (exclusive write access) - * - This allows concurrent GET/PUT operations without serialization - * - UUID-based keys guarantee uniqueness (always insert, never update) - * - * 4. Memory Management: - * - Request body allocated in request_handler (*con_cls = new std::string()) - * - Body lifetime managed by libmicrohttpd - valid until request_completed() - * - All handler functions complete synchronously before returning - * - request_completed() safely deletes body after response sent - * - No memory leaks under sustained concurrent load - * - * 5. Synchronous Operation Guarantees: - * - GetObject: Waits for S3, reads full response stream, then returns - * - PutObject: Waits for S3 operation to complete, then returns - * - No async callbacks or background operations - * - Client receives response only after S3 operation completes - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using json = nlohmann::json; -using namespace Aws::S3Encryption; -using Aws::S3Encryption::Materials::KMSWithContextEncryptionMaterials; - -// LRU cache for S3 encryption clients -// Limits memory and connection pool growth by evicting least recently used clients -const size_t MAX_CACHED_CLIENTS = 100; // Reasonable limit for concurrent test operations - -struct ClientCacheEntry { - std::shared_ptr client; - std::list::iterator lru_iter; -}; - -std::unordered_map client_cache_secret; -std::list lru_order; // Most recently used at front -std::shared_timed_mutex client_mutex; // Using shared_timed_mutex (C++14 compatible) for concurrent reads - -// Threading configuration - set at startup based on CPU cores -unsigned int g_thread_pool_size = 8; // Default, will be overwritten in main() - -std::string generate_uuid() { - uuid_t uuid; - uuid_generate(uuid); - char uuid_str[37]; - uuid_unparse(uuid, uuid_str); - return std::string(uuid_str); -} - -std::shared_ptr get_client(const std::string &client_id) -{ - // Need unique_lock to update LRU order even on reads - std::unique_lock lock(client_mutex); - auto it = client_cache_secret.find(client_id); - if (it == client_cache_secret.end()) { - return std::shared_ptr(); - } else { - // Move to front of LRU list (mark as most recently used) - lru_order.erase(it->second.lru_iter); - lru_order.push_front(client_id); - it->second.lru_iter = lru_order.begin(); - - return it->second.client; - } -} - -void set_client(const std::string &client_id, std::shared_ptr client) -{ - // UUID guarantees unique keys - always insert, never update - // Still need exclusive lock because std::unordered_map isn't thread-safe for concurrent inserts - std::unique_lock lock(client_mutex); - - // Add to front of LRU list (most recently used) - lru_order.push_front(client_id); - - ClientCacheEntry entry; - entry.client = client; - entry.lru_iter = lru_order.begin(); - - client_cache_secret.emplace(client_id, entry); - - // Evict least recently used clients if we exceed the limit - while (client_cache_secret.size() > MAX_CACHED_CLIENTS) { - std::string lru_client_id = lru_order.back(); - lru_order.pop_back(); - - auto evict_it = client_cache_secret.find(lru_client_id); - if (evict_it != client_cache_secret.end()) { - fprintf(stderr, "[CPP-V2] [CACHE-EVICT] Evicting client %s (cache size was %zu)\n", - lru_client_id.c_str(), client_cache_secret.size()); - client_cache_secret.erase(evict_it); - } - } - - fprintf(stderr, "[CPP-V2] [CACHE-ADD] Added client %s (cache size now %zu)\n", - client_id.c_str(), client_cache_secret.size()); -} - -std::string get_header_value(struct MHD_Connection *connection, - const char *key) { - const char *value = - MHD_lookup_connection_value(connection, MHD_HEADER_KIND, key); - return value ? std::string(value) : ""; -} - -MHD_Result send_response(struct MHD_Connection *connection, int status_code, - const std::string &content) { - struct MHD_Response *response = MHD_create_response_from_buffer( - content.length(), (void *)content.data(), MHD_RESPMEM_MUST_COPY); - MHD_Result ret = MHD_queue_response(connection, status_code, response); - MHD_destroy_response(response); - return ret; -} - -std::string make_error(const std::string &message, int status_code) { - return "{\"__type\": " - "\"software.amazon.encryption.s3#S3EncryptionClientError\", " - "\"message\": \"" + - message + "\"}"; -} - -MHD_Result handle_create_client(struct MHD_Connection *connection, - const std::string &body) { - // Body is kept alive by *con_cls until request_completed fires, so it's safe to use directly - // All operations here are synchronous and complete before returning to caller - - try { - json request = json::parse(body); - std::string kms_key_id = request["config"]["keyMaterial"]["kmsKeyId"]; - bool legacy1 = request["config"]["enableLegacyWrappingAlgorithms"]; - bool legacy2 = request["config"]["enableLegacyUnauthenticatedModes"]; - bool inst_put = false; - if (request["config"].contains("instructionFileConfig") && - request["config"]["instructionFileConfig"].contains("enableInstructionFilePutObject")) { - inst_put = request["config"]["instructionFileConfig"]["enableInstructionFilePutObject"]; - } - - auto materials = - std::make_shared(kms_key_id); - CryptoConfigurationV2 config(materials); - if (legacy1 || legacy2) - config.SetSecurityProfile(SecurityProfile::V2_AND_LEGACY); - if (legacy2) - config.SetUnAuthenticatedRangeGet(RangeGetMode::ALL); - if (inst_put) - config.SetStorageMethod(StorageMethod::INSTRUCTION_FILE); - - // Each client gets a large connection pool since we cannot share HTTP clients - Aws::Client::ClientConfiguration clientConfig; - clientConfig.maxConnections = 512; // Large pool per client - clientConfig.retryStrategy = Aws::Client::InitRetryStrategy("standard"); - - // Disable automatic checksum calculation for encrypted streams - // The ChecksumInterceptor cannot handle non-seekable SymmetricCryptoStream - // which causes intermittent "BadDigest: CRC64NVME you specified did not match" errors - // when the stream gets consumed during checksum calculation and can't be rewound - clientConfig.checksumConfig.requestChecksumCalculation = - Aws::Client::RequestChecksumCalculation::WHEN_REQUIRED; - - auto encryption_client = std::make_shared(config, clientConfig); - - std::string client_id = generate_uuid(); - set_client(client_id, encryption_client); - - json response = {{"clientId", client_id}}; - return send_response(connection, 200, response.dump()); - } catch (const std::exception &e) { - fprintf(stderr, "[CPP-V2] handle_create_client exception: %s\n", e.what()); - return send_response(connection, 500, - "{\"error\":\"An exception was thrown.\"}"); - } catch (...) { - return send_response(connection, 500, "{\"error\":\"Unknown error\"}"); - } -} - -void fill_context(Aws::Map &map, - const std::string &metadata) { - if (metadata.empty()) { - fprintf(stderr, "[CPP-V2] [DEBUG] fill_context: metadata is empty\n"); - return; - } - - fprintf(stderr, "[CPP-V2] [DEBUG] fill_context: raw metadata='%s' (length=%zu)\n", - metadata.c_str(), metadata.length()); - - // Parse metadata format: [key1]:[value1],[key2]:[value2],... - // or single pair: [key]:[value] - std::string current = metadata; - size_t pos = 0; - int pair_count = 0; - - while (pos < current.length()) { - // Find opening bracket for key - size_t key_start = current.find('[', pos); - if (key_start == std::string::npos) - break; - - // Find closing bracket for key - size_t key_end = current.find(']', key_start); - if (key_end == std::string::npos) - break; - - // Find colon separator - size_t colon = current.find(':', key_end); - if (colon == std::string::npos) - break; - - // Find opening bracket for value - size_t value_start = current.find('[', colon); - if (value_start == std::string::npos) - break; - - // Find closing bracket for value - size_t value_end = current.find(']', value_start); - if (value_end == std::string::npos) - break; - - // Extract key and value - std::string key = current.substr(key_start + 1, key_end - key_start - 1); - std::string value = - current.substr(value_start + 1, value_end - value_start - 1); - - fprintf(stderr, "[CPP-V2] [DEBUG] fill_context: parsed pair #%d: key='%s', value='%s'\n", - ++pair_count, key.c_str(), value.c_str()); - - // Add to map - map.emplace(key, value); - - // Move to next pair (look for comma or next opening bracket) - pos = value_end + 1; - size_t comma = current.find(',', pos); - if (comma != std::string::npos) { - pos = comma + 1; - } - } - - fprintf(stderr, "[CPP-V2] [DEBUG] fill_context: completed, parsed %d pairs into map\n", pair_count); -} - -MHD_Result handle_get_object(struct MHD_Connection *connection, - std::string bucket, - std::string key, - std::string client_id, - std::string metadata, - std::string range) { - // Get thread ID for debugging concurrent operations - std::thread::id thread_id = std::this_thread::get_id(); - - fprintf(stderr, "[CPP-V2] [DEBUG] GetObject START: thread=%lu, bucket=%s, key=%s, client_id=%s, metadata_length=%zu, range=%s\n", - (unsigned long)std::hash{}(thread_id), bucket.c_str(), key.c_str(), client_id.c_str(), metadata.length(), range.c_str()); - - auto client = get_client(client_id); - if (!client) { - fprintf(stderr, "[CPP-V2] GetObject error: Client not found for client_id=%s\n", client_id.c_str()); - return send_response(connection, 404, "{\"error\":\"Client not found\"}"); - } - - try { - Aws::S3::Model::GetObjectRequest request; - request.SetBucket(bucket); - request.SetKey(key); - - // Add range header if provided - if (!range.empty()) { - request.SetRange(range); - fprintf(stderr, "[CPP-V2] [DEBUG] GetObject: Setting range=%s\n", range.c_str()); - } - - Aws::Map kmsContextMap; - fill_context(kmsContextMap, metadata); - - // Log the encryption context map size and contents - fprintf(stderr, "[CPP-V2] [DEBUG] GetObject: encryption context map size=%zu\n", kmsContextMap.size()); - for (const auto& pair : kmsContextMap) { - fprintf(stderr, "[CPP-V2] [DEBUG] GetObject: context['%s']='%s'\n", - pair.first.c_str(), pair.second.c_str()); - } - - fprintf(stderr, "[CPP-V2] [DEBUG] GetObject: calling client->GetObject() for key=%s\n", key.c_str()); - - // Keep outcome alive to ensure stream remains valid - auto outcome = client->GetObject(request, kmsContextMap); - - fprintf(stderr, "[CPP-V2] [DEBUG] GetObject: client->GetObject() returned for key=%s\n", key.c_str()); - - if (outcome.IsSuccess()) { - // Read the stream completely before outcome goes out of scope - auto &stream = outcome.GetResult().GetBody(); - std::stringstream buffer; - buffer << stream.rdbuf(); - std::string content = buffer.str(); - - // Validate we read something - if (content.empty() && stream.fail()) { - fprintf(stderr, "[CPP-V2] GetObject error: Failed to read stream for bucket=%s, key=%s\n", - bucket.c_str(), key.c_str()); - auto msg = make_error("Failed to read response stream", 500); - return send_response(connection, 500, msg); - } - - fprintf(stderr, "[CPP-V2] GetObject success: bucket=%s, key=%s, size=%zu bytes\n", - bucket.c_str(), key.c_str(), content.length()); - - // Create and send response - struct MHD_Response *response = MHD_create_response_from_buffer( - content.length(), (void *)content.data(), MHD_RESPMEM_MUST_COPY); - - // Add keep-alive header - MHD_add_response_header(response, "Connection", "keep-alive"); - MHD_add_response_header(response, "Keep-Alive", "timeout=30, max=100"); - - MHD_Result ret = MHD_queue_response(connection, 200, response); - MHD_destroy_response(response); - - return ret; - } else { - // Enhanced error logging with thread info - auto error = outcome.GetError(); - fprintf(stderr, "[CPP-V2] [DEBUG] GetObject FAILED: thread=%lu, key=%s\n", - (unsigned long)std::hash{}(thread_id), key.c_str()); - fprintf(stderr, "[CPP-V2] [DEBUG] GetObject error details:\n"); - fprintf(stderr, "[CPP-V2] [DEBUG] - Message: %s\n", error.GetMessage().c_str()); - fprintf(stderr, "[CPP-V2] [DEBUG] - ExceptionName: %s\n", error.GetExceptionName().c_str()); - fprintf(stderr, "[CPP-V2] [DEBUG] - ResponseCode: %d\n", (int)error.GetResponseCode()); - fprintf(stderr, "[CPP-V2] [DEBUG] - ShouldRetry: %s\n", error.ShouldRetry() ? "true" : "false"); - - auto msg = make_error(outcome.GetError().GetMessage(), 500); - fprintf(stderr, "[CPP-V2] GetObject AWS error: %s\n", msg.c_str()); - return send_response(connection, 500, msg); - } - } catch (const std::exception &e) { - fprintf(stderr, "[CPP-V2] [DEBUG] GetObject EXCEPTION: thread=%lu, key=%s, what=%s\n", - (unsigned long)std::hash{}(thread_id), key.c_str(), e.what()); - auto msg = make_error(e.what(), 500); - return send_response(connection, 500, msg); - } catch (...) { - fprintf(stderr, "[CPP-V2] [DEBUG] GetObject UNKNOWN EXCEPTION: thread=%lu, key=%s\n", - (unsigned long)std::hash{}(thread_id), key.c_str()); - auto msg = make_error("Unknown error in GetObject", 500); - return send_response(connection, 500, msg); - } -} - -MHD_Result handle_put_object(struct MHD_Connection *connection, - std::string bucket, - std::string key, - std::string client_id, - std::string body, - std::string metadata) { - fprintf(stderr, "[CPP-V2] PutObject request: bucket=%s, key=%s, client_id=%s, body_size=%zu\n", - bucket.c_str(), key.c_str(), client_id.c_str(), body.length()); - - auto client = get_client(client_id); - if (!client) { - fprintf(stderr, "[CPP-V2] PutObject error: Client not found for client_id=%s\n", client_id.c_str()); - return send_response(connection, 404, "{\"error\":\"Client not found\"}"); - } - - try { - // Create owned copy of body data to ensure it lives through the S3 operation - auto body_ptr = std::make_shared(body); - - Aws::Map kmsContextMap; - fill_context(kmsContextMap, metadata); - - Aws::S3::Model::PutObjectRequest request; - request.SetBucket(bucket); - request.SetKey(key); - - // Create stream from owned body data - auto stream = std::make_shared(*body_ptr); - request.SetBody(stream); - - // Synchronous call - waits for S3 operation to complete - // body_ptr keeps the data alive through this entire operation - auto outcome = client->PutObject(request, kmsContextMap); - if (outcome.IsSuccess()) { - fprintf(stderr, "[CPP-V2] PutObject success: bucket=%s, key=%s\n", bucket.c_str(), key.c_str()); - json response = {{"bucket", bucket}, {"key", key}}; - return send_response(connection, 200, response.dump()); - } else { - auto msg = make_error(outcome.GetError().GetMessage(), 500); - fprintf(stderr, "[CPP-V2] PutObject AWS error: %s\n", msg.c_str()); - return send_response(connection, 500, msg); - } - } catch (const std::exception &e) { - fprintf(stderr, "[CPP-V2] PutObject exception: %s\n", e.what()); - auto msg = make_error(e.what(), 500); - return send_response(connection, 500, msg); - } -} - -void request_completed(void *cls, struct MHD_Connection *connection, - void **con_cls, enum MHD_RequestTerminationCode toe) { - // Clean up the request-specific context when request is truly complete - // This is called AFTER all handlers have returned and the response has been sent - - // Log why the request was terminated - const char* reason = "UNKNOWN"; - switch (toe) { - case MHD_REQUEST_TERMINATED_COMPLETED_OK: - reason = "COMPLETED_OK"; - break; - case MHD_REQUEST_TERMINATED_WITH_ERROR: - reason = "WITH_ERROR"; - break; - case MHD_REQUEST_TERMINATED_TIMEOUT_REACHED: - reason = "TIMEOUT_REACHED"; - break; - case MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN: - reason = "DAEMON_SHUTDOWN"; - break; - case MHD_REQUEST_TERMINATED_READ_ERROR: - reason = "READ_ERROR"; - break; - case MHD_REQUEST_TERMINATED_CLIENT_ABORT: - reason = "CLIENT_ABORT"; - break; - } - fprintf(stderr, "[CPP-V2] request_completed called, reason=%s, con_cls=%p\n", - reason, *con_cls); - - if (*con_cls != nullptr) { - std::string *body = static_cast(*con_cls); - delete body; // Safe to delete now - all synchronous operations are complete - *con_cls = nullptr; - } -} - -MHD_Result request_handler(void *cls, struct MHD_Connection *connection, - const char *url, const char *method, - const char *version, const char *upload_data, - size_t *upload_data_size, void **con_cls) { - try { - std::string method_str(method); - std::string url_str(url); - bool is_push = method_str == "POST" || method_str == "PUT"; - - // LOG: Every request entry (even first-time calls) - if (*con_cls == nullptr) { - fprintf(stderr, "[CPP-V2] REQUEST START: method=%s, url=%s, version=%s, con_cls=NULL, upload_data_size=%zu\n", - method, url, version, *upload_data_size); - } - - // Initialize request context on first call - if (*con_cls == nullptr) { - // Allocate unique state for each request to avoid race conditions - *con_cls = new std::string(); - fprintf(stderr, "[CPP-V2] REQUEST INIT: allocated new request context for %s %s\n", method, url); - return MHD_YES; - } - - // LOG: Subsequent calls - if (is_push && *upload_data_size > 0) { - fprintf(stderr, "[CPP-V2] REQUEST DATA: %s %s receiving %zu bytes\n", method, url, *upload_data_size); - } else if (*upload_data_size == 0) { - fprintf(stderr, "[CPP-V2] REQUEST COMPLETE: %s %s ready for processing\n", method, url); - } - - // Accumulate request body data for POST/PUT requests - if (is_push && *upload_data_size > 0) { - std::string *body = static_cast(*con_cls); - body->append(upload_data, *upload_data_size); - *upload_data_size = 0; - return MHD_YES; - } - - // At this point, *upload_data_size == 0, meaning we have all the data - // Now we can safely process the request - - // LOG: About to process request - fprintf(stderr, "[CPP-V2] PROCESSING: %s %s\n", method, url); - - // Handle client creation endpoint - if (is_push && url_str == "/client") { - fprintf(stderr, "[CPP-V2] Handling /client endpoint\n"); - std::string *body = static_cast(*con_cls); - MHD_Result result = handle_create_client(connection, *body); - fprintf(stderr, "[CPP-V2] /client handler returned: %d\n", result); - return result; - } - - // Handle object operations - if (url_str.find("/object/") == 0) { - fprintf(stderr, "[CPP-V2] Handling /object/ endpoint\n"); - std::string path = url_str.substr(8); // Remove "/object/" - size_t slash_pos = path.find('/'); - if (slash_pos != std::string::npos) { - std::string bucket = path.substr(0, slash_pos); - std::string key = path.substr(slash_pos + 1); - std::string client_id = get_header_value(connection, "clientid"); - std::string metadata = get_header_value(connection, "content-metadata"); - - fprintf(stderr, "[CPP-V2] Object operation: bucket=%s, key=%s, client_id=%s, method=%s\n", - bucket.c_str(), key.c_str(), client_id.c_str(), method); - - if (method_str == "GET") { - fprintf(stderr, "[CPP-V2] Dispatching to handle_get_object\n"); - std::string range = get_header_value(connection, "Range"); - MHD_Result result = handle_get_object(connection, bucket, key, client_id, metadata, range); - fprintf(stderr, "[CPP-V2] handle_get_object returned: %d\n", result); - return result; - } else if (method_str == "PUT") { - fprintf(stderr, "[CPP-V2] Dispatching to handle_put_object\n"); - std::string *body = static_cast(*con_cls); - MHD_Result result = handle_put_object(connection, bucket, key, client_id, *body, metadata); - fprintf(stderr, "[CPP-V2] handle_put_object returned: %d\n", result); - return result; - } else { - fprintf(stderr, "[CPP-V2] Method not allowed: %s\n", method); - return send_response(connection, 405, "{\"error\":\"Method not allowed\"}"); - } - } - } - - // Return error for unrecognized endpoints - fprintf(stderr, "[CPP-V2] ERROR: Unrecognized endpoint: %s %s\n", method, url); - return send_response(connection, 404, - "{\"error\":\"Not idea what is happening\"}"); - } catch (const std::exception &e) { - fprintf(stderr, "[CPP-V2] FATAL: Unhandled exception in request_handler: %s (method=%s, url=%s)\n", - e.what(), method, url); - // Try to send error response, but connection might already be broken - try { - return send_response(connection, 500, - "{\"error\":\"Internal server error: unhandled exception\"}"); - } catch (...) { - fprintf(stderr, "[CPP-V2] FATAL: Failed to send error response\n"); - return MHD_NO; - } - } catch (...) { - fprintf(stderr, "[CPP-V2] FATAL: Unknown exception in request_handler (method=%s, url=%s)\n", - method, url); - // Try to send error response, but connection might already be broken - try { - return send_response(connection, 500, - "{\"error\":\"Internal server error: unknown exception\"}"); - } catch (...) { - fprintf(stderr, "[CPP-V2] FATAL: Failed to send error response\n"); - return MHD_NO; - } - } -} - -// Error log callback for libmicrohttpd -void log_mhd_error(void* cls, const char* fmt, va_list ap) { - fprintf(stderr, "[CPP-V2] [MHD-ERROR] "); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); -} - -// Connection notification callback - called when a client connects -MHD_Result notify_connection(void *cls, - struct MHD_Connection *connection, - void **socket_context, - enum MHD_ConnectionNotificationCode toe) { - if (toe == MHD_CONNECTION_NOTIFY_STARTED) { - fprintf(stderr, "[CPP-V2] [MHD-CONNECT] New connection started\n"); - } else if (toe == MHD_CONNECTION_NOTIFY_CLOSED) { - fprintf(stderr, "[CPP-V2] [MHD-DISCONNECT] Connection closed\n"); - } - return MHD_YES; -} - -int main() { - Aws::SDKOptions options; - - // Configure AWS SDK logging to output to stderr (which goes to server.log) - // Using Debug level to capture all SDK activity including CryptoModule errors - options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Debug; - options.loggingOptions.logger_create_fn = []() { - return std::make_shared( - Aws::Utils::Logging::LogLevel::Debug - ); - }; - - fprintf(stderr, "[CONFIG] AWS SDK logging enabled at Debug level\n"); - - Aws::InitAPI(options); - - // Detect CPU core count and configure threading - unsigned int num_cores = std::thread::hardware_concurrency(); - if (num_cores == 0) { - num_cores = 4; - fprintf(stderr, "[CPP-V2] [WARNING] CPU core detection failed, defaulting to %u cores\n", num_cores); - } - - g_thread_pool_size = num_cores * 2; - unsigned int connection_limit = g_thread_pool_size; - - // Log configuration - fprintf(stderr, "[CONFIG] Detected CPU cores: %u\n", num_cores); - fprintf(stderr, "[CONFIG] Thread pool size: %u\n", g_thread_pool_size); - fprintf(stderr, "[CONFIG] Connection limit: %u\n", connection_limit); - fprintf(stderr, "[CONFIG] Each S3 client will use 512 max connections\n"); - - int port = 8085; - - struct MHD_Daemon *daemon = - MHD_start_daemon(MHD_USE_POLL_INTERNALLY | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG, - port, NULL, NULL, - &request_handler, NULL, - MHD_OPTION_EXTERNAL_LOGGER, log_mhd_error, NULL, - MHD_OPTION_NOTIFY_CONNECTION, notify_connection, NULL, - MHD_OPTION_NOTIFY_COMPLETED, request_completed, NULL, - MHD_OPTION_THREAD_POOL_SIZE, g_thread_pool_size, - MHD_OPTION_CONNECTION_LIMIT, connection_limit, - MHD_OPTION_CONNECTION_TIMEOUT, 10, - MHD_OPTION_END); - - if (!daemon) { - fprintf(stderr, "[CPP-V2] Failed to start server on port %d\n", port); - Aws::ShutdownAPI(options); - return 1; - } - - fprintf(stderr, "Server running on port %d\n", port); - sleep(10000); - - MHD_stop_daemon(daemon); - Aws::ShutdownAPI(options); - fprintf(stderr, "Ending server\n"); - return 0; -} diff --git a/test-server/cpp-v2-transition-server/aws-sdk-cpp b/test-server/cpp-v2-transition-server/aws-sdk-cpp index cec1f193..9110b0ff 160000 --- a/test-server/cpp-v2-transition-server/aws-sdk-cpp +++ b/test-server/cpp-v2-transition-server/aws-sdk-cpp @@ -1 +1 @@ -Subproject commit cec1f1933be672f65627c11ff2d853e07c5b3ff4 +Subproject commit 9110b0ff85094134a4f78316485fd7fe754a2a9c diff --git a/test-server/cpp-v3-server/aws-sdk-cpp b/test-server/cpp-v3-server/aws-sdk-cpp index cec1f193..9110b0ff 160000 --- a/test-server/cpp-v3-server/aws-sdk-cpp +++ b/test-server/cpp-v3-server/aws-sdk-cpp @@ -1 +1 @@ -Subproject commit cec1f1933be672f65627c11ff2d853e07c5b3ff4 +Subproject commit 9110b0ff85094134a4f78316485fd7fe754a2a9c diff --git a/test-server/cpp-v3-server/main.cpp b/test-server/cpp-v3-server/main.cpp index 4e7227df..169fa517 100644 --- a/test-server/cpp-v3-server/main.cpp +++ b/test-server/cpp-v3-server/main.cpp @@ -296,6 +296,11 @@ MHD_Result handle_create_client(struct MHD_Connection *connection, clientConfig.maxConnections = 512; // Large pool per client clientConfig.retryStrategy = Aws::Client::InitRetryStrategy("standard"); + // Increase timeouts for CI environments where SSL handshakes can be slow + // Default connectTimeoutMs is 1000ms, which is too short for busy CI runners + clientConfig.connectTimeoutMs = 10000; // 10 seconds for SSL connection establishment + clientConfig.requestTimeoutMs = 30000; // 30 seconds for complete request/response + // Disable automatic checksum calculation for encrypted streams // The ChecksumInterceptor cannot handle non-seekable SymmetricCryptoStream // which causes intermittent "BadDigest: CRC64NVME you specified did not match" errors diff --git a/test-server/go-v3-server/Makefile b/test-server/go-v3-server/Makefile deleted file mode 100644 index 80928dbd..00000000 --- a/test-server/go-v3-server/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -# Makefile for S3 Encryption Client Testing - -.PHONY: build-server start-server stop-server wait-for-server - -PID_FILE := server.pid -PORT := 8082 - -build-server: - @echo "Building Go V3 server..." - go mod tidy - -start-server: - @echo "Starting Go V3 server..." - AWS_ACCESS_KEY_ID="$$AWS_ACCESS_KEY_ID" \ - AWS_SECRET_ACCESS_KEY="$$AWS_SECRET_ACCESS_KEY" \ - AWS_SESSION_TOKEN="$$AWS_SESSION_TOKEN" \ - AWS_REGION="us-west-2" \ - go run . > server.log 2>&1 & echo $$! > $(PID_FILE) - @echo "Go V3 server starting..." - -stop-server: - @echo "Stopping server on port $(PORT)..." - @lsof -ti:$(PORT) | xargs kill -9 2>/dev/null || true - @if [ -f $(PID_FILE) ]; then \ - pkill -P $$(cat $(PID_FILE)) 2>/dev/null || true; \ - kill -9 $$(cat $(PID_FILE)) 2>/dev/null || true; \ - rm -f $(PID_FILE); \ - fi - @rm -f server.log - @echo "Server stopped" - -wait-for-server: - $(MAKE) -C .. wait-for-port PORT=$(PORT) - -duvet: - duvet report - -view-report-mac: - open .duvet/reports/report.html diff --git a/test-server/go-v3-server/README.md b/test-server/go-v3-server/README.md deleted file mode 100644 index cf1692b6..00000000 --- a/test-server/go-v3-server/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# S3EC Go V3 Test Server - -This is the Go implementation of the S3ECTestServer framework for S3EC Go V3. It provides a server implementation for testing Go S3 Encryption Client V3 functionality. - -## Overview - -The S3EC Go test server implements the S3ECTestServer service defined in the shared Smithy model. It provides endpoints for: - -- Creating S3 Encryption Clients -- Putting objects with encryption -- Getting and decrypting objects - -## Usage - -To run the server: - -```console -go run . -``` - -This will start the server running on port `8082`. - -The server is used as part of the testing framework to verify cross-language compatibility of the S3 Encryption Client implementations. diff --git a/test-server/go-v3-server/go.mod b/test-server/go-v3-server/go.mod deleted file mode 100644 index 014a64da..00000000 --- a/test-server/go-v3-server/go.mod +++ /dev/null @@ -1,31 +0,0 @@ -module github.com/aws/amazon-s3-encryption-client-python/test-server/go-server - -go 1.21 - -require ( - github.com/aws/amazon-s3-encryption-client-go/v3 v3.1.0 - github.com/aws/aws-sdk-go-v2 v1.24.0 - github.com/aws/aws-sdk-go-v2/config v1.26.1 - github.com/aws/aws-sdk-go-v2/service/kms v1.27.4 - github.com/aws/aws-sdk-go-v2/service/s3 v1.47.5 - github.com/google/uuid v1.5.0 - github.com/gorilla/mux v1.8.1 -) - -require ( - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.16.12 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.9 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.9 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 // indirect - github.com/aws/smithy-go v1.19.0 // indirect -) diff --git a/test-server/go-v3-server/go.sum b/test-server/go-v3-server/go.sum deleted file mode 100644 index 4fc073e0..00000000 --- a/test-server/go-v3-server/go.sum +++ /dev/null @@ -1,46 +0,0 @@ -github.com/aws/amazon-s3-encryption-client-go/v3 v3.1.0 h1:P4dOTmTkEb8Dj/LuAoA4bqRZZrDq4DqZQI88vdMaj18= -github.com/aws/amazon-s3-encryption-client-go/v3 v3.1.0/go.mod h1:olnwkBTbWjaJCaGOHohvJu98q40GiJZuDHLXj751mII= -github.com/aws/aws-sdk-go-v2 v1.24.0 h1:890+mqQ+hTpNuw0gGP6/4akolQkSToDJgHfQE7AwGuk= -github.com/aws/aws-sdk-go-v2 v1.24.0/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 h1:OCs21ST2LrepDfD3lwlQiOqIGp6JiEUqG84GzTDoyJs= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4/go.mod h1:usURWEKSNNAcAZuzRn/9ZYPT8aZQkR7xcCtunK/LkJo= -github.com/aws/aws-sdk-go-v2/config v1.26.1 h1:z6DqMxclFGL3Zfo+4Q0rLnAZ6yVkzCRxhRMsiRQnD1o= -github.com/aws/aws-sdk-go-v2/config v1.26.1/go.mod h1:ZB+CuKHRbb5v5F0oJtGdhFTelmrxd4iWO1lf0rQwSAg= -github.com/aws/aws-sdk-go-v2/credentials v1.16.12 h1:v/WgB8NxprNvr5inKIiVVrXPuuTegM+K8nncFkr1usU= -github.com/aws/aws-sdk-go-v2/credentials v1.16.12/go.mod h1:X21k0FjEJe+/pauud82HYiQbEr9jRKY3kXEIQ4hXeTQ= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 h1:w98BT5w+ao1/r5sUuiH6JkVzjowOKeOJRHERyy1vh58= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10/go.mod h1:K2WGI7vUvkIv1HoNbfBA1bvIZ+9kL3YVmWxeKuLQsiw= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 h1:v+HbZaCGmOwnTTVS86Fleq0vPzOd7tnJGbFhP0stNLs= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9/go.mod h1:Xjqy+Nyj7VDLBtCMkQYOw1QYfAEZCVLrfI0ezve8wd4= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 h1:N94sVhRACtXyVcjXxrwK1SKFIJrA9pOJ5yu2eSHnmls= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9/go.mod h1:hqamLz7g1/4EJP+GH5NBhcUMLjW+gKLQabgyz6/7WAU= -github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 h1:GrSw8s0Gs/5zZ0SX+gX4zQjRnRsMJDJ2sLur1gRBhEM= -github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9 h1:ugD6qzjYtB7zM5PN/ZIeaAIyefPaD82G8+SJopgvUpw= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9/go.mod h1:YD0aYBWCrPENpHolhKw2XDlTIWae2GKXT1T4o6N6hiM= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.9 h1:/90OR2XbSYfXucBMJ4U14wrjlfleq/0SB6dZDPncgmo= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.9/go.mod h1:dN/Of9/fNZet7UrQQ6kTDo/VSwKPIq94vjlU16bRARc= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9 h1:Nf2sHxjMJR8CSImIVCONRi4g0Su3J+TSTbS7G0pUeMU= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9/go.mod h1:idky4TER38YIjr2cADF1/ugFMKvZV7p//pVeV5LZbF0= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.9 h1:iEAeF6YC3l4FzlJPP9H3Ko1TXpdjdqWffxXjp8SY6uk= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.9/go.mod h1:kjsXoK23q9Z/tLBrckZLLyvjhZoS+AGrzqzUfEClvMM= -github.com/aws/aws-sdk-go-v2/service/kms v1.27.4 h1:c75pHGBV3h6WOsIjbJhLyOnlCPXzap45nbiP2Z5jk5M= -github.com/aws/aws-sdk-go-v2/service/kms v1.27.4/go.mod h1:D9FVDkZjkZnnFHymJ3fPVz0zOUlNSd0xcIIVmmrAac8= -github.com/aws/aws-sdk-go-v2/service/s3 v1.47.5 h1:Keso8lIOS+IzI2MkPZyK6G0LYcK3My2LQ+T5bxghEAY= -github.com/aws/aws-sdk-go-v2/service/s3 v1.47.5/go.mod h1:vADO6Jn+Rq4nDtfwNjhgR84qkZwiC6FqCaXdw/kYwjA= -github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 h1:ldSFWz9tEHAwHNmjx2Cvy1MjP5/L9kNoR0skc6wyOOM= -github.com/aws/aws-sdk-go-v2/service/sso v1.18.5/go.mod h1:CaFfXLYL376jgbP7VKC96uFcU8Rlavak0UlAwk1Dlhc= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 h1:2k9KmFawS63euAkY4/ixVNsYYwrwnd5fIvgEKkfZFNM= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5/go.mod h1:W+nd4wWDVkSUIox9bacmkBP5NMFQeTJ/xqNabpzSR38= -github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 h1:5UYvv8JUvllZsRnfrcMQ+hJ9jNICmcgKPAO1CER25Wg= -github.com/aws/aws-sdk-go-v2/service/sts v1.26.5/go.mod h1:XX5gh4CB7wAs4KhcF46G6C8a2i7eupU19dcAAE+EydU= -github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM= -github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= -github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= diff --git a/test-server/go-v3-server/main.go b/test-server/go-v3-server/main.go deleted file mode 100644 index 0384c5ff..00000000 --- a/test-server/go-v3-server/main.go +++ /dev/null @@ -1,370 +0,0 @@ -package main - -import ( - "context" - "encoding/json" - "fmt" - "io" - "log" - "net/http" - "strings" - "sync" - - "github.com/aws/amazon-s3-encryption-client-go/v3/client" - "github.com/aws/amazon-s3-encryption-client-go/v3/materials" - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/config" - "github.com/aws/aws-sdk-go-v2/service/kms" - "github.com/aws/aws-sdk-go-v2/service/s3" - "github.com/google/uuid" - "github.com/gorilla/mux" -) - -// Server represents the Go test server -type Server struct { - clientCache map[string]*client.S3EncryptionClientV3 - kmsClient *kms.Client - mu sync.RWMutex -} - -// CreateClientInput represents the input for creating a client -type CreateClientInput struct { - Config S3ECConfig `json:"config"` -} - -// CreateClientOutput represents the output for creating a client -type CreateClientOutput struct { - ClientID string `json:"clientId"` -} - -// S3ECConfig represents the S3 encryption client configuration -type S3ECConfig struct { - EnableLegacyUnauthenticatedModes bool `json:"enableLegacyUnauthenticatedModes"` - EnableDelayedAuthenticationMode bool `json:"enableDelayedAuthenticationMode"` - EnableLegacyWrappingAlgorithms bool `json:"enableLegacyWrappingAlgorithms"` - SetBufferSize int64 `json:"setBufferSize"` - KeyMaterial KeyMaterial `json:"keyMaterial"` -} - -// KeyMaterial represents the key material for encryption -type KeyMaterial struct { - RSAKey []byte `json:"rsaKey"` - AESKey []byte `json:"aesKey"` - KMSKeyID string `json:"kmsKeyId"` -} - -// PutObjectOutput represents the output for put object operation -type PutObjectOutput struct { - Bucket string `json:"bucket"` - Key string `json:"key"` - Metadata []string `json:"metadata"` -} - -// ErrorResponse represents an error response -type ErrorResponse struct { - Type string `json:"__type"` - Message string `json:"message"` -} - -// NewServer creates a new server instance -func NewServer() (*Server, error) { - cfg, err := config.LoadDefaultConfig( - context.TODO(), - config.WithRegion("us-west-2"), - config.WithRetryMaxAttempts(5), - config.WithRetryMode(aws.RetryModeAdaptive), - ) - if err != nil { - return nil, fmt.Errorf("failed to load AWS config: %w", err) - } - - return &Server{ - clientCache: make(map[string]*client.S3EncryptionClientV3), - kmsClient: kms.NewFromConfig(cfg), - }, nil -} - -// createGenericServerError creates a generic server error response -func (s *Server) createGenericServerError(w http.ResponseWriter, message string, statusCode int) { - // Echo error to console - log.Printf("[Go V3] GenericServerError: %s (Status: %d)", message, statusCode) - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(statusCode) - json.NewEncoder(w).Encode(ErrorResponse{ - Type: "software.amazon.encryption.s3#GenericServerError", - Message: message, - }) -} - -// createS3EncryptionClientError creates an S3 encryption client error response -func (s *Server) createS3EncryptionClientError(w http.ResponseWriter, message string, statusCode int) { - // Echo error to console - log.Printf("[Go V3] S3EncryptionClientError: %s (Status: %d)", message, statusCode) - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(statusCode) - json.NewEncoder(w).Encode(ErrorResponse{ - Type: "software.amazon.encryption.s3#S3EncryptionClientError", - Message: message, - }) -} - -// metadataStringToMap converts metadata string to map -func metadataStringToMap(mdString string) (map[string]string, error) { - md := make(map[string]string) - if mdString == "" { - return md, nil - } - - mdList := strings.Split(mdString, ",") - for _, entry := range mdList { - // Split on "]:[" to separate key and value - parts := strings.Split(entry, "]:[") - if len(parts) == 2 { - // Remove remaining brackets from start and end - key := parts[0][1:] // Remove first character - value := parts[1][:len(parts[1])-1] // Remove last character - md[key] = value - } else { - return nil, fmt.Errorf("malformed metadata list entry: %s", entry) - } - } - return md, nil -} - -// createClient handles POST /client -func (s *Server) createClient(w http.ResponseWriter, r *http.Request) { - // Read body - body, err := io.ReadAll(r.Body) - if err != nil { - s.createGenericServerError(w, "Failed to read request body", http.StatusBadRequest) - return - } - - var input CreateClientInput - if err := json.Unmarshal(body, &input); err != nil { - s.createGenericServerError(w, "Invalid JSON in request body", http.StatusBadRequest) - return - } - - cfg, err := config.LoadDefaultConfig( - context.TODO(), - config.WithRegion("us-west-2"), - config.WithRetryMaxAttempts(5), - config.WithRetryMode(aws.RetryModeAdaptive), - ) - if err != nil { - s.createS3EncryptionClientError(w, fmt.Sprintf("Failed to load AWS config: %v", err), http.StatusInternalServerError) - return - } - - // Create KMS keyring - kmsClient := kms.NewFromConfig(cfg) - keyring := materials.NewKmsKeyring(kmsClient, input.Config.KeyMaterial.KMSKeyID, func(options *materials.KeyringOptions) { - options.EnableLegacyWrappingAlgorithms = input.Config.EnableLegacyWrappingAlgorithms - }) - cmm, err := materials.NewCryptographicMaterialsManager(keyring) - - if err != nil { - s.createS3EncryptionClientError(w, fmt.Sprintf("Failed to create CMM: %v", err), http.StatusInternalServerError) - return - } - - // Create S3 encryption client - var s3EncryptionClient *client.S3EncryptionClientV3 - s3PlaintextClient := s3.NewFromConfig(cfg) - s3EncryptionClient, err = client.New(s3PlaintextClient, cmm) - - if err != nil { - s.createS3EncryptionClientError(w, fmt.Sprintf("Failed to create S3EC: %v", err), http.StatusInternalServerError) - return - } - - // Generate client ID - clientID := uuid.New().String() - - // Store client in cache (protected by mutex) - s.mu.Lock() - s.clientCache[clientID] = s3EncryptionClient - s.mu.Unlock() - - // Return response - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(CreateClientOutput{ - ClientID: clientID, - }) -} - -// putObject handles PUT /object/{bucket}/{key} -func (s *Server) putObject(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - bucket := vars["bucket"] - key := vars["key"] - - clientID := r.Header.Get("ClientID") - if clientID == "" { - s.createGenericServerError(w, "ClientID header is required", http.StatusBadRequest) - return - } - - // Get client from cache (protected by mutex) - s.mu.RLock() - client, exists := s.clientCache[clientID] - s.mu.RUnlock() - - if !exists { - s.createGenericServerError(w, fmt.Sprintf("No client found for ClientID: %s", clientID), http.StatusNotFound) - return - } - - // Read body - body, err := io.ReadAll(r.Body) - if err != nil { - s.createGenericServerError(w, "Failed to read request body", http.StatusBadRequest) - return - } - - // Get metadata from header - metadataHeader := r.Header.Get("Content-Metadata") - encCtx, err := metadataStringToMap(metadataHeader) - - // Create context with encryption context - ctx := context.Background() - encryptionContext := context.WithValue(ctx, "EncryptionContext", encCtx) - if err != nil { - s.createS3EncryptionClientError(w, fmt.Sprintf("Failed to parse metadata: %v", err), http.StatusBadRequest) - return - } - - // Create put object input - putInput := &s3.PutObjectInput{ - Bucket: aws.String(bucket), - Key: aws.String(key), - Body: strings.NewReader(string(body)), - } - - // Add metadata if present - if len(encCtx) > 0 { - putInput.Metadata = encCtx - } - - // Make the put object request using the encryption client - _, err = client.PutObject(encryptionContext, putInput) - if err != nil { - s.createS3EncryptionClientError(w, fmt.Sprintf("Failed to put object: %v", err), http.StatusInternalServerError) - return - } - - log.Printf("[Go V3] PutObject SUCCESS: Bucket=%s, Key=%s", bucket, key) - - // Return response - w.Header().Set("Content-Type", "application/json") - response := PutObjectOutput{ - Bucket: bucket, - Key: key, - Metadata: []string{}, // Return empty metadata list as per the model - } - json.NewEncoder(w).Encode(response) -} - -// getObject handles GET /object/{bucket}/{key} -func (s *Server) getObject(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - bucket := vars["bucket"] - key := vars["key"] - - clientID := r.Header.Get("ClientID") - if clientID == "" { - s.createGenericServerError(w, "ClientID header is required", http.StatusBadRequest) - return - } - - // Get client from cache (protected by mutex) - s.mu.RLock() - client, exists := s.clientCache[clientID] - s.mu.RUnlock() - - if !exists { - s.createGenericServerError(w, fmt.Sprintf("No client found for ClientID: %s", clientID), http.StatusNotFound) - return - } - - // Get metadata from header - metadataHeader := r.Header.Get("Content-Metadata") - encCtx, err := metadataStringToMap(metadataHeader) - - // Create context with encryption context - // Note: S3EC Go V3 does not validate encryption context on decrypt, so the value provided here - // will not be validated against the encryption context stored on the object. - ctx := context.Background() - encryptionContext := context.WithValue(ctx, "EncryptionContext", encCtx) - if err != nil { - s.createS3EncryptionClientError(w, fmt.Sprintf("Failed to parse metadata: %v", err), http.StatusBadRequest) - return - } - - // Create get object input - getInput := &s3.GetObjectInput{ - Bucket: aws.String(bucket), - Key: aws.String(key), - } - - // Make the get object request using the encryption client - result, err := client.GetObject(encryptionContext, getInput) - if err != nil { - errMsg := err.Error() - // Shim the S3EC error message to the error message expected by the test server. - // We don't want to change the S3EC error message but the test server expects a specific error message; - // This is the appropriate place to rewrite the error message. - if strings.Contains(errMsg, "to decrypt x-amz-cek-alg value `kms` you must enable legacyWrappingAlgorithms on the keyring") { - s.createS3EncryptionClientError(w, "Enable legacy wrapping algorithms to use legacy key wrapping algorithm: kms", http.StatusInternalServerError) - return - } - s.createS3EncryptionClientError(w, fmt.Sprintf("Failed to get object: %v", err), http.StatusInternalServerError) - return - } - defer result.Body.Close() - - // Read the body - body, err := io.ReadAll(result.Body) - if err != nil { - s.createS3EncryptionClientError(w, fmt.Sprintf("Failed to read object body: %v", err), http.StatusInternalServerError) - return - } - - // Convert metadata to string format - var metadataList []string - if result.Metadata != nil { - for k, v := range result.Metadata { - metadataList = append(metadataList, fmt.Sprintf("%s=%s", k, v)) - } - } - - metadataStr := strings.Join(metadataList, ",") - - log.Printf("[Go V3] GetObject SUCCESS: Bucket=%s, Key=%s", bucket, key) - - // Set response headers - w.Header().Set("Content-Metadata", metadataStr) - - // Return the body as response - w.Write(body) -} - -func main() { - server, err := NewServer() - if err != nil { - log.Fatalf("[Go V3] Failed to create Go V3 server: %v", err) - } - - r := mux.NewRouter() - - // Register routes - r.HandleFunc("/client", server.createClient).Methods("POST") - r.HandleFunc("/object/{bucket}/{key}", server.putObject).Methods("PUT") - r.HandleFunc("/object/{bucket}/{key}", server.getObject).Methods("GET") - - fmt.Println("[Go V3] Starting Go V3 server on :8082...") - log.Fatal(http.ListenAndServe(":8082", r)) -} diff --git a/test-server/go-v3-transition-server/local-go-s3ec b/test-server/go-v3-transition-server/local-go-s3ec index 912914ad..bf8a12f6 160000 --- a/test-server/go-v3-transition-server/local-go-s3ec +++ b/test-server/go-v3-transition-server/local-go-s3ec @@ -1 +1 @@ -Subproject commit 912914ad1c14942c3ea8638fb37f9e2c46445a84 +Subproject commit bf8a12f61694d750a13a44f0a691dd7ced0ff904 diff --git a/test-server/go-v4-server/local-go-s3ec b/test-server/go-v4-server/local-go-s3ec index 912914ad..bf8a12f6 160000 --- a/test-server/go-v4-server/local-go-s3ec +++ b/test-server/go-v4-server/local-go-s3ec @@ -1 +1 @@ -Subproject commit 912914ad1c14942c3ea8638fb37f9e2c46445a84 +Subproject commit bf8a12f61694d750a13a44f0a691dd7ced0ff904 diff --git a/test-server/java-tests/src/it/java/software/amazon/encryption/s3/RoundTripTests.java b/test-server/java-tests/src/it/java/software/amazon/encryption/s3/RoundTripTests.java index cf45006e..e6cfae84 100644 --- a/test-server/java-tests/src/it/java/software/amazon/encryption/s3/RoundTripTests.java +++ b/test-server/java-tests/src/it/java/software/amazon/encryption/s3/RoundTripTests.java @@ -213,7 +213,7 @@ public void crossLanguageTestKmsWithSubsetEncCtxFails(LanguageServerTarget encLa .build()); fail("Expected exception!"); } catch (S3EncryptionClientError e) { - if (decLang.getLanguageName().equals(RUBY_V3) || decLang.getLanguageName().equals(RUBY_V2_CURRENT) || decLang.getLanguageName().equals(RUBY_V2_TRANSITION)) { + if (decLang.getLanguageName().equals(RUBY_V3) || decLang.getLanguageName().equals(RUBY_V2_TRANSITION)) { assertTrue(e.getMessage().contains("Value of encryption context from envelope does not match the provided encryption context"), "Actual error: " + e.getMessage()); } else { assertTrue(e.getMessage().contains("Provided encryption context does not match information retrieved from S3"), "Actual error: " + e.getMessage()); @@ -277,7 +277,7 @@ public void crossLanguageTestKmsWithIncorrectEncCtxFails(LanguageServerTarget en .build()); fail("Expected exception!"); } catch (S3EncryptionClientError e) { - if (decLang.getLanguageName().equals(RUBY_V3) || decLang.getLanguageName().equals(RUBY_V2_CURRENT) || decLang.getLanguageName().equals(RUBY_V2_TRANSITION)) { + if (decLang.getLanguageName().equals(RUBY_V3) || decLang.getLanguageName().equals(RUBY_V2_TRANSITION)) { assertTrue(e.getMessage().contains("Value of encryption context from envelope does not match the provided encryption context"), "Actual error: " + e.getMessage()); } else { assertTrue(e.getMessage().contains("Provided encryption context does not match information retrieved from S3"), "Actual error: " + e.getMessage()); @@ -423,12 +423,12 @@ public void kmsV1LegacyFailsWhenLegacyDisabled(TestUtils.LanguageServerTarget la .build()); fail("Expected Exception"); } catch (S3EncryptionClientError e) { - if (language.getLanguageName().equals(NET_V3_CURRENT) || language.getLanguageName().equals(NET_V2_CURRENT) || language.getLanguageName().equals(NET_V3_TRANSITION) || language.getLanguageName().equals(NET_V4) - || language.getLanguageName().equals(CPP_V2_CURRENT) || language.getLanguageName().equals(CPP_V2_TRANSITION) || language.getLanguageName().equals(CPP_V3)) { + if (language.getLanguageName().equals(NET_V3_TRANSITION) || language.getLanguageName().equals(NET_V4) + || language.getLanguageName().equals(CPP_V2_TRANSITION) || language.getLanguageName().equals(CPP_V3)) { assertTrue(e.getMessage().contains( "The requested object is encrypted with V1 encryption schemas that have been disabled by client configuration" ), "Actual error:" + e.getMessage()); - } else if (language.getLanguageName().equals(RUBY_V3) || language.getLanguageName().equals(RUBY_V2_CURRENT) || language.getLanguageName().equals(RUBY_V2_TRANSITION)) { + } else if (language.getLanguageName().equals(RUBY_V3) || language.getLanguageName().equals(RUBY_V2_TRANSITION)) { assertTrue(e.getMessage().contains( "The requested object is encrypted with V1 encryption schemas that have been disabled by client configuration security_profile = :v2. Retry with :v2_and_legacy or re-encrypt the object." ), "Actual error:" + e.getMessage()); @@ -549,10 +549,6 @@ public void instructionFileWriteAndRead(LanguageServerTarget encLang, LanguageSe if (KMS_INSTRUCTION_FILE_UNSUPPORTED.contains(decLang.getLanguageName())) { throw new TestAbortedException("not testing " + encLang.getLanguageName()); } - // We skip PHP-V2-Current because it writes an instruction file that other languages may not read. - if (encLang.getLanguageName().equals("PHP-V2-Current")) { - throw new TestAbortedException("not testing " + encLang.getLanguageName()); - } S3ECTestServerClient encClient = testServerClientFor(encLang); S3ECTestServerClient decClient = testServerClientFor(decLang); final String objectKey = appendTestSuffix(String.format("write-%s-read-%s-instruction-file", encLang.getLanguageName(), decLang.getLanguageName())); diff --git a/test-server/java-tests/src/it/java/software/amazon/encryption/s3/TestUtils.java b/test-server/java-tests/src/it/java/software/amazon/encryption/s3/TestUtils.java index f2065115..2b9cd062 100644 --- a/test-server/java-tests/src/it/java/software/amazon/encryption/s3/TestUtils.java +++ b/test-server/java-tests/src/it/java/software/amazon/encryption/s3/TestUtils.java @@ -59,32 +59,25 @@ public class TestUtils { // vN-Transition: Proposed feature release version. Supports reading messages encrypted with key commitment. // vN+1: Proposed breaking release version. Supports reading/writing messages encrypted with key commitment. - public static final String JAVA_V3_CURRENT = "Java-V3-Current"; public static final String JAVA_V3_TRANSITION = "Java-V3-Transition"; public static final String JAVA_V4 = "Java-V4"; // No Python S3EC versions are released. Only test V3 as the "vN+1" version. public static final String PYTHON_V3 = "Python-V3"; - public static final String GO_V3_CURRENT = "Go-V3-Current"; public static final String GO_V3_TRANSITION = "Go-V3-Transition"; public static final String GO_V4 = "Go-V4"; - public static final String NET_V2_CURRENT = "NET-V2-Current"; - public static final String NET_V3_CURRENT = "NET-V3-Current"; public static final String NET_V2_TRANSITION = "NET-V2-Transition"; public static final String NET_V3_TRANSITION = "NET-V3-Transition"; public static final String NET_V4 = "NET-V4"; - public static final String CPP_V2_CURRENT = "CPP-V2-Current"; public static final String CPP_V2_TRANSITION = "CPP-V2-Transition"; public static final String CPP_V3 = "CPP-V3"; - public static final String RUBY_V2_CURRENT = "Ruby-V2-Current"; public static final String RUBY_V2_TRANSITION = "Ruby-V2-Transition"; public static final String RUBY_V3 = "Ruby-V3"; - public static final String PHP_V2_CURRENT = "PHP-V2-Current"; public static final String PHP_V2_TRANSITION = "PHP-V2-Transition"; public static final String PHP_V3 = "PHP-V3"; @@ -97,33 +90,25 @@ public class TestUtils { // Sets of unsupported features by language public static final Set ENCRYPTION_CONTEXT_ON_DECRYPT_UNSUPPORTED = - Set.of(GO_V3_CURRENT, PHP_V2_CURRENT, PHP_V2_TRANSITION, PHP_V3, NET_V2_CURRENT, NET_V3_CURRENT, NET_V3_TRANSITION, NET_V4); + Set.of(PHP_V2_TRANSITION, PHP_V3, NET_V3_TRANSITION, NET_V4); public static final Set ENCRYPTION_CONTEXT_ON_ENCRYPT_UNSUPPORTED = - Set.of(NET_V2_CURRENT, NET_V3_CURRENT, NET_V3_TRANSITION, NET_V4); + Set.of(NET_V3_TRANSITION, NET_V4); public static final Set RE_ENCRYPT_SUPPORTED = - Set.of(JAVA_V3_CURRENT, JAVA_V3_TRANSITION, JAVA_V4); + Set.of(JAVA_V3_TRANSITION, JAVA_V4); public static final Set RANGED_GETS_SUPPORTED = Set.of( - JAVA_V3_CURRENT, JAVA_V3_TRANSITION, JAVA_V4 - , CPP_V2_CURRENT, CPP_V2_TRANSITION, CPP_V3 + JAVA_V3_TRANSITION, JAVA_V4, CPP_V2_TRANSITION, CPP_V3 ); // Cpp only supports Raw AES public static final Set RAW_AES_SUPPORTED = - Set.of(JAVA_V3_CURRENT, JAVA_V3_TRANSITION, JAVA_V4 - , NET_V2_CURRENT, NET_V3_CURRENT, NET_V3_TRANSITION, NET_V4 - , RUBY_V2_TRANSITION, RUBY_V3 - , CPP_V2_CURRENT, CPP_V2_TRANSITION, CPP_V3 - ); + Set.of(JAVA_V3_TRANSITION, JAVA_V4, NET_V3_TRANSITION, NET_V4, RUBY_V2_TRANSITION, RUBY_V3, CPP_V2_TRANSITION, CPP_V3); public static final Set RAW_RSA_SUPPORTED = - Set.of(JAVA_V3_CURRENT, JAVA_V3_TRANSITION, JAVA_V4 - , NET_V2_CURRENT, NET_V3_CURRENT, NET_V3_TRANSITION, NET_V4 - , RUBY_V2_TRANSITION, RUBY_V3 - ); + Set.of(JAVA_V3_TRANSITION, JAVA_V4, NET_V3_TRANSITION, NET_V4, RUBY_V2_TRANSITION, RUBY_V3); // Intersection of RAW_AES_SUPPORTED and RAW_RSA_SUPPORTED public static final Set RAW_SUPPORTED = @@ -134,13 +119,11 @@ public class TestUtils { // .NET only supports decrypting instruction files using AES and RSA. // Python MUST support decrypting KMS instruction files, but does not yet. public static final Set KMS_INSTRUCTION_FILE_UNSUPPORTED = - Set.of(NET_V2_CURRENT, NET_V2_TRANSITION, NET_V3_CURRENT, NET_V3_TRANSITION, NET_V4); + Set.of(NET_V2_TRANSITION, NET_V3_TRANSITION, NET_V4); // Go does not write with instruction files public static final Set INSTRUCTION_FILE_PUT_UNSUPPORTED = - Set.of(GO_V3_CURRENT, GO_V3_TRANSITION, GO_V4, PYTHON_V3 - // Apparently C++ V2 Current does not work, even though it should - , CPP_V2_CURRENT); + Set.of(GO_V3_TRANSITION, GO_V4, PYTHON_V3); // Not implemented yet in Python. public static final Set INSTRUCTION_FILE_GET_UNSUPPORTED = @@ -159,22 +142,10 @@ public class TestUtils { PHP_V3 ); - public static final Set CURRENT_VERSIONS = - Set.of( - JAVA_V3_CURRENT, - GO_V3_CURRENT, - NET_V2_CURRENT, - NET_V3_CURRENT, - CPP_V2_CURRENT, - RUBY_V2_CURRENT, - PHP_V2_CURRENT - ); - public static final Set TRANSITION_VERSIONS = Set.of( JAVA_V3_TRANSITION, GO_V3_TRANSITION, - // NET_V2_TRANSITION, NET_V3_TRANSITION, CPP_V2_TRANSITION, PHP_V2_TRANSITION, @@ -196,23 +167,15 @@ public class TestUtils { static { final Map servers = new LinkedHashMap<>(); - servers.put(JAVA_V3_CURRENT, new LanguageServerTarget(JAVA_V3_CURRENT, "8080")); servers.put(PYTHON_V3, new LanguageServerTarget(PYTHON_V3, "8081")); - servers.put(GO_V3_CURRENT, new LanguageServerTarget(GO_V3_CURRENT, "8082")); - servers.put(NET_V2_CURRENT, new LanguageServerTarget(NET_V2_CURRENT, "8083")); - servers.put(NET_V3_CURRENT, new LanguageServerTarget(NET_V3_CURRENT, "8084")); - servers.put(CPP_V2_CURRENT, new LanguageServerTarget(CPP_V2_CURRENT, "8085")); servers.put(CPP_V2_TRANSITION, new LanguageServerTarget(CPP_V2_TRANSITION, "8097")); servers.put(CPP_V3, new LanguageServerTarget(CPP_V3, "8091")); - // servers.put(RUBY_V2_CURRENT, new LanguageServerTarget(RUBY_V2_CURRENT, "8086")); - servers.put(PHP_V2_CURRENT, new LanguageServerTarget(PHP_V2_CURRENT, "8087")); servers.put(GO_V4, new LanguageServerTarget(GO_V4, "8089")); servers.put(NET_V4, new LanguageServerTarget(NET_V4, "8090")); servers.put(RUBY_V3, new LanguageServerTarget(RUBY_V3, "8092")); servers.put(PHP_V3, new LanguageServerTarget(PHP_V3, "8093")); servers.put(JAVA_V3_TRANSITION, new LanguageServerTarget(JAVA_V3_TRANSITION, "8094")); servers.put(GO_V3_TRANSITION, new LanguageServerTarget(GO_V3_TRANSITION, "8095")); - // servers.put(NET_V2_TRANSITION, new LanguageServerTarget(NET_V2_TRANSITION, "8096")); servers.put(RUBY_V2_TRANSITION, new LanguageServerTarget(RUBY_V2_TRANSITION, "8098")); servers.put(PHP_V2_TRANSITION, new LanguageServerTarget(PHP_V2_TRANSITION, "8099")); servers.put(JAVA_V4, new LanguageServerTarget(JAVA_V4, "8088")); @@ -377,15 +340,6 @@ public static Stream clientsForTest() { .map(Arguments::of); } - /** - * Get stream of arguments for current version clients for testing. - */ - public static Stream currentClientsForTest() { - return serverMap.values().stream() - .filter(target -> CURRENT_VERSIONS.contains(target.getLanguageName())) - .map(Arguments::of); - } - /** * Get stream of arguments for transition version clients for testing. */ @@ -454,38 +408,6 @@ public static Stream encryptTransitionDecryptImproved() { ))); } - public static Stream encryptImprovedDecryptCurrent() { - return improvedClientsForTest() - .flatMap(encrypt -> currentClientsForTest() - .flatMap(decrypt -> Stream.of( - Arguments.of(encrypt.get()[0], decrypt.get()[0]) - ))); - } - - public static Stream encryptCurrentDecryptImproved() { - return currentClientsForTest() - .flatMap(encrypt -> improvedClientsForTest() - .flatMap(decrypt -> Stream.of( - Arguments.of(encrypt.get()[0], decrypt.get()[0]) - ))); - } - - public static Stream encryptTransitionDecryptCurrent() { - return transitionClientsForTest() - .flatMap(encrypt -> currentClientsForTest() - .flatMap(decrypt -> Stream.of( - Arguments.of(encrypt.get()[0], decrypt.get()[0]) - ))); - } - - public static Stream encryptCurrentDecryptTransition() { - return currentClientsForTest() - .flatMap(encrypt -> transitionClientsForTest() - .flatMap(decrypt -> Stream.of( - Arguments.of(encrypt.get()[0], decrypt.get()[0]) - ))); - } - /** * Provides a stream of arguments for parameterized tests that test cross-language compatibility * @return Stream of Arguments containing pairs of LanguageServerTarget for encryption and decryption diff --git a/test-server/java-v3-server/.duvet/.gitignore b/test-server/java-v3-server/.duvet/.gitignore deleted file mode 100644 index 93956e36..00000000 --- a/test-server/java-v3-server/.duvet/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -reports/ -requirements/ -specification/ \ No newline at end of file diff --git a/test-server/java-v3-server/.duvet/config.toml b/test-server/java-v3-server/.duvet/config.toml deleted file mode 100644 index 988fb5fa..00000000 --- a/test-server/java-v3-server/.duvet/config.toml +++ /dev/null @@ -1,21 +0,0 @@ -'$schema' = "https://awslabs.github.io/duvet/config/v0.4.0.json" - -[[source]] -pattern = "s3ec-staging/**/*.java" - -# Include required specifications here -[[specification]] -source = "specification/s3-encryption/data-format/content-metadata.md" -[[specification]] -source = "specification/s3-encryption/data-format/metadata-strategy.md" -[[specification]] -source = "specification/s3-encryption/encryption.md" -[[specification]] -source = "specification/s3-encryption/key-derivation.md" - -[report.html] -enabled = true - -# Enable snapshots to prevent requirement coverage regressions -[report.snapshot] -enabled = false diff --git a/test-server/java-v3-server/.gitignore b/test-server/java-v3-server/.gitignore deleted file mode 100644 index e660fd93..00000000 --- a/test-server/java-v3-server/.gitignore +++ /dev/null @@ -1 +0,0 @@ -bin/ diff --git a/test-server/java-v3-server/Makefile b/test-server/java-v3-server/Makefile deleted file mode 100644 index 59dcdff5..00000000 --- a/test-server/java-v3-server/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -# Makefile for S3 Encryption Client Testing - -.PHONY: build-server start-server stop-server wait-for-server - -PID_FILE := server.pid -PORT := 8080 - -build-server: - @echo "Building Java V3 server..." - ./gradlew --build-cache --parallel --no-daemon build - -start-server: - @echo "Starting Java V3 server..." - AWS_ACCESS_KEY_ID="$$AWS_ACCESS_KEY_ID" \ - AWS_SECRET_ACCESS_KEY="$$AWS_SECRET_ACCESS_KEY" \ - AWS_SESSION_TOKEN="$$AWS_SESSION_TOKEN" \ - AWS_REGION="us-west-2" \ - ./gradlew --build-cache --parallel run > server.log 2>&1 & echo $$! > $(PID_FILE) - @echo "Java V3 server starting..." - -stop-server: - @echo "Stopping server on port $(PORT)..." - @lsof -ti:$(PORT) | xargs kill -9 2>/dev/null || true - @if [ -f $(PID_FILE) ]; then \ - pkill -P $$(cat $(PID_FILE)) 2>/dev/null || true; \ - kill -9 $$(cat $(PID_FILE)) 2>/dev/null || true; \ - rm -f $(PID_FILE); \ - fi - @rm -f server.log - @echo "Server stopped" - -wait-for-server: - $(MAKE) -C .. wait-for-port PORT=$(PORT) - -duvet: - duvet report - -view-report-mac: - open .duvet/reports/report.html diff --git a/test-server/java-v3-server/README.md b/test-server/java-v3-server/README.md deleted file mode 100644 index e00eb496..00000000 --- a/test-server/java-v3-server/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# S3EC Java V3 Test Server - -This is the Java implementation of the S3ECTestServer framework for S3EC Java V3. It provides a server implementation for testing Java S3 Encryption Client V3 functionality. - -## Overview - -The S3ECJavaTestServer implements the S3ECTestServer service defined in the shared Smithy model. It provides endpoints for: - -- Creating S3 Encryption Clients -- Putting objects with encryption -- Getting and decrypting objects - -## Usage - -To run the server: - -```console -gradle run -``` - -This will start the server running on port `8080`. - -The server is used as part of the testing framework to verify cross-language compatibility of the S3 Encryption Client implementations. diff --git a/test-server/java-v3-server/build.gradle.kts b/test-server/java-v3-server/build.gradle.kts deleted file mode 100644 index baae4947..00000000 --- a/test-server/java-v3-server/build.gradle.kts +++ /dev/null @@ -1,56 +0,0 @@ -plugins { - `java-library` - id("software.amazon.smithy.gradle.smithy-base") - application -} - -dependencies { - val smithyJavaVersion: String by project - - smithyBuild("software.amazon.smithy.java:plugins:$smithyJavaVersion") - - implementation("software.amazon.smithy:smithy-rules-engine:1.59.0") - implementation("software.amazon.smithy.java:server-netty:$smithyJavaVersion") - implementation("software.amazon.smithy.java:aws-server-restjson:$smithyJavaVersion") - - compileOnly("software.amazon.awssdk:aws-sdk-java:2.31.66") - // This MUST stay at 3.5.0 - implementation("software.amazon.encryption.s3:amazon-s3-encryption-client-java:3.5.0") -} - -// Use that application plugin to start the service via the `run` task. -application { - mainClass = "software.amazon.encryption.s3.S3ECJavaTestServer" -} - -// Add generated Java files to the main sourceSet -afterEvaluate { - val serverPath = smithy.getPluginProjectionPath(smithy.sourceProjection.get(), "java-server-codegen") - sourceSets { - main { - java { - srcDir(serverPath) - } - } - } -} - -tasks { - compileJava { - dependsOn(smithyBuild) - } -} - -// Helps Intellij IDE's discover smithy models -sourceSets { - main { - java { - srcDir("../model") - } - } -} - -repositories { - mavenLocal() - mavenCentral() -} diff --git a/test-server/java-v3-server/gradle.properties b/test-server/java-v3-server/gradle.properties deleted file mode 100644 index 483cd315..00000000 --- a/test-server/java-v3-server/gradle.properties +++ /dev/null @@ -1,24 +0,0 @@ -# Smithy versions -smithyJavaVersion=[0,1] -smithyGradleVersion=1.1.0 -smithyVersion=[1,2] - -# Performance optimization settings - -# Force no-daemon mode - ensures Gradle doesn't try to keep a daemon alive -org.gradle.daemon=false - -# Set minimal idle timeout for any daemon-like behavior (1 second) -org.gradle.daemon.idletimeout=1000 - -# JVM arguments to prevent forking a separate JVM process -# By matching the JVM args here with what Gradle expects, we avoid the -# "single-use Daemon process will be forked" behavior -org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+UseParallelGC - -# Keep builds fast with parallel execution and caching -org.gradle.parallel=true -org.gradle.caching=true - -# Configure on demand to reduce startup time -org.gradle.configureondemand=true diff --git a/test-server/java-v3-server/gradle/wrapper/gradle-wrapper.jar b/test-server/java-v3-server/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index e6441136..00000000 Binary files a/test-server/java-v3-server/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/test-server/java-v3-server/gradle/wrapper/gradle-wrapper.properties b/test-server/java-v3-server/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index a4413138..00000000 --- a/test-server/java-v3-server/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/test-server/java-v3-server/gradlew b/test-server/java-v3-server/gradlew deleted file mode 100755 index b740cf13..00000000 --- a/test-server/java-v3-server/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# 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 -# -# https://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. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/test-server/java-v3-server/gradlew.bat b/test-server/java-v3-server/gradlew.bat deleted file mode 100644 index 7101f8e4..00000000 --- a/test-server/java-v3-server/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/test-server/java-v3-server/license.txt b/test-server/java-v3-server/license.txt deleted file mode 100644 index 2dd564b3..00000000 --- a/test-server/java-v3-server/license.txt +++ /dev/null @@ -1,4 +0,0 @@ -/* - * Example file license header. - * File header line two - */ \ No newline at end of file diff --git a/test-server/java-v3-server/settings.gradle.kts b/test-server/java-v3-server/settings.gradle.kts deleted file mode 100644 index e7c41714..00000000 --- a/test-server/java-v3-server/settings.gradle.kts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Basic usage of generated server stubs. - */ - -pluginManagement { - val smithyGradleVersion: String by settings - - plugins { - id("software.amazon.smithy.gradle.smithy-base").version(smithyGradleVersion) - } - - repositories { - mavenLocal() - mavenCentral() - gradlePluginPortal() - } -} - -rootProject.name = "S3ECJavaTestServer" diff --git a/test-server/java-v3-server/smithy-build.json b/test-server/java-v3-server/smithy-build.json deleted file mode 100644 index a0fcb8e5..00000000 --- a/test-server/java-v3-server/smithy-build.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "2.0", - "plugins": { - "java-server-codegen": { - "service": "software.amazon.encryption.s3#S3ECTestServer", - "namespace": "software.amazon.encryption.s3", - "headerFile": "license.txt" - } - }, - "sources": ["../model"] -} diff --git a/test-server/java-v3-server/specification b/test-server/java-v3-server/specification deleted file mode 120000 index b173f708..00000000 --- a/test-server/java-v3-server/specification +++ /dev/null @@ -1 +0,0 @@ -../specification \ No newline at end of file diff --git a/test-server/java-v3-server/src/main/java/software/amazon/encryption/s3/CreateClientOperationImpl.java b/test-server/java-v3-server/src/main/java/software/amazon/encryption/s3/CreateClientOperationImpl.java deleted file mode 100644 index 6a3da066..00000000 --- a/test-server/java-v3-server/src/main/java/software/amazon/encryption/s3/CreateClientOperationImpl.java +++ /dev/null @@ -1,155 +0,0 @@ -package software.amazon.encryption.s3; - -import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; -import software.amazon.awssdk.core.retry.RetryPolicy; -import software.amazon.awssdk.core.retry.backoff.BackoffStrategy; -import software.amazon.awssdk.core.traits.Trait; -import software.amazon.awssdk.services.s3.S3Client; -import software.amazon.encryption.s3.S3EncryptionClient; -import software.amazon.encryption.s3.internal.InstructionFileConfig; -import software.amazon.encryption.s3.materials.AesKeyring; -import software.amazon.encryption.s3.materials.Keyring; -import software.amazon.encryption.s3.materials.KmsKeyring; -import software.amazon.encryption.s3.materials.PartialRsaKeyPair; -import software.amazon.encryption.s3.materials.RsaKeyring; -import software.amazon.smithy.java.core.schema.Schema; -import software.amazon.smithy.java.server.RequestContext; -import software.amazon.encryption.s3.model.CreateClientInput; -import software.amazon.encryption.s3.model.CreateClientOutput; -import software.amazon.encryption.s3.model.GenericServerError; -import software.amazon.encryption.s3.model.KeyMaterial; -import software.amazon.encryption.s3.service.CreateClientOperation; - -import javax.crypto.spec.SecretKeySpec; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.PublicKey; -import java.security.interfaces.RSAPrivateCrtKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.RSAPublicKeySpec; -import java.util.Arrays; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; - -public class CreateClientOperationImpl implements CreateClientOperation { - private Map clientCache_; - private Map keyringCache_; - - public CreateClientOperationImpl(Map clientCache, Map keyringCache) { - clientCache_ = clientCache; - keyringCache_ = keyringCache; - } - - // Copied from S3EC. - private boolean onlyOneNonNull(Object... values) { - boolean haveOneNonNull = false; - for (Object o : values) { - if (o != null) { - if (haveOneNonNull) { - return false; - } - - haveOneNonNull = true; - } - } - - return haveOneNonNull; - } - - @Override - public CreateClientOutput createClient(CreateClientInput input, RequestContext context) { - try { - // Key Material / Keyring Creation - KeyMaterial key = input.getConfig().getKeyMaterial(); - if (!onlyOneNonNull(key.getAesKey(), key.getKmsKeyId(), key.getRsaKey())) { - throw new RuntimeException("KeyMaterial must be only one, non-null input!"); - } - Keyring keyring; - if (key.getAesKey() != null) { - byte[] keyBytes = new byte[key.getAesKey().remaining()]; - key.getAesKey().get(keyBytes); - keyring = AesKeyring.builder() - .wrappingKey(new SecretKeySpec(keyBytes, "AES")) - .enableLegacyWrappingAlgorithms(input.getConfig().isEnableLegacyWrappingAlgorithms()) - .build(); - } else if (key.getRsaKey() != null) { - try { - byte[] keyBytes = new byte[key.getRsaKey().remaining()]; - key.getRsaKey().get(keyBytes); - PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) keyFactory.generatePrivate(keySpec); - RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec( - privateKey.getModulus(), - privateKey.getPublicExponent() - ); - - // Generate public key - PublicKey publicKey = keyFactory.generatePublic(publicKeySpec); - - keyring = RsaKeyring.builder() - .enableLegacyWrappingAlgorithms(input.getConfig().isEnableLegacyWrappingAlgorithms()) - .wrappingKeyPair(PartialRsaKeyPair.builder() - .publicKey(publicKey) - .privateKey(privateKey).build()) - .build(); - } catch (NoSuchAlgorithmException | InvalidKeySpecException nse) { - throw GenericServerError.builder() - .message(nse.getMessage()) - .build(); - } - } else if (key.getKmsKeyId() != null) { - keyring = KmsKeyring.builder() - .enableLegacyWrappingAlgorithms(input.getConfig().isEnableLegacyWrappingAlgorithms()) - .wrappingKeyId(key.getKmsKeyId()) - .build(); - } else { - throw new RuntimeException("No KeyMaterial found!"); - } - - // Configure S3 client with adaptive retry for throttling - RetryPolicy retryPolicy = RetryPolicy.builder() - .numRetries(5) - .throttlingBackoffStrategy(BackoffStrategy.defaultThrottlingStrategy()) - .build(); - - S3Client wrappedClient = S3Client.builder() - .overrideConfiguration(ClientOverrideConfiguration.builder() - .retryPolicy(retryPolicy) - .build()) - .build(); - - // Client Creation - boolean instFilePut = false; - if (input.getConfig().getInstructionFileConfig() != null) { - instFilePut = input.getConfig().getInstructionFileConfig().isEnableInstructionFilePutObject(); - } - S3Client s3Client = S3EncryptionClient.builder() - .wrappedClient(wrappedClient) - .instructionFileConfig(InstructionFileConfig.builder() - .instructionFileClient(S3Client.create()) - .enableInstructionFilePutObject(instFilePut) - .build()) - .keyring(keyring) - .build(); - UUID uuid = UUID.randomUUID(); - String uuidString = uuid.toString(); - clientCache_.put(uuidString, s3Client); - keyringCache_.put(uuidString, keyring); - return CreateClientOutput.builder() - .clientId(uuidString) - .build(); - } catch (Exception e) { - StringWriter sw = new StringWriter(); - e.printStackTrace(new PrintWriter(sw)); - String stackTrace = sw.toString(); - throw GenericServerError.builder() - .message(stackTrace) - .build(); - } - } -} diff --git a/test-server/java-v3-server/src/main/java/software/amazon/encryption/s3/GetObjectOperationImpl.java b/test-server/java-v3-server/src/main/java/software/amazon/encryption/s3/GetObjectOperationImpl.java deleted file mode 100644 index fbccd458..00000000 --- a/test-server/java-v3-server/src/main/java/software/amazon/encryption/s3/GetObjectOperationImpl.java +++ /dev/null @@ -1,78 +0,0 @@ -package software.amazon.encryption.s3; - -import software.amazon.awssdk.core.ResponseBytes; -import software.amazon.awssdk.services.s3.S3Client; -import software.amazon.awssdk.services.s3.model.GetObjectResponse; -import software.amazon.encryption.s3.S3EncryptionClientException; -import software.amazon.smithy.java.server.RequestContext; -import software.amazon.encryption.s3.model.GenericServerError; -import software.amazon.encryption.s3.model.GetObjectInput; -import software.amazon.encryption.s3.model.GetObjectOutput; -import software.amazon.encryption.s3.model.S3EncryptionClientError; -import software.amazon.encryption.s3.service.GetObjectOperation; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.nio.ByteBuffer; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static software.amazon.encryption.s3.S3EncryptionClient.withAdditionalConfiguration; -import static software.amazon.encryption.s3.MetadataUtils.metadataListToMap; -import static software.amazon.encryption.s3.MetadataUtils.metadataMapToList; - -public class GetObjectOperationImpl implements GetObjectOperation { - private Map clientCache_; - public GetObjectOperationImpl(Map clientCache) { - clientCache_ = clientCache; - } - @Override - public GetObjectOutput getObject(GetObjectInput input, RequestContext context) { - try { - S3Client s3Client = clientCache_.get(input.getClientID()); - Map ecMap = metadataListToMap(input.getMetadata()); - - try { - ResponseBytes resp = s3Client.getObjectAsBytes(builder -> { - builder.bucket(input.getBucket()) - .key(input.getKey()) - .overrideConfiguration(withAdditionalConfiguration(ecMap)); - - // Add range header if provided - if (input.getRange() != null && !input.getRange().isEmpty()) { - builder.range(input.getRange()); - } - }); - - List mdAsList = metadataMapToList(resp.response().metadata()); - // Can't use asBB else it gets mad bc cant access backing array - ByteBuffer bb = ByteBuffer.wrap(resp.asByteArray()); - GetObjectOutput output = GetObjectOutput.builder() - .body(bb) - .metadata(mdAsList) - .build(); - return output; - } catch (S3EncryptionClientException s3EncryptionClientException) { - // Modeled exceptions MUST be returned as such - StringWriter sw = new StringWriter(); - s3EncryptionClientException.printStackTrace(new PrintWriter(sw)); - String stackTrace = sw.toString(); - throw S3EncryptionClientError.builder() - .message(stackTrace) - .build(); - } - } catch (Exception e) { - // Don't wrap modeled errors - if (e instanceof S3EncryptionClientError) { - throw e; - } - StringWriter sw = new StringWriter(); - e.printStackTrace(new PrintWriter(sw)); - String stackTrace = sw.toString(); - throw GenericServerError.builder() - .message(stackTrace) - .build(); - } - } -} diff --git a/test-server/java-v3-server/src/main/java/software/amazon/encryption/s3/MetadataUtils.java b/test-server/java-v3-server/src/main/java/software/amazon/encryption/s3/MetadataUtils.java deleted file mode 100644 index 036289ec..00000000 --- a/test-server/java-v3-server/src/main/java/software/amazon/encryption/s3/MetadataUtils.java +++ /dev/null @@ -1,43 +0,0 @@ -package software.amazon.encryption.s3; - -import software.amazon.encryption.s3.model.GenericServerError; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class MetadataUtils { - - /** - * Annoyingly, Smithy doesn't provide an interface for map types - * in HTTP headers, so we have to do the serde ourselves - */ - public static List metadataMapToList(Map md) { - List mdAsList = new ArrayList<>(md.size()); - for (Map.Entry keyValue : md.entrySet()) { - mdAsList.add("[" + keyValue.getKey() + "]:[" + keyValue.getValue() + "]"); - } - return mdAsList; - } - - public static Map metadataListToMap(List mdList) { - Map md = new HashMap<>(); - for (String entry : mdList) { - // Split on "]:[" to separate key and value - String[] parts = entry.split("]:\\["); - if (parts.length == 2) { - // Remove remaining brackets from start and end - String key = parts[0].substring(1); - String value = parts[1].substring(0, parts[1].length() - 1); - md.put(key, value); - } else { - throw GenericServerError.builder() - .message("Malformed metadata list entry: " + entry) - .build(); - } - } - return md; - } - -} diff --git a/test-server/java-v3-server/src/main/java/software/amazon/encryption/s3/PutObjectOperationImpl.java b/test-server/java-v3-server/src/main/java/software/amazon/encryption/s3/PutObjectOperationImpl.java deleted file mode 100644 index 4c772673..00000000 --- a/test-server/java-v3-server/src/main/java/software/amazon/encryption/s3/PutObjectOperationImpl.java +++ /dev/null @@ -1,55 +0,0 @@ -package software.amazon.encryption.s3; - -import software.amazon.awssdk.core.sync.RequestBody; -import software.amazon.awssdk.services.s3.S3Client; -import software.amazon.awssdk.services.s3.model.PutObjectResponse; -import software.amazon.smithy.java.server.RequestContext; -import software.amazon.encryption.s3.model.GenericServerError; -import software.amazon.encryption.s3.model.PutObjectInput; -import software.amazon.encryption.s3.model.PutObjectOutput; -import software.amazon.encryption.s3.service.PutObjectOperation; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.Map; -import java.util.stream.Collectors; - -import static software.amazon.encryption.s3.S3EncryptionClient.withAdditionalConfiguration; -import static software.amazon.encryption.s3.MetadataUtils.metadataListToMap; - -public class PutObjectOperationImpl implements PutObjectOperation { - - private Map clientCache_; - - public PutObjectOperationImpl(Map clientCache) { - clientCache_ = clientCache; - } - - @Override - public PutObjectOutput putObject(PutObjectInput input, RequestContext context) { - try { - final Map metadata = metadataListToMap(input.getMetadata()); - S3Client s3Client = clientCache_.get(input.getClientID()); - s3Client.putObject(builder -> builder - .bucket(input.getBucket()) - .key(input.getKey()) - .overrideConfiguration(withAdditionalConfiguration(metadata)), - RequestBody.fromByteBuffer(input.getBody()) - ); - // The real S3 doesn't provide bucket/key/metadata, so Test doesn't need to either, but we do anyway - return PutObjectOutput.builder() - .bucket(input.getBucket()) - .key(input.getKey()) - .metadata(input.getMetadata()) - .build(); - } catch (Exception e) { - StringWriter sw = new StringWriter(); - e.printStackTrace(new PrintWriter(sw)); - String stackTrace = sw.toString(); - throw GenericServerError.builder() - .message(stackTrace) - .build(); - } - } -} diff --git a/test-server/java-v3-server/src/main/java/software/amazon/encryption/s3/ReEncryptOperationImpl.java b/test-server/java-v3-server/src/main/java/software/amazon/encryption/s3/ReEncryptOperationImpl.java deleted file mode 100644 index dd376429..00000000 --- a/test-server/java-v3-server/src/main/java/software/amazon/encryption/s3/ReEncryptOperationImpl.java +++ /dev/null @@ -1,185 +0,0 @@ -package software.amazon.encryption.s3; - -import software.amazon.awssdk.services.s3.S3Client; -import software.amazon.encryption.s3.internal.ReEncryptInstructionFileRequest; -import software.amazon.encryption.s3.internal.ReEncryptInstructionFileResponse; -import software.amazon.encryption.s3.materials.AesKeyring; -import software.amazon.encryption.s3.materials.MaterialsDescription; -import software.amazon.encryption.s3.materials.PartialRsaKeyPair; -import software.amazon.encryption.s3.materials.RawKeyring; -import software.amazon.encryption.s3.materials.RsaKeyring; -import software.amazon.encryption.s3.model.GenericServerError; -import software.amazon.encryption.s3.model.KeyMaterial; -import software.amazon.encryption.s3.model.ReEncryptInput; -import software.amazon.encryption.s3.model.ReEncryptOutput; -import software.amazon.encryption.s3.model.S3EncryptionClientError; -import software.amazon.encryption.s3.service.ReEncryptOperation; -import software.amazon.smithy.java.server.RequestContext; - -import javax.crypto.SecretKey; -import javax.crypto.spec.SecretKeySpec; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.security.KeyFactory; -import java.security.PublicKey; -import java.security.interfaces.RSAPrivateCrtKey; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.RSAPublicKeySpec; -import java.util.HashMap; -import java.util.Map; - -public class ReEncryptOperationImpl implements ReEncryptOperation { - private final Map clientCache_; - private final Map keyringCache_; - - public ReEncryptOperationImpl(Map clientCache, Map keyringCache) { - clientCache_ = clientCache; - keyringCache_ = keyringCache; - } - - @Override - public ReEncryptOutput reEncrypt(ReEncryptInput input, RequestContext context) { - try { - S3Client s3Client = clientCache_.get(input.getClientID()); - - // Ensure we have an S3EncryptionClient, not just a plain S3Client - if (!(s3Client instanceof S3EncryptionClient)) { - throw new IllegalStateException( - "Client " + input.getClientID() + " is not an S3EncryptionClient"); - } - - S3EncryptionClient s3EncryptionClient = (S3EncryptionClient) s3Client; - - // Create a new keyring from the provided newKeyMaterial - KeyMaterial newKeyMaterial = input.getNewKeyMaterial(); - if (newKeyMaterial == null) { - throw new IllegalStateException( - "newKeyMaterial is required for ReEncrypt operation"); - } - - RawKeyring newKeyring = createKeyringFromMaterial(newKeyMaterial); - - try { - // Build the ReEncryptInstructionFileRequest - ReEncryptInstructionFileRequest.Builder requestBuilder = - ReEncryptInstructionFileRequest.builder() - .bucket(input.getBucket()) - .key(input.getKey()) - .newKeyring(newKeyring); - - // Add optional instruction file suffix if provided - if (input.getInstructionFileSuffix() != null && !input.getInstructionFileSuffix().isEmpty()) { - requestBuilder.instructionFileSuffix(input.getInstructionFileSuffix()); - } - - // Add optional enforceRotation if provided - if (input.isEnforceRotation() != null) { - requestBuilder.enforceRotation(input.isEnforceRotation()); - } - - ReEncryptInstructionFileRequest reEncryptRequest = requestBuilder.build(); - - // Perform the re-encryption - ReEncryptInstructionFileResponse response = - s3EncryptionClient.reEncryptInstructionFile(reEncryptRequest); - - // Build and return the output - return ReEncryptOutput.builder() - .bucket(response.bucket()) - .key(response.key()) - .instructionFileSuffix(response.instructionFileSuffix()) - .enforceRotation(response.enforceRotation()) - .build(); - - } catch (S3EncryptionClientException s3EncryptionClientException) { - // Modeled exceptions MUST be returned as such - StringWriter sw = new StringWriter(); - s3EncryptionClientException.printStackTrace(new PrintWriter(sw)); - String stackTrace = sw.toString(); - throw S3EncryptionClientError.builder() - .message(stackTrace) - .build(); - } - } catch (Exception e) { - // Don't wrap modeled errors - if (e instanceof S3EncryptionClientError) { - throw e; - } - StringWriter sw = new StringWriter(); - e.printStackTrace(new PrintWriter(sw)); - String stackTrace = sw.toString(); - throw GenericServerError.builder() - .message(stackTrace) - .build(); - } - } - - /** - * Creates a RawKeyring from KeyMaterial. - * The KeyMaterial should have exactly one of: aesKey, rsaKey, or kmsKeyId set. - */ - private RawKeyring createKeyringFromMaterial(KeyMaterial keyMaterial) { - try { - // Get materials description from KeyMaterial if provided - MaterialsDescription materialsDescription = null; - if (keyMaterial.getMaterialsDescription() != null && !keyMaterial.getMaterialsDescription().isEmpty()) { - MaterialsDescription.Builder builder = MaterialsDescription.builder(); - for (Map.Entry entry : keyMaterial.getMaterialsDescription().entrySet()) { - builder.put(entry.getKey(), entry.getValue()); - } - materialsDescription = builder.build(); - } - - // Check for AES key - if (keyMaterial.getAesKey() != null) { - byte[] aesKeyBytes = new byte[keyMaterial.getAesKey().remaining()]; - keyMaterial.getAesKey().get(aesKeyBytes); - SecretKey secretKey = new SecretKeySpec(aesKeyBytes, "AES"); - - AesKeyring.Builder keyringBuilder = AesKeyring.builder() - .wrappingKey(secretKey); - - if (materialsDescription != null) { - keyringBuilder.materialsDescription(materialsDescription); - } - - return keyringBuilder.build(); - } - - // Check for RSA key - if (keyMaterial.getRsaKey() != null) { - byte[] rsaKeyBytes = new byte[keyMaterial.getRsaKey().remaining()]; - keyMaterial.getRsaKey().get(rsaKeyBytes); - PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(rsaKeyBytes); - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) keyFactory.generatePrivate(keySpec); - - // Derive the public key from the private key - RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec( - privateKey.getModulus(), - privateKey.getPublicExponent() - ); - PublicKey publicKey = keyFactory.generatePublic(publicKeySpec); - - PartialRsaKeyPair keyPair = PartialRsaKeyPair.builder() - .privateKey(privateKey) - .publicKey(publicKey) - .build(); - - RsaKeyring.Builder keyringBuilder = RsaKeyring.builder() - .wrappingKeyPair(keyPair); - - if (materialsDescription != null) { - keyringBuilder.materialsDescription(materialsDescription); - } - - return keyringBuilder.build(); - } - - throw new IllegalStateException( - "KeyMaterial must have either aesKey or rsaKey set"); - } catch (Exception e) { - throw new IllegalStateException("Failed to create keyring from KeyMaterial: " + e.getMessage(), e); - } - } -} diff --git a/test-server/java-v3-server/src/main/java/software/amazon/encryption/s3/S3ECJavaTestServer.java b/test-server/java-v3-server/src/main/java/software/amazon/encryption/s3/S3ECJavaTestServer.java deleted file mode 100644 index be53f20c..00000000 --- a/test-server/java-v3-server/src/main/java/software/amazon/encryption/s3/S3ECJavaTestServer.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package software.amazon.encryption.s3; - -import software.amazon.awssdk.services.s3.S3Client; - -import java.net.URI; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutionException; -import software.amazon.smithy.java.server.Server; -import software.amazon.encryption.s3.service.S3ECTestServer; - -public class S3ECJavaTestServer implements Runnable { - static final URI endpoint = URI.create("http://localhost:8080"); - - public static void main(String[] args) { - new S3ECJavaTestServer().run(); - } - - @Override - public void run() { - // All the S3EC instances live here. - // Obviously this can get messy in a real service. - // Assume that the tests behave and don't induce weird race conditions. - Map clientCache = new ConcurrentHashMap<>(); - Map keyringCache = new ConcurrentHashMap<>(); - - Server server = Server.builder() - .endpoints(endpoint) - .addService( - S3ECTestServer.builder() - .addCreateClientOperation(new CreateClientOperationImpl(clientCache, keyringCache)) - .addGetObjectOperation(new GetObjectOperationImpl(clientCache)) - .addPutObjectOperation(new PutObjectOperationImpl(clientCache)) - .addReEncryptOperation(new ReEncryptOperationImpl(clientCache, keyringCache)) - .build()) - .build(); - System.out.println("Starting server..."); - server.start(); - try { - Thread.currentThread().join(); - } catch (InterruptedException e) { - System.out.println("Stopping server..."); - try { - server.shutdown().get(); - } catch (InterruptedException | ExecutionException ex) { - throw new RuntimeException(ex); - } - } - } -} diff --git a/test-server/java-v3-transition-server/build.gradle.kts b/test-server/java-v3-transition-server/build.gradle.kts index 7f249d65..7f474fa0 100644 --- a/test-server/java-v3-transition-server/build.gradle.kts +++ b/test-server/java-v3-transition-server/build.gradle.kts @@ -4,6 +4,10 @@ plugins { application } +// Dynamically read S3EC version from submodule's pom.xml +val s3ecVersion = file("s3ec-staging/pom.xml").readText() + .let { Regex("(.*?)").find(it)?.groupValues?.get(1) ?: "3.6.0" } + dependencies { val smithyJavaVersion: String by project @@ -14,7 +18,8 @@ dependencies { implementation("software.amazon.smithy.java:aws-server-restjson:$smithyJavaVersion") // S3EC from local Maven repository (installed by mvn install) - implementation("software.amazon.encryption.s3:amazon-s3-encryption-client-java:3.4.0-read-kc") + // Version is dynamically read from s3ec-staging/pom.xml + implementation("software.amazon.encryption.s3:amazon-s3-encryption-client-java:$s3ecVersion") } // Use that application plugin to start the service via the `run` task. diff --git a/test-server/java-v3-transition-server/s3ec-staging b/test-server/java-v3-transition-server/s3ec-staging index 183f1984..d829a235 160000 --- a/test-server/java-v3-transition-server/s3ec-staging +++ b/test-server/java-v3-transition-server/s3ec-staging @@ -1 +1 @@ -Subproject commit 183f1984ed1679e8aa4cb368aeda66f2131a2061 +Subproject commit d829a235854996e0f25736662510c2aa25e61fae diff --git a/test-server/java-v4-server/build.gradle.kts b/test-server/java-v4-server/build.gradle.kts index fcb3c3ca..d55d93d7 100644 --- a/test-server/java-v4-server/build.gradle.kts +++ b/test-server/java-v4-server/build.gradle.kts @@ -4,6 +4,10 @@ plugins { application } +// Dynamically read S3EC version from submodule's pom.xml +val s3ecVersion = file("s3ec-staging/pom.xml").readText() + .let { Regex("(.*?)").find(it)?.groupValues?.get(1) ?: "4.0.0" } + dependencies { val smithyJavaVersion: String by project @@ -14,7 +18,8 @@ dependencies { implementation("software.amazon.smithy.java:aws-server-restjson:$smithyJavaVersion") // S3EC from local Maven repository (installed by mvn install) - implementation("software.amazon.encryption.s3:amazon-s3-encryption-client-java:3.4.0-add-kc") + // Version is dynamically read from s3ec-staging/pom.xml + implementation("software.amazon.encryption.s3:amazon-s3-encryption-client-java:$s3ecVersion") } // Use that application plugin to start the service via the `run` task. diff --git a/test-server/java-v4-server/s3ec-staging b/test-server/java-v4-server/s3ec-staging index 7a1899bb..a95aa3fd 160000 --- a/test-server/java-v4-server/s3ec-staging +++ b/test-server/java-v4-server/s3ec-staging @@ -1 +1 @@ -Subproject commit 7a1899bb8be6f137a3031ff76f2a1bf3f278e98d +Subproject commit a95aa3fddb5abf4e17551c0ef3c247c7a43edf40 diff --git a/test-server/model/client.smithy b/test-server/model/client.smithy index 5772e8c2..11f65f57 100644 --- a/test-server/model/client.smithy +++ b/test-server/model/client.smithy @@ -52,9 +52,14 @@ enum EncryptionAlgorithm { structure InstructionFileConfig { /// This allows specifying a (non-encrypted) client for languages which /// support this for instruction files. - /// In general, languages should not require specifying it, - /// so it is best to leave it null until there's a good reason not to. + /// In general, languages do not require specifying a client; + /// they use the usual wrapped client for instruction file operations, + /// so it is fine to leave it null for now. /// This also requires a way to create non-encrypted clients which we don't have yet. + /// Some languages (Java) do allow a client to be passed specifically for instruction files, + /// so this should be implemented eventually for full coverage, + /// especially if other languages add this feature. Until then, + /// the Java integ tests are sufficient. clientId: String, enableInstructionFilePutObject: Boolean = false, disableInstructionFile: Boolean = false diff --git a/test-server/net-v2-v3-server/.duvet/.gitignore b/test-server/net-v2-v3-server/.duvet/.gitignore deleted file mode 100644 index 93956e36..00000000 --- a/test-server/net-v2-v3-server/.duvet/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -reports/ -requirements/ -specification/ \ No newline at end of file diff --git a/test-server/net-v2-v3-server/.duvet/config.toml b/test-server/net-v2-v3-server/.duvet/config.toml deleted file mode 100644 index 04d2e812..00000000 --- a/test-server/net-v2-v3-server/.duvet/config.toml +++ /dev/null @@ -1,21 +0,0 @@ -'$schema' = "https://awslabs.github.io/duvet/config/v0.4.0.json" - -[[source]] -pattern = "**/*.cs" - -# Include required specifications here -[[specification]] -source = "../specification/s3-encryption/data-format/content-metadata.md" -[[specification]] -source = "../specification/s3-encryption/data-format/metadata-strategy.md" -[[specification]] -source = "../specification/s3-encryption/encryption.md" -[[specification]] -source = "../specification/s3-encryption/key-derivation.md" - -[report.html] -enabled = true - -# Enable snapshots to prevent requirement coverage regressions -[report.snapshot] -enabled = false diff --git a/test-server/net-v2-v3-server/.gitignore b/test-server/net-v2-v3-server/.gitignore deleted file mode 100644 index 4c20cbc8..00000000 --- a/test-server/net-v2-v3-server/.gitignore +++ /dev/null @@ -1,44 +0,0 @@ -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -[Ww][Ii][Nn]32/ -[Aa][Rr][Mm]/ -[Aa][Rr][Mm]64/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ -[Ll]ogs/ - -# Visual Studio 2015/2017 cache/options directory -.vs/ - -# User-specific files -*.rsuser -*.suo -*.user -*.userosscache -*.sln.docstates - -# NuGet Packages -*.nupkg -*.snupkg -packages/ - -# JetBrains Rider -.idea/ -*.sln.iml - -# VS Code -.vscode/ - -# macOS -.DS_Store - -# Temporary files -*.tmp -*.temp diff --git a/test-server/net-v2-v3-server/Controllers/ClientController.cs b/test-server/net-v2-v3-server/Controllers/ClientController.cs deleted file mode 100644 index 437233a8..00000000 --- a/test-server/net-v2-v3-server/Controllers/ClientController.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System.Net; -using System.Security.Cryptography; -using System.Text.Json; -using Amazon.Extensions.S3.Encryption; -using Amazon.Extensions.S3.Encryption.Primitives; -using Microsoft.AspNetCore.Mvc; -using NetV2V3Server.Models; -using NetV2V3Server.Services; - -namespace NetV2V3Server.Controllers; - -[ApiController] -[Route("[controller]")] -public class ClientController(IClientCacheService clientCacheService, ILogger logger) : ControllerBase -{ - [HttpPost] - public IActionResult CreateClient([FromBody] ClientRequest request) - { - // Return 501 for not implemented features by the server - if (request.Config.EnableDelayedAuthenticationMode) - return StatusCode(501, new GenericServerError { Message = "[NET-current] EnableDelayedAuthenticationMode not supported" }); - if (request.Config.SetBufferSize.HasValue) - return StatusCode(501, new GenericServerError { Message = "[NET-current] SetBufferSize not supported" }); - - try - { - EncryptionMaterialsV2 encryptionMaterial; - if (request.Config.KeyMaterial.KmsKeyId != null) - { - // The POST request does not contain encryption context. - // However, encryption context is a required field when using KMS. - // So, we are passing empty dictionary. - var encryptionContext = new Dictionary(); - var kmsKeyId = request.Config.KeyMaterial.KmsKeyId; - encryptionMaterial = new EncryptionMaterialsV2(kmsKeyId, KmsType.KmsContext, encryptionContext); - logger.LogInformation( - "[NET-current] Created EncryptionMaterialsV2: KMS={KmsKeyId}", - kmsKeyId); - } - else if (request.Config.KeyMaterial.RsaKey != null) - { - var rsaKeyBytes = request.Config.KeyMaterial.RsaKey; - var rsaKey = RSA.Create(); - rsaKey.ImportPkcs8PrivateKey(new ReadOnlySpan(rsaKeyBytes), out _); - encryptionMaterial = new EncryptionMaterialsV2(rsaKey, AsymmetricAlgorithmType.RsaOaepSha1); - logger.LogInformation( - "Created EncryptionMaterialsV2: RSA"); - } - else if (request.Config.KeyMaterial.AesKey != null) - { - var aesKeyBytes = request.Config.KeyMaterial.AesKey; - var aes = Aes.Create(); - aes.Key = aesKeyBytes; - encryptionMaterial = new EncryptionMaterialsV2(aes, SymmetricAlgorithmType.AesGcm); - logger.LogInformation( - "[NET-current] Created EncryptionMaterialsV2: AES"); - } else - { - return StatusCode(501, new GenericServerError { Message = "[NET-current] Unknown or missing key material!" }); - } - - var enableLegacyUnauthenticatedModes = request.Config.EnableLegacyUnauthenticatedModes; - var enableLegacyWrappingAlgorithms = request.Config.EnableLegacyWrappingAlgorithms; - - // SecurityProfile V2AndLegacy can decrypt from legacy S3EC but V2 cannot - var enableLegacyMode = enableLegacyUnauthenticatedModes || enableLegacyWrappingAlgorithms; - var securityProfile = enableLegacyMode ? SecurityProfile.V2AndLegacy : SecurityProfile.V2; - - logger.LogInformation("[NET-current] Created securityProfile= {securityProfile}", securityProfile.ToString()); - - var configuration = new AmazonS3CryptoConfigurationV2(securityProfile); - - // Add retry configuration for throttling - configuration.RetryMode = Amazon.Runtime.RequestRetryMode.Adaptive; - configuration.MaxErrorRetry = 5; - - if (request.Config.InstructionFileConfig?.EnableInstructionFilePutObject == true) - { - configuration.StorageMode = CryptoStorageMode.InstructionFile; - logger.LogInformation("[NET-current] Created StorageMode= InstructionFile"); - } - // Create S3 encryption client - var encryptionClient = new AmazonS3EncryptionClientV2(configuration, encryptionMaterial); - // Add to cache and return client ID - var clientId = clientCacheService.AddClient(encryptionClient); - var response = new ClientResponse { ClientId = clientId }; - - logger.LogInformation("[NET-current] Created S3EC client with ID: {clientId}", clientId); - - return new ContentResult - { - Content = JsonSerializer.Serialize(response), - ContentType = "application/json", - StatusCode = 200 - }; - } - catch (Exception ex) - { - logger.LogError(ex, "[NET-current] Failed to create S3EC client"); - return StatusCode(500, new S3EncryptionClientError - { - Message = $"[NET-current] Failed to create client: {ex.Message}" - }); - } - } -} diff --git a/test-server/net-v2-v3-server/Controllers/ObjectController.cs b/test-server/net-v2-v3-server/Controllers/ObjectController.cs deleted file mode 100644 index bf1842ae..00000000 --- a/test-server/net-v2-v3-server/Controllers/ObjectController.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System.Text.Json; -using Amazon.S3.Model; -using Microsoft.AspNetCore.Mvc; -using NetV2V3Server.Models; -using NetV2V3Server.Services; - -namespace NetV2V3Server.Controllers; - -[ApiController] -[Route("[controller]")] -public class ObjectController(IClientCacheService clientCacheService, ILogger logger) : ControllerBase -{ - [HttpPut("{bucket}/{key}")] - public async Task PutObject(string bucket, string key) - { - logger.LogInformation("Starting PutObject"); - var clientId = Request.Headers["clientId"].FirstOrDefault(); - if (string.IsNullOrEmpty(clientId)) - return BadRequest(new GenericServerError { Message = "ClientID header is required" }); - - var client = clientCacheService.GetClient(clientId); - if (client == null) - return NotFound(new GenericServerError { Message = $"No client found for ClientID: {clientId}" }); - - try - { - // Read raw body data - using var memoryStream = new MemoryStream(); - // Request is the HTTP request this method is currently handling - await Request.Body.CopyToAsync(memoryStream); - var bodyBytes = memoryStream.ToArray(); - - // Create put request - var putRequest = new PutObjectRequest - { - BucketName = bucket, - Key = key, - InputStream = new MemoryStream(bodyBytes) - }; - - await client.PutObjectAsync(putRequest); - - var response = new { bucket, key }; - - logger.LogInformation( - "Put object succeeded for bucket={bucket}, key={key} and clientId = {clientId}", - bucket, key, clientId); - return new ContentResult - { - Content = JsonSerializer.Serialize(response), - ContentType = "application/json", - StatusCode = 200 - }; - } - catch (Exception ex) - { - logger.LogError(ex, "Failed to put object from S3 for bucket={bucket}, key={key}", bucket, key); - return StatusCode(500, new S3EncryptionClientError { Message = $"Failed to put object: {ex.Message}" }); - } - } - - [HttpGet("{bucket}/{key}")] - public async Task GetObject(string bucket, string key) - { - logger.LogInformation("Starting GetObject"); - var clientId = Request.Headers["clientId"].FirstOrDefault(); - if (string.IsNullOrEmpty(clientId)) - return BadRequest(new GenericServerError { Message = "ClientID header is required" }); - - var client = clientCacheService.GetClient(clientId); - if (client == null) - return NotFound(new GenericServerError { Message = $"No client found for ClientID: {clientId}" }); - - try - { - var getRequest = new GetObjectRequest - { - BucketName = bucket, - Key = key - }; - var response = await client.GetObjectAsync(getRequest); - logger.LogInformation("Got object from S3 for bucket={bucket}, key={key}", bucket, key); - // Read response body - using var memoryStream = new MemoryStream(); - await response.ResponseStream.CopyToAsync(memoryStream); - var bodyBytes = memoryStream.ToArray(); - - // Convert metadata to content-metadata header format - var metadataList = response.Metadata.Keys - .Select(metaDataKey => $"{metaDataKey}={response.Metadata[metaDataKey]}") - .ToList(); - var metadataStr = string.Join(",", metadataList); - - // Set response headers - Response.Headers["Content-Metadata"] = metadataStr; - - return File(bodyBytes, "application/octet-stream"); - } - catch (Exception ex) - { - logger.LogError(ex, "Failed to get object from S3 for bucket={bucket}, key={key}", bucket, key); - return StatusCode(500, new S3EncryptionClientError { Message = ex.Message }); - } - } -} \ No newline at end of file diff --git a/test-server/net-v2-v3-server/Makefile b/test-server/net-v2-v3-server/Makefile deleted file mode 100644 index 9881ee38..00000000 --- a/test-server/net-v2-v3-server/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -# Makefile for S3 Encryption Client .NET Testing - -.PHONY: build-server start-server stop-server wait-for-server - -PID_FILE_NET_V2 := net-v2-server.pid -PID_FILE_NET_V3 := net-v3-server.pid -PORT_NET_V2 := 8083 -PORT_NET_V3 := 8084 - -build-server: - @echo "Building .NET V2 and V3 servers..." - rm -rf obj/v2 bin/v2 obj/v3 bin/v3 - dotnet build -p:S3EncryptionVersion=v2 -o bin/v2 -p:BaseIntermediateOutputPath=obj/v2/ - rm -rf obj - dotnet build -p:S3EncryptionVersion=v3 -o bin/v3 -p:BaseIntermediateOutputPath=obj/v3/ - -start-server: - $(MAKE) start-net-v2-server; \ - $(MAKE) start-net-v3-server; - -stop-server: - @echo "Stopping .NET V2 server on port $(PORT_NET_V2)..." - @lsof -ti:$(PORT_NET_V2) | xargs kill -9 2>/dev/null || true - @if [ -f $(PID_FILE_NET_V2) ]; then \ - pkill -P $$(cat $(PID_FILE_NET_V2)) 2>/dev/null || true; \ - kill -9 $$(cat $(PID_FILE_NET_V2)) 2>/dev/null || true; \ - rm -f $(PID_FILE_NET_V2); \ - fi - @rm -f net-v2-server.log - @echo "Stopping .NET V3 server on port $(PORT_NET_V3)..." - @lsof -ti:$(PORT_NET_V3) | xargs kill -9 2>/dev/null || true - @if [ -f $(PID_FILE_NET_V3) ]; then \ - pkill -P $$(cat $(PID_FILE_NET_V3)) 2>/dev/null || true; \ - kill -9 $$(cat $(PID_FILE_NET_V3)) 2>/dev/null || true; \ - rm -f $(PID_FILE_NET_V3); \ - fi - @rm -f net-v3-server.log - @echo "Servers stopped" - -# Start .NET V2 server in background -start-net-v2-server: - @echo "Starting .NET V2 server..." - AWS_ACCESS_KEY_ID="$$AWS_ACCESS_KEY_ID" \ - AWS_SECRET_ACCESS_KEY="$$AWS_SECRET_ACCESS_KEY" \ - AWS_SESSION_TOKEN="$$AWS_SESSION_TOKEN" \ - AWS_REGION="us-west-2" \ - dotnet bin/v2/NetV2V3Server.dll > net-v2-server.log 2>&1 & echo $$! > net-v2-server.pid - @echo ".NET V2 server starting..." - -# Start .NET V3 server in background -start-net-v3-server: - @echo "Starting .NET V3 server..." - AWS_ACCESS_KEY_ID="$$AWS_ACCESS_KEY_ID" \ - AWS_SECRET_ACCESS_KEY="$$AWS_SECRET_ACCESS_KEY" \ - AWS_SESSION_TOKEN="$$AWS_SESSION_TOKEN" \ - AWS_REGION="us-west-2" \ - dotnet bin/v3/NetV2V3Server.dll > net-v3-server.log 2>&1 & echo $$! > net-v3-server.pid - @echo ".NET V3 server starting..." - -wait-for-server: - $(MAKE) -C .. wait-for-port PORT=$(PORT_NET_V2) - $(MAKE) -C .. wait-for-port PORT=$(PORT_NET_V3) - -duvet: - duvet report - -view-report-mac: - open .duvet/reports/report.html diff --git a/test-server/net-v2-v3-server/Models/ClientRequest.cs b/test-server/net-v2-v3-server/Models/ClientRequest.cs deleted file mode 100644 index e51a9c25..00000000 --- a/test-server/net-v2-v3-server/Models/ClientRequest.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace NetV2V3Server.Models; - -public class ClientRequest -{ - [Required] - public ClientConfig Config { get; set; } = new(); -} - -public class ClientConfig -{ - public bool EnableLegacyUnauthenticatedModes { get; set; } = false; - public bool EnableLegacyWrappingAlgorithms { get; set; } = false; - public bool EnableDelayedAuthenticationMode { get; set; } = false; - public long? SetBufferSize { get; set; } - [Required] - public KeyMaterial KeyMaterial { get; set; } = new(); - public InstructionFileConfig? InstructionFileConfig { get; set; } -} - -public class KeyMaterial -{ - public byte[]? RsaKey { get; set; } - public byte[]? AesKey { get; set; } - public string? KmsKeyId { get; set; } -} - -public class InstructionFileConfig -{ - public string? ClientId { get; set; } - public bool EnableInstructionFilePutObject { get; set; } = false; - public bool DisableInstructionFile { get; set; } = false; -} \ No newline at end of file diff --git a/test-server/net-v2-v3-server/Models/ClientResponse.cs b/test-server/net-v2-v3-server/Models/ClientResponse.cs deleted file mode 100644 index 1e029ef7..00000000 --- a/test-server/net-v2-v3-server/Models/ClientResponse.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System.Text.Json.Serialization; - -namespace NetV2V3Server.Models; - -public class ClientResponse -{ - [JsonPropertyName("clientId")] public string ClientId { get; set; } = string.Empty; -} \ No newline at end of file diff --git a/test-server/net-v2-v3-server/Models/ErrorModels.cs b/test-server/net-v2-v3-server/Models/ErrorModels.cs deleted file mode 100644 index af1646e7..00000000 --- a/test-server/net-v2-v3-server/Models/ErrorModels.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Text.Json.Serialization; - -namespace NetV2V3Server.Models; - -public class GenericServerError -{ - [JsonPropertyName("__type")] - public string Type { get; set; } = "software.amazon.encryption.s3#GenericServerError"; - public string Message { get; set; } = string.Empty; -} - -public class S3EncryptionClientError -{ - [JsonPropertyName("__type")] - public string Type { get; set; } = "software.amazon.encryption.s3#S3EncryptionClientError"; - public string Message { get; set; } = string.Empty; -} diff --git a/test-server/net-v2-v3-server/NetV2V3Server.csproj b/test-server/net-v2-v3-server/NetV2V3Server.csproj deleted file mode 100644 index 8d664eff..00000000 --- a/test-server/net-v2-v3-server/NetV2V3Server.csproj +++ /dev/null @@ -1,39 +0,0 @@ - - - - net8.0 - enable - enable - false - - - - false - - - - S3EC_V2 - - - - S3EC_V3 - - - - - - - - - - - - - - - - - - - - diff --git a/test-server/net-v2-v3-server/Program.cs b/test-server/net-v2-v3-server/Program.cs deleted file mode 100644 index 1b77de5d..00000000 --- a/test-server/net-v2-v3-server/Program.cs +++ /dev/null @@ -1,21 +0,0 @@ -using NetV2V3Server.Services; - -var builder = WebApplication.CreateBuilder(args); - -builder.Services.AddControllers(); -builder.Services.AddSingleton(); - -#if S3EC_V2 -const int port = 8083; -#else -const int port = 8084; -#endif - -builder.WebHost.UseUrls($"http://localhost:{port}"); - -var app = builder.Build(); - -app.MapControllers(); - -Console.WriteLine($"Starting server on port {port}"); -app.Run(); diff --git a/test-server/net-v2-v3-server/README.md b/test-server/net-v2-v3-server/README.md deleted file mode 100644 index 9463d8b5..00000000 --- a/test-server/net-v2-v3-server/README.md +++ /dev/null @@ -1,72 +0,0 @@ -# Net-V2-V3-Server - -A .NET test server for Amazon S3 encryption client .NET v2 and v3. - -## Project Structure - -``` -net-v2-v3-server/ -├── Controllers/ # API controllers -├── Models/ # Data models -├── Services/ # Business logic services -├── Program.cs # Application entry point -├── NetV2V3Server.csproj # Project file -└── README.md # This file -``` - -## Running the Server - -For S3 Encryption Client v2 (runs on port 8083): - -```bash -dotnet run -p:S3EncryptionVersion=v2 -``` - -For S3 Encryption Client v3 (runs on port 8084): - -```bash -dotnet run -p:S3EncryptionVersion=v3 -``` - -## API Endpoints - -### Client Management - -- `POST /Client` - Create a new S3 encryption client - -### Object Operations - -- `PUT /{bucket}/{key}` - Upload an encrypted object to S3 -- `GET /{bucket}/{key}` - Download and decrypt an object from S3 - -All object operations require a `clientId` header to specify which client to use. - -## Example Usage - -### Create a Client - -```bash -curl -i -X POST \ - -H "Content-Type: application/json" \ - -H "User-Agent: smithy-java/0.0.3 ua/2.1 os/macos#15.5 lang/java#23.0.2" \ - -d '{"config":{"enableLegacyUnauthenticatedModes":true,"enableLegacyWrappingAlgorithms":true,"keyMaterial":{"kmsKeyId":"arn:aws:kms:us-west-2:370957321024:alias/S3EC-Test-Server-Github-KMS-Key"}, "encryptionContext": {"abc": "b"}}}' \ - http://localhost:8083/client -``` - -### Upload an Object - -```bash -curl -X PUT \ - -H "clientid: 7978763a-a02b-4dea-a5d4-78ef11d13d12" \ - -H "content-type: application/octet-stream" \ - -d "simple-test-input-net" \ - http://localhost:8083/object/s3ec-test-server-github-bucket/cross-lang-test-key-kms-ec-dotnet -``` - -### Download an Object - -```bash -curl -X GET \ - -H "clientid: 7978763a-a02b-4dea-a5d4-78ef11d13d12" \ - http://localhost:8083/object/s3ec-test-server-github-bucket/cross-lang-test-key-kms-ec-dotnet -``` diff --git a/test-server/net-v2-v3-server/Services/ClientCacheService.cs b/test-server/net-v2-v3-server/Services/ClientCacheService.cs deleted file mode 100644 index d8239c9b..00000000 --- a/test-server/net-v2-v3-server/Services/ClientCacheService.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Amazon.Extensions.S3.Encryption; -using System.Collections.Concurrent; - -namespace NetV2V3Server.Services; - -public interface IClientCacheService -{ - string AddClient(AmazonS3EncryptionClientV2 client); - AmazonS3EncryptionClientV2? GetClient(string clientId); -} - -public class ClientCacheService : IClientCacheService -{ - private readonly ConcurrentDictionary _clients = new(); - - public string AddClient(AmazonS3EncryptionClientV2 client) - { - var clientId = Guid.NewGuid().ToString(); - _clients[clientId] = client; - return clientId; - } - - public AmazonS3EncryptionClientV2? GetClient(string clientId) - { - _clients.TryGetValue(clientId, out var client); - return client; - } -} diff --git a/test-server/net-v2-v3-server/s3ec-net-v2 b/test-server/net-v2-v3-server/s3ec-net-v2 deleted file mode 160000 index ba85c07e..00000000 --- a/test-server/net-v2-v3-server/s3ec-net-v2 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ba85c07e0706bae8df242fb7bbfa7e53a264bafa diff --git a/test-server/net-v2-v3-server/s3ec-net-v3 b/test-server/net-v2-v3-server/s3ec-net-v3 deleted file mode 160000 index cc942cb5..00000000 --- a/test-server/net-v2-v3-server/s3ec-net-v3 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit cc942cb541a733a4340f46bd3e4a1d29a9cbb9a3 diff --git a/test-server/net-v3-transition-server/README.md b/test-server/net-v3-transition-server/README.md index 7634a4e7..ea925c73 100644 --- a/test-server/net-v3-transition-server/README.md +++ b/test-server/net-v3-transition-server/README.md @@ -1,11 +1,11 @@ -# Net-V2-V3-Server +# Net-V3-Transition-Server A .NET test server for Amazon S3 encryption client .NET v3 transition. ## Project Structure ``` -net-v2-v3-server/ +net-v3-transition-server/ ├── Controllers/ # API controllers ├── Models/ # Data models ├── Services/ # Business logic services diff --git a/test-server/net-v3-transition-server/s3ec-v3-transition-branch b/test-server/net-v3-transition-server/s3ec-v3-transition-branch index c3bf38b9..7a552940 160000 --- a/test-server/net-v3-transition-server/s3ec-v3-transition-branch +++ b/test-server/net-v3-transition-server/s3ec-v3-transition-branch @@ -1 +1 @@ -Subproject commit c3bf38b93c25f7169982073b1ffd1f3d00f59073 +Subproject commit 7a55294068bb3bb7f96226efd6d9edcd1057184b diff --git a/test-server/net-v4-server/README.md b/test-server/net-v4-server/README.md index dd5a6753..487d8471 100644 --- a/test-server/net-v4-server/README.md +++ b/test-server/net-v4-server/README.md @@ -1,11 +1,11 @@ -# Net-V2-V3-Server +# Net-V4-Server -A .NET test server for Amazon S3 encryption client .NET v2 and v3. +A .NET test server for Amazon S3 encryption client .NET v4. ## Project Structure ``` -net-v2-v3-server/ +net-v4-server/ ├── Controllers/ # API controllers ├── Models/ # Data models ├── Services/ # Business logic services diff --git a/test-server/net-v4-server/s3ec-net-v4-improved b/test-server/net-v4-server/s3ec-net-v4-improved index 04f70c8b..9b628b06 160000 --- a/test-server/net-v4-server/s3ec-net-v4-improved +++ b/test-server/net-v4-server/s3ec-net-v4-improved @@ -1 +1 @@ -Subproject commit 04f70c8b70e25c7a1a36fcd5a420c40806157c66 +Subproject commit 9b628b06e5c1bf12696c752afb2631c38cae11f9 diff --git a/test-server/php-v2-server/.duvet/.gitignore b/test-server/php-v2-server/.duvet/.gitignore deleted file mode 100644 index 93956e36..00000000 --- a/test-server/php-v2-server/.duvet/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -reports/ -requirements/ -specification/ \ No newline at end of file diff --git a/test-server/php-v2-server/.duvet/config.toml b/test-server/php-v2-server/.duvet/config.toml deleted file mode 100644 index 64b00927..00000000 --- a/test-server/php-v2-server/.duvet/config.toml +++ /dev/null @@ -1,24 +0,0 @@ -'$schema' = "https://awslabs.github.io/duvet/config/v0.4.0.json" - -[[source]] -pattern = "local-php-sdk/src/S3/**/*.php" - -[[source]] -pattern = "local-php-sdk/src/Crypto/**/*.php" - -# Include required specifications here -[[specification]] -source = "../specification/s3-encryption/data-format/content-metadata.md" -[[specification]] -source = "../specification/s3-encryption/data-format/metadata-strategy.md" -[[specification]] -source = "../specification/s3-encryption/encryption.md" -[[specification]] -source = "../specification/s3-encryption/key-derivation.md" - -[report.html] -enabled = true - -# Enable snapshots to prevent requirement coverage regressions -[report.snapshot] -enabled = false diff --git a/test-server/php-v2-server/.gitignore b/test-server/php-v2-server/.gitignore deleted file mode 100644 index 07108589..00000000 --- a/test-server/php-v2-server/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -vendor/* -cookies.txt -server.pid -composer.lock \ No newline at end of file diff --git a/test-server/php-v2-server/Makefile b/test-server/php-v2-server/Makefile deleted file mode 100644 index 719ea238..00000000 --- a/test-server/php-v2-server/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -# Makefile for S3 Encryption Client Testing - -.PHONY: build-server start-server stop-server wait-for-server - -PID_FILE := server.pid -PORT := 8087 - -build-server: - @echo "Building PHP V2 server..." - composer install - -start-server: - @echo "Starting PHP V2 server..." - AWS_ACCESS_KEY_ID="$$AWS_ACCESS_KEY_ID" \ - AWS_SECRET_ACCESS_KEY="$$AWS_SECRET_ACCESS_KEY" \ - AWS_SESSION_TOKEN="$$AWS_SESSION_TOKEN" \ - AWS_REGION="us-west-2" \ - composer run start --timeout=0 > server.log 2>&1 & echo $$! > $(PID_FILE) - @echo "PHP V2 server starting..." - -stop-server: - @echo "Stopping server on port $(PORT)..." - @lsof -ti:$(PORT) | xargs kill -9 2>/dev/null || true - @if [ -f $(PID_FILE) ]; then \ - pkill -P $$(cat $(PID_FILE)) 2>/dev/null || true; \ - kill -9 $$(cat $(PID_FILE)) 2>/dev/null || true; \ - rm -f $(PID_FILE); \ - fi - @rm -f server.log - @echo "Server stopped" - -wait-for-server: - $(MAKE) -C .. wait-for-port PORT=$(PORT) - -duvet: - duvet report - -view-report-mac: - open .duvet/reports/report.html diff --git a/test-server/php-v2-server/README.md b/test-server/php-v2-server/README.md deleted file mode 100644 index c4ba49fe..00000000 --- a/test-server/php-v2-server/README.md +++ /dev/null @@ -1,69 +0,0 @@ -# S3EC PHP v2 Test Server - -This is the PHP V2 implementation of the S3ECTestServer framework. It provides a server implementation for testing S3 Encryption Client functionality. - -## Overview - -The S3ECPhpV2TestServer implements the S3ECTestServer service defined in the shared Smithy model. It provides endpoints for: - -- Creating S3 Encryption Clients with session-based caching -- Putting objects with encryption -- Getting and decrypting objects - -## Starting the Server - -### Method 1: Using Composer (Recommended) -```bash -composer run start -``` - -The server will start on port `8087`. - -## Available Endpoints - -### Server Status -- **GET /** - Returns server status and available endpoints - -### Client Management -- **POST /client** - Creates an S3EncryptionClient and caches it with session persistence -- **GET /cache** - Shows current session state and cached clients (for debugging) - -### Object Operations -- **GET /object/{bucket}/{key}** - Handle GET requests using the S3EncryptionClient -- **PUT /object/{bucket}/{key}** - Handle PUT requests using the S3EncryptionClient - -## Testing with curl - -### Important: Session Cookie Management - -To properly test the server and maintain session persistence, you **must** use cookies with curl: - -#### First Request (creates session cookie): -```bash -curl -X POST http://localhost:8087/client \ - -H "Content-Type: application/json" \ - -c cookies.txt \ - -v -``` - -#### Subsequent Requests (reuses session cookie): -```bash -curl -X POST http://localhost:8087/client \ - -H "Content-Type: application/json" \ - -b cookies.txt \ - -c cookies.txt \ - -v -``` - -#### Check Cache Status: -```bash -curl http://localhost:8087/cache \ - -b cookies.txt -``` - -#### Helpful Notes -- **Session Storage**: Client configurations are stored in `$_SESSION['s3ecCache']` -- **Object Recreation**: AWS SDK objects are recreated from stored configuration (they cannot be serialized) -AWS SDK obbjects cannot be serialized due to internal resources and closures. -- **Helper Function**: `getCachedClient($clientId)` retrieves and recreates clients from cache -- **Debugging**: Enhanced logging and `/cache` endpoint for troubleshooting diff --git a/test-server/php-v2-server/composer.json b/test-server/php-v2-server/composer.json deleted file mode 100644 index d5177951..00000000 --- a/test-server/php-v2-server/composer.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "aws/s3ec-php-v2-test-server", - "description": "PHP v2 implementation of the S3EC Test Server framework", - "type": "project", - "license": "Apache-2.0", - "repositories": [ - { - "type": "path", - "url": "./local-php-sdk", - "options": { - "symlink": true - } - } - ], - "require": { - "php": ">=7.4", - "aws/aws-sdk-php": "@dev", - "ramsey/uuid": "^4.9" - }, - "autoload": { - "psr-4": { - "S3EC\\PhpV2Server\\": "src/" - } - }, - "scripts": { - "start": [ - "php -S 0.0.0.0:8087 src/index.php" - ] - }, - "config": { - "optimize-autoloader": true, - "platform": { - "php": "8.1" - } - } -} \ No newline at end of file diff --git a/test-server/php-v2-server/local-php-sdk b/test-server/php-v2-server/local-php-sdk deleted file mode 160000 index ab8aee74..00000000 --- a/test-server/php-v2-server/local-php-sdk +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ab8aee74db1141da07c9c979cf313418fddae256 diff --git a/test-server/php-v2-server/src/client.php b/test-server/php-v2-server/src/client.php deleted file mode 100644 index 9c39d540..00000000 --- a/test-server/php-v2-server/src/client.php +++ /dev/null @@ -1,74 +0,0 @@ -toString(); - $kmsKeyId = $keyMaterial["kmsKeyId"] ?? null; - $instFileConfig = $configData['instructionFileConfig'] ?? null; - $instFilePut = false; - if ($instFileConfig != null) { - $instFilePut = $instFileConfig['enableInstructionFilePutObject'] ?? false; - } - - if ($configData == []) { - return GenericServerError("Invalid config in request body", 400); - } - if (($keyMaterial || $kmsKeyId) === null) { - return GenericServerError("Invalid keyMaterial in config", 400); - } - - // Store client configuration instead of objects (AWS objects can't be serialized) - $_SESSION['s3ecCache'][$clientId] = [ - 's3Config' => [ - 'region' => 'us-west-2', - 'version' => 'latest', - 'http' => [ - 'debug' => false, - 'verify' => true, - 'curl' => [ - CURLOPT_VERBOSE => false, - CURLOPT_NOPROGRESS => true - ] - ] - ], - 'kmsConfig' => [ - 'region' => 'us-west-2', - 'version' => 'latest', - 'http' => [ - 'debug' => false, - 'verify' => true, - 'curl' => [ - CURLOPT_VERBOSE => false, - CURLOPT_NOPROGRESS => true - ] - ] - ], - 'kmsKeyId' => $kmsKeyId, - 'legacy' => $legacyAlgorithms, - 'instFilePut' => $instFilePut, - 'created' => time() - ]; - - // Auto-update cookies.txt with current session ID so tests can access cached clients - writeSessionIdToCookiesFile(session_id()); - - header("Content-Type: application/json"); - return json_encode([ - 'clientId' => $clientId, - ]); -} diff --git a/test-server/php-v2-server/src/errors.php b/test-server/php-v2-server/src/errors.php deleted file mode 100644 index 2b59861d..00000000 --- a/test-server/php-v2-server/src/errors.php +++ /dev/null @@ -1,42 +0,0 @@ - 'GenericServerError', - 'message' => $message - ]; - - return json_encode($errorResponse); -} - -/** - * Used for modeled errors, e.g. errors thrown by the S3EC - * Tests SHOULD expect this error in negative tests. - * - * @param string $message The error message to include in the response - * @return string JSON-encoded error response - */ -function S3EncryptionClientError($message) -{ - http_response_code(500); - header('Content-Type: application/json'); - - $errorResponse = [ - "__type" => "software.amazon.encryption.s3#S3EncryptionClientError", - 'message' => $message - ]; - - return json_encode($errorResponse); -} diff --git a/test-server/php-v2-server/src/get_object.php b/test-server/php-v2-server/src/get_object.php deleted file mode 100644 index 61bacb5b..00000000 --- a/test-server/php-v2-server/src/get_object.php +++ /dev/null @@ -1,85 +0,0 @@ -getObject([ - '@SecurityProfile' => $legacy, - '@MaterialsProvider' => $materialProvider, - '@KmsEncryptionContext' => $encryptionContext, - 'Bucket' => $bucket, - 'Key' => $key, - ]); - - // Capture and discard any unwanted output from AWS SDK - $unwantedOutput = ob_get_clean(); - if (!empty($unwantedOutput)) { - error_log("AWS SDK produced unexpected output: " . strlen($unwantedOutput) . " bytes"); - } - - $body = $result['Body']->getContents(); - $formattedMetadata = formatMetadataForResponse($result["Metadata"]); - - // Now set headers safely - header("Content-Metadata: " . $formattedMetadata); - header("Content-Type: application/octet-stream"); - header("Content-Length: " . strlen($body)); - return $body; - } catch (InvalidArgumentException $e) { - // Clean up output buffer if still active - if (ob_get_level()) { - ob_end_clean(); - } - return GenericServerError("Invalid argument: " . $e->getMessage(), 400); - } catch (Exception $e) { - // Clean up output buffer if still active - if (ob_get_level()) { - ob_end_clean(); - } - if (strpos($e->getMessage(), "@SecurityProfile=V2") !== false) { - return S3EncryptionClientError($e->getMessage() . " " . "Enable legacy wrapping algorithms to use legacy key wrapping algorithm: kms"); - } else { - return GenericServerError("Server argument: " . $e->getMessage(), 500); - } - } -} diff --git a/test-server/php-v2-server/src/index.php b/test-server/php-v2-server/src/index.php deleted file mode 100644 index 167834e0..00000000 --- a/test-server/php-v2-server/src/index.php +++ /dev/null @@ -1,295 +0,0 @@ -= 7 && $parts[5] === 'PHPSESSID') { - error_log("Found session ID in cookies.txt: " . $parts[6]); - return $parts[6]; // Return the session ID value - } - } - - error_log("No PHPSESSID found in cookies.txt file"); - return null; -} - -// Function to write session ID to cookies.txt file -function writeSessionIdToCookiesFile($sessionId) -{ - $cookiesFile = __DIR__ . '/../cookies.txt'; - - // Create Netscape cookie format entry - $cookieLine = "localhost\tFALSE\t/\tFALSE\t0\tPHPSESSID\t$sessionId"; - - // Write header and cookie entry - $content = "# Netscape HTTP Cookie File\n"; - $content .= "# https://curl.se/docs/http-cookies.html\n"; - $content .= "# This file was generated by libcurl! Edit at your own risk.\n\n"; - $content .= $cookieLine . "\n"; - - $result = file_put_contents($cookiesFile, $content); - - if ($result === false) { - error_log("Failed to write session ID to cookies.txt file: $cookiesFile"); - return false; - } - - error_log("Successfully wrote session ID to cookies.txt: $sessionId"); - return true; -} - -set_time_limit(600); -// Start session to persist cache across requests -// First try to use session ID from cookies.txt if available -$sessionId = getSessionIdFromCookiesFile(); -if ($sessionId) { - session_id($sessionId); -} -session_start(); - -// Initialize session cache if it doesn't exist -if (!isset($_SESSION['s3ecCache'])) { - $_SESSION['s3ecCache'] = []; -} - -// Simple router class -class SimpleRouter -{ - private $routes = []; - - public function addRoute($method, $path, $handler) - { - $this->routes[] = [ - 'method' => strtoupper($method), - 'path' => $path, - 'handler' => $handler - ]; - } - - public function handleRequest() - { - $method = $_SERVER['REQUEST_METHOD']; - $path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); - - foreach ($this->routes as $route) { - if ($route['method'] === $method) { - $params = $this->matchPathWithParams($route['path'], $path); - if ($params !== false) { - return call_user_func($route['handler'], $params); - } - } - } - - // Default 404 response - http_response_code(404); - return json_encode(['error' => 'Not Found']); - } - - private function matchPathWithParams($routePath, $requestPath) - { - // Handle exact matches first (for routes without parameters) - if ($routePath === $requestPath) { - return []; - } - - // Convert route path like '/object/{bucket}/{key}' to regex - $pattern = preg_replace('/\{([^}]+)\}/', '([^/]+)', $routePath); - $pattern = '/^' . str_replace('/', '\/', $pattern) . '$/'; - - if (preg_match($pattern, $requestPath, $matches)) { - array_shift($matches); // Remove full match - - // Extract parameter names - preg_match_all('/\{([^}]+)\}/', $routePath, $paramNames); - $params = []; - - foreach ($paramNames[1] as $index => $paramName) { - $params[$paramName] = $matches[$index] ?? null; - } - - return $params; - } - - return false; - } -} - -// Helper function to get cached client by ID -function getCachedClient($clientId) -{ - if (!isset($_SESSION['s3ecCache'][$clientId])) { - return null; - } - - $config = $_SESSION['s3ecCache'][$clientId]; - - // Recreate the AWS clients from stored configuration - $s3Client = new S3Client($config['s3Config']); - $encryptionClient = new S3EncryptionClientV2($s3Client); - - $kmsClient = new KmsClient($config['kmsConfig']); - $materialsProvider = new KmsMaterialsProviderV2($kmsClient, $config['kmsKeyId']); - - return [ - 's3Client' => $s3Client, - 'encryptionClient' => $encryptionClient, - 'materialsProvider' => $materialsProvider, - 'config' => $config - ]; -} - -function createDefaultClientTuple(): array -{ - $s3Client = new S3Client([ - 'region' => 'us-west-2', - 'version' => 'latest', - 'http' => [ - 'debug' => false, - 'verify' => true, - 'curl' => [ - CURLOPT_VERBOSE => false, - CURLOPT_NOPROGRESS => true - ] - ] - ]); - $encryptionClient = new S3EncryptionClientV2($s3Client); - - $kmsClient = new KmsClient([ - 'region' => 'us-west-2', - 'version' => 'latest', - 'http' => [ - 'debug' => false, - 'verify' => true, - 'curl' => [ - CURLOPT_VERBOSE => false, - CURLOPT_NOPROGRESS => true - ] - ] - ]); - $materialsProvider = new KmsMaterialsProviderV2($kmsClient, 'arn:aws:kms:us-west-2:370957321024:alias/S3EC-Test-Server-Github-KMS-Key'); - - return [ - 'encryptionClient' => $encryptionClient, - 'materialsProvider' => $materialsProvider - ]; -} - -function metadataStringToMap($metadata): array -{ - $md = []; - - if (empty($metadata)) { - return $md; - } - - $mdList = explode(',', $metadata); - - foreach ($mdList as $entry) { - $parts = explode(']:[', $entry); - - if (count($parts) === 2) { - $key = substr($parts[0], 1); - $value = substr($parts[1], 0, -1); - $md[$key] = $value; - } else { - throw new InvalidArgumentException("Malformed metadata list entry: " . $entry); - } - } - - return $md; -} -function formatMetadataForResponse($metadata) -{ - $metadataList = []; - // Handle different metadata input types - if (is_array($metadata)) { - // If it's an associative array (like Python dict) - foreach ($metadata as $key => $value) { - $metadataList[] = $key . '=' . $value; - } - } elseif (is_string($metadata) && !empty($metadata)) { - // If it's already a string, assume it's in the correct format - return $metadata; - } - - // Convert array to comma-separated string - return implode(',', $metadataList); -} - -// Initialize router -$router = new SimpleRouter(); - -// Add basic routes -$router->addRoute('GET', '/', function () { - return json_encode([ - 'service' => 'S3EC PHP v2 Test Server', - 'status' => 'running', - 'port' => 8087, - 'endpoints' => [ - 'GET /' => 'Server status', - 'POST /client' => 'Create an S3EncryptionClient and cache it.', - 'GET /object/{bucket}/{key}' => 'Handle GET requests to /object/{bucket}/{key} by using the S3EncryptionClient to make a GetObject request to S3.', - 'PUT /object/{bucket}/{key}' => 'Handle PUT requests to /object/{bucket}/{key} by using the S3EncryptionClient to make a PutObject request to S3.', - ] - ]); -}); - -$router->addRoute('GET', '/cache', function () { - return json_encode([ - 'sessionId' => session_id(), - 'sessionStatus' => session_status(), - 'totalCachedClients' => count($_SESSION['s3ecCache'] ?? []), - 'allClientIds' => array_keys($_SESSION['s3ecCache'] ?? []), - 'cacheDetails' => $_SESSION['s3ecCache'] ?? [] - ]); -}); - -$router->addRoute('GET', '/object/{bucket}/{key}', function ($params) { - return handleGetObject($params); -}); - -$router->addRoute('PUT', '/object/{bucket}/{key}', function ($params) { - return handlePutObject($params); -}); - -$router->addRoute('POST', '/client', function () { - return handleCreateClient(); -}); - -// Handle the request and output response -$result = $router->handleRequest(); -if ($result !== false) { - echo $result; -} diff --git a/test-server/php-v2-server/src/put_object.php b/test-server/php-v2-server/src/put_object.php deleted file mode 100644 index c6c592fe..00000000 --- a/test-server/php-v2-server/src/put_object.php +++ /dev/null @@ -1,79 +0,0 @@ - 'gcm', - 'KeySize' => 256, - ]; - $legacyConfig = $s3ecClientTuple["legacy"] ?? false; - $legacy = null; - if ($legacyConfig === false) { - $legacy = "V2"; - } else { - $legacy = "V2_AND_LEGACY"; - } - $strategy = $s3ecClientTuple["config"]["instFilePut"] ? - new InstructionFileMetadataStrategy($s3Client) : - new HeadersMetadataStrategy(); - try { - $result = $s3ec->putObject([ - '@SecurityProfile' => $legacy, - '@MaterialsProvider' => $materialProvider, - '@KmsEncryptionContext' => $encryptionContext, - '@MetadataStrategy' => $strategy, - '@CipherOptions' => $cipherOptions, - 'Bucket' => $bucket, - 'Key' => $key, - 'Body' => $rawBody, - ]); - - header("Content-Type: application/json"); - return json_encode([ - "bucket" => $bucket, - "key" => $key, - // php for some reason blows java's heap if we pass the metadata - // "metadata" => $encryptionContext - ]); - - } catch (InvalidArgumentException $e) { - return S3EncryptionClientError("Invalid arguement: " . $e->getMessage()); - } catch (Exception $e) { - return GenericServerError("Server error: " . $e->getMessage()); - } -} diff --git a/test-server/php-v3-server/local-php-sdk b/test-server/php-v3-server/local-php-sdk index 163fe386..f53d8fc6 160000 --- a/test-server/php-v3-server/local-php-sdk +++ b/test-server/php-v3-server/local-php-sdk @@ -1 +1 @@ -Subproject commit 163fe3866e7122d6cd1dbff6f121302db8d98aae +Subproject commit f53d8fc6cdbc1e64e7d14e72d1e315d05003b2b4 diff --git a/test-server/ruby-v2-server/local-ruby-sdk b/test-server/ruby-v2-server/local-ruby-sdk index 1f32f5b9..93985e94 160000 --- a/test-server/ruby-v2-server/local-ruby-sdk +++ b/test-server/ruby-v2-server/local-ruby-sdk @@ -1 +1 @@ -Subproject commit 1f32f5b9ade757b6f2bce0650af43eefe9581d01 +Subproject commit 93985e94bbe8345cc7d615d1cdbcd7516ac16bcd diff --git a/test-server/ruby-v3-server/local-ruby-sdk b/test-server/ruby-v3-server/local-ruby-sdk index 1f32f5b9..93985e94 160000 --- a/test-server/ruby-v3-server/local-ruby-sdk +++ b/test-server/ruby-v3-server/local-ruby-sdk @@ -1 +1 @@ -Subproject commit 1f32f5b9ade757b6f2bce0650af43eefe9581d01 +Subproject commit 93985e94bbe8345cc7d615d1cdbcd7516ac16bcd diff --git a/test/test_exceptions.py b/test/test_exceptions.py new file mode 100644 index 00000000..f93e3d9d --- /dev/null +++ b/test/test_exceptions.py @@ -0,0 +1,51 @@ +import pytest +from botocore.exceptions import BotoCoreError + +from s3_encryption.exceptions import ( + S3EncryptionClientError, + S3EncryptionClientSecurityError, +) + + +class TestS3EncryptionClientError: + def test_default_message(self): + error = S3EncryptionClientError() + assert str(error) == "An unspecified S3 Encryption Client error occurred" + + def test_custom_message(self): + error = S3EncryptionClientError("Custom error message") + assert str(error) == "Custom error message" + + def test_empty_message(self): + error = S3EncryptionClientError("") + assert str(error) == "" + + def test_inherits_from_botocore_error(self): + error = S3EncryptionClientError("test") + assert isinstance(error, BotoCoreError) + + def test_can_be_caught_as_botocore_error(self): + with pytest.raises(BotoCoreError): + raise S3EncryptionClientError("test error") + + +class TestS3EncryptionClientSecurityError: + def test_default_message(self): + error = S3EncryptionClientSecurityError() + assert str(error) == "An unspecified S3 Encryption Client Security error occurred" + + def test_custom_message(self): + error = S3EncryptionClientSecurityError("Custom security error") + assert str(error) == "Custom security error" + + def test_empty_message(self): + error = S3EncryptionClientSecurityError("") + assert str(error) == "" + + def test_inherits_from_botocore_error(self): + error = S3EncryptionClientSecurityError("test") + assert isinstance(error, BotoCoreError) + + def test_can_be_caught_as_botocore_error(self): + with pytest.raises(BotoCoreError): + raise S3EncryptionClientSecurityError("test security error")