From d7c73a06eac4b043a91b553f5c069fda1f35e8ab Mon Sep 17 00:00:00 2001 From: Luke McCrone Date: Tue, 2 Sep 2025 16:27:55 -0300 Subject: [PATCH] test: universal REST structure checks, delete-bucket-tagging test --- .github/workflows/system.yml | 4 +- .../drivers/list_buckets/list_buckets_rest.sh | 120 +++++++++++++++++- tests/drivers/rest.sh | 113 ++++++++++++----- tests/drivers/user.sh | 32 +++++ tests/rest_scripts/generate_command.go | 98 ++++++++++---- tests/run.sh | 8 +- ...t_rest_delete_bucket_ownership_controls.sh | 24 +++- tests/test_rest_delete_bucket_tagging.sh | 38 ++++++ tests/test_rest_list_buckets.sh | 87 ++++++++++++- tests/test_rest_put_object.sh | 12 ++ tests/test_s3api_bucket.sh | 1 + tests/test_user_aws.sh | 2 +- tests/test_user_s3cmd.sh | 1 + tests/util/util_setup.sh | 16 --- 14 files changed, 460 insertions(+), 96 deletions(-) create mode 100755 tests/test_rest_delete_bucket_tagging.sh diff --git a/.github/workflows/system.yml b/.github/workflows/system.yml index 0f35496c..4d608562 100644 --- a/.github/workflows/system.yml +++ b/.github/workflows/system.yml @@ -33,9 +33,9 @@ jobs: RECREATE_BUCKETS: "true" DELETE_BUCKETS_AFTER_TEST: "true" BACKEND: "posix" - - set: "REST, posix, non-static, not implemented|rest-delete-bucket-ownership-controls, folder IAM" + - set: "REST, posix, non-static, not implemented|rest-delete-bucket-ownership-controls|rest-delete-bucket-tagging, folder IAM" IAM_TYPE: folder - RUN_SET: "rest-not-implemented,rest-delete-bucket-ownership-controls" + RUN_SET: "rest-not-implemented,rest-delete-bucket-ownership-controls,rest-delete-bucket-tagging" RECREATE_BUCKETS: "true" DELETE_BUCKETS_AFTER_TEST: "true" BACKEND: "posix" diff --git a/tests/drivers/list_buckets/list_buckets_rest.sh b/tests/drivers/list_buckets/list_buckets_rest.sh index 67ff0922..1104bda5 100644 --- a/tests/drivers/list_buckets/list_buckets_rest.sh +++ b/tests/drivers/list_buckets/list_buckets_rest.sh @@ -30,18 +30,29 @@ list_check_buckets_rest() { if ! check_param_count_gt "expected buckets" 1 $#; then return 1 fi - if ! list_buckets_rest "" "parse_bucket_list"; then + if ! list_check_buckets_rest_with_params "" "$@"; then + log 2 "error listing and checking buckets" + return 1 + fi + return 0 +} + +list_check_buckets_rest_with_params() { + if ! check_param_count_gt "params, expected buckets" 2 $#; then + return 1 + fi + if ! list_buckets_rest "$1" "parse_bucket_list"; then log 2 "error listing buckets" return 1 fi - for bucket in "$@"; do + for bucket in "${@:2}"; do log 5 "bucket: $bucket" if ! bucket_exists_in_list "$bucket"; then log 2 "bucket $bucket not found" return 1 fi done - return 0 + return 0 } parse_bucket_list() { @@ -148,4 +159,105 @@ list_check_buckets_rest_with_prefix() { return 1 fi return 0 -} \ No newline at end of file +} + +list_buckets_check_authorization_scheme_error() { + bad_scheme_name="AWS-HMAC-SHA25" + if ! send_rest_go_command_expect_error_callback "400" "InvalidArgument" "Unsupported Authorization Type" "parse_and_check_authorization_data" "-authorizationScheme" "$bad_scheme_name"; then + log 2 "error sending command and checking results" + return 1 + fi +} + +parse_and_check_authorization_data() { + if ! check_param_count_v2 "data file" 1 $#; then + return 1 + fi + # shellcheck disable=SC2154 + log 5 "bucket list: $(cat "$1")" + if ! argument_name=$(get_element_text "$1" "Error" "ArgumentName"); then + log 2 "error getting argument name" + return 1 + fi + if [ "$argument_name" != "Authorization" ]; then + log 2 "expected 'Authorization', was '$argument_name'" + return 1 + fi + if ! argument_value=$(get_element_text "$1" "Error" "ArgumentValue"); then + log 2 "error getting argument value" + return 1 + fi + if [[ "$argument_value" != "$bad_scheme_name "* ]]; then + log 2 "expected '$argument_value' to start with '$bad_scheme_name'" + return 1 + fi + return 0 +} + +list_buckets_check_request_time_too_skewed_error() { + bad_scheme_name="AWS-HMAC-SHA25" + if ! send_rest_go_command_expect_error_callback "403" "RequestTimeTooSkewed" "difference between the request time and the " \ + "parse_and_check_time_skew_parameters" "-incorrectYearMonthDay"; then + log 2 "error sending command and checking results" + return 1 + fi +} + +is_iso8601() { + if ! check_param_count_v2 "date" 1 $#; then + return 1 + fi + if [[ "$1" =~ ^[0-9]{8}[Tt\ ][0-9]{6}Z$ ]]; then + return 0 + fi + if [[ "$1" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}([Tt ][0-9]{2}:[0-9]{2}(:[0-9]{2})?(Z|[+-][0-9]{2}(:?[0-9]{2})?)?)?$ ]]; then + return 0 + fi + return 1 +} + +parse_and_check_time_skew_parameters() { + if ! check_param_count_v2 "data file" 1 $#; then + return 1 + fi + if ! request_time=$(get_element_text "$1" "Error" "RequestTime"); then + log 2 "error getting request time" + return 1 + fi + if ! is_iso8601 "$request_time"; then + log 2 "'$request_time' is not valid ISO-8601" + return 1 + fi + if ! server_time=$(get_element_text "$1" "Error" "ServerTime"); then + log 2 "error getting request time" + return 1 + fi + if ! is_iso8601 "$server_time"; then + log 2 "'$request_time' is not valid ISO-8601" + return 1 + fi + if ! max_allowed_skew_milliseconds=$(get_element_text "$1" "Error" "MaxAllowedSkewMilliseconds"); then + log 2 "error getting max allowed skew milliseconds" + return 1 + fi + if ! [[ "$max_allowed_skew_milliseconds" =~ ^[0-9]+$ ]]; then + log 2 "'$max_allowed_skew_milliseconds' is not a valid integer" + return 1 + fi + return 0 +} + +list_check_buckets_user() { + if ! check_param_count_gt "username, password, minimum of one bucket" 3 $#; then + return 1 + fi + if ! list_check_buckets_rest_with_params "AWS_ACCESS_KEY_ID=$1 AWS_SECRET_ACCESS_KEY=$2" "${@:3}"; then + log 2 "error sending go command" + return 1 + fi + if [ ${#bucket_array[@]} != ${#:3} ]; then + log 2 "unexpected number of buckets" + return 1 + fi + return 0 +} diff --git a/tests/drivers/rest.sh b/tests/drivers/rest.sh index 4d5d23e7..14cee9c1 100644 --- a/tests/drivers/rest.sh +++ b/tests/drivers/rest.sh @@ -35,8 +35,11 @@ check_rest_go_expected_error() { if ! check_param_count_v2 "response file, expected http code, expected error code, expected error" 4 $#; then return 1 fi - status_line=$(head -n 1 "$1") - status_code=$(echo "$status_line" | awk '{print $2}') + result="$(cat "$1")" + if ! bypass_continues; then + log 2 "error bypassing continues" + return 1 + fi if [ "$2" != "$status_code" ]; then log 2 "expected curl response '$2', was '$status_code'" return 1 @@ -91,10 +94,12 @@ check_rest_expected_header_error() { if ! check_param_count_v2 "file, expected response, expected error" 3 $#; then return 1 fi - status_line=$(head -n 1 "$1") - - # Parse the status code and message - status_code=$(echo "$status_line" | awk '{print $2}') + result="$(cat "$1")" + if ! bypass_continues; then + log 2 "error bypassing continues" + return 1 + fi + log 5 "status line: $status_line" status_message=$(echo "$status_line" | cut -d' ' -f3- | tr -d '\r') log 5 "status code: $status_code, status message: $status_message" if [ "$2" != "$status_code" ]; then @@ -164,24 +169,8 @@ send_rest_command_expect_success_callback() { return 0 } -send_rest_go_command_expect_error() { - if [ $# -lt 3 ] && [ $(($# % 2)) -ne 1 ]; then - log 2 "'send_rest_go_command_expect_error' param count must be 3 or greater, odd (expected HTTP code, expected error code, expected message, key/value pairs)" - return 1 - fi - if ! send_rest_go_command_expect_error_callback "$1" "$2" "$3" "" "${@:4}"; then - log 2 "error sending go command and checking error" - return 1 - fi - return 0 -} - -send_rest_go_command_expect_error_callback() { - if [ $# -lt 4 ] && [ $(($# % 2)) -eq 1 ]; then - log 2 "'send_rest_go_command_expect_error' param count must be 4 or greater, even (expected HTTP code, expected error code, expected message, callback, key/value pairs)" - return 1 - fi - if ! curl_command=$(go run ./tests/rest_scripts/generate_command.go -awsAccessKeyId "$AWS_ACCESS_KEY_ID" -awsSecretAccessKey "$AWS_SECRET_ACCESS_KEY" -url "$AWS_ENDPOINT_URL" "${@:5}" 2>&1); then +rest_go_command_perform_send() { + if ! curl_command=$(go run ./tests/rest_scripts/generate_command.go -awsAccessKeyId "$AWS_ACCESS_KEY_ID" -awsSecretAccessKey "$AWS_SECRET_ACCESS_KEY" -url "$AWS_ENDPOINT_URL" "$@" 2>&1); then log 2 "error: $curl_command" return 1 fi @@ -192,6 +181,29 @@ send_rest_go_command_expect_error_callback() { return 1 fi log 5 "result: $result" +} + +send_rest_go_command_expect_error() { + if [ $# -lt 3 ]; then + log 2 "'send_rest_go_command_expect_error' param count must be 3 or greater, odd (expected HTTP code, expected error code, expected message, go params)" + return 1 + fi + if ! send_rest_go_command_expect_error_callback "$1" "$2" "$3" "" "${@:4}"; then + log 2 "error sending go command and checking error" + return 1 + fi + return 0 +} + +send_rest_go_command_expect_error_callback() { + if [ $# -lt 4 ]; then + log 2 "'send_rest_go_command_expect_error' param count must be 4 or greater, even (expected HTTP code, expected error code, expected message, callback, go params)" + return 1 + fi + if ! rest_go_command_perform_send "${@:5}"; then + log 2 "error sending rest go command" + return 1 + fi echo -n "$result" > "$TEST_FILE_FOLDER/result.txt" if ! check_rest_go_expected_error "$TEST_FILE_FOLDER/result.txt" "$1" "$2" "$3"; then log 2 "error checking expected header error" @@ -204,26 +216,57 @@ send_rest_go_command_expect_error_callback() { return 0 } +bypass_continues() { + status_line_idx=1 + status_code="" + continue_count=0 + while ((continue_count<10)); do + status_line=$(sed -n "${status_line_idx}p" <<< "$result") + status_code=$(echo "$status_line" | awk '{print $2}') + if [ "$status_code" != "100" ]; then + break + fi + ((status_line_idx+=2)) + ((continue_count++)) + done + if [ "$continue_count" -ge 10 ]; then + log 2 "too many continues" + return 1 + fi + return 0 +} + send_rest_go_command() { - if [ $# -lt 1 ] && [ $(($# % 2)) -ne 1 ]; then - log 2 "'send_rest_go_command_expect_failure' param count must be 1 or greater, odd (key/value pairs)" + if [ $# -lt 1 ]; then + log 2 "'send_rest_go_command_expect_failure' param count must be 1 or greater (expected response code, params)" + return 1 + fi + if ! send_rest_go_command_callback "$1" "" "${@:2}"; then + log 2 "error sending rest go command" return 1 fi - if ! curl_command=$(go run ./tests/rest_scripts/generate_command.go -awsAccessKeyId "$AWS_ACCESS_KEY_ID" -awsSecretAccessKey "$AWS_SECRET_ACCESS_KEY" -url "$AWS_ENDPOINT_URL" "${@:2}" 2>&1); then - log 2 "error: $curl_command" + return 0 +} + +send_rest_go_command_callback() { + if ! check_param_count_gt "response code, callback, params" 2 $#; then return 1 fi - local full_command="send_command $curl_command" - log 5 "curl command: $curl_command" - if ! result=$(eval "${full_command[*]}" 2>&1); then - log 3 "error sending command: $result" + if ! rest_go_command_perform_send "${@:3}"; then + log 2 "error sending rest go command" return 1 fi - log 5 "result: $result" - status_line=$(sed -n 1p <<< "$result") - status_code=$(echo "$status_line" | awk '{print $2}') + if ! bypass_continues; then + log 2 "error bypassing continues" + return 1 + fi if [ "$1" != "$status_code" ]; then log 2 "expected curl response '$1', was '$status_code'" + return 1 + fi + echo -n "$result" > "$TEST_FILE_FOLDER/result.txt" + if [ "$2" != "" ] && ! "$2" "$TEST_FILE_FOLDER/result.txt"; then + log 2 "error in callback" return 1 fi return 0 diff --git a/tests/drivers/user.sh b/tests/drivers/user.sh index 7c28602b..a931a735 100644 --- a/tests/drivers/user.sh +++ b/tests/drivers/user.sh @@ -47,3 +47,35 @@ create_versitygw_acl_user_or_get_direct_user() { echo "$username" echo "$password" } + +setup_bucket_and_user() { + if ! check_param_count "setup_bucket_and_user" "bucket, username, password, user type" 4 $#; then + return 1 + fi + if ! setup_bucket "$1"; then + log 2 "error setting up bucket" + return 1 + fi + if ! result=$(setup_user_versitygw_or_direct "$2" "$3" "$4" "$1"); then + log 2 "error setting up user" + return 1 + fi + echo "$result" + return 0 +} + +setup_bucket_and_user_v2() { + if ! check_param_count_v2 "bucket, username, password" 3 $#; then + return 1 + fi + if ! setup_bucket "$1"; then + log 2 "error setting up bucket" + return 1 + fi + if ! result=$(create_versitygw_acl_user_or_get_direct_user "$2" "$3"); then + log 2 "error creating or getting user" + return 1 + fi + echo "$result" + return 0 +} diff --git a/tests/rest_scripts/generate_command.go b/tests/rest_scripts/generate_command.go index 3417b180..0b86178f 100644 --- a/tests/rest_scripts/generate_command.go +++ b/tests/rest_scripts/generate_command.go @@ -24,19 +24,30 @@ var serviceName *string var debug *bool var signedParamsMap restParams var payloadFile *string +var incorrectSignature *bool +var incorrectCredential *string +var authorizationScheme *string +var incorrectYearMonthDay *bool +var invalidYearMonthDay *bool type S3Command struct { - Method string - Url string - BucketName string - ObjectKey string - Query string - AwsRegion string - AwsAccessKeyId string - AwsSecretAccessKey string - ServiceName string - SignedParams map[string]string - PayloadFile string + Method string + Url string + BucketName string + ObjectKey string + Query string + AwsRegion string + AwsAccessKeyId string + AwsSecretAccessKey string + ServiceName string + SignedParams map[string]string + PayloadFile string + IncorrectSignature bool + AuthorizationHeaderMalformed bool + AuthorizationScheme string + IncorrectCredential string + IncorrectYearMonthDay bool + InvalidYearMonthDay bool currentDateTime string host string @@ -76,17 +87,22 @@ func main() { } s3Command := &S3Command{ - Method: *method, - Url: *url, - BucketName: *bucketName, - ObjectKey: *objectKey, - Query: *query, - AwsRegion: *awsRegion, - AwsAccessKeyId: *awsAccessKeyId, - AwsSecretAccessKey: *awsSecretAccessKey, - ServiceName: *serviceName, - SignedParams: signedParamsMap, - PayloadFile: *payloadFile, + Method: *method, + Url: *url, + BucketName: *bucketName, + ObjectKey: *objectKey, + Query: *query, + AwsRegion: *awsRegion, + AwsAccessKeyId: *awsAccessKeyId, + AwsSecretAccessKey: *awsSecretAccessKey, + ServiceName: *serviceName, + SignedParams: signedParamsMap, + PayloadFile: *payloadFile, + IncorrectSignature: *incorrectSignature, + AuthorizationScheme: *authorizationScheme, + IncorrectCredential: *incorrectCredential, + IncorrectYearMonthDay: *incorrectYearMonthDay, + InvalidYearMonthDay: *invalidYearMonthDay, } curlShellCommand, err := s3Command.CurlShellCommand() if err != nil { @@ -108,6 +124,11 @@ func checkFlags() error { debug = flag.Bool("debug", false, "Print debug statements") flag.Var(&signedParamsMap, "signedParams", "Signed params, separated by comma") payloadFile = flag.String("payloadFile", "", "Payload file path, if any") + incorrectSignature = flag.Bool("incorrectSignature", false, "Simulate an incorrect signature") + incorrectYearMonthDay = flag.Bool("incorrectYearMonthDay", false, "Simulate an incorrect year/month/day") + invalidYearMonthDay = flag.Bool("invalidYearMonthDay", false, "Simulate an invalid year/month/day") + incorrectCredential = flag.String("incorrectCredential", "", "Add an incorrect credential string") + authorizationScheme = flag.String("authorizationScheme", "AWS4-HMAC-SHA256", "Authorization Scheme") // Parse the flags flag.Parse() @@ -133,7 +154,11 @@ func hmacSHA256(key []byte, data string) []byte { } func (s *S3Command) CurlShellCommand() (string, error) { - s.currentDateTime = time.Now().UTC().Format("20060102T150405Z") + if s.IncorrectYearMonthDay { + s.currentDateTime = time.Now().Add(-48 * time.Hour).UTC().Format("20060102T150405Z") + } else { + s.currentDateTime = time.Now().UTC().Format("20060102T150405Z") + } protocolAndHost := strings.Split(s.Url, "://") if len(protocolAndHost) != 2 { return "", fmt.Errorf("invalid URL value: %s", s.Url) @@ -141,6 +166,7 @@ func (s *S3Command) CurlShellCommand() (string, error) { s.host = protocolAndHost[1] s.payloadHash = "UNSIGNED-PAYLOAD" s.headerValues = [][]string{ + {"host", s.host}, {"x-amz-content-sha256", s.payloadHash}, {"x-amz-date", s.currentDateTime}, } @@ -158,6 +184,9 @@ func (s *S3Command) CurlShellCommand() (string, error) { s.generateCanonicalRequestString() s.yearMonthDay = strings.Split(s.currentDateTime, "T")[0] + if s.InvalidYearMonthDay { + s.yearMonthDay = s.yearMonthDay[:len(s.yearMonthDay)-1] + } s.getStsSignature() return s.buildCurlShellCommand(), nil @@ -168,9 +197,9 @@ func (s *S3Command) generateCanonicalRequestString() { canonicalRequestLines = append(canonicalRequestLines, s.path) canonicalRequestLines = append(canonicalRequestLines, s.Query) - canonicalRequestLines = append(canonicalRequestLines, "host:"+s.host) + //canonicalRequestLines = append(canonicalRequestLines, "host:"+s.host) - signedParams := []string{"host"} + var signedParams []string for _, headerValue := range s.headerValues { key := strings.ToLower(headerValue[0]) canonicalRequestLines = append(canonicalRequestLines, key+":"+headerValue[1]) @@ -191,7 +220,7 @@ func (s *S3Command) generateCanonicalRequestString() { func (s *S3Command) getStsSignature() { thirdLine := fmt.Sprintf("%s/%s/%s/aws4_request", s.yearMonthDay, s.AwsRegion, s.ServiceName) stsDataLines := []string{ - "AWS4-HMAC-SHA256", + s.AuthorizationScheme, s.currentDateTime, thirdLine, s.canonicalRequestHash, @@ -206,6 +235,13 @@ func (s *S3Command) getStsSignature() { // Generate signature signatureBytes := hmacSHA256(signingKey, stsDataString) + if s.IncorrectSignature { + if signatureBytes[0] == 'a' { + signatureBytes[0] = 'A' + } else { + signatureBytes[0] = 'a' + } + } // Print hex-encoded signature s.signature = hex.EncodeToString(signatureBytes) @@ -222,8 +258,14 @@ func (s *S3Command) buildCurlShellCommand() string { } fullPath += "\"" curlCommand = append(curlCommand, fullPath) - authorizationString := fmt.Sprintf("\"Authorization: AWS4-HMAC-SHA256 Credential=%s/%s/%s/%s/aws4_request,SignedHeaders=%s,Signature=%s\"", - s.AwsAccessKeyId, s.yearMonthDay, s.AwsRegion, s.ServiceName, s.signedParamString, s.signature) + var credentialString string + if s.IncorrectCredential == "" { + credentialString = fmt.Sprintf("%s/%s/%s/%s/aws4_request", s.AwsAccessKeyId, s.yearMonthDay, s.AwsRegion, s.ServiceName) + } else { + credentialString = s.IncorrectCredential + } + authorizationString := fmt.Sprintf("\"Authorization: %s Credential=%s,SignedHeaders=%s,Signature=%s\"", + s.AuthorizationScheme, credentialString, s.signedParamString, s.signature) curlCommand = append(curlCommand, "-H", authorizationString) for _, headerValue := range s.headerValues { headerString := fmt.Sprintf("\"%s: %s\"", headerValue[0], headerValue[1]) diff --git a/tests/run.sh b/tests/run.sh index 9f2d4198..f1d0cc1e 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -40,6 +40,7 @@ show_help() { echo " rest-checksum Run REST checksum tests" echo " rest-create-bucket Run REST create bucket tests" echo " rest-delete-bucket-ownership-controls Run REST delete bucket ownership controls tests" + echo " rest-delete-bucket-tagging Run REST delete bucket tagging tests" echo " rest-head-bucket Run REST head bucket tests" echo " rest-list-buckets Run REST list-buckets tests" echo " rest-multipart Run REST multipart tests" @@ -59,7 +60,8 @@ handle_param() { s3cmd-file-count|mc|mc-non-file-count|mc-file-count|s3api-user|rest|s3api-policy|\ s3api-bucket|s3api-object|s3api-multipart|rest-base|rest-acl|rest-chunked|rest-checksum|\ rest-create-bucket|rest-head-bucket|rest-list-buckets|rest-not-implemented|\ - rest-put-object|rest-versioning|rest-bucket|rest-multipart|rest-delete-bucket-ownership-controls) + rest-put-object|rest-versioning|rest-bucket|rest-multipart|rest-delete-bucket-ownership-controls|\ + rest-delete-bucket-tagging) run_suite "$1" ;; *) # Handle unrecognized options or positional arguments @@ -214,6 +216,10 @@ run_suite() { echo "Running REST delete bucket ownership controls tests ..." "$HOME"/bin/bats ./tests/test_rest_delete_bucket_ownership_controls.sh || exit_code=$? ;; + rest-delete-bucket-tagging) + echo "Running REST delete bucket tagging tests ..." + "$HOME"/bin/bats ./tests/test_rest_delete_bucket_tagging.sh || exit_code=$? + ;; rest-head-bucket) echo "Running REST head bucket tests ..." "$HOME"/bin/bats ./tests/test_rest_head_bucket.sh || exit_code=$? diff --git a/tests/test_rest_delete_bucket_ownership_controls.sh b/tests/test_rest_delete_bucket_ownership_controls.sh index da4eec0a..6739f1b6 100755 --- a/tests/test_rest_delete_bucket_ownership_controls.sh +++ b/tests/test_rest_delete_bucket_ownership_controls.sh @@ -27,22 +27,32 @@ export RUN_USERS=true if [ "$SKIP_USERS_TESTS" == "true" ]; then skip fi - run setup_bucket "$BUCKET_ONE_NAME" - assert_success - - run create_versitygw_acl_user_or_get_direct_user "$USERNAME_ONE" "$PASSWORD_ONE" + run setup_bucket_and_user_v2 "$BUCKET_ONE_NAME" "$USERNAME_ONE" "$PASSWORD_ONE" assert_success username=${lines[2]} password=${lines[3]} - - run put_bucket_ownership_controls_rest "$BUCKET_ONE_NAME" "BucketOwnerPreferred" - assert_success + log 5 "username: $username, password: $password" run send_rest_go_command_expect_error "403" "AccessDenied" "Access Denied" "-awsAccessKeyId" "$username" "-awsSecretAccessKey" "$password" \ "-method" "DELETE" "-bucketName" "$BUCKET_ONE_NAME" "-query" "ownershipControls=" assert_success } +@test "REST - DeleteBucketOwnershipControls - invalid username" { + if [ "$SKIP_USERS_TESTS" == "true" ]; then + skip + fi + run setup_bucket "$BUCKET_ONE_NAME" + assert_success + + username="invalid with spaces" + password="dummy" + + run send_rest_go_command_expect_error "403" "InvalidAccessKeyId" "does not exist in our records" "-awsAccessKeyId" "$username" "-awsSecretAccessKey" "$password" \ + "-method" "DELETE" "-bucketName" "$BUCKET_ONE_NAME" "-query" "ownershipControls=" + assert_success +} + @test "REST - DeleteBucketOwnershipControls - success" { run setup_bucket "$BUCKET_ONE_NAME" assert_success diff --git a/tests/test_rest_delete_bucket_tagging.sh b/tests/test_rest_delete_bucket_tagging.sh new file mode 100755 index 00000000..5d143861 --- /dev/null +++ b/tests/test_rest_delete_bucket_tagging.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bats + +# 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. + +load ./bats-support/load +load ./bats-assert/load + +source ./tests/drivers/user.sh +source ./tests/setup.sh +source ./tests/drivers/user.sh + +export RUN_USERS=true + +@test "REST - DeleteBucketTagging - lack permission" { + if [ "$SKIP_USERS_TESTS" == "true" ]; then + skip + fi + run setup_bucket_and_user_v2 "$BUCKET_ONE_NAME" "$USERNAME_ONE" "$PASSWORD_ONE" + assert_success + username=${lines[${#lines[@]}-2]} + password=${lines[${#lines[@]}-1]} + + run send_rest_go_command_expect_error "403" "AccessDenied" "Access Denied" "-awsAccessKeyId" "$username" "-awsSecretAccessKey" "$password" \ + "-method" "DELETE" "-bucketName" "$BUCKET_ONE_NAME" "-query" "tagging=" + assert_success +} diff --git a/tests/test_rest_list_buckets.sh b/tests/test_rest_list_buckets.sh index 3e376469..c9e226b6 100755 --- a/tests/test_rest_list_buckets.sh +++ b/tests/test_rest_list_buckets.sh @@ -19,9 +19,12 @@ load ./bats-assert/load source ./tests/commands/list_buckets.sh source ./tests/drivers/list_buckets/list_buckets_rest.sh +source ./tests/drivers/user.sh source ./tests/logger.sh source ./tests/setup.sh +export RUN_USERS=true + @test "REST - empty message" { test_file="test_file" if [ "$DIRECT" != "true" ]; then @@ -40,14 +43,70 @@ source ./tests/setup.sh if [ "$DIRECT" != "true" ]; then skip "https://github.com/versity/versitygw/issues/1364" fi - run setup_bucket_and_file "$BUCKET_ONE_NAME" "$test_file" - assert_success echo -en "abcdefg\r\n\r\n" > "$TEST_FILE_FOLDER/deformed.txt" run send_via_openssl_check_code_error_contains "$TEST_FILE_FOLDER/deformed.txt" 400 "BadRequest" "An error occurred when parsing the HTTP request." assert_success } +@test "REST - invalid authorization scheme" { + if [ "$DIRECT" != "true" ]; then + skip "https://github.com/versity/versitygw/issues/1512" + fi + run list_buckets_check_authorization_scheme_error + assert_success +} + +@test "REST - very invalid credential string" { + if [ "$DIRECT" != "true" ]; then + skip "https://github.com/versity/versitygw/issues/1513" + fi + run send_rest_go_command_expect_error "400" "AuthorizationHeaderMalformed" "the Credential is mal-formed" "-incorrectCredential" "Credentials" + assert_success +} + +@test "REST - nonexistent key ID" { + run send_rest_go_command_expect_error "403" "InvalidAccessKeyId" "does not exist" "-awsAccessKeyId" "dummy" + assert_success +} + +@test "REST - invalid year/month/day" { + if [ "$DIRECT" != "true" ]; then + skip "https://github.com/versity/versitygw/issues/1513" + fi + run send_rest_go_command_expect_error "400" "AuthorizationHeaderMalformed" "incorrect date format" "-invalidYearMonthDay" + assert_success +} + +@test "REST - incorrect year/month/day" { + if [ "$DIRECT" != "true" ]; then + skip "https://github.com/versity/versitygw/issues/1514" + fi + run list_buckets_check_request_time_too_skewed_error + assert_success +} + +@test "REST - invalid region" { + if [ "$DIRECT" != "true" ]; then + skip "https://github.com/versity/versitygw/issues/1513" + fi + run send_rest_go_command_expect_error "400" "AuthorizationHeaderMalformed" "the region 'us-eest-1' is wrong" "-awsRegion" "us-eest-1" + assert_success +} + +@test "REST - invalid service name" { + if [ "$DIRECT" != "true" ]; then + skip "https://github.com/versity/versitygw/issues/1513" + fi + run send_rest_go_command_expect_error "400" "AuthorizationHeaderMalformed" "incorrect service" "-serviceName" "s2" + assert_success +} + +@test "REST - incorrect signature" { + run send_rest_go_command_expect_error "403" "SignatureDoesNotMatch" "does not match" "-incorrectSignature" + assert_success +} + @test "test_rest_list_buckets" { run setup_bucket "$BUCKET_ONE_NAME" assert_success @@ -88,3 +147,27 @@ source ./tests/setup.sh run list_check_buckets_rest_with_prefix "$BUCKET_TWO_NAME" assert_success } + +@test "REST - ListBuckets - correct buckets show up" { + if [ "$SKIP_USERS_TESTS" == "true" ]; then + skip + fi + if [ "$DIRECT" == "true" ]; then + skip + fi + run setup_bucket_and_user "$BUCKET_ONE_NAME" "$USERNAME_ONE" "$PASSWORD_ONE" "user" + assert_success + username=${lines[${#lines[@]}-2]} + password=${lines[${#lines[@]}-1]} + + run setup_bucket "$BUCKET_TWO_NAME" + assert_success + + run change_bucket_owner "$AWS_ACCESS_KEY_ID" "$AWS_SECRET_ACCESS_KEY" "$BUCKET_TWO_NAME" "$username" + assert_success + + log 5 "username: $username, password: $password" + run list_check_buckets_user "$username" "$password" "$BUCKET_TWO_NAME" + assert_success +} + diff --git a/tests/test_rest_put_object.sh b/tests/test_rest_put_object.sh index 35953233..852e4fdb 100755 --- a/tests/test_rest_put_object.sh +++ b/tests/test_rest_put_object.sh @@ -212,3 +212,15 @@ export RUN_USERS=true run put_object_rest_user_bad_signature "$username" "$password" "$TEST_FILE_FOLDER/$test_file" "$BUCKET_ONE_NAME" "$test_file" assert_success } + +@test "REST - PutObject - expect continue - success" { + if [ "$DIRECT" != "true" ]; then + skip "https://github.com/versity/versitygw/issues/1517" + fi + run setup_bucket_and_file "$BUCKET_ONE_NAME" "$test_file" + assert_success + + run send_rest_go_command "200" "-bucketName" "$BUCKET_ONE_NAME" "-objectKey" "$test_file" "-method" "PUT" "-payloadFile" "$TEST_FILE_FOLDER/$test_file" \ + "-signedParams" "Expect:100-continue" + assert_success +} diff --git a/tests/test_s3api_bucket.sh b/tests/test_s3api_bucket.sh index 001854f9..b81e25ea 100755 --- a/tests/test_s3api_bucket.sh +++ b/tests/test_s3api_bucket.sh @@ -50,6 +50,7 @@ source ./tests/commands/put_object_retention.sh source ./tests/commands/put_public_access_block.sh source ./tests/commands/select_object_content.sh source ./tests/drivers/get_bucket_acl/get_bucket_acl.sh +source ./tests/drivers/user.sh export RUN_USERS=true diff --git a/tests/test_user_aws.sh b/tests/test_user_aws.sh index ac307330..7909db76 100755 --- a/tests/test_user_aws.sh +++ b/tests/test_user_aws.sh @@ -19,9 +19,9 @@ load ./bats-assert/load source ./tests/test_user_common.sh source ./tests/util/util_setup.sh -source ./tests/util/util_users.sh source ./tests/commands/get_object.sh source ./tests/commands/put_object.sh +source ./tests/drivers/user.sh export RUN_USERS=true diff --git a/tests/test_user_s3cmd.sh b/tests/test_user_s3cmd.sh index 62d3a898..2707b70b 100755 --- a/tests/test_user_s3cmd.sh +++ b/tests/test_user_s3cmd.sh @@ -18,6 +18,7 @@ load ./bats-support/load load ./bats-assert/load source ./tests/test_user_common.sh +source ./tests/drivers/user.sh export RUN_S3CMD=true export RUN_USERS=true diff --git a/tests/util/util_setup.sh b/tests/util/util_setup.sh index 3656ea97..0f349b5f 100644 --- a/tests/util/util_setup.sh +++ b/tests/util/util_setup.sh @@ -43,22 +43,6 @@ setup_bucket_and_large_file() { return 0 } -setup_bucket_and_user() { - if ! check_param_count "setup_bucket_and_user" "bucket, username, password, user type" 4 $#; then - return 1 - fi - if ! setup_bucket "$1"; then - log 2 "error setting up bucket" - return 1 - fi - if ! result=$(setup_user_versitygw_or_direct "$2" "$3" "$4" "$1"); then - log 2 "error setting up user" - return 1 - fi - echo "$result" - return 0 -} - setup_bucket_file_and_user() { if ! check_param_count "setup_bucket_file_and_user" "bucket, file, username, password, user type" 5 $#; then return 1