diff --git a/.github/workflows/docker-bats.yaml b/.github/workflows/docker-bats.yaml index ca18158..e8373cf 100644 --- a/.github/workflows/docker-bats.yaml +++ b/.github/workflows/docker-bats.yaml @@ -25,4 +25,4 @@ jobs: run: sudo apt-get install -y docker-compose - name: Run Docker Container - run: docker-compose -f docker-compose-bats.yml up posix_backend + run: docker-compose -f docker-compose-bats.yml up --exit-code-from posix_backend posix_backend diff --git a/.github/workflows/system.yml b/.github/workflows/system.yml index 2d1ff7c..f8bea9d 100644 --- a/.github/workflows/system.yml +++ b/.github/workflows/system.yml @@ -85,6 +85,17 @@ jobs: RECREATE_BUCKETS: "true" PORT: 7076 BACKEND: "s3" + - set: 8 + LOCAL_FOLDER: /tmp/gw8 + BUCKET_ONE_NAME: versity-gwtest-bucket-one-7 + BUCKET_TWO_NAME: versity-gwtest-bucket-two-7 + IAM_TYPE: folder + USERS_FOLDER: /tmp/iam8 + AWS_ENDPOINT_URL: https://127.0.0.1:7077 + RUN_SET: "rest" + RECREATE_BUCKETS: "true" + PORT: 7077 + BACKEND: "posix" steps: - name: Check out code into the Go module directory uses: actions/checkout@v4 @@ -115,6 +126,10 @@ jobs: curl https://dl.min.io/client/mc/release/linux-amd64/mc --create-dirs -o /usr/local/bin/mc chmod 755 /usr/local/bin/mc + - name: Install xmllint (for rest) + run: | + sudo apt-get install libxml2-utils + - name: Build and run, posix backend env: LOCAL_FOLDER: ${{ matrix.LOCAL_FOLDER }} diff --git a/Dockerfile_test_bats b/Dockerfile_test_bats index cb2ea60..ab52e3f 100644 --- a/Dockerfile_test_bats +++ b/Dockerfile_test_bats @@ -19,6 +19,7 @@ RUN apt-get update && \ s3cmd \ jq \ bc \ + libxml2-utils \ ca-certificates && \ update-ca-certificates && \ rm -rf /var/lib/apt/lists/* diff --git a/tests/.env.default b/tests/.env.default index 1c4c7ed..e83e675 100644 --- a/tests/.env.default +++ b/tests/.env.default @@ -26,4 +26,4 @@ PASSWORD_ONE=HIJKLMN USERNAME_TWO=HIJKLMN PASSWORD_TWO=OPQRSTU TEST_FILE_FOLDER=$PWD/versity-gwtest-files -REMOVE_TEST_FILE_FOLDER=false +REMOVE_TEST_FILE_FOLDER=true diff --git a/tests/.env.docker.default b/tests/.env.docker.default index 73ba181..0ea1637 100644 --- a/tests/.env.docker.default +++ b/tests/.env.docker.default @@ -24,4 +24,5 @@ PASSWORD_ONE=HIJKLMN USERNAME_TWO=HIJKLMN PASSWORD_TWO=OPQRSTU TEST_FILE_FOLDER=$PWD/versity-gwtest-files -RECREATE_BUCKETS=true \ No newline at end of file +RECREATE_BUCKETS=true +REMOVE_TEST_FILE_FOLDER=true \ No newline at end of file diff --git a/tests/commands/list_buckets.sh b/tests/commands/list_buckets.sh index 7bc8c0d..6e3a171 100644 --- a/tests/commands/list_buckets.sh +++ b/tests/commands/list_buckets.sh @@ -31,6 +31,8 @@ list_buckets() { buckets=$(s3cmd "${S3CMD_OPTS[@]}" --no-check-certificate ls s3:// 2>&1) || exit_code=$? elif [[ $1 == 'mc' ]]; then buckets=$(mc --insecure ls "$MC_ALIAS" 2>&1) || exit_code=$? + elif [[ $1 == 'rest' ]]; then + list_buckets_rest || exit_code=$? else echo "list buckets command not implemented for '$1'" return 1 @@ -40,7 +42,7 @@ list_buckets() { return 1 fi - if [[ $1 == 's3api' ]] || [[ $1 == 'aws' ]]; then + if [[ $1 == 's3api' ]] || [[ $1 == 'aws' ]] || [[ $1 == 'rest' ]]; then return 0 fi @@ -113,3 +115,32 @@ list_buckets_s3api() { return 0 } + +list_buckets_rest() { + generate_hash_for_payload "" + + current_date_time=$(date -u +"%Y%m%dT%H%M%SZ") + # shellcheck disable=SC2154 + canonical_request="GET +/ + +host:${AWS_ENDPOINT_URL#*//} +x-amz-content-sha256:$payload_hash +x-amz-date:$current_date_time + +host;x-amz-content-sha256;x-amz-date +$payload_hash" + + if ! generate_sts_string "$current_date_time" "$canonical_request"; then + log 2 "error generating sts string" + return 1 + fi + + get_signature + # shellcheck disable=SC2034,SC2154 + reply=$(curl -ks "$AWS_ENDPOINT_URL" \ + -H "Authorization: AWS4-HMAC-SHA256 Credential=$AWS_ACCESS_KEY_ID/$ymd/$AWS_REGION/s3/aws4_request,SignedHeaders=host;x-amz-content-sha256;x-amz-date,Signature=$signature" \ + -H "x-amz-content-sha256: $payload_hash" \ + -H "x-amz-date: $current_date_time" 2>&1) + parse_bucket_list +} diff --git a/tests/commands/list_objects.sh b/tests/commands/list_objects.sh index 3c8ecda..018ee6c 100644 --- a/tests/commands/list_objects.sh +++ b/tests/commands/list_objects.sh @@ -1,5 +1,7 @@ #!/usr/bin/env bash +source ./tests/util_list_objects.sh + # Copyright 2024 Versity Software # This file is licensed under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance @@ -35,6 +37,9 @@ list_objects() { output=$(s3cmd "${S3CMD_OPTS[@]}" --no-check-certificate ls s3://"$2" 2>&1) || result=$? elif [[ $1 == 'mc' ]]; then output=$(mc --insecure ls "$MC_ALIAS"/"$2" 2>&1) || result=$? + elif [[ $1 == 'rest' ]]; then + list_objects_rest "$2" || result=$? + return $result else fail "invalid command type $1" return 1 @@ -126,3 +131,41 @@ list_objects_with_prefix() { export objects return 0 } + +list_objects_rest() { + if [ $# -ne 1 ]; then + log 2 "'list_objects_rest' requires bucket name" + return 1 + fi + + generate_hash_for_payload "" + + current_date_time=$(date -u +"%Y%m%dT%H%M%SZ") + aws_endpoint_url_address=${AWS_ENDPOINT_URL#*//} + header=$(echo "$AWS_ENDPOINT_URL" | awk -F: '{print $1}') + # shellcheck disable=SC2154 + canonical_request="GET +/$1 + +host:$aws_endpoint_url_address +x-amz-content-sha256:$payload_hash +x-amz-date:$current_date_time + +host;x-amz-content-sha256;x-amz-date +$payload_hash" + + log 5 "canonical request: $canonical_request" + + if ! generate_sts_string "$current_date_time" "$canonical_request"; then + log 2 "error generating sts string" + return 1 + fi + get_signature + # shellcheck disable=SC2154 + reply=$(curl -ks "$header://$aws_endpoint_url_address/$1" \ + -H "Authorization: AWS4-HMAC-SHA256 Credential=$AWS_ACCESS_KEY_ID/$ymd/$AWS_REGION/s3/aws4_request,SignedHeaders=host;x-amz-content-sha256;x-amz-date,Signature=$signature" \ + -H "x-amz-content-sha256: $payload_hash" \ + -H "x-amz-date: $current_date_time" 2>&1) + log 5 "reply: $reply" + parse_objects_list_rest +} diff --git a/tests/run.sh b/tests/run.sh index a1df0c4..3f670f4 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -24,6 +24,7 @@ show_help() { echo " s3 Run tests with s3 cli" echo " s3cmd Run tests with s3cmd utility" echo " mc Run tests with mc utility" + echo " rest Run tests with rest cli" echo " aws-user Run user tests with aws cli" } @@ -33,7 +34,7 @@ handle_param() { show_help exit 0 ;; - s3|s3api|aws|s3cmd|mc|aws-user) + s3|s3api|aws|s3cmd|mc|aws-user|rest) set_command_type "$1" ;; *) # Handle unrecognized options or positional arguments @@ -85,6 +86,10 @@ case $command_type in echo "Running mc tests ..." "$HOME"/bin/bats ./tests/test_mc.sh || exit_code=$? ;; + rest) + echo "Running rest tests ..." + "$HOME"/bin/bats ./tests/test_rest.sh || exit_code=$? + ;; aws-user) echo "Running aws user tests ..." "$HOME"/bin/bats ./tests/test_user_aws.sh || exit_code=$? diff --git a/tests/run_all.sh b/tests/run_all.sh index 07de901..617f20d 100755 --- a/tests/run_all.sh +++ b/tests/run_all.sh @@ -31,4 +31,7 @@ fi if ! ./tests/run.sh mc; then exit 1 fi +if ! ./tests/run.sh rest; then + exit 1 +fi exit 0 diff --git a/tests/setup.sh b/tests/setup.sh index 9c83cde..28c892e 100644 --- a/tests/setup.sh +++ b/tests/setup.sh @@ -63,6 +63,12 @@ setup() { # bats teardown function teardown() { # shellcheck disable=SC2154 + if ! delete_bucket_or_contents_if_exists "$BUCKET_ONE_NAME"; then + log 3 "error deleting bucket $BUCKET_ONE_NAME or contents" + fi + if ! delete_bucket_or_contents_if_exists "$BUCKET_TWO_NAME"; then + log 3 "error deleting bucket $BUCKET_TWO_NAME or contents" + fi if [ "$REMOVE_TEST_FILE_FOLDER" == "true" ]; then log 6 "removing test file folder" if ! error=$(rm -rf "${TEST_FILE_FOLDER:?}" 2>&1); then diff --git a/tests/test_aws_root_inner.sh b/tests/test_aws_root_inner.sh index 3d5fbf9..2524cc7 100755 --- a/tests/test_aws_root_inner.sh +++ b/tests/test_aws_root_inner.sh @@ -17,6 +17,12 @@ source ./tests/commands/delete_objects.sh source ./tests/commands/list_objects_v2.sh source ./tests/commands/list_parts.sh +source ./tests/util_get_bucket_acl.sh +source ./tests/util_get_object_attributes.sh +source ./tests/util_get_object_retention.sh +source ./tests/util_head_object.sh +source ./tests/util_legal_hold.sh +source ./tests/util_list_objects.sh test_abort_multipart_upload_aws_root() { local bucket_file="bucket-file" @@ -30,31 +36,29 @@ test_abort_multipart_upload_aws_root() { run setup_bucket "aws" "$BUCKET_ONE_NAME" assert_success - run_then_abort_multipart_upload "$BUCKET_ONE_NAME" "$bucket_file" "$TEST_FILE_FOLDER"/"$bucket_file" 4 || fail "abort failed" + run run_then_abort_multipart_upload "$BUCKET_ONE_NAME" "$bucket_file" "$TEST_FILE_FOLDER"/"$bucket_file" 4 + assert_success - if object_exists "aws" "$BUCKET_ONE_NAME" "$bucket_file"; then - fail "Upload file exists after abort" - fi - - delete_bucket_or_contents "aws" "$BUCKET_ONE_NAME" - delete_test_files $bucket_file + run object_exists "aws" "$BUCKET_ONE_NAME" "$bucket_file" + assert_failure 1 } test_complete_multipart_upload_aws_root() { local bucket_file="bucket-file" run create_test_files "$bucket_file" assert_success - dd if=/dev/urandom of="$TEST_FILE_FOLDER/$bucket_file" bs=5M count=1 || fail "error creating test file" + + run dd if=/dev/urandom of="$TEST_FILE_FOLDER/$bucket_file" bs=5M count=1 + assert_success run setup_bucket "aws" "$BUCKET_ONE_NAME" assert_success - multipart_upload "$BUCKET_ONE_NAME" "$bucket_file" "$TEST_FILE_FOLDER"/"$bucket_file" 4 || fail "error performing multipart upload" + run multipart_upload "$BUCKET_ONE_NAME" "$bucket_file" "$TEST_FILE_FOLDER"/"$bucket_file" 4 + assert_success - download_and_compare_file "s3api" "$TEST_FILE_FOLDER/$bucket_file" "$BUCKET_ONE_NAME" "$bucket_file" "$TEST_FILE_FOLDER/$bucket_file-copy" || fail "error downloading and comparing file" - - delete_bucket_or_contents "aws" "$BUCKET_ONE_NAME" - delete_test_files $bucket_file + run download_and_compare_file "s3api" "$TEST_FILE_FOLDER/$bucket_file" "$BUCKET_ONE_NAME" "$bucket_file" "$TEST_FILE_FOLDER/$bucket_file-copy" + assert_success } test_create_multipart_upload_properties_aws_root() { @@ -67,7 +71,6 @@ test_create_multipart_upload_properties_aws_root() { local expected_retention_mode="GOVERNANCE" local expected_tag_key="TestTag" local expected_tag_val="TestTagVal" - local five_seconds_later os_name="$(uname)" if [[ "$os_name" == "Darwin" ]]; then @@ -80,64 +83,42 @@ test_create_multipart_upload_properties_aws_root() { run create_test_files "$bucket_file" assert_success - dd if=/dev/urandom of="$TEST_FILE_FOLDER/$bucket_file" bs=5M count=1 || fail "error creating test file" + + run dd if=/dev/urandom of="$TEST_FILE_FOLDER/$bucket_file" bs=5M count=1 + assert_success run delete_bucket_or_contents_if_exists "s3api" "$BUCKET_ONE_NAME" assert_success # in static bucket config, bucket will still exist - bucket_exists "s3api" "$BUCKET_ONE_NAME" || local exists_result=$? - [[ $exists_result -ne 2 ]] || fail "error checking for bucket existence" - if [[ $exists_result -eq 1 ]]; then + if ! bucket_exists "s3api" "$BUCKET_ONE_NAME"; then run create_bucket_object_lock_enabled "$BUCKET_ONE_NAME" assert_success fi - get_object_lock_configuration "$BUCKET_ONE_NAME" || fail "error getting log config" - # shellcheck disable=SC2154 - log 5 "LOG CONFIG: $log_config" - log 5 "LATER: $later" - multipart_upload_with_params "$BUCKET_ONE_NAME" "$bucket_file" "$TEST_FILE_FOLDER"/"$bucket_file" 4 \ + run multipart_upload_with_params "$BUCKET_ONE_NAME" "$bucket_file" "$TEST_FILE_FOLDER"/"$bucket_file" 4 \ "$expected_content_type" \ "{\"$expected_meta_key\": \"$expected_meta_val\"}" \ "$expected_hold_status" \ "$expected_retention_mode" \ "$later" \ "$expected_tag_key=$expected_tag_val" || fail "error performing multipart upload" + assert_success - head_object "s3api" "$BUCKET_ONE_NAME" "$bucket_file" || fail "error getting metadata" - # shellcheck disable=SC2154 - raw_metadata=$(echo "$metadata" | grep -v "InsecureRequestWarning") - log 5 "raw metadata: $raw_metadata" + run get_and_verify_metadata "$bucket_file" "$expected_content_type" "$expected_meta_key" "$expected_meta_val" \ + "$expected_hold_status" "$expected_retention_mode" "$later" + assert_success - content_type=$(echo "$raw_metadata" | jq -r ".ContentType") - [[ $content_type == "$expected_content_type" ]] || fail "content type mismatch ($content_type, $expected_content_type)" - meta_val=$(echo "$raw_metadata" | jq -r ".Metadata.$expected_meta_key") - [[ $meta_val == "$expected_meta_val" ]] || fail "metadata val mismatch ($meta_val, $expected_meta_val)" - hold_status=$(echo "$raw_metadata" | jq -r ".ObjectLockLegalHoldStatus") - [[ $hold_status == "$expected_hold_status" ]] || fail "hold status mismatch ($hold_status, $expected_hold_status)" - retention_mode=$(echo "$raw_metadata" | jq -r ".ObjectLockMode") - [[ $retention_mode == "$expected_retention_mode" ]] || fail "retention mode mismatch ($retention_mode, $expected_retention_mode)" - retain_until_date=$(echo "$raw_metadata" | jq -r ".ObjectLockRetainUntilDate") - [[ $retain_until_date == "$later"* ]] || fail "retention date mismatch ($retain_until_date, $five_seconds_later)" + run get_and_check_bucket_tags "$BUCKET_ONE_NAME" "$expected_tag_key" "$expected_tag_val" + assert_success - get_object_tagging "aws" "$BUCKET_ONE_NAME" "$bucket_file" || fail "error getting tagging" - # shellcheck disable=SC2154 - log 5 "tags: $tags" - tag_key=$(echo "$tags" | jq -r ".TagSet[0].Key") - [[ $tag_key == "$expected_tag_key" ]] || fail "tag mismatch ($tag_key, $expected_tag_key)" - tag_val=$(echo "$tags" | jq -r ".TagSet[0].Value") - [[ $tag_val == "$expected_tag_val" ]] || fail "tag mismatch ($tag_val, $expected_tag_val)" + run put_object_legal_hold "$BUCKET_ONE_NAME" "$bucket_file" "OFF" + assert_success - put_object_legal_hold "$BUCKET_ONE_NAME" "$bucket_file" "OFF" || fail "error disabling legal hold" - head_object "s3api" "$BUCKET_ONE_NAME" "$bucket_file" || fail "error getting metadata" + run get_and_check_legal_hold "s3api" "$BUCKET_ONE_NAME" "$bucket_file" "OFF" + assert_success - get_object "s3api" "$BUCKET_ONE_NAME" "$bucket_file" "$TEST_FILE_FOLDER/$bucket_file-copy" || fail "error getting object" - compare_files "$TEST_FILE_FOLDER/$bucket_file" "$TEST_FILE_FOLDER/$bucket_file-copy" || fail "files not equal" - - sleep 15 - - delete_bucket_or_contents "aws" "$BUCKET_ONE_NAME" - delete_test_files $bucket_file + run download_and_compare_file "s3api" "$TEST_FILE_FOLDER/$bucket_file" "$BUCKET_ONE_NAME" "$bucket_file" "$TEST_FILE_FOLDER/$bucket_file-copy" || fail "error getting object" + assert_success } test_delete_objects_aws_root() { @@ -150,18 +131,20 @@ test_delete_objects_aws_root() { run setup_bucket "s3api" "$BUCKET_ONE_NAME" assert_success - put_object "s3api" "$TEST_FILE_FOLDER"/"$object_one" "$BUCKET_ONE_NAME" "$object_one" || fail "error adding object one" - put_object "s3api" "$TEST_FILE_FOLDER"/"$object_two" "$BUCKET_ONE_NAME" "$object_two" || fail "error adding object two" + run put_object "s3api" "$TEST_FILE_FOLDER"/"$object_one" "$BUCKET_ONE_NAME" "$object_one" + assert_success - delete_objects "$BUCKET_ONE_NAME" "$object_one" "$object_two" || fail "error deleting objects" + run put_object "s3api" "$TEST_FILE_FOLDER"/"$object_two" "$BUCKET_ONE_NAME" "$object_two" + assert_success - object_exists "s3api" "$BUCKET_ONE_NAME" "$object_one" || local object_one_exists_result=$? - [[ $object_one_exists_result -eq 1 ]] || fail "object $object_one not deleted" - object_exists "s3api" "$BUCKET_ONE_NAME" "$object_two" || local object_two_exists_result=$? - [[ $object_two_exists_result -eq 1 ]] || fail "object $object_two not deleted" + run delete_objects "$BUCKET_ONE_NAME" "$object_one" "$object_two" + assert_success - delete_bucket_or_contents "s3api" "$BUCKET_ONE_NAME" - delete_test_files "$object_one" "$object_two" + run object_exists "s3api" "$BUCKET_ONE_NAME" "$object_one" + assert_failure 1 + + run object_exists "s3api" "$BUCKET_ONE_NAME" "$object_two" + assert_failure 1 } test_get_bucket_acl_aws_root() { @@ -172,14 +155,8 @@ test_get_bucket_acl_aws_root() { run setup_bucket "aws" "$BUCKET_ONE_NAME" assert_success - get_bucket_acl "s3api" "$BUCKET_ONE_NAME" || fail "error retreving ACL" - - # shellcheck disable=SC2154 - log 5 "ACL: $acl" - id=$(echo "$acl" | grep -v "InsecureRequestWarning" | jq -r '.Owner.ID') - [[ $id == "$AWS_ACCESS_KEY_ID" ]] || fail "Acl mismatch" - - delete_bucket_or_contents "aws" "$BUCKET_ONE_NAME" + run get_bucket_acl_and_check_owner "s3api" "$BUCKET_ONE_NAME" + assert_success } test_get_object_full_range_aws_root() { @@ -192,9 +169,13 @@ test_get_object_full_range_aws_root() { run setup_bucket "s3api" "$BUCKET_ONE_NAME" assert_success - put_object "s3api" "$TEST_FILE_FOLDER/$bucket_file" "$BUCKET_ONE_NAME" "$bucket_file" || fail "error putting object" - get_object_with_range "$BUCKET_ONE_NAME" "$bucket_file" "bytes=9-15" "$TEST_FILE_FOLDER/$bucket_file-range" || fail "error getting range" - [[ "$(cat "$TEST_FILE_FOLDER/$bucket_file-range")" == "9" ]] || fail "byte range not copied properly" + run put_object "s3api" "$TEST_FILE_FOLDER/$bucket_file" "$BUCKET_ONE_NAME" "$bucket_file" + assert_success + + run get_object_with_range "$BUCKET_ONE_NAME" "$bucket_file" "bytes=9-15" "$TEST_FILE_FOLDER/$bucket_file-range" + assert_success + + assert [ "$(cat "$TEST_FILE_FOLDER/$bucket_file-range")" == "9" ] } test_get_object_invalid_range_aws_root() { @@ -205,9 +186,11 @@ test_get_object_invalid_range_aws_root() { run setup_bucket "s3api" "$BUCKET_ONE_NAME" assert_success - put_object "s3api" "$TEST_FILE_FOLDER/$bucket_file" "$BUCKET_ONE_NAME" "$bucket_file" || fail "error putting object" - get_object_with_range "$BUCKET_ONE_NAME" "$bucket_file" "bytes=0-0" "$TEST_FILE_FOLDER/$bucket_file-range" || local get_result=$? - [[ $get_result -ne 0 ]] || fail "Get object with zero range returned no error" + run put_object "s3api" "$TEST_FILE_FOLDER/$bucket_file" "$BUCKET_ONE_NAME" "$bucket_file" + assert_success + + run get_object_with_range "$BUCKET_ONE_NAME" "$bucket_file" "bytes=0-0" "$TEST_FILE_FOLDER/$bucket_file-range" + assert_failure } test_put_object_aws_root() { @@ -227,10 +210,6 @@ test_put_object_aws_root() { run download_and_compare_file "s3api" "$TEST_FILE_FOLDER/$bucket_file" "$BUCKET_ONE_NAME" "$bucket_file" "$TEST_FILE_FOLDER/${bucket_file}_copy" assert_success - - delete_bucket_or_contents "aws" "$BUCKET_ONE_NAME" - delete_bucket_or_contents "aws" "$BUCKET_TWO_NAME" - delete_test_files "$bucket_file" } test_create_bucket_invalid_name_aws_root() { @@ -238,11 +217,8 @@ test_create_bucket_invalid_name_aws_root() { return fi - create_bucket_invalid_name "aws" || local create_result=$? - [[ $create_result -eq 0 ]] || fail "Invalid name test failed" - - # shellcheck disable=SC2154 - [[ "$bucket_create_error" == *"Invalid bucket name "* ]] || fail "unexpected error: $bucket_create_error" + run create_and_check_bucket_invalid_name "aws" + assert_success } test_get_object_attributes_aws_root() { @@ -253,17 +229,11 @@ test_get_object_attributes_aws_root() { run setup_bucket "s3api" "$BUCKET_ONE_NAME" assert_success - put_object "s3api" "$TEST_FILE_FOLDER/$bucket_file" "$BUCKET_ONE_NAME" "$bucket_file" || fail "failed to add object to bucket" - get_object_attributes "$BUCKET_ONE_NAME" "$bucket_file" || failed "failed to get object attributes" - # shellcheck disable=SC2154 - has_object_size=$(echo "$attributes" | jq 'has("ObjectSize")' 2>&1) || fail "error checking for ObjectSize parameters: $has_object_size" - if [[ $has_object_size == "true" ]]; then - object_size=$(echo "$attributes" | jq -r ".ObjectSize") - [[ $object_size == 10 ]] || fail "Incorrect object size: $object_size" - else - fail "ObjectSize parameter missing: $attributes" - fi - delete_bucket_or_contents "s3api" "$BUCKET_ONE_NAME" + run put_object "s3api" "$TEST_FILE_FOLDER/$bucket_file" "$BUCKET_ONE_NAME" "$bucket_file" + assert_success + + run get_and_check_object_size "$BUCKET_ONE_NAME" "$bucket_file" 10 + assert_success } test_get_put_object_legal_hold_aws_root() { @@ -276,37 +246,34 @@ test_get_put_object_legal_hold_aws_root() { username=$USERNAME_ONE password=$PASSWORD_ONE - legal_hold_retention_setup "$username" "$password" "$bucket_file" + run legal_hold_retention_setup "$username" "$password" "$bucket_file" + assert_success - get_object_lock_configuration "$BUCKET_ONE_NAME" || fail "error getting lock configuration" - # shellcheck disable=SC2154 - log 5 "$lock_config" - enabled=$(echo "$lock_config" | jq -r ".ObjectLockConfiguration.ObjectLockEnabled") - [[ $enabled == "Enabled" ]] || fail "ObjectLockEnabled should be 'Enabled', is '$enabled'" + run get_check_object_lock_config_enabled "$BUCKET_ONE_NAME" + assert_success - put_object_legal_hold "$BUCKET_ONE_NAME" "$bucket_file" "ON" || fail "error putting legal hold on object" - get_object_legal_hold "$BUCKET_ONE_NAME" "$bucket_file" || fail "error getting object legal hold status" - # shellcheck disable=SC2154 - log 5 "$legal_hold" - hold_status=$(echo "$legal_hold" | grep -v "InsecureRequestWarning" | jq -r ".LegalHold.Status" 2>&1) || fail "error obtaining hold status: $hold_status" - [[ $hold_status == "ON" ]] || fail "Status should be 'ON', is '$hold_status'" + run put_object_legal_hold "$BUCKET_ONE_NAME" "$bucket_file" "ON" + assert_success + + run get_and_check_legal_hold "s3api" "$BUCKET_ONE_NAME" "$bucket_file" "ON" + assert_success echo "fdkljafajkfs" > "$TEST_FILE_FOLDER/$bucket_file" - if put_object_with_user "s3api" "$TEST_FILE_FOLDER/$bucket_file" "$BUCKET_ONE_NAME" "$bucket_file" "$username" "$password"; then - fail "able to overwrite object with hold" - fi + run put_object_with_user "s3api" "$TEST_FILE_FOLDER/$bucket_file" "$BUCKET_ONE_NAME" "$bucket_file" "$username" "$password" + assert_failure 1 # shellcheck disable=SC2154 #[[ $put_object_error == *"Object is WORM protected and cannot be overwritten"* ]] || fail "unexpected error message: $put_object_error" - if delete_object_with_user "s3api" "$BUCKET_ONE_NAME" "$bucket_file" "$username" "$password"; then - fail "able to delete object with hold" - fi + run delete_object_with_user "s3api" "$BUCKET_ONE_NAME" "$bucket_file" "$username" "$password" + assert_failure 1 # shellcheck disable=SC2154 - [[ $delete_object_error == *"Object is WORM protected and cannot be overwritten"* ]] || fail "unexpected error message: $delete_object_error" - put_object_legal_hold "$BUCKET_ONE_NAME" "$bucket_file" "OFF" || fail "error removing legal hold on object" - delete_object_with_user "s3api" "$BUCKET_ONE_NAME" "$bucket_file" "$username" "$password" || fail "error deleting object after removing legal hold" + assert_output --partial "Object is WORM protected and cannot be overwritten" - delete_bucket_recursive "s3api" "$BUCKET_ONE_NAME" + run put_object_legal_hold "$BUCKET_ONE_NAME" "$bucket_file" "OFF" + assert_success + + run delete_object_with_user "s3api" "$BUCKET_ONE_NAME" "$bucket_file" "$username" "$password" + assert_success } test_get_put_object_retention_aws_root() { @@ -319,12 +286,11 @@ test_get_put_object_retention_aws_root() { skip fi - legal_hold_retention_setup "$username" "$secret_key" "$bucket_file" + run legal_hold_retention_setup "$username" "$secret_key" "$bucket_file" + assert_success - get_object_lock_configuration "$BUCKET_ONE_NAME" || fail "error getting lock configuration" - log 5 "$lock_config" - enabled=$(echo "$lock_config" | jq -r ".ObjectLockConfiguration.ObjectLockEnabled") - [[ $enabled == "Enabled" ]] || fail "ObjectLockEnabled should be 'Enabled', is '$enabled'" + run get_check_object_lock_config_enabled "$BUCKET_ONE_NAME" + assert_success if [[ "$OSTYPE" == "darwin"* ]]; then retention_date=$(TZ="UTC" date -v+5S +"%Y-%m-%dT%H:%M:%S") @@ -332,30 +298,23 @@ test_get_put_object_retention_aws_root() { retention_date=$(TZ="UTC" date -d "+5 seconds" +"%Y-%m-%dT%H:%M:%S") fi log 5 "retention date: $retention_date" - put_object_retention "$BUCKET_ONE_NAME" "$bucket_file" "GOVERNANCE" "$retention_date" || fail "failed to add object retention" - get_object_retention "$BUCKET_ONE_NAME" "$bucket_file" || fail "failed to get object retention" - log 5 "$retention" - retention=$(echo "$retention" | grep -v "InsecureRequestWarning") - mode=$(echo "$retention" | jq -r ".Retention.Mode") - retain_until_date=$(echo "$retention" | jq -r ".Retention.RetainUntilDate") - [[ $mode == "GOVERNANCE" ]] || fail "retention mode should be governance, is $mode" - [[ $retain_until_date == "$retention_date"* ]] || fail "retain until date should be $retention_date, is $retain_until_date" + + run put_object_retention "$BUCKET_ONE_NAME" "$bucket_file" "GOVERNANCE" "$retention_date" + assert_success + + run get_check_object_retention "$BUCKET_ONE_NAME" "$bucket_file" "$retention_date" + assert_success echo "fdkljafajkfs" > "$TEST_FILE_FOLDER/$bucket_file" - put_object_with_user "s3api" "$TEST_FILE_FOLDER/$bucket_file" "$BUCKET_ONE_NAME" "$bucket_file" "$username" "$secret_key" || local put_result=$? - [[ $put_result -ne 0 ]] || fail "able to overwrite object with hold" + run put_object_with_user "s3api" "$TEST_FILE_FOLDER/$bucket_file" "$BUCKET_ONE_NAME" "$bucket_file" "$username" "$secret_key" + assert_failure 1 # shellcheck disable=SC2154 - [[ $put_object_error == *"Object is WORM protected and cannot be overwritten"* ]] || fail "unexpected error message: $error" + assert_output --partial "Object is WORM protected and cannot be overwritten" - delete_object_with_user "s3api" "$BUCKET_ONE_NAME" "$bucket_file" "$username" "$secret_key" || local delete_result=$? - [[ $delete_result -ne 0 ]] || fail "able to delete object with hold" - [[ $delete_object_error == *"Object is WORM protected and cannot be overwritten"* ]] || fail "unexpected error message: $error" - - sleep 5 - - delete_object "s3api" "$BUCKET_ONE_NAME" "$bucket_file" || fail "error deleting object" - delete_bucket_or_contents "s3api" "$BUCKET_ONE_NAME" - delete_test_files "$bucket_file" + run delete_object_with_user "s3api" "$BUCKET_ONE_NAME" "$bucket_file" "$username" "$secret_key" + assert_failure 1 + # shellcheck disable=SC2154 + assert_output --partial "Object is WORM protected and cannot be overwritten" } test_retention_bypass_aws_root() { @@ -368,12 +327,11 @@ test_retention_bypass_aws_root() { secret_key=$PASSWORD_ONE policy_file="policy_file" - legal_hold_retention_setup "$username" "$secret_key" "$bucket_file" + run legal_hold_retention_setup "$username" "$secret_key" "$bucket_file" + assert_success - get_object_lock_configuration "$BUCKET_ONE_NAME" || fail "error getting lock configuration" - log 5 "$lock_config" - enabled=$(echo "$lock_config" | jq -r ".ObjectLockConfiguration.ObjectLockEnabled") - [[ $enabled == "Enabled" ]] || fail "ObjectLockEnabled should be 'Enabled', is '$enabled'" + run get_check_object_lock_config_enabled "$BUCKET_ONE_NAME" + assert_success if [[ "$OSTYPE" == "darwin"* ]]; then retention_date=$(TZ="UTC" date -v+30S +"%Y-%m-%dT%H:%M:%S") @@ -381,28 +339,22 @@ test_retention_bypass_aws_root() { retention_date=$(TZ="UTC" date -d "+30 seconds" +"%Y-%m-%dT%H:%M:%S") fi log 5 "retention date: $retention_date" - put_object_retention "$BUCKET_ONE_NAME" "$bucket_file" "GOVERNANCE" "$retention_date" || fail "failed to add object retention" - if delete_object_with_user "s3api" "$BUCKET_ONE_NAME" "$bucket_file"; then - log 2 "able to delete object despite retention" - return 1 - fi - cat < "$TEST_FILE_FOLDER/$policy_file" -{ - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Principal": "$username", - "Action": ["s3:BypassGovernanceRetention","s3:DeleteObject"], - "Resource": "arn:aws:s3:::$BUCKET_ONE_NAME/*" - } - ] -} -EOF - put_bucket_policy "s3api" "$BUCKET_ONE_NAME" "$TEST_FILE_FOLDER/$policy_file" || fail "error putting bucket policy" - delete_object_bypass_retention "$BUCKET_ONE_NAME" "$bucket_file" "$username" "$secret_key" || fail "error deleting object and bypassing retention" - delete_bucket_or_contents "s3api" "$BUCKET_ONE_NAME" - delete_test_files "$bucket_file" "$policy_file" + + run put_object_retention "$BUCKET_ONE_NAME" "$bucket_file" "GOVERNANCE" "$retention_date" + assert_success + + run delete_object_with_user "s3api" "$BUCKET_ONE_NAME" "$bucket_file" + assert_failure 1 + + run setup_policy_with_single_statement "$TEST_FILE_FOLDER/$policy_file" "2012-10-17" "Allow" "$username" \ + "[\"s3:BypassGovernanceRetention\",\"s3:DeleteObject\"]" "arn:aws:s3:::$BUCKET_ONE_NAME/*" + assert_success + + run put_bucket_policy "s3api" "$BUCKET_ONE_NAME" "$TEST_FILE_FOLDER/$policy_file" + assert_success + + run delete_object_bypass_retention "$BUCKET_ONE_NAME" "$bucket_file" "$username" "$secret_key" + assert_success } legal_hold_retention_setup() { @@ -411,24 +363,23 @@ legal_hold_retention_setup() { run delete_bucket_or_contents_if_exists "s3api" "$BUCKET_ONE_NAME" assert_success - setup_user "$1" "$2" "user" || fail "error creating user if nonexistent" + run setup_user "$1" "$2" "user" + assert_success run create_test_file "$3" assert_success #create_bucket "s3api" "$BUCKET_ONE_NAME" || fail "error creating bucket" if [[ $RECREATE_BUCKETS == "true" ]]; then - create_bucket_object_lock_enabled "$BUCKET_ONE_NAME" || fail "error creating bucket" + run create_bucket_object_lock_enabled "$BUCKET_ONE_NAME" + assert_success fi - change_bucket_owner "$AWS_ACCESS_KEY_ID" "$AWS_SECRET_ACCESS_KEY" "$BUCKET_ONE_NAME" "$1" || fail "error changing bucket ownership" - get_bucket_policy "s3api" "$BUCKET_ONE_NAME" || fail "error getting bucket policy" - # shellcheck disable=SC2154 - log 5 "POLICY: $bucket_policy" - get_bucket_owner "$BUCKET_ONE_NAME" - # shellcheck disable=SC2154 - log 5 "owner: $bucket_owner" - #put_bucket_ownership_controls "$BUCKET_ONE_NAME" "BucketOwnerPreferred" || fail "error putting bucket ownership controls" - put_object_with_user "s3api" "$TEST_FILE_FOLDER/$3" "$BUCKET_ONE_NAME" "$3" "$1" "$2" || fail "failed to add object to bucket" + + run change_bucket_owner "$AWS_ACCESS_KEY_ID" "$AWS_SECRET_ACCESS_KEY" "$BUCKET_ONE_NAME" "$1" + assert_success + + run put_object_with_user "s3api" "$TEST_FILE_FOLDER/$3" "$BUCKET_ONE_NAME" "$3" "$1" "$2" + assert_success } test_s3api_list_objects_v1_aws_root() { @@ -441,95 +392,50 @@ test_s3api_list_objects_v1_aws_root() { run setup_bucket "aws" "$BUCKET_ONE_NAME" assert_success - put_object "s3api" "$TEST_FILE_FOLDER"/"$object_one" "$BUCKET_ONE_NAME" "$object_one" || local copy_result_one=$? - [[ $copy_result_one -eq 0 ]] || fail "Failed to add object $object_one" - put_object "s3api" "$TEST_FILE_FOLDER"/"$object_two" "$BUCKET_ONE_NAME" "$object_two" || local copy_result_two=$? - [[ $copy_result_two -eq 0 ]] || fail "Failed to add object $object_two" + run put_object "s3api" "$TEST_FILE_FOLDER"/"$object_one" "$BUCKET_ONE_NAME" "$object_one" + assert_success - list_objects_s3api_v1 "$BUCKET_ONE_NAME" - # shellcheck disable=SC2154 - key_one=$(echo "$objects" | jq -r '.Contents[0].Key') - [[ $key_one == "$object_one" ]] || fail "Object one mismatch ($key_one, $object_one)" - size_one=$(echo "$objects" | jq -r '.Contents[0].Size') - [[ $size_one -eq 10 ]] || fail "Object one size mismatch ($size_one, 0)" - key_two=$(echo "$objects" | jq -r '.Contents[1].Key') - [[ $key_two == "$object_two" ]] || fail "Object two mismatch ($key_two, $object_two)" - size_two=$(echo "$objects" | jq '.Contents[1].Size') - [[ $size_two -eq 10 ]] || fail "Object two size mismatch ($size_two, 10)" + run put_object "s3api" "$TEST_FILE_FOLDER"/"$object_two" "$BUCKET_ONE_NAME" "$object_two" + assert_success - delete_bucket_or_contents "aws" "$BUCKET_ONE_NAME" - delete_test_files "$object_one" "$object_two" + run list_check_objects_v1 "$BUCKET_ONE_NAME" "$object_one" 10 "$object_two" 10 + assert_success } test_s3api_list_objects_v2_aws_root() { local object_one="test-file-one" local object_two="test-file-two" + run create_test_files "$object_one" "$object_two" assert_success run setup_bucket "aws" "$BUCKET_ONE_NAME" assert_success - put_object "s3api" "$TEST_FILE_FOLDER"/"$object_one" "$BUCKET_ONE_NAME" "$object_one" || local copy_object_one=$? - [[ $copy_object_one -eq 0 ]] || fail "Failed to add object $object_one" - put_object "s3api" "$TEST_FILE_FOLDER"/"$object_two" "$BUCKET_ONE_NAME" "$object_two" || local copy_object_two=$? - [[ $copy_object_two -eq 0 ]] || fail "Failed to add object $object_two" + run put_object "s3api" "$TEST_FILE_FOLDER"/"$object_one" "$BUCKET_ONE_NAME" "$object_one" + assert_success - list_objects_v2 "$BUCKET_ONE_NAME" || fail "error listing objects (v2)" - key_one=$(echo "$objects" | jq -r '.Contents[0].Key') - [[ $key_one == "$object_one" ]] || fail "Object one mismatch ($key_one, $object_one)" - size_one=$(echo "$objects" | jq -r '.Contents[0].Size') - [[ $size_one -eq 10 ]] || fail "Object one size mismatch ($size_one, 10)" - key_two=$(echo "$objects" | jq -r '.Contents[1].Key') - [[ $key_two == "$object_two" ]] || fail "Object two mismatch ($key_two, $object_two)" - size_two=$(echo "$objects" | jq -r '.Contents[1].Size') - [[ $size_two -eq 10 ]] || fail "Object two size mismatch ($size_two, 10)" + run put_object "s3api" "$TEST_FILE_FOLDER"/"$object_two" "$BUCKET_ONE_NAME" "$object_two" + assert_success - delete_bucket_or_contents "aws" "$BUCKET_ONE_NAME" - delete_test_files "$object_one" "$object_two" + run list_check_objects_v2 "$BUCKET_ONE_NAME" "$object_one" 10 "$object_two" 10 + assert_success } test_multipart_upload_list_parts_aws_root() { local bucket_file="bucket-file" - run create_test_file "$bucket_file" + run create_test_file "$bucket_file" 0 + assert_success + run dd if=/dev/urandom of="$TEST_FILE_FOLDER/$bucket_file" bs=5M count=1 assert_success - dd if=/dev/urandom of="$TEST_FILE_FOLDER/$bucket_file" bs=5M count=1 || fail "error filling test file" run setup_bucket "aws" "$BUCKET_ONE_NAME" assert_success - start_multipart_upload_and_list_parts "$BUCKET_ONE_NAME" "$bucket_file" "$TEST_FILE_FOLDER"/"$bucket_file" 4 || fail "listing multipart upload parts failed" + run start_multipart_upload_list_check_parts "$BUCKET_ONE_NAME" "$bucket_file" "$TEST_FILE_FOLDER"/"$bucket_file" + assert_success - declare -a parts_map - # shellcheck disable=SC2154 - log 5 "parts: $parts" - for i in {0..3}; do - local part_number - local etag - # shellcheck disable=SC2154 - part=$(echo "$parts" | grep -v "InsecureRequestWarning" | jq -r ".[$i]" 2>&1) || fail "error getting part: $part" - part_number=$(echo "$part" | jq ".PartNumber" 2>&1) || fail "error parsing part number: $part_number" - [[ $part_number != "" ]] || fail "error: blank part number" - - etag=$(echo "$part" | jq ".ETag" 2>&1) || fail "error parsing etag: $etag" - [[ $etag != "" ]] || fail "error: blank etag" - # shellcheck disable=SC2004 - parts_map[$part_number]=$etag - done - [[ ${#parts_map[@]} -ne 0 ]] || fail "error loading multipart upload parts to check" - - for i in {0..3}; do - local part_number - local etag - # shellcheck disable=SC2154 - listed_part=$(echo "$listed_parts" | grep -v "InsecureRequestWarning" | jq -r ".Parts[$i]" 2>&1) || fail "error parsing listed part: $listed_part" - part_number=$(echo "$listed_part" | jq ".PartNumber" 2>&1) || fail "error parsing listed part number: $part_number" - etag=$(echo "$listed_part" | jq ".ETag" 2>&1) || fail "error getting listed etag: $etag" - [[ ${parts_map[$part_number]} == "$etag" ]] || fail "error: etags don't match (part number: $part_number, etags ${parts_map[$part_number]},$etag)" - done - - run_then_abort_multipart_upload "$BUCKET_ONE_NAME" "$bucket_file" "$TEST_FILE_FOLDER/$bucket_file" 4 - delete_bucket_or_contents "aws" "$BUCKET_ONE_NAME" - delete_test_files $bucket_file + run run_then_abort_multipart_upload "$BUCKET_ONE_NAME" "$bucket_file" "$TEST_FILE_FOLDER/$bucket_file" 4 + assert_success } diff --git a/tests/test_mc.sh b/tests/test_mc.sh index e5cdd97..9c3941f 100755 --- a/tests/test_mc.sh +++ b/tests/test_mc.sh @@ -16,7 +16,7 @@ source ./tests/test_common.sh source ./tests/setup.sh -source ./tests/util_bucket_create.sh +source ./tests/util_create_bucket.sh source ./tests/commands/delete_bucket_policy.sh source ./tests/commands/get_bucket_policy.sh source ./tests/commands/put_bucket_policy.sh diff --git a/tests/test_rest.sh b/tests/test_rest.sh new file mode 100755 index 0000000..788a132 --- /dev/null +++ b/tests/test_rest.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bats + +source ./tests/commands/list_buckets.sh +source ./tests/commands/put_object.sh +source ./tests/logger.sh +source ./tests/setup.sh +source ./tests/util.sh +source ./tests/util_rest.sh +source ./tests/util_list_buckets.sh +source ./tests/util_list_objects.sh + +@test "test_rest_list_objects" { + run setup_bucket "s3api" "$BUCKET_ONE_NAME" + assert_success + + test_file="test_file" + run create_test_files "$test_file" + assert_success + + run put_object "s3api" "$TEST_FILE_FOLDER/$test_file" "$BUCKET_ONE_NAME" "$test_file" + assert_success + + run list_check_objects_rest "$BUCKET_ONE_NAME" + assert_success +} + +@test "test_authorization_list_buckets" { + run setup_bucket "s3api" "$BUCKET_ONE_NAME" + assert_success + + run list_check_buckets_rest + assert_success +} diff --git a/tests/test_s3api.sh b/tests/test_s3api.sh index 6392a19..a843b8c 100755 --- a/tests/test_s3api.sh +++ b/tests/test_s3api.sh @@ -20,7 +20,7 @@ load ./bats-assert/load source ./tests/setup.sh source ./tests/util.sh source ./tests/util_aws.sh -source ./tests/util_bucket_create.sh +source ./tests/util_create_bucket.sh source ./tests/util_file.sh source ./tests/util_lock_config.sh source ./tests/util_users.sh diff --git a/tests/test_s3cmd.sh b/tests/test_s3cmd.sh index a29ae9b..1eb63c7 100755 --- a/tests/test_s3cmd.sh +++ b/tests/test_s3cmd.sh @@ -17,7 +17,7 @@ source ./tests/setup.sh source ./tests/test_common.sh source ./tests/util.sh -source ./tests/util_bucket_create.sh +source ./tests/util_create_bucket.sh source ./tests/util_users.sh source ./tests/commands/delete_bucket_policy.sh source ./tests/commands/get_bucket_policy.sh diff --git a/tests/test_user_common.sh b/tests/test_user_common.sh index c3fb0c7..f451557 100755 --- a/tests/test_user_common.sh +++ b/tests/test_user_common.sh @@ -17,7 +17,7 @@ source ./tests/setup.sh source ./tests/util_users.sh source ./tests/util.sh -source ./tests/util_bucket_create.sh +source ./tests/util_create_bucket.sh source ./tests/commands/list_buckets.sh test_admin_user() { diff --git a/tests/util.sh b/tests/util.sh index 7709660..5d25b93 100644 --- a/tests/util.sh +++ b/tests/util.sh @@ -14,7 +14,7 @@ # specific language governing permissions and limitations # under the License. -source ./tests/util_bucket_create.sh +source ./tests/util_create_bucket.sh source ./tests/util_mc.sh source ./tests/logger.sh source ./tests/commands/abort_multipart_upload.sh diff --git a/tests/util_bucket_create.sh b/tests/util_create_bucket.sh similarity index 77% rename from tests/util_bucket_create.sh rename to tests/util_create_bucket.sh index 6914f00..ca4f373 100644 --- a/tests/util_bucket_create.sh +++ b/tests/util_create_bucket.sh @@ -41,3 +41,21 @@ create_bucket_invalid_name() { fi export bucket_create_error } + +create_and_check_bucket_invalid_name() { + if [ $# -ne 1 ]; then + log 2 "'create_and_check_bucket_invalid_name' requires client" + return 1 + fi + if ! create_bucket_invalid_name "$1"; then + log 2 "error creating bucket with invalid name" + return 1 + fi + + # shellcheck disable=SC2154 + if [[ "$bucket_create_error" != *"Invalid bucket name "* ]]; then + log 2 "unexpected error: $bucket_create_error" + return 1 + fi + return 0 +} diff --git a/tests/util_get_bucket_acl.sh b/tests/util_get_bucket_acl.sh new file mode 100644 index 0000000..a54506a --- /dev/null +++ b/tests/util_get_bucket_acl.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +# Copyright 2024 Versity Software +# This file is licensed under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +get_bucket_acl_and_check_owner() { + if [ $# -ne 2 ]; then + log 2 "'get_acl_and_check_owner' requires client, bucket name" + return 1 + fi + if ! get_bucket_acl "$1" "$2"; then + log 2 "error getting bucket acl" + return 1 + fi + + # shellcheck disable=SC2154 + log 5 "ACL: $acl" + id=$(echo "$acl" | jq -r '.Owner.ID') + [[ $id == "$AWS_ACCESS_KEY_ID" ]] || fail "Acl mismatch" +} \ No newline at end of file diff --git a/tests/util_get_object_attributes.sh b/tests/util_get_object_attributes.sh new file mode 100644 index 0000000..2490b0c --- /dev/null +++ b/tests/util_get_object_attributes.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash + +# Copyright 2024 Versity Software +# This file is licensed under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +get_and_check_object_size() { + if [ $# -ne 3 ]; then + log 2 "'get_and_check_object_size' requires bucket, key, object size" + return 1 + fi + if ! get_object_attributes "$1" "$2"; then + log 2 "failed to get object attributes" + return 1 + fi + # shellcheck disable=SC2154 + if ! has_object_size=$(echo "$attributes" | jq 'has("ObjectSize")' 2>&1); then + log 2 "error checking for ObjectSize parameters: $has_object_size" + return 1 + fi + if [[ $has_object_size != "true" ]]; then + log 2 "ObjectSize parameter missing: $attributes" + return 1 + fi + if ! object_size=$(echo "$attributes" | jq -r ".ObjectSize" 2>&1); then + log 2 "error getting object size: $object_size" + return 1 + fi + if [[ $object_size != "$3" ]]; then + log 2 "Incorrect object size: $object_size" + return 1 + fi + return 0 +} \ No newline at end of file diff --git a/tests/util_get_object_retention.sh b/tests/util_get_object_retention.sh new file mode 100644 index 0000000..e515c22 --- /dev/null +++ b/tests/util_get_object_retention.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +# Copyright 2024 Versity Software +# This file is licensed under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +get_check_object_retention() { + if [ $# -ne 3 ]; then + log 2 "'get_check_object_retention' requires bucket, file, expected retention date" + return 1 + fi + # shellcheck disable=SC2154 + if ! get_object_retention "$BUCKET_ONE_NAME" "$bucket_file"; then + log 2 "failed to get object retention" + return 1 + fi + log 5 "RETENTION: $retention" + retention=$(echo "$retention" | grep -v "InsecureRequestWarning") + if ! mode=$(echo "$retention" | jq -r ".Retention.Mode" 2>&1); then + log 2 "error getting retention mode: $mode" + return 1 + fi + if ! retain_until_date=$(echo "$retention" | jq -r ".Retention.RetainUntilDate" 2>&1); then + log 2 "error getting retain until date: $retain_until_date" + return 1 + fi + if [[ $mode != "GOVERNANCE" ]]; then + log 2 "retention mode should be governance, is $mode" + return 1 + fi + if [[ $retain_until_date != "$3"* ]]; then + log 2 "retain until date should be $3, is $retain_until_date" + return 1 + fi + return 0 +} \ No newline at end of file diff --git a/tests/util_head_object.sh b/tests/util_head_object.sh new file mode 100644 index 0000000..53d8f70 --- /dev/null +++ b/tests/util_head_object.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash + +# Copyright 2024 Versity Software +# This file is licensed under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +get_and_verify_metadata() { + if [ $# -ne 7 ]; then + log 2 "'get_and_verify_metadata' requires bucket file, expected content type, + expected metadata key, expected metadata val, expected hold status, expected retention mode, expected retention date" + return 1 + fi + if ! head_object "s3api" "$BUCKET_ONE_NAME" "$1"; then + log 2 "error retrieving metadata" + return 1 + fi + # shellcheck disable=SC2154 + raw_metadata=$(echo "$metadata" | grep -v "InsecureRequestWarning") + log 5 "raw metadata: $raw_metadata" + + if ! content_type=$(echo "$raw_metadata" | jq -r ".ContentType" 2>&1); then + log 2 "error retrieving content type: $content_type" + return 1 + fi + if [[ $content_type != "$2" ]]; then + log 2 "content type mismatch ($content_type, $2)" + return 1 + fi + if ! meta_val=$(echo "$raw_metadata" | jq -r ".Metadata.$3" 2>&1); then + log 2 "error retrieving metadata val: $meta_val" + return 1 + fi + if [[ $meta_val != "$4" ]]; then + log 2 "metadata val mismatch ($meta_val, $4)" + return 1 + fi + if ! hold_status=$(echo "$raw_metadata" | jq -r ".ObjectLockLegalHoldStatus" 2>&1); then + log 2 "error retrieving hold status: $hold_status" + return 1 + fi + if [[ $hold_status != "$5" ]]; then + log 2 "hold status mismatch ($hold_status, $5)" + return 1 + fi + if ! retention_mode=$(echo "$raw_metadata" | jq -r ".ObjectLockMode" 2>&1); then + log 2 "error retrieving retention mode: $retention_mode" + return 1 + fi + if [[ $retention_mode != "$6" ]]; then + log 2 "retention mode mismatch ($retention_mode, $6)" + return 1 + fi + if ! retain_until_date=$(echo "$raw_metadata" | jq -r ".ObjectLockRetainUntilDate" 2>&1); then + log 2 "error retrieving retain until date: $retain_until_date" + return 1 + fi + if [[ $retain_until_date != "$7"* ]]; then + log 2"retention date mismatch ($retain_until_date, $7)" + return 1 + fi + return 0 +} \ No newline at end of file diff --git a/tests/util_legal_hold.sh b/tests/util_legal_hold.sh new file mode 100644 index 0000000..25ae304 --- /dev/null +++ b/tests/util_legal_hold.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +# Copyright 2024 Versity Software +# This file is licensed under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +get_and_check_legal_hold() { + if [ $# -ne 4 ]; then + log 2 "'get_and_check_legal_hold' requires client, bucket, key, expected status" + return 1 + fi + if ! head_object "$1" "$2" "$3"; then + log 2 "error getting object metadata" + return 1 + fi + # shellcheck disable=SC2154 + raw_metadata=$(echo "$metadata" | grep -v "InsecureRequestWarning") + log 5 "raw metadata: $raw_metadata" + if ! hold_status=$(echo "$raw_metadata" | jq -r ".ObjectLockLegalHoldStatus" 2>&1); then + log 2 "error retrieving hold status: $hold_status" + return 1 + fi + if [[ "$hold_status" != "$4" ]]; then + log 2 "hold status mismatch ($hold_status, $4)" + return 1 + fi + return 0 +} \ No newline at end of file diff --git a/tests/util_list_buckets.sh b/tests/util_list_buckets.sh new file mode 100644 index 0000000..91a7c2f --- /dev/null +++ b/tests/util_list_buckets.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +# Copyright 2024 Versity Software +# This file is licensed under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +list_check_buckets_rest() { + if ! list_buckets "rest"; then + log 2 "error listing buckets" + return 1 + fi + bucket_found=false + # shellcheck disable=SC2154 + for bucket in "${bucket_array[@]}"; do + log 5 "bucket: $bucket" + if [[ $bucket == "$BUCKET_ONE_NAME" ]]; then + bucket_found=true + break + fi + done + if [[ $bucket_found == "false" ]]; then + log 2 "bucket not found" + return 1 + fi + return 0 +} \ No newline at end of file diff --git a/tests/util_list_objects.sh b/tests/util_list_objects.sh new file mode 100644 index 0000000..1124ef9 --- /dev/null +++ b/tests/util_list_objects.sh @@ -0,0 +1,121 @@ +#!/usr/bin/env bash + +source ./tests/commands/list_objects_v2.sh + +# Copyright 2024 Versity Software +# This file is licensed under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +parse_objects_list_rest() { + # shellcheck disable=SC2154 + object_list=$(echo "$reply" | xmllint --xpath '//*[local-name()="Key"]/text()' -) + object_array=() + while read -r object; do + object_array+=("$object") + done <<< "$object_list" + log 5 "object array: ${object_array[*]}" +} + +list_check_objects_v1() { + if [ $# -ne 5 ]; then + log 2 "'list_check_objects_v1' requires bucket, expected key one, expected size one, expected key two, expected size two" + return 1 + fi + if ! list_objects_s3api_v1 "$1"; then + log 2 "error listing objects (s3api, v1)" + return 1 + fi + if ! check_listed_objects "$2" "$3" "$4" "$5"; then + log 2 "error checking listed objects" + return 1 + fi + return 0 +} + +check_listed_objects() { + if [ $# -ne 4 ]; then + log 2 "'check_listed_objects' requires expected key one, expected size one, expected key two, expected size two" + return 1 + fi + # shellcheck disable=SC2154 + if ! key_one=$(echo "$objects" | jq -r '.Contents[0].Key' 2>&1); then + log 2 "error obtaining key one: $key_one" + return 1 + fi + if [[ $key_one != "$1" ]]; then + log 2 "Object one mismatch ($key_one, $1)" + return 1 + fi + if ! size_one=$(echo "$objects" | jq -r '.Contents[0].Size' 2>&1); then + log 2 "error obtaining size one: $size_one" + return 1 + fi + if [[ $size_one -ne "$2" ]]; then + log 2 "Object one size mismatch ($size_one, $2)" + return 1 + fi + if ! key_two=$(echo "$objects" | jq -r '.Contents[1].Key' 2>&1); then + log 2 "error obtaining key two: $key_two" + return 1 + fi + if [[ $key_two != "$3" ]]; then + log 2 "Object two mismatch ($key_two, $3)" + return 1 + fi + if ! size_two=$(echo "$objects" | jq '.Contents[1].Size' 2>&1); then + log 2 "error obtaining size two: $size_two" + return 1 + fi + if [[ $size_two -ne "$4" ]]; then + log 2 "Object two size mismatch ($size_two, $4)" + return 1 + fi +} + +list_check_objects_v2() { + if [ $# -ne 5 ]; then + log 2 "'list_check_objects_v1' requires bucket, expected key one, expected size one, expected key two, expected size two" + return 1 + fi + if ! list_objects_v2 "$1"; then + log 2 "error listing objects (s3api, v1)" + return 1 + fi + if ! check_listed_objects "$2" "$3" "$4" "$5"; then + log 2 "error checking listed objects" + return 1 + fi + return 0 +} + +list_check_objects_rest() { + if [ $# -ne 1 ]; then + log 2 "'list_check_objects_rest' requires bucket name" + return 1 + fi + list_objects "rest" "$1" + object_found=false + # shellcheck disable=SC2154 + for object in "${object_array[@]}"; do + log 5 "object: $object" + if [[ $object == "$test_file" ]]; then + object_found=true + break + fi + done + if [[ $object_found == "false" ]]; then + log 2 "object not found" + return 1 + fi + return 0 +} diff --git a/tests/util_lock_config.sh b/tests/util_lock_config.sh index 7893d9d..2bb2420 100644 --- a/tests/util_lock_config.sh +++ b/tests/util_lock_config.sh @@ -61,4 +61,26 @@ get_and_check_object_lock_config() { return 1 fi return 0 -} \ No newline at end of file +} + +get_check_object_lock_config_enabled() { + if [ $# -ne 1 ]; then + log 2 "'get_check_object_lock_config_enabled' requires bucket name" + return 1 + fi + if ! get_object_lock_configuration "$1"; then + log 2 "error getting lock configuration" + return 1 + fi + # shellcheck disable=SC2154 + log 5 "Lock config: $lock_config" + if ! enabled=$(echo "$lock_config" | jq -r ".ObjectLockConfiguration.ObjectLockEnabled" 2>&1); then + log 2 "error parsing enabled value: $enabled" + return 1 + fi + if [[ $enabled != "Enabled" ]]; then + log 2 "ObjectLockEnabled should be 'Enabled', is '$enabled'" + return 1 + fi + return 0 +} diff --git a/tests/util_multipart.sh b/tests/util_multipart.sh index 86fa61d..878776e 100644 --- a/tests/util_multipart.sh +++ b/tests/util_multipart.sh @@ -46,3 +46,94 @@ create_upload_and_test_parts_listing() { fi return 0 } + +start_multipart_upload_list_check_parts() { + if [ $# -ne 3 ]; then + log 2 "'start_multipart_upload_and_list_parts' requires bucket, key, original source" + return 1 + fi + if ! start_multipart_upload_and_list_parts "$1" "$2" "$3" 4; then + log 2 "error starting upload" + return 1 + fi + + declare -a parts_map + # shellcheck disable=SC2154 + log 5 "parts: $parts" + for i in {0..3}; do + if ! parse_parts_and_etags "$i"; then + log 2 "error parsing part $i" + return 1 + fi + done + if [[ ${#parts_map[@]} -eq 0 ]]; then + log 2 "error loading multipart upload parts to check" + return 1 + fi + + for i in {0..3}; do + if ! compare_parts_to_listed_parts "$i"; then + log 2 "error comparing parts to listed parts" + return 1 + fi + done + return 0 +} + +parse_parts_and_etags() { + if [ $# -ne 1 ]; then + log 2 "'parse_parts_and_etags' requires part id" + return 1 + fi + local part_number + local etag + # shellcheck disable=SC2154 + if ! part=$(echo "$parts" | grep -v "InsecureRequestWarning" | jq -r ".[$i]" 2>&1); then + log 2 "error getting part: $part" + return 1 + fi + if ! part_number=$(echo "$part" | jq ".PartNumber" 2>&1); then + log 2 "error parsing part number: $part_number" + return 1 + fi + if [[ $part_number == "" ]]; then + log 2 "error: blank part number" + return 1 + fi + if ! etag=$(echo "$part" | jq ".ETag" 2>&1); then + log 2 "error parsing etag: $etag" + return 1 + fi + if [[ $etag == "" ]]; then + log 2 "error: blank etag" + return 1 + fi + # shellcheck disable=SC2004 + parts_map[$part_number]=$etag +} + +compare_parts_to_listed_parts() { + if [ $# -ne 1 ]; then + log 2 "'compare_parts_to_listed_parts' requires part number" + return 1 + fi + local part_number + local etag + # shellcheck disable=SC2154 + if ! listed_part=$(echo "$listed_parts" | grep -v "InsecureRequestWarning" | jq -r ".Parts[$i]" 2>&1); then + log 2 "error parsing listed part: $listed_part" + return 1 + fi + if ! part_number=$(echo "$listed_part" | jq ".PartNumber" 2>&1); then + log 2 "error parsing listed part number: $part_number" + return 1 + fi + if ! etag=$(echo "$listed_part" | jq ".ETag" 2>&1); then + log 2 "error getting listed etag: $etag" + return 1 + fi + if [[ ${parts_map[$part_number]} != "$etag" ]]; then + log 2 "error: etags don't match (part number: $part_number, etags ${parts_map[$part_number]},$etag)" + return 1 + fi +} diff --git a/tests/util_policy.sh b/tests/util_policy.sh index 8ab4323..2ec56ea 100644 --- a/tests/util_policy.sh +++ b/tests/util_policy.sh @@ -44,7 +44,10 @@ check_for_empty_policy() { get_modified_principal() { log 6 "get_modified_principal" - assert [ $# -eq 1 ] + if [ $# -ne 1 ]; then + log 2 "'get_modified_principal' requires principal" + return 1 + fi local first_char="${1:0:1}" if [ "$first_char" != '{' ] && [ "$first_char" != '[' ] && [ "$first_char" != '"' ]; then # shellcheck disable=SC2089 @@ -52,16 +55,40 @@ get_modified_principal() { else modified_principal=$1 fi - export modified_principal +} + +get_modified_action() { + log 6 "get_modified_action" + if [ $# -ne 1 ]; then + log 2 "'get_modified_action' requires action" + return 1 + fi + local first_char="${1:0:1}" + if [ "$first_char" != '{' ] && [ "$first_char" != '[' ] && [ "$first_char" != '"' ]; then + # shellcheck disable=SC2089 + modified_action="\"$1\"" + else + modified_action=$1 + fi } # params: file, version, effect, principal, action, resource # fail on error setup_policy_with_single_statement() { log 6 "setup_policy_with_single_statement" - assert [ $# -eq 6 ] + if [ $# -ne 6 ]; then + log 2 "'setup_policy_with_single_statement' requires policy file, version, effect, principal, action, resource" + return 1 + fi log 5 "policy file: $1" - get_modified_principal "$4" + if ! get_modified_principal "$4"; then + log 2 "error getting modified principal" + return 1 + fi + if ! get_modified_action "$5"; then + log 2 "error getting modified action" + return 1 + fi bash -c "cat < $1 { \"Version\": \"$2\", @@ -69,7 +96,7 @@ setup_policy_with_single_statement() { { \"Effect\": \"$3\", \"Principal\": $modified_principal, - \"Action\": \"$5\", + \"Action\": $modified_action, \"Resource\": \"$6\" } ] @@ -81,15 +108,24 @@ EOF" } # params: file, version, two sets: effect, principal, action, resource -# fail on error +# return 0 on success, 1 on error setup_policy_with_double_statement() { log 6 "setup_policy_with_double_statement" - assert [ $# -eq 10 ] - get_modified_principal "$4" + if [ $# -ne 10 ]; then + log 2 "invalid number of parameters" + return 1 + fi + if ! get_modified_principal "$4"; then + log 2 "error getting first modified principal" + return 1 + fi principal_one=$modified_principal - get_modified_principal "$8" + if ! get_modified_principal "$8"; then + log 2 "error getting second modified principal" + return 1 + fi principal_two=$modified_principal - run bash -c "cat < $1 + bash -c "cat < $1 { \"Version\": \"$2\", \"Statement\": [ @@ -109,6 +145,5 @@ setup_policy_with_double_statement() { } EOF" # shellcheck disable=SC2154 - assert_success "failed to set up policy: $output" log 5 "policy data: $(cat "$1")" } \ No newline at end of file diff --git a/tests/util_rest.sh b/tests/util_rest.sh new file mode 100644 index 0000000..6a53b11 --- /dev/null +++ b/tests/util_rest.sh @@ -0,0 +1,145 @@ +#!/usr/bin/env bash + +parse_bucket_list() { + # shellcheck disable=SC2154 + bucket_list=$(echo "$reply" | xmllint --xpath '//*[local-name()="Bucket"]/*[local-name()="Name"]/text()' -) + bucket_array=() + while read -r bucket; do + bucket_array+=("$bucket") + done <<< "$bucket_list" + log 5 "bucket array: ${bucket_array[*]}" +} + +parse_object_list() { + object_list=$(echo "$reply" | xmllint --xpath '//*[local-name()="Bucket"]/*[local-name()="Name"]/text()' -) + object_array=() + while read -r object; do + object_array+=("$object") + done <<< "$object_list" + log 5 "object array: ${object_array[*]}" +} + +get_signature() { + date_key=$(echo -n "$ymd" | openssl dgst -sha256 -mac HMAC -macopt key:"AWS4${AWS_SECRET_ACCESS_KEY}" | awk '{print $2}') + date_region_key=$(echo -n "$AWS_REGION" | openssl dgst -sha256 -mac HMAC -macopt hexkey:"$date_key" | awk '{print $2}') + date_region_service_key=$(echo -n "s3" | openssl dgst -sha256 -mac HMAC -macopt hexkey:"$date_region_key" | awk '{print $2}') + signing_key=$(echo -n "aws4_request" | openssl dgst -sha256 -mac HMAC -macopt hexkey:"$date_region_service_key" | awk '{print $2}') + # shellcheck disable=SC2034 + signature=$(echo -n "$sts_data" | openssl dgst -sha256 \ + -mac HMAC \ + -macopt hexkey:"$signing_key" | awk '{print $2}') +} + +hmac_sha256() { + key="$1" + data="$2" + #echo "key: $1" + echo -n "$data" | openssl dgst -sha256 -mac HMAC -macopt "$key" | sed 's/^.* //' +} + +send_rest_command_no_payload_no_bucket() { + generate_hash_for_payload "" + get_creq_string +} + +send_rest_command_no_payload() { + if [ $# -ne 1 ]; then + log 2 "'send_rest_command_no_payload' requires payload" + return 1 + fi +} + +generate_hash_for_payload() { + if [ $# -ne 1 ]; then + log 2 "'generate_hash_for_payload' requires payload string" + return 1 + fi + payload_hash="$(echo -n "$1" | sha256sum | awk '{print $1}')" +} + +get_creq_string_list_buckets() { + + current_date_time=$(date -u +"%Y%m%dT%H%M%SZ") + canonical_request="GET +/ + +host:${AWS_ENDPOINT_URL#*//} +x-amz-content-sha256:$payload_hash +x-amz-date:$current_date_time + +host;x-amz-content-sha256;x-amz-date +$payload_hash" +} + +generate_creq_file() { + if [ $# -ne 3 ]; then + log 2 "'generate_creq_file' command requires bucket name, creq file name, hash" + return 1 + fi + current_time=$(date -u +"%Y%m%dT%H%M%SZ") +cat < "$2" +GET +/ + +host:$1.s3.amazonaws.com +x-amz-content-sha256:$3 +x-amz-date:$current_time + +host;x-amz-content-sha256;x-amz-date +$3 +EOF + + canonical_request="GET +/ + +host:$1.s3.amazonaws.com +x-amz-content-sha256:$3 +x-amz-date:$current_time + +host;x-amz-content-sha256;x-amz-date +$3" + echo "canonical: $canonical_request" + + echo "TEST CREQ" + cat test.creq +} + +generate_sts_string() { + if [ $# -ne 2 ]; then + log 2 "'generate_sts_string' requires current date and time, canonical request string" + return 1 + fi + + ymd=$(echo "$1" | cut -c1-8) + creq_hash="$(echo -n "$2" | openssl dgst -sha256 | awk '{print $2}')" + sts_data="AWS4-HMAC-SHA256 +$1 +$ymd/$AWS_REGION/s3/aws4_request +$creq_hash" + + return 0 +} + +generate_sts_file() { + if [ $# -ne 3 ]; then + log 2 "'generate_sts_file' requires date, hash, file name" + return 1 + fi + ymd=$(echo "$current_time" | cut -c1-8) + creq_hash="$(echo -n "$canonical_request" | openssl dgst -sha256 | awk '{print $2}')" + echo "creq hash: $creq_hash" +cat < "$3" +AWS4-HMAC-SHA256 +$1 +$ymd/us-west-2/s3/aws4_request +$creq_hash +EOF + sts_data="AWS4-HMAC-SHA256 +$1 +$ymd/us-west-2/s3/aws4_request +$creq_hash" + + echo "TEST STS" + cat test.sts +} +