// Copyright 2023 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. package integration import ( "context" "fmt" "io" "net/http" "net/url" "strconv" "strings" "time" "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/versity/versitygw/s3err" ) func PresignedAuth_security_token_not_supported(s *S3Conf) error { testName := "PresignedAuth_security_token_not_supported" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignDeleteBucket(ctx, &s3.DeleteBucketInput{Bucket: &bucket}) cancel() if err != nil { return err } uri := v4req.URL + "&X-Amz-Security-Token=my_token" req, err := http.NewRequest(v4req.Method, uri, nil) if err != nil { return err } resp, err := s.httpClient.Do(req) if err != nil { return err } return checkHTTPResponseApiErr(resp, s3err.QueryAuthErrors.SecurityTokenNotSupported()) }) } func PresignedAuth_unsupported_algorithm(s *S3Conf) error { testName := "PresignedAuth_unsupported_algorithm" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignDeleteBucket(ctx, &s3.DeleteBucketInput{Bucket: &bucket}) cancel() if err != nil { return err } uri := strings.Replace(v4req.URL, "AWS4-HMAC-SHA256", "AWS4-SHA256", 1) req, err := http.NewRequest(v4req.Method, uri, nil) if err != nil { return err } resp, err := s.httpClient.Do(req) if err != nil { return err } return checkHTTPResponseApiErr(resp, s3err.QueryAuthErrors.UnsupportedAlgorithm()) }) } func PresignedAuth_ECDSA_not_supported(s *S3Conf) error { testName := "PresignedAuth_ECDSA_not_supported" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignDeleteBucket(ctx, &s3.DeleteBucketInput{Bucket: &bucket}) cancel() if err != nil { return err } uri := strings.Replace(v4req.URL, "AWS4-HMAC-SHA256", "AWS4-ECDSA-P256-SHA256", 1) req, err := http.NewRequest(v4req.Method, uri, nil) if err != nil { return err } resp, err := s.httpClient.Do(req) if err != nil { return err } return checkHTTPResponseApiErr(resp, s3err.QueryAuthErrors.OnlyHMACSupported()) }) } func PresignedAuth_missing_signature_query_param(s *S3Conf) error { testName := "PresignedAuth_missing_signature_query_param" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignDeleteBucket(ctx, &s3.DeleteBucketInput{Bucket: &bucket}) cancel() if err != nil { return err } urlParsed, err := url.Parse(v4req.URL) if err != nil { return err } queries := urlParsed.Query() queries.Del("X-Amz-Signature") urlParsed.RawQuery = queries.Encode() req, err := http.NewRequest(v4req.Method, urlParsed.String(), nil) if err != nil { return err } resp, err := s.httpClient.Do(req) if err != nil { return err } return checkHTTPResponseApiErr(resp, s3err.QueryAuthErrors.MissingRequiredParams()) }) } func PresignedAuth_missing_credentials_query_param(s *S3Conf) error { testName := "PresignedAuth_missing_credentials_query_param" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignDeleteBucket(ctx, &s3.DeleteBucketInput{Bucket: &bucket}) cancel() if err != nil { return err } urlParsed, err := url.Parse(v4req.URL) if err != nil { return err } queries := urlParsed.Query() queries.Del("X-Amz-Credential") urlParsed.RawQuery = queries.Encode() req, err := http.NewRequest(v4req.Method, urlParsed.String(), nil) if err != nil { return err } resp, err := s.httpClient.Do(req) if err != nil { return err } return checkHTTPResponseApiErr(resp, s3err.QueryAuthErrors.MissingRequiredParams()) }) } func PresignedAuth_malformed_creds_invalid_parts(s *S3Conf) error { testName := "PresignedAuth_malformed_creds_invalid_parts" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignDeleteBucket(ctx, &s3.DeleteBucketInput{Bucket: &bucket}) cancel() if err != nil { return err } urlParsed, err := url.Parse(v4req.URL) if err != nil { return err } queries := urlParsed.Query() queries.Set("X-Amz-Credential", "access/hello/world") urlParsed.RawQuery = queries.Encode() req, err := http.NewRequest(v4req.Method, urlParsed.String(), nil) if err != nil { return err } resp, err := s.httpClient.Do(req) if err != nil { return err } return checkHTTPResponseApiErr(resp, s3err.QueryAuthErrors.MalformedCredential("")) }) } func PresignedAuth_creds_invalid_terminal(s *S3Conf) error { testName := "PresignedAuth_creds_invalid_terminal" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignDeleteBucket(ctx, &s3.DeleteBucketInput{Bucket: &bucket}) cancel() if err != nil { return err } uri, err := changeAuthCred(v4req.URL, "aws5_request", credTerminator) if err != nil { return err } req, err := http.NewRequest(v4req.Method, uri, nil) if err != nil { return err } resp, err := s.httpClient.Do(req) if err != nil { return err } return checkHTTPResponseApiErr(resp, s3err.QueryAuthErrors.IncorrectTerminal("", "aws5_request")) }) } func PresignedAuth_creds_incorrect_service(s *S3Conf) error { testName := "PresignedAuth_creds_incorrect_service" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignDeleteBucket(ctx, &s3.DeleteBucketInput{Bucket: &bucket}) cancel() if err != nil { return err } uri, err := changeAuthCred(v4req.URL, "sns", credService) if err != nil { return err } req, err := http.NewRequest(v4req.Method, uri, nil) if err != nil { return err } resp, err := s.httpClient.Do(req) if err != nil { return err } return checkHTTPResponseApiErr(resp, s3err.QueryAuthErrors.IncorrectService("", "sns")) }) } func PresignedAuth_creds_incorrect_region(s *S3Conf) error { testName := "PresignedAuth_creds_incorrect_region" return presignedAuthHandler(s, testName, func(_ *s3.PresignClient, bucket string) error { cfg := *s if cfg.awsRegion == "us-east-1" { cfg.awsRegion = "us-west-1" } else { cfg.awsRegion = "us-east-1" } client := cfg.GetPresignClient() ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignDeleteBucket(ctx, &s3.DeleteBucketInput{Bucket: &bucket}) cancel() if err != nil { return err } req, err := http.NewRequest(v4req.Method, v4req.URL, nil) if err != nil { return err } resp, err := s.httpClient.Do(req) if err != nil { return err } return checkHTTPResponseApiErr(resp, s3err.QueryAuthErrors.IncorrectRegion(s.awsRegion, cfg.awsRegion)) }) } func PresignedAuth_creds_invalid_date(s *S3Conf) error { testName := "PresignedAuth_creds_invalid_date" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignDeleteBucket(ctx, &s3.DeleteBucketInput{Bucket: &bucket}) cancel() if err != nil { return err } uri, err := changeAuthCred(v4req.URL, "32234Z34", credDate) if err != nil { return err } req, err := http.NewRequest(v4req.Method, uri, nil) if err != nil { return err } resp, err := s.httpClient.Do(req) if err != nil { return err } return checkHTTPResponseApiErr(resp, s3err.QueryAuthErrors.InvalidDateFormat("", "32234Z34")) }) } func PresignedAuth_non_existing_access_key_id(s *S3Conf) error { testName := "PresignedAuth_non_existing_access_key_id" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { accessKeyID := "a_rarely_existing_access_key_id890asd6f807as6ydf870say" ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignDeleteBucket(ctx, &s3.DeleteBucketInput{Bucket: &bucket}) cancel() if err != nil { return err } uri, err := changeAuthCred(v4req.URL, accessKeyID, credAccess) if err != nil { return err } req, err := http.NewRequest(v4req.Method, uri, nil) if err != nil { return err } resp, err := s.httpClient.Do(req) if err != nil { return err } return checkHTTPResponseApiErr(resp, s3err.GetInvalidAccessKeyIdErr(accessKeyID)) }) } func PresignedAuth_missing_date_query(s *S3Conf) error { testName := "PresignedAuth_missing_date_query" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignDeleteBucket(ctx, &s3.DeleteBucketInput{Bucket: &bucket}) cancel() if err != nil { return err } urlParsed, err := url.Parse(v4req.URL) if err != nil { return err } queries := urlParsed.Query() queries.Del("X-Amz-Date") urlParsed.RawQuery = queries.Encode() req, err := http.NewRequest(v4req.Method, urlParsed.String(), nil) if err != nil { return err } resp, err := s.httpClient.Do(req) if err != nil { return err } return checkHTTPResponseApiErr(resp, s3err.QueryAuthErrors.MissingRequiredParams()) }) } func PresignedAuth_dates_mismatch(s *S3Conf) error { testName := "PresignedAuth_dates_mismatch" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignDeleteBucket(ctx, &s3.DeleteBucketInput{Bucket: &bucket}) cancel() if err != nil { return err } urlParsed, err := url.Parse(v4req.URL) if err != nil { return err } tDate := urlParsed.Query().Get("X-Amz-Date") date := tDate[:8] uri, err := changeAuthCred(v4req.URL, "20060102", credDate) if err != nil { return err } req, err := http.NewRequest(v4req.Method, uri, nil) if err != nil { return err } resp, err := s.httpClient.Do(req) if err != nil { return err } return checkHTTPResponseApiErr(resp, s3err.QueryAuthErrors.DateMismatch("20060102", date)) }) } func PresignedAuth_missing_signed_headers_query_param(s *S3Conf) error { testName := "PresignedAuth_missing_signed_headers_query_param" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignDeleteBucket(ctx, &s3.DeleteBucketInput{Bucket: &bucket}) cancel() if err != nil { return err } urlParsed, err := url.Parse(v4req.URL) if err != nil { return err } queries := urlParsed.Query() queries.Del("X-Amz-SignedHeaders") urlParsed.RawQuery = queries.Encode() req, err := http.NewRequest(v4req.Method, urlParsed.String(), nil) if err != nil { return err } resp, err := s.httpClient.Do(req) if err != nil { return err } return checkHTTPResponseApiErr(resp, s3err.QueryAuthErrors.MissingRequiredParams()) }) } func PresignedAuth_unsigned_required_header(s *S3Conf) error { testName := "PresignedAuth_unsigned_required_header" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignPutObject(ctx, &s3.PutObjectInput{Bucket: &bucket, Key: getPtr("my-obj")}) cancel() if err != nil { return err } req, err := http.NewRequest(v4req.Method, v4req.URL, nil) if err != nil { return err } req.Header.Set("X-Amz-Copy-Source", "source-bucket/source-key") req.Header.Set("X-Amz-Tagging", "a=b") resp, err := s.httpClient.Do(req) if err != nil { return err } return checkHTTPResponseApiErr(resp, s3err.GetHeadersNotSignedErr([]string{"x-amz-copy-source", "x-amz-tagging"})) }) } func PresignedAuth_unsigned_non_required_header(s *S3Conf) error { testName := "PresignedAuth_unsigned_non_required_header" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignPutObject(ctx, &s3.PutObjectInput{Bucket: &bucket, Key: getPtr("my-obj")}) cancel() if err != nil { return err } req, err := http.NewRequest(v4req.Method, v4req.URL, nil) if err != nil { return err } req.Header.Set("Content-Type", "text/plain") req.Header.Set("X-Custom-Header", "value") req.Header.Set("X-Another-Custom-Header", "value") resp, err := s.httpClient.Do(req) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return fmt.Errorf("expected response status code to be %v, instead got %v", http.StatusOK, resp.StatusCode) } return nil }) } func PresignedAuth_missing_expiration_query_param(s *S3Conf) error { testName := "PresignedAuth_missing_expiration_query_param" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignDeleteBucket(ctx, &s3.DeleteBucketInput{Bucket: &bucket}) cancel() if err != nil { return err } urlParsed, err := url.Parse(v4req.URL) if err != nil { return err } queries := urlParsed.Query() queries.Del("X-Amz-Expires") urlParsed.RawQuery = queries.Encode() req, err := http.NewRequest(v4req.Method, urlParsed.String(), nil) if err != nil { return err } resp, err := s.httpClient.Do(req) if err != nil { return err } return checkHTTPResponseApiErr(resp, s3err.QueryAuthErrors.MissingRequiredParams()) }) } func PresignedAuth_invalid_expiration_query_param(s *S3Conf) error { testName := "PresignedAuth_invalid_expiration_query_param" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignDeleteBucket(ctx, &s3.DeleteBucketInput{Bucket: &bucket}) cancel() if err != nil { return err } urlParsed, err := url.Parse(v4req.URL) if err != nil { return err } queries := urlParsed.Query() queries.Set("X-Amz-Expires", "invalid_value") urlParsed.RawQuery = queries.Encode() req, err := http.NewRequest(v4req.Method, urlParsed.String(), nil) if err != nil { return err } resp, err := s.httpClient.Do(req) if err != nil { return err } return checkHTTPResponseApiErr(resp, s3err.QueryAuthErrors.ExpiresNumber()) }) } func PresignedAuth_negative_expiration_query_param(s *S3Conf) error { testName := "PresignedAuth_negative_expiration_query_param" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignDeleteBucket(ctx, &s3.DeleteBucketInput{Bucket: &bucket}) cancel() if err != nil { return err } urlParsed, err := url.Parse(v4req.URL) if err != nil { return err } queries := urlParsed.Query() queries.Set("X-Amz-Expires", "-3") urlParsed.RawQuery = queries.Encode() req, err := http.NewRequest(v4req.Method, urlParsed.String(), nil) if err != nil { return err } resp, err := s.httpClient.Do(req) if err != nil { return err } return checkHTTPResponseApiErr(resp, s3err.QueryAuthErrors.ExpiresNegative()) }) } func PresignedAuth_exceeding_expiration_query_param(s *S3Conf) error { testName := "PresignedAuth_exceeding_expiration_query_param" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignDeleteBucket(ctx, &s3.DeleteBucketInput{Bucket: &bucket}) cancel() if err != nil { return err } urlParsed, err := url.Parse(v4req.URL) if err != nil { return err } queries := urlParsed.Query() queries.Set("X-Amz-Expires", "60580000") urlParsed.RawQuery = queries.Encode() req, err := http.NewRequest(v4req.Method, urlParsed.String(), nil) if err != nil { return err } resp, err := s.httpClient.Do(req) if err != nil { return err } return checkHTTPResponseApiErr(resp, s3err.QueryAuthErrors.ExpiresTooLarge()) }) } func PresignedAuth_expired_request(s *S3Conf) error { testName := "PresignedAuth_expired_request" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignDeleteBucket(ctx, &s3.DeleteBucketInput{Bucket: &bucket}) cancel() if err != nil { return err } urlParsed, err := url.Parse(v4req.URL) if err != nil { return err } expDate := time.Now().AddDate(0, -1, 0).Format(iso8601Format) queries := urlParsed.Query() queries.Set("X-Amz-Date", expDate) urlParsed.RawQuery = queries.Encode() xAmzExpires, err := strconv.Atoi(queries.Get("X-Amz-Expires")) if err != nil { return err } uri, err := changeAuthCred(urlParsed.String(), expDate[:8], credDate) if err != nil { return err } req, err := http.NewRequest(v4req.Method, uri, nil) if err != nil { return err } resp, err := s.httpClient.Do(req) if err != nil { return err } if err := checkHTTPResponseApiErr(resp, s3err.GetExpiredPresignedURLError(xAmzExpires, "", "")); err != nil { return err } return nil }) } func PresignedAuth_incorrect_secret_key(s *S3Conf) error { testName := "PresignedAuth_incorrect_secret_key" return presignedAuthHandler(s, testName, func(_ *s3.PresignClient, bucket string) error { cfg := *s cfg.awsSecret += "x" client := cfg.GetPresignClient() ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignDeleteBucket(ctx, &s3.DeleteBucketInput{Bucket: &bucket}) cancel() if err != nil { return err } req, err := http.NewRequest(v4req.Method, v4req.URL, nil) if err != nil { return err } resp, err := s.httpClient.Do(req) if err != nil { return err } if err := checkHTTPResponseApiErr(resp, s3err.GetAPIError(s3err.ErrSignatureDoesNotMatch)); err != nil { return err } return nil }) } func PresignedAuth_sigv2_not_supported(s *S3Conf) error { testName := "PresignedAuth_sigv2_not_supported" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { expires := time.Now().UTC().Add(time.Hour).Unix() uri := fmt.Sprintf("%s/%s/object?AWSAccessKeyId=%s&Expires=%d&Signature=my-signature", s.endpoint, bucket, s.awsID, expires) ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri, nil) if err != nil { cancel() return err } resp, err := s.httpClient.Do(req) cancel() if err != nil { return err } return checkHTTPResponseApiErr(resp, s3err.GetAPIError(s3err.ErrUnsupportedAuthorizationMechanism)) }) } func PresignedAuth_PutObject_success(s *S3Conf) error { testName := "PresignedAuth_PutObject_success" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignPutObject(ctx, &s3.PutObjectInput{Bucket: &bucket, Key: getPtr("my-obj")}) cancel() if err != nil { return err } req, err := http.NewRequest(http.MethodPut, v4req.URL, nil) if err != nil { return err } resp, err := s.httpClient.Do(req) if err != nil { return err } if resp.StatusCode != http.StatusOK { return fmt.Errorf("expected my-obj to be successfully uploaded and get 200 response status, instead got %v", resp.StatusCode) } return nil }) } func PresignedAuth_Put_GetObject_with_data(s *S3Conf) error { testName := "PresignedAuth_Put_GetObject_with_data" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { obj := "my-obj" data := "Hello world" body := strings.NewReader(data) ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignPutObject(ctx, &s3.PutObjectInput{Bucket: &bucket, Key: &obj, Body: body}) cancel() if err != nil { return err } req, err := http.NewRequest(v4req.Method, v4req.URL, body) if err != nil { return err } req.Header = v4req.SignedHeader resp, err := s.httpClient.Do(req) if err != nil { return err } if resp.StatusCode != http.StatusOK { return fmt.Errorf("expected my-obj to be successfully uploaded and get %v response status, instead got %v", http.StatusOK, resp.StatusCode) } ctx, cancel = context.WithTimeout(context.Background(), shortTimeout) v4GetReq, err := client.PresignGetObject(ctx, &s3.GetObjectInput{Bucket: &bucket, Key: &obj}) cancel() if err != nil { return err } req, err = http.NewRequest(v4GetReq.Method, v4GetReq.URL, nil) if err != nil { return err } resp, err = s.httpClient.Do(req) if err != nil { return err } if resp.StatusCode != http.StatusOK { return fmt.Errorf("expected get object response status to be %v, instead got %v", http.StatusOK, resp.StatusCode) } defer resp.Body.Close() respBody, err := io.ReadAll(resp.Body) if err != nil { return fmt.Errorf("read get object response body %w", err) } if string(respBody) != data { return fmt.Errorf("expected get object response body to be %v, instead got %s", data, respBody) } return nil }) } func PresignedAuth_Put_GetObject_with_UTF8_chars(s *S3Conf) error { testName := "PresignedAuth_Put_GetObject_with_UTF8_chars" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { obj := "my-$%^&*;" if s.windowsTests { // '*' is not a valid filename character on Windows obj = "my-$%^&;" } ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignPutObject(ctx, &s3.PutObjectInput{Bucket: &bucket, Key: &obj}) cancel() if err != nil { return err } req, err := http.NewRequest(v4req.Method, v4req.URL, nil) if err != nil { return err } req.Header = v4req.SignedHeader resp, err := s.httpClient.Do(req) if err != nil { return err } if resp.StatusCode != http.StatusOK { return fmt.Errorf("expected my-obj to be successfully uploaded and get %v response status, instead got %v", http.StatusOK, resp.StatusCode) } ctx, cancel = context.WithTimeout(context.Background(), shortTimeout) v4GetReq, err := client.PresignGetObject(ctx, &s3.GetObjectInput{Bucket: &bucket, Key: &obj}) cancel() if err != nil { return err } req, err = http.NewRequest(v4GetReq.Method, v4GetReq.URL, nil) if err != nil { return err } resp, err = s.httpClient.Do(req) if err != nil { return err } if resp.StatusCode != http.StatusOK { return fmt.Errorf("expected get object response status to be %v, instead got %v", http.StatusOK, resp.StatusCode) } return nil }) } func PresignedAuth_UploadPart(s *S3Conf) error { testName := "PresignedAuth_UploadPart" return presignedAuthHandler(s, testName, func(client *s3.PresignClient, bucket string) error { key, partNumber := "my-mp", int32(1) clt := s.GetClient() mp, err := createMp(clt, bucket, key) if err != nil { return err } ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) v4req, err := client.PresignUploadPart(ctx, &s3.UploadPartInput{Bucket: &bucket, Key: &key, UploadId: mp.UploadId, PartNumber: &partNumber}) cancel() if err != nil { return err } req, err := http.NewRequest(v4req.Method, v4req.URL, nil) if err != nil { return err } resp, err := s.httpClient.Do(req) if err != nil { return err } if resp.StatusCode != http.StatusOK { return fmt.Errorf("expected response status code to be %v, instead got %v", http.StatusOK, resp.StatusCode) } etag := resp.Header.Get("Etag") ctx, cancel = context.WithTimeout(context.Background(), shortTimeout) out, err := clt.ListParts(ctx, &s3.ListPartsInput{Bucket: &bucket, Key: &key, UploadId: mp.UploadId}) cancel() if err != nil { return err } if len(out.Parts) != 1 { return fmt.Errorf("expected mp upload parts length to be 1, instead got %v", len(out.Parts)) } if getString(out.Parts[0].ETag) != etag { return fmt.Errorf("expected uploaded part etag to be %v, instead got %v", etag, getString(out.Parts[0].ETag)) } if out.Parts[0].PartNumber == nil { return fmt.Errorf("expected uploaded part part-number to be not nil") } if *out.Parts[0].PartNumber != partNumber { return fmt.Errorf("expected uploaded part part-number to be %v, instead got %v", partNumber, *out.Parts[0].PartNumber) } return nil }) }