Compare commits

..

15 Commits

Author SHA1 Message Date
Ben McClelland
85dc8e71b5 Merge pull request #663 from versity/test_cmdline_acl_correction
Test cmdline acl correction
2024-07-11 08:32:46 -07:00
Luke McCrone
059205c174 test: re-addition of some tests after default ACL disable, cleanup 2024-07-11 12:20:35 -03:00
Ben McClelland
4749c80698 Merge pull request #666 from versity/dependabot/go_modules/dev-dependencies-0e3fd1ac96
chore(deps): bump the dev-dependencies group with 9 updates
2024-07-09 21:50:14 -07:00
dependabot[bot]
b87ed2ae63 chore(deps): bump the dev-dependencies group with 9 updates
Bumps the dev-dependencies group with 9 updates:

| Package | From | To |
| --- | --- | --- |
| [github.com/aws/aws-sdk-go-v2/service/s3](https://github.com/aws/aws-sdk-go-v2) | `1.57.1` | `1.58.0` |
| [golang.org/x/sys](https://github.com/golang/sys) | `0.21.0` | `0.22.0` |
| [github.com/Azure/azure-sdk-for-go/sdk/internal](https://github.com/Azure/azure-sdk-for-go) | `1.9.0` | `1.9.1` |
| [github.com/aws/aws-sdk-go-v2/service/ssooidc](https://github.com/aws/aws-sdk-go-v2) | `1.26.1` | `1.26.2` |
| [golang.org/x/crypto](https://github.com/golang/crypto) | `0.24.0` | `0.25.0` |
| [golang.org/x/net](https://github.com/golang/net) | `0.26.0` | `0.27.0` |
| [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) | `1.27.23` | `1.27.24` |
| [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2) | `1.17.23` | `1.17.24` |
| [github.com/aws/aws-sdk-go-v2/feature/s3/manager](https://github.com/aws/aws-sdk-go-v2) | `1.17.3` | `1.17.5` |


Updates `github.com/aws/aws-sdk-go-v2/service/s3` from 1.57.1 to 1.58.0
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/s3/v1.57.1...service/s3/v1.58.0)

Updates `golang.org/x/sys` from 0.21.0 to 0.22.0
- [Commits](https://github.com/golang/sys/compare/v0.21.0...v0.22.0)

Updates `github.com/Azure/azure-sdk-for-go/sdk/internal` from 1.9.0 to 1.9.1
- [Release notes](https://github.com/Azure/azure-sdk-for-go/releases)
- [Changelog](https://github.com/Azure/azure-sdk-for-go/blob/main/documentation/release.md)
- [Commits](https://github.com/Azure/azure-sdk-for-go/compare/sdk/azcore/v1.9.0...sdk/azcore/v1.9.1)

Updates `github.com/aws/aws-sdk-go-v2/service/ssooidc` from 1.26.1 to 1.26.2
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.26.1...v1.26.2)

Updates `golang.org/x/crypto` from 0.24.0 to 0.25.0
- [Commits](https://github.com/golang/crypto/compare/v0.24.0...v0.25.0)

Updates `golang.org/x/net` from 0.26.0 to 0.27.0
- [Commits](https://github.com/golang/net/compare/v0.26.0...v0.27.0)

Updates `github.com/aws/aws-sdk-go-v2/config` from 1.27.23 to 1.27.24
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.27.23...config/v1.27.24)

Updates `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.23 to 1.17.24
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/credentials/v1.17.23...credentials/v1.17.24)

Updates `github.com/aws/aws-sdk-go-v2/feature/s3/manager` from 1.17.3 to 1.17.5
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/v1.17.5/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.17.3...v1.17.5)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/service/s3
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: dev-dependencies
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: dev-dependencies
- dependency-name: github.com/Azure/azure-sdk-for-go/sdk/internal
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: github.com/aws/aws-sdk-go-v2/service/ssooidc
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: dev-dependencies
- dependency-name: golang.org/x/net
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: dev-dependencies
- dependency-name: github.com/aws/aws-sdk-go-v2/config
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: github.com/aws/aws-sdk-go-v2/credentials
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: github.com/aws/aws-sdk-go-v2/feature/s3/manager
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-08 21:13:07 +00:00
Ben McClelland
2529028e22 Merge pull request #665 from versity/get-object-resp-body-stream
GetObject response body streaming
2024-07-08 15:12:27 -06:00
jonaustin09
e773872c48 feat: Implemented response body streaming for GetObject action 2024-07-08 15:56:24 -04:00
Ben McClelland
157f22b08b Merge pull request #662 from versity/test_cmdline_policy_multipart
Test cmdline policy multipart
2024-07-05 12:24:48 -06:00
Luke McCrone
e81fac9558 test: multipart abort policy, direct s3 user setup, ACLs on/off command 2024-07-04 15:21:08 -03:00
Ben McClelland
36738022ed Merge pull request #661 from versity/dependabot/go_modules/dev-dependencies-5c141c1c43
chore(deps): bump the dev-dependencies group with 19 updates
2024-07-01 17:33:33 -06:00
dependabot[bot]
e2d69cfb66 chore(deps): bump the dev-dependencies group with 19 updates
Bumps the dev-dependencies group with 19 updates:

| Package | From | To |
| --- | --- | --- |
| [github.com/aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) | `1.30.0` | `1.30.1` |
| [github.com/aws/aws-sdk-go-v2/service/s3](https://github.com/aws/aws-sdk-go-v2) | `1.56.1` | `1.57.1` |
| [github.com/aws/smithy-go](https://github.com/aws/smithy-go) | `1.20.2` | `1.20.3` |
| [github.com/gofiber/fiber/v2](https://github.com/gofiber/fiber) | `2.52.4` | `2.52.5` |
| [github.com/aws/aws-sdk-go-v2/feature/ec2/imds](https://github.com/aws/aws-sdk-go-v2) | `1.16.8` | `1.16.9` |
| [github.com/aws/aws-sdk-go-v2/service/sso](https://github.com/aws/aws-sdk-go-v2) | `1.21.1` | `1.22.1` |
| [github.com/aws/aws-sdk-go-v2/service/ssooidc](https://github.com/aws/aws-sdk-go-v2) | `1.25.1` | `1.26.1` |
| [github.com/aws/aws-sdk-go-v2/service/sts](https://github.com/aws/aws-sdk-go-v2) | `1.29.1` | `1.30.1` |
| [github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream](https://github.com/aws/aws-sdk-go-v2) | `1.6.2` | `1.6.3` |
| [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) | `1.27.21` | `1.27.23` |
| [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2) | `1.17.21` | `1.17.23` |
| [github.com/aws/aws-sdk-go-v2/feature/s3/manager](https://github.com/aws/aws-sdk-go-v2) | `1.17.1` | `1.17.3` |
| [github.com/aws/aws-sdk-go-v2/internal/configsources](https://github.com/aws/aws-sdk-go-v2) | `1.3.12` | `1.3.13` |
| [github.com/aws/aws-sdk-go-v2/internal/endpoints/v2](https://github.com/aws/aws-sdk-go-v2) | `2.6.12` | `2.6.13` |
| [github.com/aws/aws-sdk-go-v2/internal/v4a](https://github.com/aws/aws-sdk-go-v2) | `1.3.12` | `1.3.13` |
| [github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding](https://github.com/aws/aws-sdk-go-v2) | `1.11.2` | `1.11.3` |
| [github.com/aws/aws-sdk-go-v2/service/internal/checksum](https://github.com/aws/aws-sdk-go-v2) | `1.3.14` | `1.3.15` |
| [github.com/aws/aws-sdk-go-v2/service/internal/presigned-url](https://github.com/aws/aws-sdk-go-v2) | `1.11.14` | `1.11.15` |
| [github.com/aws/aws-sdk-go-v2/service/internal/s3shared](https://github.com/aws/aws-sdk-go-v2) | `1.17.12` | `1.17.13` |


Updates `github.com/aws/aws-sdk-go-v2` from 1.30.0 to 1.30.1
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.30.0...v1.30.1)

Updates `github.com/aws/aws-sdk-go-v2/service/s3` from 1.56.1 to 1.57.1
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/s3/v1.56.1...service/s3/v1.57.1)

Updates `github.com/aws/smithy-go` from 1.20.2 to 1.20.3
- [Release notes](https://github.com/aws/smithy-go/releases)
- [Changelog](https://github.com/aws/smithy-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/aws/smithy-go/compare/v1.20.2...v1.20.3)

Updates `github.com/gofiber/fiber/v2` from 2.52.4 to 2.52.5
- [Release notes](https://github.com/gofiber/fiber/releases)
- [Commits](https://github.com/gofiber/fiber/compare/v2.52.4...v2.52.5)

Updates `github.com/aws/aws-sdk-go-v2/feature/ec2/imds` from 1.16.8 to 1.16.9
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/v1.16.9/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.16.8...v1.16.9)

Updates `github.com/aws/aws-sdk-go-v2/service/sso` from 1.21.1 to 1.22.1
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.21.1...v1.22.1)

Updates `github.com/aws/aws-sdk-go-v2/service/ssooidc` from 1.25.1 to 1.26.1
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.25.1...v1.26.1)

Updates `github.com/aws/aws-sdk-go-v2/service/sts` from 1.29.1 to 1.30.1
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/s3/v1.29.1...v1.30.1)

Updates `github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream` from 1.6.2 to 1.6.3
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/pi/v1.6.2...credentials/v1.6.3)

Updates `github.com/aws/aws-sdk-go-v2/config` from 1.27.21 to 1.27.23
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.27.21...config/v1.27.23)

Updates `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.21 to 1.17.23
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/credentials/v1.17.21...credentials/v1.17.23)

Updates `github.com/aws/aws-sdk-go-v2/feature/s3/manager` from 1.17.1 to 1.17.3
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/v1.17.3/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.17.1...v1.17.3)

Updates `github.com/aws/aws-sdk-go-v2/internal/configsources` from 1.3.12 to 1.3.13
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/internal/ini/v1.3.12...internal/ini/v1.3.13)

Updates `github.com/aws/aws-sdk-go-v2/internal/endpoints/v2` from 2.6.12 to 2.6.13
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/internal/endpoints/v2.6.12...internal/endpoints/v2.6.13)

Updates `github.com/aws/aws-sdk-go-v2/internal/v4a` from 1.3.12 to 1.3.13
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/internal/ini/v1.3.12...internal/ini/v1.3.13)

Updates `github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding` from 1.11.2 to 1.11.3
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.11.2...service/dlm/v1.11.3)

Updates `github.com/aws/aws-sdk-go-v2/service/internal/checksum` from 1.3.14 to 1.3.15
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/internal/ini/v1.3.14...internal/ini/v1.3.15)

Updates `github.com/aws/aws-sdk-go-v2/service/internal/presigned-url` from 1.11.14 to 1.11.15
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/sso/v1.11.14...service/waf/v1.11.15)

Updates `github.com/aws/aws-sdk-go-v2/service/internal/s3shared` from 1.17.12 to 1.17.13
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/credentials/v1.17.12...credentials/v1.17.13)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: github.com/aws/aws-sdk-go-v2/service/s3
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: dev-dependencies
- dependency-name: github.com/aws/smithy-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: github.com/gofiber/fiber/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: github.com/aws/aws-sdk-go-v2/feature/ec2/imds
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: github.com/aws/aws-sdk-go-v2/service/sso
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: dev-dependencies
- dependency-name: github.com/aws/aws-sdk-go-v2/service/ssooidc
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: dev-dependencies
- dependency-name: github.com/aws/aws-sdk-go-v2/service/sts
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: dev-dependencies
- dependency-name: github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: github.com/aws/aws-sdk-go-v2/config
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: github.com/aws/aws-sdk-go-v2/credentials
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: github.com/aws/aws-sdk-go-v2/feature/s3/manager
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: github.com/aws/aws-sdk-go-v2/internal/configsources
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: github.com/aws/aws-sdk-go-v2/internal/endpoints/v2
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: github.com/aws/aws-sdk-go-v2/internal/v4a
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: github.com/aws/aws-sdk-go-v2/service/internal/checksum
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: github.com/aws/aws-sdk-go-v2/service/internal/presigned-url
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: github.com/aws/aws-sdk-go-v2/service/internal/s3shared
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-01 21:44:01 +00:00
Ben McClelland
68db536587 Merge pull request #659 from versity/bucket-ownership-control
Bucket ownership control
2024-06-28 21:18:43 -07:00
Luke McCrone
f66deb9b9a test: commented out failing acls-related tests
Recent change requires fixes to tests that depended on bucket
ACLs enabled by default. Comment these out until tests can be
fixed up for new behavior.
2024-06-28 21:07:29 -07:00
jonaustin09
7545e6236c feat: Implement bucket ownership controls
Bucket ACLs are now disabled by default the same as AWS.
By default the object ownership is BucketOwnerEnforced
which means that bucket ACLs are disabled. If one attempts
to set bucket ACL the following error is returned both in
the gateway and on AWS:
	ErrAclNotSupported: {
		Code:           "AccessControlListNotSupported",
		Description:    "The bucket does not allow ACLs",
		HTTPStatusCode: http.StatusBadRequest,
	},

ACls can be enabled with PutBucketOwnershipControls

Changed bucket canned ACL translation

New backend interface methods:
PutBucketOwnershipControls
GetBucketOwnershipControls
DeleteBucketOwnershipControls

Added these to metrics
2024-06-28 21:03:09 -07:00
Ben McClelland
2db2481f04 Merge pull request #658 from versity/test_cmdline_policy_delete_obj
Test cmdline policy delete obj
2024-06-28 08:04:13 -07:00
Luke McCrone
812efe6d43 test: multiple policy-related tests, multipart upload test rewrites 2024-06-27 20:19:44 -03:00
40 changed files with 2480 additions and 788 deletions

View File

@@ -8,17 +8,17 @@ jobs:
fail-fast: false
matrix:
include:
- set: 1
LOCAL_FOLDER: /tmp/gw1
BUCKET_ONE_NAME: versity-gwtest-bucket-one-1
BUCKET_TWO_NAME: versity-gwtest-bucket-two-1
IAM_TYPE: folder
USERS_FOLDER: /tmp/iam1
AWS_ENDPOINT_URL: https://127.0.0.1:7070
RUN_SET: "s3cmd"
RECREATE_BUCKETS: "true"
PORT: 7070
BACKEND: "posix"
#- set: 1
# LOCAL_FOLDER: /tmp/gw1
# BUCKET_ONE_NAME: versity-gwtest-bucket-one-1
# BUCKET_TWO_NAME: versity-gwtest-bucket-two-1
# IAM_TYPE: folder
# USERS_FOLDER: /tmp/iam1
# AWS_ENDPOINT_URL: https://127.0.0.1:7070
# RUN_SET: "s3cmd"
# RECREATE_BUCKETS: "true"
# PORT: 7070
# BACKEND: "posix"
- set: 2
LOCAL_FOLDER: /tmp/gw2
BUCKET_ONE_NAME: versity-gwtest-bucket-one-2

View File

@@ -28,7 +28,6 @@ import (
)
type ACL struct {
ACL types.BucketCannedACL
Owner string
Grantees []Grantee
}
@@ -94,12 +93,34 @@ func UpdateACL(input *s3.PutBucketAclInput, acl ACL, iam IAMService) ([]byte, er
return nil, s3err.GetAPIError(s3err.ErrAccessDenied)
}
defaultGrantees := []Grantee{
{
Permission: types.PermissionFullControl,
Access: acl.Owner,
},
}
// if the ACL is specified, set the ACL, else replace the grantees
if input.ACL != "" {
acl.ACL = input.ACL
acl.Grantees = []Grantee{}
switch input.ACL {
case types.BucketCannedACLPublicRead:
defaultGrantees = append(defaultGrantees, Grantee{
Permission: types.PermissionRead,
Access: "all-users",
})
case types.BucketCannedACLPublicReadWrite:
defaultGrantees = append(defaultGrantees, []Grantee{
{
Permission: types.PermissionRead,
Access: "all-users",
},
{
Permission: types.PermissionWrite,
Access: "all-users",
},
}...)
}
} else {
grantees := []Grantee{}
accs := []string{}
if input.GrantRead != nil || input.GrantReadACP != nil || input.GrantFullControl != nil || input.GrantWrite != nil || input.GrantWriteACP != nil {
@@ -108,31 +129,31 @@ func UpdateACL(input *s3.PutBucketAclInput, acl ACL, iam IAMService) ([]byte, er
if input.GrantFullControl != nil && *input.GrantFullControl != "" {
fullControlList = splitUnique(*input.GrantFullControl, ",")
for _, str := range fullControlList {
grantees = append(grantees, Grantee{Access: str, Permission: "FULL_CONTROL"})
defaultGrantees = append(defaultGrantees, Grantee{Access: str, Permission: "FULL_CONTROL"})
}
}
if input.GrantRead != nil && *input.GrantRead != "" {
readList = splitUnique(*input.GrantRead, ",")
for _, str := range readList {
grantees = append(grantees, Grantee{Access: str, Permission: "READ"})
defaultGrantees = append(defaultGrantees, Grantee{Access: str, Permission: "READ"})
}
}
if input.GrantReadACP != nil && *input.GrantReadACP != "" {
readACPList = splitUnique(*input.GrantReadACP, ",")
for _, str := range readACPList {
grantees = append(grantees, Grantee{Access: str, Permission: "READ_ACP"})
defaultGrantees = append(defaultGrantees, Grantee{Access: str, Permission: "READ_ACP"})
}
}
if input.GrantWrite != nil && *input.GrantWrite != "" {
writeList = splitUnique(*input.GrantWrite, ",")
for _, str := range writeList {
grantees = append(grantees, Grantee{Access: str, Permission: "WRITE"})
defaultGrantees = append(defaultGrantees, Grantee{Access: str, Permission: "WRITE"})
}
}
if input.GrantWriteACP != nil && *input.GrantWriteACP != "" {
writeACPList = splitUnique(*input.GrantWriteACP, ",")
for _, str := range writeACPList {
grantees = append(grantees, Grantee{Access: str, Permission: "WRITE_ACP"})
defaultGrantees = append(defaultGrantees, Grantee{Access: str, Permission: "WRITE_ACP"})
}
}
@@ -143,7 +164,7 @@ func UpdateACL(input *s3.PutBucketAclInput, acl ACL, iam IAMService) ([]byte, er
if grt.Grantee == nil || grt.Grantee.ID == nil || grt.Permission == "" {
return nil, s3err.GetAPIError(s3err.ErrInvalidRequest)
}
grantees = append(grantees, Grantee{Access: *grt.Grantee.ID, Permission: grt.Permission})
defaultGrantees = append(defaultGrantees, Grantee{Access: *grt.Grantee.ID, Permission: grt.Permission})
if _, ok := cache[*grt.Grantee.ID]; !ok {
cache[*grt.Grantee.ID] = true
accs = append(accs, *grt.Grantee.ID)
@@ -159,11 +180,10 @@ func UpdateACL(input *s3.PutBucketAclInput, acl ACL, iam IAMService) ([]byte, er
if len(accList) > 0 {
return nil, fmt.Errorf("accounts does not exist: %s", strings.Join(accList, ", "))
}
acl.Grantees = grantees
acl.ACL = ""
}
acl.Grantees = defaultGrantees
result, err := json.Marshal(acl)
if err != nil {
return nil, err
@@ -207,34 +227,21 @@ func splitUnique(s, divider string) []string {
}
func verifyACL(acl ACL, access string, permission types.Permission) error {
if acl.ACL != "" {
if (permission == "READ" || permission == "READ_ACP") && (acl.ACL != "public-read" && acl.ACL != "public-read-write") {
return s3err.GetAPIError(s3err.ErrAccessDenied)
}
if (permission == "WRITE" || permission == "WRITE_ACP") && acl.ACL != "public-read-write" {
return s3err.GetAPIError(s3err.ErrAccessDenied)
}
grantee := Grantee{Access: access, Permission: permission}
granteeFullCtrl := Grantee{Access: access, Permission: "FULL_CONTROL"}
granteeAllUsers := Grantee{Access: "all-users", Permission: permission}
isFound := false
for _, grt := range acl.Grantees {
if grt == grantee || grt == granteeFullCtrl || grt == granteeAllUsers {
isFound = true
break
}
}
if isFound {
return nil
} else {
if len(acl.Grantees) == 0 {
return nil
}
grantee := Grantee{Access: access, Permission: permission}
granteeFullCtrl := Grantee{Access: access, Permission: "FULL_CONTROL"}
isFound := false
for _, grt := range acl.Grantees {
if grt == grantee || grt == granteeFullCtrl {
isFound = true
break
}
}
if isFound {
return nil
}
}
return s3err.GetAPIError(s3err.ErrAccessDenied)
@@ -295,23 +302,16 @@ func VerifyAccess(ctx context.Context, be backend.Backend, opts AccessOptions) e
if opts.Acc.Role == RoleAdmin {
return nil
}
if opts.Acc.Access == opts.Acl.Owner {
return nil
}
policy, policyErr := be.GetBucketPolicy(ctx, opts.Bucket)
if policyErr != nil && !errors.Is(policyErr, s3err.GetAPIError(s3err.ErrNoSuchBucketPolicy)) {
return policyErr
if policyErr != nil {
if !errors.Is(policyErr, s3err.GetAPIError(s3err.ErrNoSuchBucketPolicy)) {
return policyErr
}
} else {
return VerifyBucketPolicy(policy, opts.Acc.Access, opts.Bucket, opts.Object, opts.Action)
}
// If bucket policy is not set and the ACL is default, only the owner has access
if errors.Is(policyErr, s3err.GetAPIError(s3err.ErrNoSuchBucketPolicy)) && opts.Acl.ACL == "" && len(opts.Acl.Grantees) == 0 {
return s3err.GetAPIError(s3err.ErrAccessDenied)
}
if err := VerifyBucketPolicy(policy, opts.Acc.Access, opts.Bucket, opts.Object, opts.Action); err != nil {
return err
}
if err := verifyACL(opts.Acl, opts.Acc.Access, opts.AclPermission); err != nil {
return err
}

View File

@@ -134,11 +134,6 @@ func ValidatePolicyDocument(policyBin []byte, bucket string, iam IAMService) err
}
func VerifyBucketPolicy(policy []byte, access, bucket, object string, action Action) error {
// If bucket policy is not set
if policy == nil {
return nil
}
var bucketPolicy BucketPolicy
if err := json.Unmarshal(policy, &bucketPolicy); err != nil {
return err

View File

@@ -55,6 +55,8 @@ const (
GetObjectRetentionAction Action = "s3:GetObjectRetention"
PutObjectRetentionAction Action = "s3:PutObjectRetention"
BypassGovernanceRetentionAction Action = "s3:BypassGovernanceRetention"
PutBucketOwnershipControlsAction Action = "s3:PutBucketOwnershipControls"
GetBucketOwnershipControlsAction Action = "s3:GetBucketOwnershipControls"
AllActions Action = "s3:*"
)
@@ -91,6 +93,8 @@ var supportedActionList = map[Action]struct{}{
GetObjectRetentionAction: {},
PutObjectRetentionAction: {},
BypassGovernanceRetentionAction: {},
PutBucketOwnershipControlsAction: {},
GetBucketOwnershipControlsAction: {},
AllActions: {},
}

View File

@@ -53,6 +53,7 @@ type key string
const (
keyAclCapital key = "Acl"
keyAclLower key = "acl"
keyOwnership key = "Ownership"
keyTags key = "Tags"
keyPolicy key = "Policy"
keyBucketLock key = "Bucket-Lock"
@@ -127,6 +128,7 @@ func (az *Azure) String() string {
func (az *Azure) CreateBucket(ctx context.Context, input *s3.CreateBucketInput, acl []byte) error {
meta := map[string]*string{
string(keyAclCapital): backend.GetStringPtr(string(acl)),
string(keyOwnership): backend.GetStringPtr(string(input.ObjectOwnership)),
}
acct, ok := ctx.Value("account").(auth.Account)
@@ -251,6 +253,67 @@ func (az *Azure) DeleteBucket(ctx context.Context, input *s3.DeleteBucketInput)
return azureErrToS3Err(err)
}
func (az *Azure) PutBucketOwnershipControls(ctx context.Context, bucket string, ownership types.ObjectOwnership) error {
client, err := az.getContainerClient(bucket)
if err != nil {
return err
}
resp, err := client.GetProperties(ctx, &container.GetPropertiesOptions{})
if err != nil {
return azureErrToS3Err(err)
}
resp.Metadata[string(keyOwnership)] = backend.GetStringPtr(string(ownership))
_, err = client.SetMetadata(ctx, &container.SetMetadataOptions{Metadata: resp.Metadata})
if err != nil {
return azureErrToS3Err(err)
}
return nil
}
func (az *Azure) GetBucketOwnershipControls(ctx context.Context, bucket string) (types.ObjectOwnership, error) {
var ownship types.ObjectOwnership
client, err := az.getContainerClient(bucket)
if err != nil {
return ownship, err
}
resp, err := client.GetProperties(ctx, &container.GetPropertiesOptions{})
if err != nil {
return ownship, azureErrToS3Err(err)
}
ownership, ok := resp.Metadata[string(keyOwnership)]
if !ok {
return ownship, s3err.GetAPIError(s3err.ErrOwnershipControlsNotFound)
}
return types.ObjectOwnership(*ownership), nil
}
func (az *Azure) DeleteBucketOwnershipControls(ctx context.Context, bucket string) error {
client, err := az.getContainerClient(bucket)
if err != nil {
return err
}
resp, err := client.GetProperties(ctx, &container.GetPropertiesOptions{})
if err != nil {
return azureErrToS3Err(err)
}
delete(resp.Metadata, string(keyOwnership))
_, err = client.SetMetadata(ctx, &container.SetMetadataOptions{Metadata: resp.Metadata})
if err != nil {
return azureErrToS3Err(err)
}
return nil
}
func (az *Azure) PutObject(ctx context.Context, po *s3.PutObjectInput) (string, error) {
tags, err := parseTags(po.Tagging)
if err != nil {
@@ -348,7 +411,7 @@ func (az *Azure) DeleteBucketTagging(ctx context.Context, bucket string) error {
return az.PutBucketTagging(ctx, bucket, nil)
}
func (az *Azure) GetObject(ctx context.Context, input *s3.GetObjectInput, writer io.Writer) (*s3.GetObjectOutput, error) {
func (az *Azure) GetObject(ctx context.Context, input *s3.GetObjectInput) (*s3.GetObjectOutput, error) {
var opts *azblob.DownloadStreamOptions
if *input.Range != "" {
offset, count, err := backend.ParseRange(0, *input.Range)
@@ -366,12 +429,6 @@ func (az *Azure) GetObject(ctx context.Context, input *s3.GetObjectInput, writer
if err != nil {
return nil, azureErrToS3Err(err)
}
defer blobDownloadResponse.Body.Close()
_, err = io.Copy(writer, blobDownloadResponse.Body)
if err != nil {
return nil, fmt.Errorf("copy data: %w", err)
}
var tagcount int32
if blobDownloadResponse.TagCount != nil {
@@ -388,6 +445,7 @@ func (az *Azure) GetObject(ctx context.Context, input *s3.GetObjectInput, writer
Metadata: parseAzMetadata(blobDownloadResponse.Metadata),
TagCount: &tagcount,
ContentRange: blobDownloadResponse.ContentRange,
Body: blobDownloadResponse.Body,
}, nil
}

View File

@@ -18,9 +18,9 @@ import (
"bufio"
"context"
"fmt"
"io"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/versity/versitygw/s3err"
"github.com/versity/versitygw/s3response"
"github.com/versity/versitygw/s3select"
@@ -43,6 +43,9 @@ type Backend interface {
PutBucketPolicy(_ context.Context, bucket string, policy []byte) error
GetBucketPolicy(_ context.Context, bucket string) ([]byte, error)
DeleteBucketPolicy(_ context.Context, bucket string) error
PutBucketOwnershipControls(_ context.Context, bucket string, ownership types.ObjectOwnership) error
GetBucketOwnershipControls(_ context.Context, bucket string) (types.ObjectOwnership, error)
DeleteBucketOwnershipControls(_ context.Context, bucket string) error
// multipart operations
CreateMultipartUpload(context.Context, *s3.CreateMultipartUploadInput) (*s3.CreateMultipartUploadOutput, error)
@@ -56,7 +59,7 @@ type Backend interface {
// standard object operations
PutObject(context.Context, *s3.PutObjectInput) (string, error)
HeadObject(context.Context, *s3.HeadObjectInput) (*s3.HeadObjectOutput, error)
GetObject(context.Context, *s3.GetObjectInput, io.Writer) (*s3.GetObjectOutput, error)
GetObject(context.Context, *s3.GetObjectInput) (*s3.GetObjectOutput, error)
GetObjectAcl(context.Context, *s3.GetObjectAclInput) (*s3.GetObjectAclOutput, error)
GetObjectAttributes(context.Context, *s3.GetObjectAttributesInput) (s3response.GetObjectAttributesResult, error)
CopyObject(context.Context, *s3.CopyObjectInput) (*s3.CopyObjectOutput, error)
@@ -138,6 +141,15 @@ func (BackendUnsupported) GetBucketPolicy(_ context.Context, bucket string) ([]b
func (BackendUnsupported) DeleteBucketPolicy(_ context.Context, bucket string) error {
return s3err.GetAPIError(s3err.ErrNotImplemented)
}
func (BackendUnsupported) PutBucketOwnershipControls(_ context.Context, bucket string, ownership types.ObjectOwnership) error {
return s3err.GetAPIError(s3err.ErrNotImplemented)
}
func (BackendUnsupported) GetBucketOwnershipControls(_ context.Context, bucket string) (types.ObjectOwnership, error) {
return types.ObjectOwnershipBucketOwnerEnforced, s3err.GetAPIError(s3err.ErrNotImplemented)
}
func (BackendUnsupported) DeleteBucketOwnershipControls(_ context.Context, bucket string) error {
return s3err.GetAPIError(s3err.ErrNotImplemented)
}
func (BackendUnsupported) CreateMultipartUpload(context.Context, *s3.CreateMultipartUploadInput) (*s3.CreateMultipartUploadOutput, error) {
return nil, s3err.GetAPIError(s3err.ErrNotImplemented)
@@ -167,7 +179,7 @@ func (BackendUnsupported) PutObject(context.Context, *s3.PutObjectInput) (string
func (BackendUnsupported) HeadObject(context.Context, *s3.HeadObjectInput) (*s3.HeadObjectOutput, error) {
return nil, s3err.GetAPIError(s3err.ErrNotImplemented)
}
func (BackendUnsupported) GetObject(context.Context, *s3.GetObjectInput, io.Writer) (*s3.GetObjectOutput, error) {
func (BackendUnsupported) GetObject(context.Context, *s3.GetObjectInput) (*s3.GetObjectOutput, error) {
return nil, s3err.GetAPIError(s3err.ErrNotImplemented)
}
func (BackendUnsupported) GetObjectAcl(context.Context, *s3.GetObjectAclInput) (*s3.GetObjectAclOutput, error) {

View File

@@ -18,7 +18,9 @@ import (
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"net/http"
"os"
"strconv"
"strings"
"time"
@@ -128,3 +130,16 @@ func md5String(data []byte) string {
sum := md5.Sum(data)
return hex.EncodeToString(sum[:])
}
type FileSectionReadCloser struct {
R io.Reader
F *os.File
}
func (f *FileSectionReadCloser) Read(p []byte) (int, error) {
return f.R.Read(p)
}
func (f *FileSectionReadCloser) Close() error {
return f.F.Close()
}

View File

@@ -75,6 +75,7 @@ const (
contentEncHdr = "content-encoding"
emptyMD5 = "d41d8cd98f00b204e9800998ecf8427e"
aclkey = "acl"
ownershipkey = "ownership"
etagkey = "etag"
policykey = "policy"
bucketLockKey = "bucket-lock"
@@ -245,6 +246,9 @@ func (p *Posix) CreateBucket(ctx context.Context, input *s3.CreateBucketInput, a
if err := p.meta.StoreAttribute(bucket, "", aclkey, acl); err != nil {
return fmt.Errorf("set acl: %w", err)
}
if err := p.meta.StoreAttribute(bucket, "", ownershipkey, []byte(input.ObjectOwnership)); err != nil {
return fmt.Errorf("set ownership: %w", err)
}
if input.ObjectLockEnabledForBucket != nil && *input.ObjectLockEnabledForBucket {
now := time.Now()
@@ -304,6 +308,61 @@ func (p *Posix) DeleteBucket(_ context.Context, input *s3.DeleteBucketInput) err
return nil
}
func (p *Posix) PutBucketOwnershipControls(_ context.Context, bucket string, ownership types.ObjectOwnership) error {
_, err := os.Stat(bucket)
if errors.Is(err, fs.ErrNotExist) {
return s3err.GetAPIError(s3err.ErrNoSuchBucket)
}
if err != nil {
return fmt.Errorf("stat bucket: %w", err)
}
if err := p.meta.StoreAttribute(bucket, "", ownershipkey, []byte(ownership)); err != nil {
return fmt.Errorf("set ownership: %w", err)
}
return nil
}
func (p *Posix) GetBucketOwnershipControls(_ context.Context, bucket string) (types.ObjectOwnership, error) {
var ownship types.ObjectOwnership
_, err := os.Stat(bucket)
if errors.Is(err, fs.ErrNotExist) {
return ownship, s3err.GetAPIError(s3err.ErrNoSuchBucket)
}
if err != nil {
return ownship, fmt.Errorf("stat bucket: %w", err)
}
ownership, err := p.meta.RetrieveAttribute(bucket, "", ownershipkey)
if errors.Is(err, meta.ErrNoSuchKey) {
return ownship, s3err.GetAPIError(s3err.ErrOwnershipControlsNotFound)
}
if err != nil {
return ownship, fmt.Errorf("get bucket ownership status: %w", err)
}
return types.ObjectOwnership(ownership), nil
}
func (p *Posix) DeleteBucketOwnershipControls(_ context.Context, bucket string) error {
_, err := os.Stat(bucket)
if errors.Is(err, fs.ErrNotExist) {
return s3err.GetAPIError(s3err.ErrNoSuchBucket)
}
if err != nil {
return fmt.Errorf("stat bucket: %w", err)
}
if err := p.meta.DeleteAttribute(bucket, "", ownershipkey); err != nil {
if errors.Is(err, meta.ErrNoSuchKey) {
return nil
}
return fmt.Errorf("delete ownership: %w", err)
}
return nil
}
func (p *Posix) CreateMultipartUpload(ctx context.Context, mpu *s3.CreateMultipartUploadInput) (*s3.CreateMultipartUploadOutput, error) {
if mpu.Bucket == nil {
return nil, s3err.GetAPIError(s3err.ErrInvalidBucketName)
@@ -1534,7 +1593,7 @@ func (p *Posix) DeleteObjects(ctx context.Context, input *s3.DeleteObjectsInput)
}, nil
}
func (p *Posix) GetObject(_ context.Context, input *s3.GetObjectInput, writer io.Writer) (*s3.GetObjectOutput, error) {
func (p *Posix) GetObject(_ context.Context, input *s3.GetObjectInput) (*s3.GetObjectOutput, error) {
if input.Bucket == nil {
return nil, s3err.GetAPIError(s3err.ErrInvalidBucketName)
}
@@ -1578,11 +1637,11 @@ func (p *Posix) GetObject(_ context.Context, input *s3.GetObjectInput, writer io
}
if length == -1 {
length = objSize - startOffset + 1
length = objSize - startOffset
}
if startOffset+length > objSize+1 {
length = objSize - startOffset + 1
if startOffset+length > objSize {
length = objSize - startOffset
}
var contentRange string
@@ -1625,21 +1684,6 @@ func (p *Posix) GetObject(_ context.Context, input *s3.GetObjectInput, writer io
}, nil
}
f, err := os.Open(objPath)
if errors.Is(err, fs.ErrNotExist) {
return nil, s3err.GetAPIError(s3err.ErrNoSuchKey)
}
if err != nil {
return nil, fmt.Errorf("open object: %w", err)
}
defer f.Close()
rdr := io.NewSectionReader(f, startOffset, length)
_, err = io.Copy(writer, rdr)
if err != nil {
return nil, fmt.Errorf("copy data: %w", err)
}
userMetaData := make(map[string]string)
contentType, contentEncoding := p.loadUserMetaData(bucket, object, userMetaData)
@@ -1660,6 +1704,16 @@ func (p *Posix) GetObject(_ context.Context, input *s3.GetObjectInput, writer io
tagCount = &tgCount
}
f, err := os.Open(objPath)
if errors.Is(err, fs.ErrNotExist) {
return nil, s3err.GetAPIError(s3err.ErrNoSuchKey)
}
if err != nil {
return nil, fmt.Errorf("open object: %w", err)
}
rdr := io.NewSectionReader(f, startOffset, length)
return &s3.GetObjectOutput{
AcceptRanges: &acceptRange,
ContentLength: &length,
@@ -1670,6 +1724,7 @@ func (p *Posix) GetObject(_ context.Context, input *s3.GetObjectInput, writer io
Metadata: userMetaData,
TagCount: tagCount,
ContentRange: &contentRange,
Body: &backend.FileSectionReadCloser{R: rdr, F: f},
}, nil
}

View File

@@ -55,6 +55,8 @@ type S3Proxy struct {
debug bool
}
var _ backend.Backend = &S3Proxy{}
func New(access, secret, endpoint, region string, disableChecksum, sslSkipVerify, debug bool) (*S3Proxy, error) {
s := &S3Proxy{
access: access,
@@ -128,6 +130,37 @@ func (s *S3Proxy) DeleteBucket(ctx context.Context, input *s3.DeleteBucketInput)
return handleError(err)
}
func (s *S3Proxy) PutBucketOwnershipControls(ctx context.Context, bucket string, ownership types.ObjectOwnership) error {
_, err := s.client.PutBucketOwnershipControls(ctx, &s3.PutBucketOwnershipControlsInput{
Bucket: &bucket,
OwnershipControls: &types.OwnershipControls{
Rules: []types.OwnershipControlsRule{
{
ObjectOwnership: ownership,
},
},
},
})
return handleError(err)
}
func (s *S3Proxy) GetBucketOwnershipControls(ctx context.Context, bucket string) (types.ObjectOwnership, error) {
var ownship types.ObjectOwnership
resp, err := s.client.GetBucketOwnershipControls(ctx, &s3.GetBucketOwnershipControlsInput{
Bucket: &bucket,
})
if err != nil {
return ownship, handleError(err)
}
return resp.OwnershipControls.Rules[0].ObjectOwnership, nil
}
func (s *S3Proxy) DeleteBucketOwnershipControls(ctx context.Context, bucket string) error {
_, err := s.client.DeleteBucketOwnershipControls(ctx, &s3.DeleteBucketOwnershipControlsInput{
Bucket: &bucket,
})
return handleError(err)
}
func (s *S3Proxy) CreateMultipartUpload(ctx context.Context, input *s3.CreateMultipartUploadInput) (*s3.CreateMultipartUploadOutput, error) {
out, err := s.client.CreateMultipartUpload(ctx, input)
return out, handleError(err)
@@ -281,17 +314,11 @@ func (s *S3Proxy) HeadObject(ctx context.Context, input *s3.HeadObjectInput) (*s
return out, handleError(err)
}
func (s *S3Proxy) GetObject(ctx context.Context, input *s3.GetObjectInput, w io.Writer) (*s3.GetObjectOutput, error) {
func (s *S3Proxy) GetObject(ctx context.Context, input *s3.GetObjectInput) (*s3.GetObjectOutput, error) {
output, err := s.client.GetObject(ctx, input)
if err != nil {
return nil, handleError(err)
}
defer output.Body.Close()
_, err = io.Copy(w, output.Body)
if err != nil {
return nil, err
}
return output, nil
}

View File

@@ -589,7 +589,7 @@ func (s *ScoutFS) retrieveUploadId(bucket, object string) (string, [32]byte, err
return entries[0].Name(), sum, nil
}
func (s *ScoutFS) GetObject(_ context.Context, input *s3.GetObjectInput, writer io.Writer) (*s3.GetObjectOutput, error) {
func (s *ScoutFS) GetObject(_ context.Context, input *s3.GetObjectInput) (*s3.GetObjectOutput, error) {
bucket := *input.Bucket
object := *input.Key
acceptRange := *input.Range
@@ -658,13 +658,8 @@ func (s *ScoutFS) GetObject(_ context.Context, input *s3.GetObjectInput, writer
if err != nil {
return nil, fmt.Errorf("open object: %w", err)
}
defer f.Close()
rdr := io.NewSectionReader(f, startOffset, length)
_, err = io.Copy(writer, rdr)
if err != nil {
return nil, fmt.Errorf("copy data: %w", err)
}
userMetaData := make(map[string]string)
@@ -694,6 +689,7 @@ func (s *ScoutFS) GetObject(_ context.Context, input *s3.GetObjectInput, writer
TagCount: &tagCount,
StorageClass: types.StorageClassStandard,
ContentRange: &contentRange,
Body: &backend.FileSectionReadCloser{R: rdr, F: f},
}, nil
}

46
go.mod
View File

@@ -7,11 +7,11 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.2
github.com/DataDog/datadog-go/v5 v5.5.0
github.com/aws/aws-sdk-go-v2 v1.30.0
github.com/aws/aws-sdk-go-v2/service/s3 v1.56.1
github.com/aws/smithy-go v1.20.2
github.com/aws/aws-sdk-go-v2 v1.30.1
github.com/aws/aws-sdk-go-v2/service/s3 v1.58.0
github.com/aws/smithy-go v1.20.3
github.com/go-ldap/ldap/v3 v3.4.8
github.com/gofiber/fiber/v2 v2.52.4
github.com/gofiber/fiber/v2 v2.52.5
github.com/google/go-cmp v0.6.0
github.com/google/uuid v1.6.0
github.com/hashicorp/vault-client-go v0.4.3
@@ -22,19 +22,19 @@ require (
github.com/urfave/cli/v2 v2.27.2
github.com/valyala/fasthttp v1.55.0
github.com/versity/scoutfs-go v0.0.0-20240325223134-38eb2f5f7d44
golang.org/x/sys v0.21.0
golang.org/x/sys v0.22.0
)
require (
github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.1 // indirect
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.8 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.9 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.21.1 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.25.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.29.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.22.1 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.30.1 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
@@ -49,25 +49,25 @@ require (
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/ryanuber/go-glob v1.0.0 // indirect
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/crypto v0.25.0 // indirect
golang.org/x/net v0.27.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/time v0.5.0 // indirect
)
require (
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 // indirect
github.com/aws/aws-sdk-go-v2/config v1.27.21
github.com/aws/aws-sdk-go-v2/credentials v1.17.21
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.1
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.12 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.12 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.12 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.14 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.14 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.12 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 // indirect
github.com/aws/aws-sdk-go-v2/config v1.27.24
github.com/aws/aws-sdk-go-v2/credentials v1.17.24
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.5
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.13 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.13 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.13 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.15 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.15 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.13 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect

92
go.sum
View File

@@ -2,8 +2,8 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.12.0 h1:1nGuui+4POelzDwI7RG56yfQ
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.12.0/go.mod h1:99EvauvlcJ1U06amZiksfYz/3aFGyIhWGHVyiZXtBAI=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.0 h1:H+U3Gk9zY56G3u872L82bk4thcsy2Gghb9ExT4Zvm1o=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.0/go.mod h1:mgrmMSgaLp9hmax62XQTd0N4aAqSE5E0DulSpVYK7vc=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.1 h1:Xy/qV1DyOhhqsU/z0PyFMJfYCxnzna+vBEUtFW0ksQo=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.1/go.mod h1:oib6iWdC+sILvNUoJbbBn3xv7TXow7mEp/WRcsYvmow=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0 h1:AifHbc4mg0x9zW52WOpKbsHaDKuRhlI7TVl47thgQ70=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0/go.mod h1:T5RfihdXtBDxt1Ch2wobif3TvzTdumDy29kahv6AV9A=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.2 h1:YUUxeiOWgdAQE3pXt2H7QXzZs0q8UBjgRbl56qo8GYM=
@@ -21,44 +21,44 @@ github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7V
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/aws/aws-sdk-go-v2 v1.30.0 h1:6qAwtzlfcTtcL8NHtbDQAqgM5s6NDipQTkPxyH/6kAA=
github.com/aws/aws-sdk-go-v2 v1.30.0/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 h1:x6xsQXGSmW6frevwDA+vi/wqhp1ct18mVXYN08/93to=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2/go.mod h1:lPprDr1e6cJdyYeGXnRaJoP4Md+cDBvi2eOj00BlGmg=
github.com/aws/aws-sdk-go-v2/config v1.27.21 h1:yPX3pjGCe2hJsetlmGNB4Mngu7UPmvWPzzWCv1+boeM=
github.com/aws/aws-sdk-go-v2/config v1.27.21/go.mod h1:4XtlEU6DzNai8RMbjSF5MgGZtYvrhBP/aKZcRtZAVdM=
github.com/aws/aws-sdk-go-v2/credentials v1.17.21 h1:pjAqgzfgFhTv5grc7xPHtXCAaMapzmwA7aU+c/SZQGw=
github.com/aws/aws-sdk-go-v2/credentials v1.17.21/go.mod h1:nhK6PtBlfHTUDVmBLr1dg+WHCOCK+1Fu/WQyVHPsgNQ=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.8 h1:FR+oWPFb/8qMVYMWN98bUZAGqPvLHiyqg1wqQGfUAXY=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.8/go.mod h1:EgSKcHiuuakEIxJcKGzVNWh5srVAQ3jKaSrBGRYvM48=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.1 h1:D9VqWMuw7lJAX6d5eINfRQ/PkvtcJAK3Qmd6f6xEeUw=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.1/go.mod h1:ckvBx7codI4wzc5inOfDp5ZbK7TjMFa7eXwmLvXQrRk=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.12 h1:SJ04WXGTwnHlWIODtC5kJzKbeuHt+OUNOgKg7nfnUGw=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.12/go.mod h1:FkpvXhA92gb3GE9LD6Og0pHHycTxW7xGpnEh5E7Opwo=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.12 h1:hb5KgeYfObi5MHkSSZMEudnIvX30iB+E21evI4r6BnQ=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.12/go.mod h1:CroKe/eWJdyfy9Vx4rljP5wTUjNJfb+fPz1uMYUhEGM=
github.com/aws/aws-sdk-go-v2 v1.30.1 h1:4y/5Dvfrhd1MxRDD77SrfsDaj8kUkkljU7XE83NPV+o=
github.com/aws/aws-sdk-go-v2 v1.30.1/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 h1:tW1/Rkad38LA15X4UQtjXZXNKsCgkshC3EbmcUmghTg=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3/go.mod h1:UbnqO+zjqk3uIt9yCACHJ9IVNhyhOCnYk8yA19SAWrM=
github.com/aws/aws-sdk-go-v2/config v1.27.24 h1:NM9XicZ5o1CBU/MZaHwFtimRpWx9ohAUAqkG6AqSqPo=
github.com/aws/aws-sdk-go-v2/config v1.27.24/go.mod h1:aXzi6QJTuQRVVusAO8/NxpdTeTyr/wRcybdDtfUwJSs=
github.com/aws/aws-sdk-go-v2/credentials v1.17.24 h1:YclAsrnb1/GTQNt2nzv+756Iw4mF8AOzcDfweWwwm/M=
github.com/aws/aws-sdk-go-v2/credentials v1.17.24/go.mod h1:Hld7tmnAkoBQdTMNYZGzztzKRdA4fCdn9L83LOoigac=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.9 h1:Aznqksmd6Rfv2HQN9cpqIV/lQRMaIpJkLLaJ1ZI76no=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.9/go.mod h1:WQr3MY7AxGNxaqAtsDWn+fBxmd4XvLkzeqQ8P1VM0/w=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.5 h1:qkipTyOc+ElVS+TgGJCf/6gqu0CL5+ii19W/eMQfY94=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.5/go.mod h1:UjB35RXl+ESpnVtyaKqdw11NhMxm90lF9o2zqJNbi14=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.13 h1:5SAoZ4jYpGH4721ZNoS1znQrhOfZinOhc4XuTXx/nVc=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.13/go.mod h1:+rdA6ZLpaSeM7tSg/B0IEDinCIBJGmW8rKDFkYpP04g=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.13 h1:WIijqeaAO7TYFLbhsZmi2rgLEAtWOC1LhxCAVTJlSKw=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.13/go.mod h1:i+kbfa76PQbWw/ULoWnp51EYVWH4ENln76fLQE3lXT8=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.12 h1:DXFWyt7ymx/l1ygdyTTS0X923e+Q2wXIxConJzrgwc0=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.12/go.mod h1:mVOr/LbvaNySK1/BTy4cBOCjhCNY2raWBwK4v+WR5J4=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.14 h1:oWccitSnByVU74rQRHac4gLfDqjB6Z1YQGOY/dXKedI=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.14/go.mod h1:8SaZBlQdCLrc/2U3CEO48rYj9uR8qRsPRkmzwNM52pM=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.14 h1:zSDPny/pVnkqABXYRicYuPf9z2bTqfH13HT3v6UheIk=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.14/go.mod h1:3TTcI5JSzda1nw/pkVC9dhgLre0SNBFj2lYS4GctXKI=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.12 h1:tzha+v1SCEBpXWEuw6B/+jm4h5z8hZbTpXz0zRZqTnw=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.12/go.mod h1:n+nt2qjHGoseWeLHt1vEr6ZRCCxIN2KcNpJxBcYQSwI=
github.com/aws/aws-sdk-go-v2/service/s3 v1.56.1 h1:wsg9Z/vNnCmxWikfGIoOlnExtEU459cR+2d+iDJ8elo=
github.com/aws/aws-sdk-go-v2/service/s3 v1.56.1/go.mod h1:8rDw3mVwmvIWWX/+LWY3PPIMZuwnQdJMCt0iVFVT3qw=
github.com/aws/aws-sdk-go-v2/service/sso v1.21.1 h1:sd0BsnAvLH8gsp2e3cbaIr+9D7T1xugueQ7V/zUAsS4=
github.com/aws/aws-sdk-go-v2/service/sso v1.21.1/go.mod h1:lcQG/MmxydijbeTOp04hIuJwXGWPZGI3bwdFDGRTv14=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.25.1 h1:1uEFNNskK/I1KoZ9Q8wJxMz5V9jyBlsiaNrM7vA3YUQ=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.25.1/go.mod h1:z0P8K+cBIsFXUr5rzo/psUeJ20XjPN0+Nn8067Nd+E4=
github.com/aws/aws-sdk-go-v2/service/sts v1.29.1 h1:myX5CxqXE0QMZNja6FA1/FSE3Vu1rVmeUmpJMMzeZg0=
github.com/aws/aws-sdk-go-v2/service/sts v1.29.1/go.mod h1:N2mQiucsO0VwK9CYuS4/c2n6Smeh1v47Rz3dWCPFLdE=
github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q=
github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.13 h1:THZJJ6TU/FOiM7DZFnisYV9d49oxXWUzsVIMTuf3VNU=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.13/go.mod h1:VISUTg6n+uBaYIWPBaIG0jk7mbBxm7DUqBtU2cUDDWI=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.15 h1:2jyRZ9rVIMisyQRnhSS/SqlckveoxXneIumECVFP91Y=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.15/go.mod h1:bDRG3m382v1KJBk1cKz7wIajg87/61EiiymEyfLvAe0=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.15 h1:I9zMeF107l0rJrpnHpjEiiTSCKYAIw8mALiXcPsGBiA=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.15/go.mod h1:9xWJ3Q/S6Ojusz1UIkfycgD1mGirJfLLKqq3LPT7WN8=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.13 h1:Eq2THzHt6P41mpjS2sUzz/3dJYFRqdWZ+vQaEMm98EM=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.13/go.mod h1:FgwTca6puegxgCInYwGjmd4tB9195Dd6LCuA+8MjpWw=
github.com/aws/aws-sdk-go-v2/service/s3 v1.58.0 h1:4rhV0Hn+bf8IAIUphRX1moBcEvKJipCPmswMCl6Q5mw=
github.com/aws/aws-sdk-go-v2/service/s3 v1.58.0/go.mod h1:hdV0NTYd0RwV4FvNKhKUNbPLZoq9CTr/lke+3I7aCAI=
github.com/aws/aws-sdk-go-v2/service/sso v1.22.1 h1:p1GahKIjyMDZtiKoIn0/jAj/TkMzfzndDv5+zi2Mhgc=
github.com/aws/aws-sdk-go-v2/service/sso v1.22.1/go.mod h1:/vWdhoIoYA5hYoPZ6fm7Sv4d8701PiG5VKe8/pPJL60=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.2 h1:ORnrOK0C4WmYV/uYt3koHEWBLYsRDwk2Np+eEoyV4Z0=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.2/go.mod h1:xyFHA4zGxgYkdD73VeezHt3vSKEG9EmFnGwoKlP00u4=
github.com/aws/aws-sdk-go-v2/service/sts v1.30.1 h1:+woJ607dllHJQtsnJLi52ycuqHMwlW+Wqm2Ppsfp4nQ=
github.com/aws/aws-sdk-go-v2/service/sts v1.30.1/go.mod h1:jiNR3JqT15Dm+QWq2SRgh0x0bCNSRP2L25+CqPNpJlQ=
github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE=
github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -71,8 +71,8 @@ github.com/go-asn1-ber/asn1-ber v1.5.7 h1:DTX+lbVTWaTw1hQ+PbZPlnDZPEIs0SS/GCZAl5
github.com/go-asn1-ber/asn1-ber v1.5.7/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-ldap/ldap/v3 v3.4.8 h1:loKJyspcRezt2Q3ZRMq2p/0v8iOurlmeXDPw6fikSvQ=
github.com/go-ldap/ldap/v3 v3.4.8/go.mod h1:qS3Sjlu76eHfHGpUdWkAXQTw4beih+cHsco2jXlIXrk=
github.com/gofiber/fiber/v2 v2.52.4 h1:P+T+4iK7VaqUsq2PALYEfBBo6bJZ4q3FP8cZ84EggTM=
github.com/gofiber/fiber/v2 v2.52.4/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo=
github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
@@ -193,8 +193,8 @@ golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
@@ -210,8 +210,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -235,8 +235,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=

View File

@@ -24,51 +24,54 @@ var (
)
var (
ActionUndetected = "ActionUnDetected"
ActionAbortMultipartUpload = "s3_AbortMultipartUpload"
ActionCompleteMultipartUpload = "s3_CompleteMultipartUpload"
ActionCopyObject = "s3_CopyObject"
ActionCreateBucket = "s3_CreateBucket"
ActionCreateMultipartUpload = "s3_CreateMultipartUpload"
ActionDeleteBucket = "s3_DeleteBucket"
ActionDeleteBucketPolicy = "s3_DeleteBucketPolicy"
ActionDeleteBucketTagging = "s3_DeleteBucketTagging"
ActionDeleteObject = "s3_DeleteObject"
ActionDeleteObjectTagging = "s3_DeleteObjectTagging"
ActionDeleteObjects = "s3_DeleteObjects"
ActionGetBucketAcl = "s3_GetBucketAcl"
ActionGetBucketPolicy = "s3_GetBucketPolicy"
ActionGetBucketTagging = "s3_GetBucketTagging"
ActionGetBucketVersioning = "s3_GetBucketVersioning"
ActionGetObject = "s3_GetObject"
ActionGetObjectAcl = "s3_GetObjectAcl"
ActionGetObjectAttributes = "s3_GetObjectAttributes"
ActionGetObjectLegalHold = "s3_GetObjectLegalHold"
ActionGetObjectLockConfiguration = "s3_GetObjectLockConfiguration"
ActionGetObjectRetention = "s3_GetObjectRetention"
ActionGetObjectTagging = "s3_GetObjectTagging"
ActionHeadBucket = "s3_HeadBucket"
ActionHeadObject = "s3_HeadObject"
ActionListAllMyBuckets = "s3_ListAllMyBuckets"
ActionListMultipartUploads = "s3_ListMultipartUploads"
ActionListObjectVersions = "s3_ListObjectVersions"
ActionListObjects = "s3_ListObjects"
ActionListObjectsV2 = "s3_ListObjectsV2"
ActionListParts = "s3_ListParts"
ActionPutBucketAcl = "s3_PutBucketAcl"
ActionPutBucketPolicy = "s3_PutBucketPolicy"
ActionPutBucketTagging = "s3_PutBucketTagging"
ActionPutBucketVersioning = "s3_PutBucketVersioning"
ActionPutObject = "s3_PutObject"
ActionPutObjectAcl = "s3_PutObjectAcl"
ActionPutObjectLegalHold = "s3_PutObjectLegalHold"
ActionPutObjectLockConfiguration = "s3_PutObjectLockConfiguration"
ActionPutObjectRetention = "s3_PutObjectRetention"
ActionPutObjectTagging = "s3_PutObjectTagging"
ActionRestoreObject = "s3_RestoreObject"
ActionSelectObjectContent = "s3_SelectObjectContent"
ActionUploadPart = "s3_UploadPart"
ActionUploadPartCopy = "s3_UploadPartCopy"
ActionUndetected = "ActionUnDetected"
ActionAbortMultipartUpload = "s3_AbortMultipartUpload"
ActionCompleteMultipartUpload = "s3_CompleteMultipartUpload"
ActionCopyObject = "s3_CopyObject"
ActionCreateBucket = "s3_CreateBucket"
ActionCreateMultipartUpload = "s3_CreateMultipartUpload"
ActionDeleteBucket = "s3_DeleteBucket"
ActionDeleteBucketPolicy = "s3_DeleteBucketPolicy"
ActionDeleteBucketTagging = "s3_DeleteBucketTagging"
ActionDeleteObject = "s3_DeleteObject"
ActionDeleteObjectTagging = "s3_DeleteObjectTagging"
ActionDeleteObjects = "s3_DeleteObjects"
ActionGetBucketAcl = "s3_GetBucketAcl"
ActionGetBucketPolicy = "s3_GetBucketPolicy"
ActionGetBucketTagging = "s3_GetBucketTagging"
ActionGetBucketVersioning = "s3_GetBucketVersioning"
ActionGetObject = "s3_GetObject"
ActionGetObjectAcl = "s3_GetObjectAcl"
ActionGetObjectAttributes = "s3_GetObjectAttributes"
ActionGetObjectLegalHold = "s3_GetObjectLegalHold"
ActionGetObjectLockConfiguration = "s3_GetObjectLockConfiguration"
ActionGetObjectRetention = "s3_GetObjectRetention"
ActionGetObjectTagging = "s3_GetObjectTagging"
ActionHeadBucket = "s3_HeadBucket"
ActionHeadObject = "s3_HeadObject"
ActionListAllMyBuckets = "s3_ListAllMyBuckets"
ActionListMultipartUploads = "s3_ListMultipartUploads"
ActionListObjectVersions = "s3_ListObjectVersions"
ActionListObjects = "s3_ListObjects"
ActionListObjectsV2 = "s3_ListObjectsV2"
ActionListParts = "s3_ListParts"
ActionPutBucketAcl = "s3_PutBucketAcl"
ActionPutBucketPolicy = "s3_PutBucketPolicy"
ActionPutBucketTagging = "s3_PutBucketTagging"
ActionPutBucketVersioning = "s3_PutBucketVersioning"
ActionPutObject = "s3_PutObject"
ActionPutObjectAcl = "s3_PutObjectAcl"
ActionPutObjectLegalHold = "s3_PutObjectLegalHold"
ActionPutObjectLockConfiguration = "s3_PutObjectLockConfiguration"
ActionPutObjectRetention = "s3_PutObjectRetention"
ActionPutObjectTagging = "s3_PutObjectTagging"
ActionRestoreObject = "s3_RestoreObject"
ActionSelectObjectContent = "s3_SelectObjectContent"
ActionUploadPart = "s3_UploadPart"
ActionUploadPartCopy = "s3_UploadPartCopy"
ActionPutBucketOwnershipControls = "s3_PutBucketOwnershipControls"
ActionGetBucketOwnershipControls = "s3_GetBucketOwnershipControls"
ActionDeleteBucketOwnershipControls = "s3_DeleteBucketOwnershipControls"
)
func init() {

View File

@@ -7,9 +7,9 @@ import (
"bufio"
"context"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/versity/versitygw/backend"
"github.com/versity/versitygw/s3response"
"io"
"sync"
)
@@ -44,6 +44,9 @@ var _ backend.Backend = &BackendMock{}
// DeleteBucketFunc: func(contextMoqParam context.Context, deleteBucketInput *s3.DeleteBucketInput) error {
// panic("mock out the DeleteBucket method")
// },
// DeleteBucketOwnershipControlsFunc: func(contextMoqParam context.Context, bucket string) error {
// panic("mock out the DeleteBucketOwnershipControls method")
// },
// DeleteBucketPolicyFunc: func(contextMoqParam context.Context, bucket string) error {
// panic("mock out the DeleteBucketPolicy method")
// },
@@ -62,6 +65,9 @@ var _ backend.Backend = &BackendMock{}
// GetBucketAclFunc: func(contextMoqParam context.Context, getBucketAclInput *s3.GetBucketAclInput) ([]byte, error) {
// panic("mock out the GetBucketAcl method")
// },
// GetBucketOwnershipControlsFunc: func(contextMoqParam context.Context, bucket string) (types.ObjectOwnership, error) {
// panic("mock out the GetBucketOwnershipControls method")
// },
// GetBucketPolicyFunc: func(contextMoqParam context.Context, bucket string) ([]byte, error) {
// panic("mock out the GetBucketPolicy method")
// },
@@ -71,7 +77,7 @@ var _ backend.Backend = &BackendMock{}
// GetBucketVersioningFunc: func(contextMoqParam context.Context, bucket string) (*s3.GetBucketVersioningOutput, error) {
// panic("mock out the GetBucketVersioning method")
// },
// GetObjectFunc: func(contextMoqParam context.Context, getObjectInput *s3.GetObjectInput, writer io.Writer) (*s3.GetObjectOutput, error) {
// GetObjectFunc: func(contextMoqParam context.Context, getObjectInput *s3.GetObjectInput) (*s3.GetObjectOutput, error) {
// panic("mock out the GetObject method")
// },
// GetObjectAclFunc: func(contextMoqParam context.Context, getObjectAclInput *s3.GetObjectAclInput) (*s3.GetObjectAclOutput, error) {
@@ -122,6 +128,9 @@ var _ backend.Backend = &BackendMock{}
// PutBucketAclFunc: func(contextMoqParam context.Context, bucket string, data []byte) error {
// panic("mock out the PutBucketAcl method")
// },
// PutBucketOwnershipControlsFunc: func(contextMoqParam context.Context, bucket string, ownership types.ObjectOwnership) error {
// panic("mock out the PutBucketOwnershipControls method")
// },
// PutBucketPolicyFunc: func(contextMoqParam context.Context, bucket string, policy []byte) error {
// panic("mock out the PutBucketPolicy method")
// },
@@ -195,6 +204,9 @@ type BackendMock struct {
// DeleteBucketFunc mocks the DeleteBucket method.
DeleteBucketFunc func(contextMoqParam context.Context, deleteBucketInput *s3.DeleteBucketInput) error
// DeleteBucketOwnershipControlsFunc mocks the DeleteBucketOwnershipControls method.
DeleteBucketOwnershipControlsFunc func(contextMoqParam context.Context, bucket string) error
// DeleteBucketPolicyFunc mocks the DeleteBucketPolicy method.
DeleteBucketPolicyFunc func(contextMoqParam context.Context, bucket string) error
@@ -213,6 +225,9 @@ type BackendMock struct {
// GetBucketAclFunc mocks the GetBucketAcl method.
GetBucketAclFunc func(contextMoqParam context.Context, getBucketAclInput *s3.GetBucketAclInput) ([]byte, error)
// GetBucketOwnershipControlsFunc mocks the GetBucketOwnershipControls method.
GetBucketOwnershipControlsFunc func(contextMoqParam context.Context, bucket string) (types.ObjectOwnership, error)
// GetBucketPolicyFunc mocks the GetBucketPolicy method.
GetBucketPolicyFunc func(contextMoqParam context.Context, bucket string) ([]byte, error)
@@ -223,7 +238,7 @@ type BackendMock struct {
GetBucketVersioningFunc func(contextMoqParam context.Context, bucket string) (*s3.GetBucketVersioningOutput, error)
// GetObjectFunc mocks the GetObject method.
GetObjectFunc func(contextMoqParam context.Context, getObjectInput *s3.GetObjectInput, writer io.Writer) (*s3.GetObjectOutput, error)
GetObjectFunc func(contextMoqParam context.Context, getObjectInput *s3.GetObjectInput) (*s3.GetObjectOutput, error)
// GetObjectAclFunc mocks the GetObjectAcl method.
GetObjectAclFunc func(contextMoqParam context.Context, getObjectAclInput *s3.GetObjectAclInput) (*s3.GetObjectAclOutput, error)
@@ -273,6 +288,9 @@ type BackendMock struct {
// PutBucketAclFunc mocks the PutBucketAcl method.
PutBucketAclFunc func(contextMoqParam context.Context, bucket string, data []byte) error
// PutBucketOwnershipControlsFunc mocks the PutBucketOwnershipControls method.
PutBucketOwnershipControlsFunc func(contextMoqParam context.Context, bucket string, ownership types.ObjectOwnership) error
// PutBucketPolicyFunc mocks the PutBucketPolicy method.
PutBucketPolicyFunc func(contextMoqParam context.Context, bucket string, policy []byte) error
@@ -373,6 +391,13 @@ type BackendMock struct {
// DeleteBucketInput is the deleteBucketInput argument value.
DeleteBucketInput *s3.DeleteBucketInput
}
// DeleteBucketOwnershipControls holds details about calls to the DeleteBucketOwnershipControls method.
DeleteBucketOwnershipControls []struct {
// ContextMoqParam is the contextMoqParam argument value.
ContextMoqParam context.Context
// Bucket is the bucket argument value.
Bucket string
}
// DeleteBucketPolicy holds details about calls to the DeleteBucketPolicy method.
DeleteBucketPolicy []struct {
// ContextMoqParam is the contextMoqParam argument value.
@@ -417,6 +442,13 @@ type BackendMock struct {
// GetBucketAclInput is the getBucketAclInput argument value.
GetBucketAclInput *s3.GetBucketAclInput
}
// GetBucketOwnershipControls holds details about calls to the GetBucketOwnershipControls method.
GetBucketOwnershipControls []struct {
// ContextMoqParam is the contextMoqParam argument value.
ContextMoqParam context.Context
// Bucket is the bucket argument value.
Bucket string
}
// GetBucketPolicy holds details about calls to the GetBucketPolicy method.
GetBucketPolicy []struct {
// ContextMoqParam is the contextMoqParam argument value.
@@ -444,8 +476,6 @@ type BackendMock struct {
ContextMoqParam context.Context
// GetObjectInput is the getObjectInput argument value.
GetObjectInput *s3.GetObjectInput
// Writer is the writer argument value.
Writer io.Writer
}
// GetObjectAcl holds details about calls to the GetObjectAcl method.
GetObjectAcl []struct {
@@ -571,6 +601,15 @@ type BackendMock struct {
// Data is the data argument value.
Data []byte
}
// PutBucketOwnershipControls holds details about calls to the PutBucketOwnershipControls method.
PutBucketOwnershipControls []struct {
// ContextMoqParam is the contextMoqParam argument value.
ContextMoqParam context.Context
// Bucket is the bucket argument value.
Bucket string
// Ownership is the ownership argument value.
Ownership types.ObjectOwnership
}
// PutBucketPolicy holds details about calls to the PutBucketPolicy method.
PutBucketPolicy []struct {
// ContextMoqParam is the contextMoqParam argument value.
@@ -693,54 +732,57 @@ type BackendMock struct {
UploadPartCopyInput *s3.UploadPartCopyInput
}
}
lockAbortMultipartUpload sync.RWMutex
lockChangeBucketOwner sync.RWMutex
lockCompleteMultipartUpload sync.RWMutex
lockCopyObject sync.RWMutex
lockCreateBucket sync.RWMutex
lockCreateMultipartUpload sync.RWMutex
lockDeleteBucket sync.RWMutex
lockDeleteBucketPolicy sync.RWMutex
lockDeleteBucketTagging sync.RWMutex
lockDeleteObject sync.RWMutex
lockDeleteObjectTagging sync.RWMutex
lockDeleteObjects sync.RWMutex
lockGetBucketAcl sync.RWMutex
lockGetBucketPolicy sync.RWMutex
lockGetBucketTagging sync.RWMutex
lockGetBucketVersioning sync.RWMutex
lockGetObject sync.RWMutex
lockGetObjectAcl sync.RWMutex
lockGetObjectAttributes sync.RWMutex
lockGetObjectLegalHold sync.RWMutex
lockGetObjectLockConfiguration sync.RWMutex
lockGetObjectRetention sync.RWMutex
lockGetObjectTagging sync.RWMutex
lockHeadBucket sync.RWMutex
lockHeadObject sync.RWMutex
lockListBuckets sync.RWMutex
lockListBucketsAndOwners sync.RWMutex
lockListMultipartUploads sync.RWMutex
lockListObjectVersions sync.RWMutex
lockListObjects sync.RWMutex
lockListObjectsV2 sync.RWMutex
lockListParts sync.RWMutex
lockPutBucketAcl sync.RWMutex
lockPutBucketPolicy sync.RWMutex
lockPutBucketTagging sync.RWMutex
lockPutBucketVersioning sync.RWMutex
lockPutObject sync.RWMutex
lockPutObjectAcl sync.RWMutex
lockPutObjectLegalHold sync.RWMutex
lockPutObjectLockConfiguration sync.RWMutex
lockPutObjectRetention sync.RWMutex
lockPutObjectTagging sync.RWMutex
lockRestoreObject sync.RWMutex
lockSelectObjectContent sync.RWMutex
lockShutdown sync.RWMutex
lockString sync.RWMutex
lockUploadPart sync.RWMutex
lockUploadPartCopy sync.RWMutex
lockAbortMultipartUpload sync.RWMutex
lockChangeBucketOwner sync.RWMutex
lockCompleteMultipartUpload sync.RWMutex
lockCopyObject sync.RWMutex
lockCreateBucket sync.RWMutex
lockCreateMultipartUpload sync.RWMutex
lockDeleteBucket sync.RWMutex
lockDeleteBucketOwnershipControls sync.RWMutex
lockDeleteBucketPolicy sync.RWMutex
lockDeleteBucketTagging sync.RWMutex
lockDeleteObject sync.RWMutex
lockDeleteObjectTagging sync.RWMutex
lockDeleteObjects sync.RWMutex
lockGetBucketAcl sync.RWMutex
lockGetBucketOwnershipControls sync.RWMutex
lockGetBucketPolicy sync.RWMutex
lockGetBucketTagging sync.RWMutex
lockGetBucketVersioning sync.RWMutex
lockGetObject sync.RWMutex
lockGetObjectAcl sync.RWMutex
lockGetObjectAttributes sync.RWMutex
lockGetObjectLegalHold sync.RWMutex
lockGetObjectLockConfiguration sync.RWMutex
lockGetObjectRetention sync.RWMutex
lockGetObjectTagging sync.RWMutex
lockHeadBucket sync.RWMutex
lockHeadObject sync.RWMutex
lockListBuckets sync.RWMutex
lockListBucketsAndOwners sync.RWMutex
lockListMultipartUploads sync.RWMutex
lockListObjectVersions sync.RWMutex
lockListObjects sync.RWMutex
lockListObjectsV2 sync.RWMutex
lockListParts sync.RWMutex
lockPutBucketAcl sync.RWMutex
lockPutBucketOwnershipControls sync.RWMutex
lockPutBucketPolicy sync.RWMutex
lockPutBucketTagging sync.RWMutex
lockPutBucketVersioning sync.RWMutex
lockPutObject sync.RWMutex
lockPutObjectAcl sync.RWMutex
lockPutObjectLegalHold sync.RWMutex
lockPutObjectLockConfiguration sync.RWMutex
lockPutObjectRetention sync.RWMutex
lockPutObjectTagging sync.RWMutex
lockRestoreObject sync.RWMutex
lockSelectObjectContent sync.RWMutex
lockShutdown sync.RWMutex
lockString sync.RWMutex
lockUploadPart sync.RWMutex
lockUploadPartCopy sync.RWMutex
}
// AbortMultipartUpload calls AbortMultipartUploadFunc.
@@ -1003,6 +1045,42 @@ func (mock *BackendMock) DeleteBucketCalls() []struct {
return calls
}
// DeleteBucketOwnershipControls calls DeleteBucketOwnershipControlsFunc.
func (mock *BackendMock) DeleteBucketOwnershipControls(contextMoqParam context.Context, bucket string) error {
if mock.DeleteBucketOwnershipControlsFunc == nil {
panic("BackendMock.DeleteBucketOwnershipControlsFunc: method is nil but Backend.DeleteBucketOwnershipControls was just called")
}
callInfo := struct {
ContextMoqParam context.Context
Bucket string
}{
ContextMoqParam: contextMoqParam,
Bucket: bucket,
}
mock.lockDeleteBucketOwnershipControls.Lock()
mock.calls.DeleteBucketOwnershipControls = append(mock.calls.DeleteBucketOwnershipControls, callInfo)
mock.lockDeleteBucketOwnershipControls.Unlock()
return mock.DeleteBucketOwnershipControlsFunc(contextMoqParam, bucket)
}
// DeleteBucketOwnershipControlsCalls gets all the calls that were made to DeleteBucketOwnershipControls.
// Check the length with:
//
// len(mockedBackend.DeleteBucketOwnershipControlsCalls())
func (mock *BackendMock) DeleteBucketOwnershipControlsCalls() []struct {
ContextMoqParam context.Context
Bucket string
} {
var calls []struct {
ContextMoqParam context.Context
Bucket string
}
mock.lockDeleteBucketOwnershipControls.RLock()
calls = mock.calls.DeleteBucketOwnershipControls
mock.lockDeleteBucketOwnershipControls.RUnlock()
return calls
}
// DeleteBucketPolicy calls DeleteBucketPolicyFunc.
func (mock *BackendMock) DeleteBucketPolicy(contextMoqParam context.Context, bucket string) error {
if mock.DeleteBucketPolicyFunc == nil {
@@ -1223,6 +1301,42 @@ func (mock *BackendMock) GetBucketAclCalls() []struct {
return calls
}
// GetBucketOwnershipControls calls GetBucketOwnershipControlsFunc.
func (mock *BackendMock) GetBucketOwnershipControls(contextMoqParam context.Context, bucket string) (types.ObjectOwnership, error) {
if mock.GetBucketOwnershipControlsFunc == nil {
panic("BackendMock.GetBucketOwnershipControlsFunc: method is nil but Backend.GetBucketOwnershipControls was just called")
}
callInfo := struct {
ContextMoqParam context.Context
Bucket string
}{
ContextMoqParam: contextMoqParam,
Bucket: bucket,
}
mock.lockGetBucketOwnershipControls.Lock()
mock.calls.GetBucketOwnershipControls = append(mock.calls.GetBucketOwnershipControls, callInfo)
mock.lockGetBucketOwnershipControls.Unlock()
return mock.GetBucketOwnershipControlsFunc(contextMoqParam, bucket)
}
// GetBucketOwnershipControlsCalls gets all the calls that were made to GetBucketOwnershipControls.
// Check the length with:
//
// len(mockedBackend.GetBucketOwnershipControlsCalls())
func (mock *BackendMock) GetBucketOwnershipControlsCalls() []struct {
ContextMoqParam context.Context
Bucket string
} {
var calls []struct {
ContextMoqParam context.Context
Bucket string
}
mock.lockGetBucketOwnershipControls.RLock()
calls = mock.calls.GetBucketOwnershipControls
mock.lockGetBucketOwnershipControls.RUnlock()
return calls
}
// GetBucketPolicy calls GetBucketPolicyFunc.
func (mock *BackendMock) GetBucketPolicy(contextMoqParam context.Context, bucket string) ([]byte, error) {
if mock.GetBucketPolicyFunc == nil {
@@ -1332,23 +1446,21 @@ func (mock *BackendMock) GetBucketVersioningCalls() []struct {
}
// GetObject calls GetObjectFunc.
func (mock *BackendMock) GetObject(contextMoqParam context.Context, getObjectInput *s3.GetObjectInput, writer io.Writer) (*s3.GetObjectOutput, error) {
func (mock *BackendMock) GetObject(contextMoqParam context.Context, getObjectInput *s3.GetObjectInput) (*s3.GetObjectOutput, error) {
if mock.GetObjectFunc == nil {
panic("BackendMock.GetObjectFunc: method is nil but Backend.GetObject was just called")
}
callInfo := struct {
ContextMoqParam context.Context
GetObjectInput *s3.GetObjectInput
Writer io.Writer
}{
ContextMoqParam: contextMoqParam,
GetObjectInput: getObjectInput,
Writer: writer,
}
mock.lockGetObject.Lock()
mock.calls.GetObject = append(mock.calls.GetObject, callInfo)
mock.lockGetObject.Unlock()
return mock.GetObjectFunc(contextMoqParam, getObjectInput, writer)
return mock.GetObjectFunc(contextMoqParam, getObjectInput)
}
// GetObjectCalls gets all the calls that were made to GetObject.
@@ -1358,12 +1470,10 @@ func (mock *BackendMock) GetObject(contextMoqParam context.Context, getObjectInp
func (mock *BackendMock) GetObjectCalls() []struct {
ContextMoqParam context.Context
GetObjectInput *s3.GetObjectInput
Writer io.Writer
} {
var calls []struct {
ContextMoqParam context.Context
GetObjectInput *s3.GetObjectInput
Writer io.Writer
}
mock.lockGetObject.RLock()
calls = mock.calls.GetObject
@@ -1971,6 +2081,46 @@ func (mock *BackendMock) PutBucketAclCalls() []struct {
return calls
}
// PutBucketOwnershipControls calls PutBucketOwnershipControlsFunc.
func (mock *BackendMock) PutBucketOwnershipControls(contextMoqParam context.Context, bucket string, ownership types.ObjectOwnership) error {
if mock.PutBucketOwnershipControlsFunc == nil {
panic("BackendMock.PutBucketOwnershipControlsFunc: method is nil but Backend.PutBucketOwnershipControls was just called")
}
callInfo := struct {
ContextMoqParam context.Context
Bucket string
Ownership types.ObjectOwnership
}{
ContextMoqParam: contextMoqParam,
Bucket: bucket,
Ownership: ownership,
}
mock.lockPutBucketOwnershipControls.Lock()
mock.calls.PutBucketOwnershipControls = append(mock.calls.PutBucketOwnershipControls, callInfo)
mock.lockPutBucketOwnershipControls.Unlock()
return mock.PutBucketOwnershipControlsFunc(contextMoqParam, bucket, ownership)
}
// PutBucketOwnershipControlsCalls gets all the calls that were made to PutBucketOwnershipControls.
// Check the length with:
//
// len(mockedBackend.PutBucketOwnershipControlsCalls())
func (mock *BackendMock) PutBucketOwnershipControlsCalls() []struct {
ContextMoqParam context.Context
Bucket string
Ownership types.ObjectOwnership
} {
var calls []struct {
ContextMoqParam context.Context
Bucket string
Ownership types.ObjectOwnership
}
mock.lockPutBucketOwnershipControls.RLock()
calls = mock.calls.PutBucketOwnershipControls
mock.lockPutBucketOwnershipControls.RUnlock()
return calls
}
// PutBucketPolicy calls PutBucketPolicyFunc.
func (mock *BackendMock) PutBucketPolicy(contextMoqParam context.Context, bucket string, policy []byte) error {
if mock.PutBucketPolicyFunc == nil {

View File

@@ -402,7 +402,7 @@ func (c S3ApiController) GetActions(ctx *fiber.Ctx) error {
Key: &key,
Range: &acceptRange,
VersionId: &versionId,
}, ctx.Response().BodyWriter())
})
if err != nil {
return SendResponse(ctx, err,
&MetaOpts{
@@ -412,15 +412,6 @@ func (c S3ApiController) GetActions(ctx *fiber.Ctx) error {
BucketOwner: parsedAcl.Owner,
})
}
if res == nil {
return SendResponse(ctx, fmt.Errorf("get object nil response"),
&MetaOpts{
Logger: c.logger,
MetricsMng: c.mm,
Action: metrics.ActionGetObject,
BucketOwner: parsedAcl.Owner,
})
}
utils.SetMetaHeaders(ctx, res.Metadata)
var lastmod string
@@ -429,10 +420,6 @@ func (c S3ApiController) GetActions(ctx *fiber.Ctx) error {
}
utils.SetResponseHeaders(ctx, []utils.CustomHeader{
{
Key: "Content-Length",
Value: fmt.Sprint(getint64(res.ContentLength)),
},
{
Key: "Content-Type",
Value: getstring(res.ContentType),
@@ -477,6 +464,10 @@ func (c S3ApiController) GetActions(ctx *fiber.Ctx) error {
status = http.StatusPartialContent
}
if res.Body != nil {
ctx.Response().SetBodyStream(res.Body, int(getint64(res.ContentLength)))
}
return SendResponse(ctx, nil,
&MetaOpts{
Logger: c.logger,
@@ -566,6 +557,43 @@ func (c S3ApiController) ListActions(ctx *fiber.Ctx) error {
})
}
if ctx.Request().URI().QueryArgs().Has("ownershipControls") {
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: types.PermissionRead,
IsRoot: isRoot,
Acc: acct,
Bucket: bucket,
Action: auth.GetBucketOwnershipControlsAction,
})
if err != nil {
return SendXMLResponse(ctx, nil, err,
&MetaOpts{
Logger: c.logger,
MetricsMng: c.mm,
Action: metrics.ActionGetBucketOwnershipControls,
BucketOwner: parsedAcl.Owner,
})
}
data, err := c.be.GetBucketOwnershipControls(ctx.Context(), bucket)
return SendXMLResponse(ctx,
s3response.OwnershipControls{
Rules: []types.OwnershipControlsRule{
{
ObjectOwnership: data,
},
},
}, err,
&MetaOpts{
Logger: c.logger,
MetricsMng: c.mm,
Action: metrics.ActionGetBucketOwnershipControls,
BucketOwner: parsedAcl.Owner,
})
}
if ctx.Request().URI().QueryArgs().Has("versioning") {
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
Readonly: c.readonly,
@@ -933,6 +961,9 @@ func (c S3ApiController) PutBucketActions(ctx *fiber.Ctx) error {
grantReadACP := ctx.Get("X-Amz-Grant-Read-Acp")
granWrite := ctx.Get("X-Amz-Grant-Write")
grantWriteACP := ctx.Get("X-Amz-Grant-Write-Acp")
objectOwnership := types.ObjectOwnership(
ctx.Get("X-Amz-Object-Ownership", string(types.ObjectOwnershipBucketOwnerEnforced)),
)
mfa := ctx.Get("X-Amz-Mfa")
contentMD5 := ctx.Get("Content-MD5")
acct := ctx.Locals("account").(auth.Account)
@@ -1000,6 +1031,57 @@ func (c S3ApiController) PutBucketActions(ctx *fiber.Ctx) error {
})
}
if ctx.Request().URI().QueryArgs().Has("ownershipControls") {
parsedAcl := ctx.Locals("parsedAcl").(auth.ACL)
var ownershipControls s3response.OwnershipControls
if err := xml.Unmarshal(ctx.Body(), &ownershipControls); err != nil {
return SendResponse(ctx, s3err.GetAPIError(s3err.ErrMalformedXML),
&MetaOpts{
Logger: c.logger,
MetricsMng: c.mm,
Action: metrics.ActionPutBucketOwnershipControls,
BucketOwner: parsedAcl.Owner,
})
}
if len(ownershipControls.Rules) != 1 || !utils.IsValidOwnership(ownershipControls.Rules[0].ObjectOwnership) {
return SendResponse(ctx, s3err.GetAPIError(s3err.ErrMalformedXML),
&MetaOpts{
Logger: c.logger,
MetricsMng: c.mm,
Action: metrics.ActionPutBucketOwnershipControls,
BucketOwner: parsedAcl.Owner,
})
}
if err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: types.PermissionWrite,
IsRoot: isRoot,
Acc: acct,
Bucket: bucket,
Action: auth.PutBucketOwnershipControlsAction,
}); err != nil {
return SendResponse(ctx, err,
&MetaOpts{
Logger: c.logger,
MetricsMng: c.mm,
Action: metrics.ActionPutBucketOwnershipControls,
BucketOwner: parsedAcl.Owner,
})
}
err := c.be.PutBucketOwnershipControls(ctx.Context(), bucket, ownershipControls.Rules[0].ObjectOwnership)
return SendResponse(ctx, err,
&MetaOpts{
Logger: c.logger,
MetricsMng: c.mm,
Action: metrics.ActionPutBucketOwnershipControls,
BucketOwner: parsedAcl.Owner,
})
}
if ctx.Request().URI().QueryArgs().Has("versioning") {
parsedAcl := ctx.Locals("parsedAcl").(auth.ACL)
err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
@@ -1141,10 +1223,33 @@ func (c S3ApiController) PutBucketActions(ctx *fiber.Ctx) error {
grants := grantFullControl + grantRead + grantReadACP + granWrite + grantWriteACP
if ctx.Request().URI().QueryArgs().Has("acl") {
parsedAcl := ctx.Locals("parsedAcl").(auth.ACL)
var input *s3.PutBucketAclInput
parsedAcl := ctx.Locals("parsedAcl").(auth.ACL)
err := auth.VerifyAccess(ctx.Context(), c.be,
ownership, err := c.be.GetBucketOwnershipControls(ctx.Context(), bucket)
if err != nil && !errors.Is(err, s3err.GetAPIError(s3err.ErrOwnershipControlsNotFound)) {
return SendResponse(ctx, err,
&MetaOpts{
Logger: c.logger,
MetricsMng: c.mm,
Action: metrics.ActionPutBucketAcl,
BucketOwner: parsedAcl.Owner,
})
}
if ownership == types.ObjectOwnershipBucketOwnerEnforced {
if c.debug {
log.Println("bucket acls are disabled")
}
return SendResponse(ctx, s3err.GetAPIError(s3err.ErrAclNotSupported),
&MetaOpts{
Logger: c.logger,
MetricsMng: c.mm,
Action: metrics.ActionPutBucketAcl,
BucketOwner: parsedAcl.Owner,
})
}
err = auth.VerifyAccess(ctx.Context(), c.be,
auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
@@ -1259,7 +1364,6 @@ func (c S3ApiController) PutBucketActions(ctx *fiber.Ctx) error {
}
}
fmt.Println(*input, parsedAcl)
updAcl, err := auth.UpdateACL(input, parsedAcl, c.iam)
if err != nil {
return SendResponse(ctx, err,
@@ -1289,16 +1393,45 @@ func (c S3ApiController) PutBucketActions(ctx *fiber.Ctx) error {
Action: metrics.ActionCreateBucket,
})
}
if ok := utils.IsValidOwnership(objectOwnership); !ok {
if c.debug {
log.Printf("invalid bucket object ownership: %v", objectOwnership)
}
return SendResponse(ctx, s3err.APIError{
Code: "InvalidArgument",
Description: fmt.Sprintf("Invalid x-amz-object-ownership header: %v", objectOwnership),
HTTPStatusCode: http.StatusBadRequest,
},
&MetaOpts{
Logger: c.logger,
MetricsMng: c.mm,
Action: metrics.ActionCreateBucket,
BucketOwner: acct.Access,
})
}
if acl+grants != "" && objectOwnership == types.ObjectOwnershipBucketOwnerEnforced {
if c.debug {
log.Printf("bucket acls are disabled for %v object ownership", objectOwnership)
}
return SendResponse(ctx, s3err.GetAPIError(s3err.ErrInvalidBucketAclWithObjectOwnership),
&MetaOpts{
Logger: c.logger,
MetricsMng: c.mm,
Action: metrics.ActionCreateBucket,
BucketOwner: acct.Access,
})
}
if acl != "" && grants != "" {
if c.debug {
log.Printf("invalid request: %q (grants) %q (acl)", grants, acl)
}
return SendResponse(ctx, s3err.GetAPIError(s3err.ErrInvalidRequest),
return SendResponse(ctx, s3err.GetAPIError(s3err.ErrBothCannedAndHeaderGrants),
&MetaOpts{
Logger: c.logger,
MetricsMng: c.mm,
Action: metrics.ActionPutBucketAcl,
Action: metrics.ActionCreateBucket,
BucketOwner: acct.Access,
})
}
@@ -1334,7 +1467,7 @@ func (c S3ApiController) PutBucketActions(ctx *fiber.Ctx) error {
err = c.be.CreateBucket(ctx.Context(), &s3.CreateBucketInput{
Bucket: &bucket,
ObjectOwnership: types.ObjectOwnership(acct.Access),
ObjectOwnership: objectOwnership,
ObjectLockEnabledForBucket: &lockEnabled,
}, updAcl)
return SendResponse(ctx, err,
@@ -2042,6 +2175,38 @@ func (c S3ApiController) DeleteBucket(ctx *fiber.Ctx) error {
})
}
if ctx.Request().URI().QueryArgs().Has("ownershipControls") {
err := auth.VerifyAccess(ctx.Context(), c.be,
auth.AccessOptions{
Readonly: c.readonly,
Acl: parsedAcl,
AclPermission: types.PermissionWrite,
IsRoot: isRoot,
Acc: acct,
Bucket: bucket,
Action: auth.PutBucketOwnershipControlsAction,
})
if err != nil {
return SendResponse(ctx, err,
&MetaOpts{
Logger: c.logger,
MetricsMng: c.mm,
Action: metrics.ActionDeleteBucketOwnershipControls,
BucketOwner: parsedAcl.Owner,
})
}
err = c.be.DeleteBucketOwnershipControls(ctx.Context(), bucket)
return SendResponse(ctx, err,
&MetaOpts{
Logger: c.logger,
MetricsMng: c.mm,
Action: metrics.ActionDeleteBucketOwnershipControls,
BucketOwner: parsedAcl.Owner,
Status: http.StatusNoContent,
})
}
if ctx.Request().URI().QueryArgs().Has("policy") {
err := auth.VerifyAccess(ctx.Context(), c.be,
auth.AccessOptions{

View File

@@ -19,7 +19,6 @@ import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/httptest"
"reflect"
@@ -191,7 +190,7 @@ func TestS3ApiController_GetActions(t *testing.T) {
GetObjectAttributesFunc: func(context.Context, *s3.GetObjectAttributesInput) (s3response.GetObjectAttributesResult, error) {
return s3response.GetObjectAttributesResult{}, nil
},
GetObjectFunc: func(context.Context, *s3.GetObjectInput, io.Writer) (*s3.GetObjectOutput, error) {
GetObjectFunc: func(context.Context, *s3.GetObjectInput) (*s3.GetObjectOutput, error) {
return &s3.GetObjectOutput{
Metadata: map[string]string{"hello": "world"},
ContentType: getPtr("application/xml"),
@@ -395,6 +394,9 @@ func TestS3ApiController_ListActions(t *testing.T) {
GetObjectLockConfigurationFunc: func(contextMoqParam context.Context, bucket string) ([]byte, error) {
return objectLockResult, nil
},
GetBucketOwnershipControlsFunc: func(contextMoqParam context.Context, bucket string) (types.ObjectOwnership, error) {
return types.ObjectOwnershipBucketOwnerEnforced, nil
},
},
}
@@ -448,6 +450,15 @@ func TestS3ApiController_ListActions(t *testing.T) {
wantErr: false,
statusCode: 404,
},
{
name: "Get-bucket-ownership-control-success",
app: app,
args: args{
req: httptest.NewRequest(http.MethodGet, "/my-bucket?ownershipControls", nil),
},
wantErr: false,
statusCode: 200,
},
{
name: "Get-bucket-tagging-success",
app: app,
@@ -562,7 +573,7 @@ func TestS3ApiController_PutBucketActions(t *testing.T) {
app := fiber.New()
// Mock valid acl
acl := auth.ACL{Owner: "valid access", ACL: "public-read-write"}
acl := auth.ACL{Owner: "valid access"}
acldata, err := json.Marshal(acl)
if err != nil {
t.Errorf("Failed to parse the params: %v", err.Error())
@@ -636,6 +647,22 @@ func TestS3ApiController_PutBucketActions(t *testing.T) {
</ObjectLockConfiguration>
`
ownershipBody := `
<OwnershipControls xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Rule>
<ObjectOwnership>BucketOwnerEnforced</ObjectOwnership>
</Rule>
</OwnershipControls>
`
invalidOwnershipBody := `
<OwnershipControls xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Rule>
<ObjectOwnership>invalid_value</ObjectOwnership>
</Rule>
</OwnershipControls>
`
s3ApiController := S3ApiController{
be: &BackendMock{
GetBucketAclFunc: func(context.Context, *s3.GetBucketAclInput) ([]byte, error) {
@@ -659,6 +686,12 @@ func TestS3ApiController_PutBucketActions(t *testing.T) {
PutObjectLockConfigurationFunc: func(contextMoqParam context.Context, bucket string, config []byte) error {
return nil
},
PutBucketOwnershipControlsFunc: func(contextMoqParam context.Context, bucket string, ownership types.ObjectOwnership) error {
return nil
},
GetBucketOwnershipControlsFunc: func(contextMoqParam context.Context, bucket string) (types.ObjectOwnership, error) {
return types.ObjectOwnershipBucketOwnerPreferred, nil
},
},
}
// Mock ctx.Locals
@@ -691,6 +724,9 @@ func TestS3ApiController_PutBucketActions(t *testing.T) {
errAclBodyReq := httptest.NewRequest(http.MethodPut, "/my-bucket?acl", strings.NewReader(body))
errAclBodyReq.Header.Set("X-Amz-Grant-Read", "hello")
invAclOwnershipReq := httptest.NewRequest(http.MethodPut, "/my-bucket", nil)
invAclOwnershipReq.Header.Set("X-Amz-Grant-Read", "hello")
tests := []struct {
name string
app *fiber.App
@@ -716,6 +752,24 @@ func TestS3ApiController_PutBucketActions(t *testing.T) {
wantErr: false,
statusCode: 200,
},
{
name: "Put-bucket-ownership-controls-invalid-ownership",
app: app,
args: args{
req: httptest.NewRequest(http.MethodPut, "/my-bucket?ownershipControls", strings.NewReader(invalidOwnershipBody)),
},
wantErr: false,
statusCode: 400,
},
{
name: "Put-bucket-ownership-controls-success",
app: app,
args: args{
req: httptest.NewRequest(http.MethodPut, "/my-bucket?ownershipControls", strings.NewReader(ownershipBody)),
},
wantErr: false,
statusCode: 200,
},
{
name: "Put-object-lock-configuration-invalid-body",
app: app,
@@ -816,7 +870,16 @@ func TestS3ApiController_PutBucketActions(t *testing.T) {
statusCode: 200,
},
{
name: "Put-bucket-invalid-bucket-name",
name: "Create-bucket-invalid-acl-ownership-combination",
app: app,
args: args{
req: invAclOwnershipReq,
},
wantErr: false,
statusCode: 400,
},
{
name: "Create-bucket-invalid-bucket-name",
app: app,
args: args{
req: httptest.NewRequest(http.MethodPut, "/aa", nil),
@@ -825,7 +888,7 @@ func TestS3ApiController_PutBucketActions(t *testing.T) {
statusCode: 400,
},
{
name: "Put-bucket-success",
name: "Create-bucket-success",
app: app,
args: args{
req: httptest.NewRequest(http.MethodPut, "/my-bucket", nil),
@@ -1160,6 +1223,12 @@ func TestS3ApiController_DeleteBucket(t *testing.T) {
DeleteBucketTaggingFunc: func(contextMoqParam context.Context, bucket string) error {
return nil
},
DeleteBucketPolicyFunc: func(contextMoqParam context.Context, bucket string) error {
return nil
},
DeleteBucketOwnershipControlsFunc: func(contextMoqParam context.Context, bucket string) error {
return nil
},
},
}
@@ -1198,6 +1267,23 @@ func TestS3ApiController_DeleteBucket(t *testing.T) {
wantErr: false,
statusCode: 204,
},
{
name: "Delete-bucket-ownership-controls-success",
app: app,
args: args{
req: httptest.NewRequest(http.MethodDelete, "/my-bucket?ownershipControls", nil),
},
wantErr: false,
statusCode: 204,
}, {
name: "Delete-bucket-policy-success",
app: app,
args: args{
req: httptest.NewRequest(http.MethodDelete, "/my-bucket?policy", nil),
},
wantErr: false,
statusCode: 204,
},
}
for _, tt := range tests {
resp, err := tt.app.Test(tt.args.req)

View File

@@ -50,7 +50,8 @@ func AclParser(be backend.Backend, logger s3log.AuditLogger, readonly bool) fibe
!ctx.Request().URI().QueryArgs().Has("tagging") &&
!ctx.Request().URI().QueryArgs().Has("versioning") &&
!ctx.Request().URI().QueryArgs().Has("policy") &&
!ctx.Request().URI().QueryArgs().Has("object-lock") {
!ctx.Request().URI().QueryArgs().Has("object-lock") &&
!ctx.Request().URI().QueryArgs().Has("ownershipControls") {
if err := auth.MayCreateBucket(acct, isRoot); err != nil {
return controllers.SendXMLResponse(ctx, nil, err, &controllers.MetaOpts{Logger: logger, Action: "CreateBucket"})
}

View File

@@ -326,3 +326,16 @@ func ParsObjectLockHdrs(ctx *fiber.Ctx) (*objLockCfg, error) {
LegalHoldStatus: legalHold,
}, nil
}
func IsValidOwnership(val types.ObjectOwnership) bool {
switch val {
case types.ObjectOwnershipBucketOwnerEnforced:
return true
case types.ObjectOwnershipBucketOwnerPreferred:
return true
case types.ObjectOwnershipObjectWriter:
return true
default:
return false
}
}

View File

@@ -335,3 +335,50 @@ func TestFilterObjectAttributes(t *testing.T) {
})
}
}
func TestIsValidOwnership(t *testing.T) {
type args struct {
val types.ObjectOwnership
}
tests := []struct {
name string
args args
want bool
}{
{
name: "valid-BucketOwnerEnforced",
args: args{
val: types.ObjectOwnershipBucketOwnerEnforced,
},
want: true,
},
{
name: "valid-BucketOwnerPreferred",
args: args{
val: types.ObjectOwnershipBucketOwnerPreferred,
},
want: true,
},
{
name: "valid-ObjectWriter",
args: args{
val: types.ObjectOwnershipObjectWriter,
},
want: true,
},
{
name: "invalid_value",
args: args{
val: types.ObjectOwnership("invalid_value"),
},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := IsValidOwnership(tt.args.val); got != tt.want {
t.Errorf("IsValidOwnership() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -123,6 +123,10 @@ const (
ErrBucketTaggingNotFound
ErrObjectLockInvalidHeaders
ErrRequestTimeTooSkewed
ErrInvalidBucketAclWithObjectOwnership
ErrBothCannedAndHeaderGrants
ErrOwnershipControlsNotFound
ErrAclNotSupported
// Non-AWS errors
ErrExistingObjectIsDirectory
@@ -472,6 +476,26 @@ var errorCodeResponse = map[ErrorCode]APIError{
Description: "The difference between the request time and the server's time is too large.",
HTTPStatusCode: http.StatusForbidden,
},
ErrInvalidBucketAclWithObjectOwnership: {
Code: "ErrInvalidBucketAclWithObjectOwnership",
Description: "Bucket cannot have ACLs set with ObjectOwnership's BucketOwnerEnforced setting",
HTTPStatusCode: http.StatusBadRequest,
},
ErrBothCannedAndHeaderGrants: {
Code: "InvalidRequest",
Description: "Specifying both Canned ACLs and Header Grants is not allowed",
HTTPStatusCode: http.StatusBadRequest,
},
ErrOwnershipControlsNotFound: {
Code: "OwnershipControlsNotFoundError",
Description: "The bucket ownership controls were not found",
HTTPStatusCode: http.StatusNotFound,
},
ErrAclNotSupported: {
Code: "AccessControlListNotSupported",
Description: "The bucket does not allow ACLs",
HTTPStatusCode: http.StatusBadRequest,
},
// non aws errors
ErrExistingObjectIsDirectory: {

View File

@@ -217,3 +217,7 @@ type Grantee struct {
ID string
DisplayName string
}
type OwnershipControls struct {
Rules []types.OwnershipControlsRule `xml:"Rule"`
}

View File

@@ -2,13 +2,24 @@
abort_multipart_upload() {
if [ $# -ne 3 ]; then
echo "command to run abort requires bucket, key, upload ID"
log 2 "'abort multipart upload' command requires bucket, key, upload ID"
return 1
fi
if ! error=$(aws --no-verify-ssl s3api abort-multipart-upload --bucket "$1" --key "$2" --upload-id "$3" 2>&1); then
log 2 "Error aborting upload: $error"
return 1
fi
return 0
}
error=$(aws --no-verify-ssl s3api abort-multipart-upload --bucket "$1" --key "$2" --upload-id "$3") || local aborted=$?
if [[ $aborted -ne 0 ]]; then
echo "Error aborting upload: $error"
abort_multipart_upload_with_user() {
if [ $# -ne 5 ]; then
log 2 "'abort multipart upload' command requires bucket, key, upload ID, username, password"
return 1
fi
if ! abort_multipart_upload_error=$(AWS_ACCESS_KEY_ID="$4" AWS_SECRET_ACCESS_KEY="$5" aws --no-verify-ssl s3api abort-multipart-upload --bucket "$1" --key "$2" --upload-id "$3" 2>&1); then
log 2 "Error aborting upload: $abort_multipart_upload_error"
export abort_multipart_upload_error
return 1
fi
return 0

View File

@@ -9,16 +9,38 @@ create_multipart_upload() {
return 1
fi
local multipart_data
multipart_data=$(aws --no-verify-ssl s3api create-multipart-upload --bucket "$1" --key "$2") || local created=$?
if [[ $created -ne 0 ]]; then
log 2 "Error creating multipart upload: $upload_id"
if ! multipart_data=$(aws --no-verify-ssl s3api create-multipart-upload --bucket "$1" --key "$2" 2>&1); then
log 2 "Error creating multipart upload: $multipart_data"
return 1
fi
upload_id=$(echo "$multipart_data" | jq '.UploadId')
if ! upload_id=$(echo "$multipart_data" | grep -v "InsecureRequestWarning" | jq -r '.UploadId' 2>&1); then
log 2 "error parsing upload ID: $upload_id"
return 1
fi
upload_id="${upload_id//\"/}"
export upload_id
return 0
}
create_multipart_upload_with_user() {
if [ $# -ne 4 ]; then
log 2 "create multipart upload function must have bucket, key, username, password"
return 1
fi
if ! multipart_data=$(AWS_ACCESS_KEY_ID="$3" AWS_SECRET_ACCESS_KEY="$4" aws --no-verify-ssl s3api create-multipart-upload --bucket "$1" --key "$2" 2>&1); then
log 2 "Error creating multipart upload: $multipart_data"
return 1
fi
if ! upload_id=$(echo "$multipart_data" | grep -v "InsecureRequestWarning" | jq -r '.UploadId' 2>&1); then
log 2 "error parsing upload ID: $upload_id"
return 1
fi
upload_id="${upload_id//\"/}"
export upload_id
return 0
}
create_multipart_upload_params() {

View File

@@ -20,4 +20,17 @@ delete_bucket_policy() {
return 1
fi
return 0
}
delete_bucket_policy_with_user() {
if [[ $# -ne 3 ]]; then
log 2 "'delete bucket policy with user' command requires bucket, username, password"
return 1
fi
if ! delete_bucket_policy_error=$(AWS_ACCESS_KEY_ID="$2" AWS_SECRET_ACCESS_KEY="$3" aws --no-verify-ssl s3api delete-bucket-policy --bucket "$1" 2>&1); then
log 2 "error deleting bucket policy: $delete_bucket_policy_error"
export delete_bucket_policy_error
return 1
fi
return 0
}

View File

@@ -19,4 +19,17 @@ get_bucket_acl() {
return 1
fi
export acl
}
get_bucket_acl_with_user() {
if [ $# -ne 3 ]; then
log 2 "'get bucket ACL with user' command requires bucket name, username, password"
return 1
fi
if ! bucket_acl=$(AWS_ACCESS_KEY_ID="$2" AWS_SECRET_ACCESS_KEY="$3" aws --no-verify-ssl s3api get-bucket-acl --bucket "$1" 2>&1); then
log 2 "error getting bucket ACLs: $bucket_acl"
return 1
fi
export bucket_acl
return 0
}

View File

@@ -0,0 +1,36 @@
#!/usr/bin/env bash
get_bucket_ownership_controls() {
if [[ $# -ne 1 ]]; then
log 2 "'get bucket ownership controls' command requires bucket name"
return 1
fi
if ! raw_bucket_ownership_controls=$(aws --no-verify-ssl s3api get-bucket-ownership-controls --bucket "$1" 2>&1); then
log 2 "error getting bucket ownership controls: $raw_bucket_ownership_controls"
return 1
fi
log 5 "Raw bucket Ownership Controls: $raw_bucket_ownership_controls"
bucket_ownership_controls=$(echo "$raw_bucket_ownership_controls" | grep -v "InsecureRequestWarning")
export bucket_ownership_controls
return 0
}
get_object_ownership_rule() {
if [[ $# -ne 1 ]]; then
log 2 "'get object ownership rule' command requires bucket name"
return 1
fi
if ! get_bucket_ownership_controls "$1"; then
log 2 "error getting bucket ownership controls"
return 1
fi
if ! object_ownership_rule=$(echo "$bucket_ownership_controls" | jq -r ".OwnershipControls.Rules[0].ObjectOwnership" 2>&1); then
log 2 "error getting object ownership rule: $object_ownership_rule"
return 1
fi
log 5 "object ownership rule: $object_ownership_rule"
export object_ownership_rule
return 0
}

View File

@@ -46,29 +46,56 @@ get_bucket_policy_aws() {
return 0
}
get_bucket_policy_with_user() {
if [[ $# -ne 3 ]]; then
log 2 "'get bucket policy with user' command requires bucket, username, password"
return 1
fi
if policy_json=$(AWS_ACCESS_KEY_ID="$2" AWS_SECRET_ACCESS_KEY="$3" aws --no-verify-ssl s3api get-bucket-policy --bucket "$1" 2>&1); then
policy_json=$(echo "$policy_json" | grep -v "InsecureRequestWarning")
bucket_policy=$(echo "$policy_json" | jq -r '.Policy')
else
if [[ "$policy_json" == *"(NoSuchBucketPolicy)"* ]]; then
bucket_policy=
else
log 2 "error getting policy for user $2: $policy_json"
return 1
fi
fi
export bucket_policy
return 0
}
get_bucket_policy_s3cmd() {
if [[ $# -ne 1 ]]; then
echo "s3cmd 'get bucket policy' command requires bucket"
log 2 "s3cmd 'get bucket policy' command requires bucket"
return 1
fi
info=$(s3cmd "${S3CMD_OPTS[@]}" --no-check-certificate info "s3://$1") || get_result=$?
if [[ $get_result -ne 0 ]]; then
echo "error getting bucket policy: $info"
if ! info=$(s3cmd "${S3CMD_OPTS[@]}" --no-check-certificate info "s3://$1" 2>&1); then
log 2 "error getting bucket policy: $info"
return 1
fi
log 5 "policy info: $info"
bucket_policy=""
policy_brackets=false
# NOTE: versitygw sends policies back in multiple lines here, direct in single line
while IFS= read -r line; do
if [[ $policy_brackets == false ]]; then
policy_line=$(echo "$line" | grep 'Policy: ')
if [[ $policy_line != "" ]]; then
if [[ $policy_line != *'{' ]]; then
if [[ $policy_line != *'{'* ]]; then
break
fi
policy_brackets=true
bucket_policy+="{"
if [[ $policy_line == *'}'* ]]; then
log 5 "policy on single line"
bucket_policy=${policy_line//Policy:/}
break
else
policy_brackets=true
bucket_policy+="{"
fi
fi
else
bucket_policy+=$line
@@ -77,6 +104,7 @@ get_bucket_policy_s3cmd() {
fi
fi
done <<< "$info"
log 5 "bucket policy: $bucket_policy"
export bucket_policy
return 0
}

View File

@@ -0,0 +1,27 @@
#!/usr/bin/env bash
list_multipart_uploads() {
if [[ $# -ne 1 ]]; then
log 2 "'list multipart uploads' command requires bucket name"
return 1
fi
if ! uploads=$(aws --no-verify-ssl s3api list-multipart-uploads --bucket "$1" 2>&1); then
log 2 "error listing uploads: $uploads"
return 1
fi
export uploads
}
list_multipart_uploads_with_user() {
if [[ $# -ne 3 ]]; then
log 2 "'list multipart uploads' command requires bucket name, username, password"
return 1
fi
if ! uploads=$(AWS_ACCESS_KEY_ID="$2" AWS_SECRET_ACCESS_KEY="$3" aws --no-verify-ssl s3api list-multipart-uploads --bucket "$1" 2>&1); then
log 2 "error listing uploads: $uploads"
list_multipart_uploads_error=$uploads
export list_multipart_uploads_error
return 1
fi
export uploads
}

View File

@@ -29,8 +29,20 @@ put_bucket_canned_acl() {
return 1
fi
if ! error=$(aws --no-verify-ssl s3api put-bucket-acl --bucket "$1" --acl "$2"); then
log 2 "error resetting bucket acls: $error"
log 2 "error re-setting bucket acls: $error"
return 1
fi
return 0
}
}
put_bucket_canned_acl_with_user() {
if [[ $# -ne 2 ]]; then
log 2 "'put bucket canned acl with user' command requires bucket name, canned ACL, username, password"
return 1
fi
if ! error=$(AWS_ACCESS_KEY_ID="$3" AWS_SECRET_ACCESS_KEY="$4" aws --no-verify-ssl s3api put-bucket-acl --bucket "$1" --acl "$2"); then
log 2 "error re-setting bucket acls: $error"
return 1
fi
return 0
}

View File

@@ -0,0 +1,14 @@
#!/usr/bin/env bash
put_bucket_ownership_controls() {
if [[ $# -ne 2 ]]; then
log 2 "'put bucket ownership controls' command requires bucket name, control"
return 1
fi
if ! controls_error=$(aws --no-verify-ssl s3api put-bucket-ownership-controls --bucket "$1" \
--ownership-controls="Rules=[{ObjectOwnership=$2}]" 2>&1); then
log 2 "error putting bucket ownership controls: $controls_error"
return 1
fi
return 0
}

View File

@@ -2,7 +2,7 @@
put_bucket_policy() {
if [[ $# -ne 3 ]]; then
log 2 "get bucket policy command requires command type, bucket, policy file"
log 2 "'put bucket policy' command requires command type, bucket, policy file"
return 1
fi
local put_policy_result=0
@@ -23,4 +23,18 @@ put_bucket_policy() {
return 1
fi
return 0
}
}
put_bucket_policy_with_user() {
if [[ $# -ne 4 ]]; then
log 2 "'put bucket policy with user' command requires bucket, policy file, username, password"
return 1
fi
if ! policy=$(AWS_ACCESS_KEY_ID="$3" AWS_SECRET_ACCESS_KEY="$4" aws --no-verify-ssl s3api put-bucket-policy --bucket "$1" --policy "file://$2" 2>&1); then
log 2 "error putting bucket policy with user $3: $policy"
put_bucket_policy_error=$policy
export put_bucket_policy_error
return 1
fi
return 0
}

View File

@@ -56,10 +56,13 @@ check_universal_vars() {
elif [ -z "$AWS_SECRET_ACCESS_KEY" ]; then
log 2 "No AWS secret access key set"
return 1
elif [ -z "$AWS_REGION" ]; then
log 2 "No AWS region set"
return 1
elif [ -z "$AWS_PROFILE" ]; then
log 2 "No AWS profile set"
return 1
elif [ -z "$AWS_ENDPOINT_URL" ]; then
elif [ "$DIRECT" != "true" ] && [ -z "$AWS_ENDPOINT_URL" ]; then
log 2 "No AWS endpoint URL set"
return 1
elif [[ $RUN_VERSITYGW != "true" ]] && [[ $RUN_VERSITYGW != "false" ]]; then
@@ -78,7 +81,7 @@ check_universal_vars() {
log 2 "RECREATE_BUCKETS must be 'true' or 'false'"
return 1
fi
export AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_PROFILE AWS_ENDPOINT_URL RUN_VERSITYGW \
export AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_REGION AWS_PROFILE AWS_ENDPOINT_URL RUN_VERSITYGW \
BUCKET_ONE_NAME BUCKET_TWO_NAME RECREATE_BUCKETS
if [[ -n "$TEST_LOG_FILE" ]]; then
export TEST_LOG_FILE
@@ -86,6 +89,9 @@ check_universal_vars() {
if [[ -n "$VERSITY_LOG_FILE" ]]; then
export VERSITY_LOG_FILE
fi
if [[ -n "$DIRECT" ]]; then
export DIRECT
fi
}
check_versity_vars() {

View File

@@ -65,6 +65,8 @@ func TestCreateBucket(s *S3Conf) {
CreateBucket_invalid_bucket_name(s)
CreateBucket_existing_bucket(s)
CreateBucket_owned_by_you(s)
CreateBucket_invalid_ownership(s)
CreateBucket_ownership_with_acl(s)
CreateBucket_as_user(s)
CreateBucket_default_acl(s)
CreateBucket_non_default_acl(s)
@@ -89,6 +91,24 @@ func TestDeleteBucket(s *S3Conf) {
DeleteBucket_success_status_code(s)
}
func TestPutBucketOwnershipControls(s *S3Conf) {
PutBucketOwnershipControls_non_existing_bucket(s)
PutBucketOwnershipControls_multiple_rules(s)
PutBucketOwnershipControls_invalid_ownership(s)
PutBucketOwnershipControls_success(s)
}
func TestGetBucketOwnershipControls(s *S3Conf) {
GetBucketOwnershipControls_non_existing_bucket(s)
GetBucketOwnershipControls_default_ownership(s)
GetBucketOwnershipControls_success(s)
}
func TestDeleteBucketOwnershipControls(s *S3Conf) {
DeleteBucketOwnershipControls_non_existing_bucket(s)
DeleteBucketOwnershipControls_success(s)
}
func TestPutBucketTagging(s *S3Conf) {
PutBucketTagging_non_existing_bucket(s)
PutBucketTagging_long_tags(s)
@@ -267,6 +287,7 @@ func TestCompleteMultipartUpload(s *S3Conf) {
func TestPutBucketAcl(s *S3Conf) {
PutBucketAcl_non_existing_bucket(s)
PutBucketAcl_disabled(s)
PutBucketAcl_invalid_acl_canned_and_acp(s)
PutBucketAcl_invalid_acl_canned_and_grants(s)
PutBucketAcl_invalid_acl_acp_and_grants(s)
@@ -280,6 +301,9 @@ func TestPutBucketAcl(s *S3Conf) {
func TestGetBucketAcl(s *S3Conf) {
GetBucketAcl_non_existing_bucket(s)
GetBucketAcl_translation_canned_public_read(s)
GetBucketAcl_translation_canned_public_read_write(s)
GetBucketAcl_translation_canned_private(s)
GetBucketAcl_access_denied(s)
GetBucketAcl_success(s)
}
@@ -395,6 +419,9 @@ func TestFullFlow(s *S3Conf) {
TestHeadBucket(s)
TestListBuckets(s)
TestDeleteBucket(s)
TestPutBucketOwnershipControls(s)
TestGetBucketOwnershipControls(s)
TestDeleteBucketOwnershipControls(s)
TestPutBucketTagging(s)
TestGetBucketTagging(s)
TestDeleteBucketTagging(s)
@@ -505,6 +532,8 @@ func GetIntTests() IntTests {
"CreateBucket_invalid_bucket_name": CreateBucket_invalid_bucket_name,
"CreateBucket_existing_bucket": CreateBucket_existing_bucket,
"CreateBucket_owned_by_you": CreateBucket_owned_by_you,
"CreateBucket_invalid_ownership": CreateBucket_invalid_ownership,
"CreateBucket_ownership_with_acl": CreateBucket_ownership_with_acl,
"CreateBucket_as_user": CreateBucket_as_user,
"CreateDeleteBucket_success": CreateDeleteBucket_success,
"CreateBucket_default_acl": CreateBucket_default_acl,
@@ -518,6 +547,15 @@ func GetIntTests() IntTests {
"DeleteBucket_non_existing_bucket": DeleteBucket_non_existing_bucket,
"DeleteBucket_non_empty_bucket": DeleteBucket_non_empty_bucket,
"DeleteBucket_success_status_code": DeleteBucket_success_status_code,
"PutBucketOwnershipControls_non_existing_bucket": PutBucketOwnershipControls_non_existing_bucket,
"PutBucketOwnershipControls_multiple_rules": PutBucketOwnershipControls_multiple_rules,
"PutBucketOwnershipControls_invalid_ownership": PutBucketOwnershipControls_invalid_ownership,
"PutBucketOwnershipControls_success": PutBucketOwnershipControls_success,
"GetBucketOwnershipControls_non_existing_bucket": GetBucketOwnershipControls_non_existing_bucket,
"GetBucketOwnershipControls_default_ownership": GetBucketOwnershipControls_default_ownership,
"GetBucketOwnershipControls_success": GetBucketOwnershipControls_success,
"DeleteBucketOwnershipControls_non_existing_bucket": DeleteBucketOwnershipControls_non_existing_bucket,
"DeleteBucketOwnershipControls_success": DeleteBucketOwnershipControls_success,
"PutBucketTagging_non_existing_bucket": PutBucketTagging_non_existing_bucket,
"PutBucketTagging_long_tags": PutBucketTagging_long_tags,
"PutBucketTagging_success": PutBucketTagging_success,
@@ -636,6 +674,9 @@ func GetIntTests() IntTests {
"PutBucketAcl_success_canned_acl": PutBucketAcl_success_canned_acl,
"PutBucketAcl_success_acp": PutBucketAcl_success_acp,
"GetBucketAcl_non_existing_bucket": GetBucketAcl_non_existing_bucket,
"GetBucketAcl_translation_canned_public_read": GetBucketAcl_translation_canned_public_read,
"GetBucketAcl_translation_canned_public_read_write": GetBucketAcl_translation_canned_public_read_write,
"GetBucketAcl_translation_canned_private": GetBucketAcl_translation_canned_private,
"GetBucketAcl_access_denied": GetBucketAcl_access_denied,
"GetBucketAcl_success": GetBucketAcl_success,
"PutBucketPolicy_non_existing_bucket": PutBucketPolicy_non_existing_bucket,

View File

@@ -1720,47 +1720,76 @@ func CreateBucket_owned_by_you(s *S3Conf) error {
})
}
func CreateBucket_default_acl(s *S3Conf) error {
testName := "CreateBucket_default_acl"
func CreateBucket_invalid_ownership(s *S3Conf) error {
testName := "CreateBucket_invalid_ownership"
runF(testName)
bucket := getBucketName()
client := s3.NewFromConfig(s.Config())
err := setup(s, bucket)
if err != nil {
invalidOwnership := types.ObjectOwnership("invalid_ownership")
err := setup(s, getBucketName(), withOwnership(invalidOwnership))
if err := checkApiErr(err, s3err.APIError{
Code: "InvalidArgument",
Description: fmt.Sprintf("Invalid x-amz-object-ownership header: %v", invalidOwnership),
HTTPStatusCode: http.StatusBadRequest,
}); err != nil {
failF("%v: %v", testName, err)
return fmt.Errorf("%v: %w", testName, err)
}
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
out, err := client.GetBucketAcl(ctx, &s3.GetBucketAclInput{Bucket: &bucket})
cancel()
if err != nil {
failF("%v: %v", testName, err)
return fmt.Errorf("%v: %w", testName, err)
}
if *out.Owner.ID != s.awsID {
failF("%v: expected bucket owner to be %v, instead got %v", testName, s.awsID, *out.Owner.ID)
return fmt.Errorf("%v: expected bucket owner to be %v, instead got %v", testName, s.awsID, *out.Owner.ID)
}
if len(out.Grants) != 0 {
failF("%v: expected grants to be empty instead got %v", testName, len(out.Grants))
return fmt.Errorf("%v: expected grants to be empty instead got %v", testName, len(out.Grants))
}
err = teardown(s, bucket)
if err != nil {
failF("%v: %v", err)
return fmt.Errorf("%v: %w", testName, err)
}
passF(testName)
return nil
}
func CreateBucket_ownership_with_acl(s *S3Conf) error {
testName := "CreateBucket_ownership_with_acl"
runF(testName)
client := s3.NewFromConfig(s.Config())
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
_, err := client.CreateBucket(ctx, &s3.CreateBucketInput{
Bucket: getPtr(getBucketName()),
ObjectOwnership: types.ObjectOwnershipBucketOwnerEnforced,
ACL: types.BucketCannedACLPublicRead,
})
cancel()
if err := checkApiErr(err, s3err.GetAPIError(s3err.ErrInvalidBucketAclWithObjectOwnership)); err != nil {
failF("%v: %v", testName, err)
return fmt.Errorf("%v: %w", testName, err)
}
passF(testName)
return nil
}
func CreateBucket_default_acl(s *S3Conf) error {
testName := "CreateBucket_default_acl"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
out, err := s3client.GetBucketAcl(ctx, &s3.GetBucketAclInput{Bucket: &bucket})
cancel()
if err != nil {
return err
}
if *out.Owner.ID != s.awsID {
return fmt.Errorf("expected bucket owner to be %v, instead got %v", s.awsID, *out.Owner.ID)
}
if len(out.Grants) != 1 {
return fmt.Errorf("expected grants length to be 1, instead got %v", len(out.Grants))
}
grt := out.Grants[0]
if grt.Permission != types.PermissionFullControl {
return fmt.Errorf("expected the grantee to have full-control permission, instead got %v", grt.Permission)
}
if *grt.Grantee.ID != s.awsID {
return fmt.Errorf("expected the grantee id to be %v, instead got %v", s.awsID, *grt.Grantee.ID)
}
return nil
})
}
func CreateBucket_non_default_acl(s *S3Conf) error {
testName := "CreateBucket_non_default_acl"
runF(testName)
@@ -1776,6 +1805,12 @@ func CreateBucket_non_default_acl(s *S3Conf) error {
}
grants := []types.Grant{
{
Grantee: &types.Grantee{
ID: &s.awsID,
},
Permission: types.PermissionFullControl,
},
{
Grantee: &types.Grantee{
ID: getPtr("grt1"),
@@ -1800,7 +1835,13 @@ func CreateBucket_non_default_acl(s *S3Conf) error {
client := s3.NewFromConfig(s.Config())
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
_, err = client.CreateBucket(ctx, &s3.CreateBucketInput{Bucket: &bucket, GrantFullControl: getPtr("grt1"), GrantReadACP: getPtr("grt2"), GrantWrite: getPtr("grt3")})
_, err = client.CreateBucket(ctx, &s3.CreateBucketInput{
Bucket: &bucket,
GrantFullControl: getPtr("grt1"),
GrantReadACP: getPtr("grt2"),
GrantWrite: getPtr("grt3"),
ObjectOwnership: types.ObjectOwnershipBucketOwnerPreferred,
})
cancel()
if err != nil {
failF("%v: %v", err)
@@ -2195,6 +2236,220 @@ func DeleteBucket_success_status_code(s *S3Conf) error {
return nil
}
func PutBucketOwnershipControls_non_existing_bucket(s *S3Conf) error {
testName := "PutBucketOwnershipControls_non_existing_bucket"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
_, err := s3client.PutBucketOwnershipControls(ctx, &s3.PutBucketOwnershipControlsInput{
Bucket: getPtr(getBucketName()),
OwnershipControls: &types.OwnershipControls{
Rules: []types.OwnershipControlsRule{
{
ObjectOwnership: types.ObjectOwnershipBucketOwnerPreferred,
},
},
},
})
cancel()
if err := checkApiErr(err, s3err.GetAPIError(s3err.ErrNoSuchBucket)); err != nil {
return err
}
return nil
})
}
func PutBucketOwnershipControls_multiple_rules(s *S3Conf) error {
testName := "PutBucketOwnershipControls_multiple_rules"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
_, err := s3client.PutBucketOwnershipControls(ctx, &s3.PutBucketOwnershipControlsInput{
Bucket: &bucket,
OwnershipControls: &types.OwnershipControls{
Rules: []types.OwnershipControlsRule{
{
ObjectOwnership: types.ObjectOwnershipBucketOwnerPreferred,
},
{
ObjectOwnership: types.ObjectOwnershipObjectWriter,
},
},
},
})
cancel()
if err := checkApiErr(err, s3err.GetAPIError(s3err.ErrMalformedXML)); err != nil {
return err
}
return nil
})
}
func PutBucketOwnershipControls_invalid_ownership(s *S3Conf) error {
testName := "PutBucketOwnershipControls_invalid_ownership"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
_, err := s3client.PutBucketOwnershipControls(ctx, &s3.PutBucketOwnershipControlsInput{
Bucket: &bucket,
OwnershipControls: &types.OwnershipControls{
Rules: []types.OwnershipControlsRule{
{
ObjectOwnership: types.ObjectOwnership("invalid_ownership"),
},
},
},
})
cancel()
if err := checkApiErr(err, s3err.GetAPIError(s3err.ErrMalformedXML)); err != nil {
return err
}
return nil
})
}
func PutBucketOwnershipControls_success(s *S3Conf) error {
testName := "PutBucketOwnershipControls_success"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
_, err := s3client.PutBucketOwnershipControls(ctx, &s3.PutBucketOwnershipControlsInput{
Bucket: &bucket,
OwnershipControls: &types.OwnershipControls{
Rules: []types.OwnershipControlsRule{
{
ObjectOwnership: types.ObjectOwnershipObjectWriter,
},
},
},
})
cancel()
if err != nil {
return err
}
return nil
})
}
func GetBucketOwnershipControls_non_existing_bucket(s *S3Conf) error {
testName := "GetBucketOwnershipControls_non_existing_bucket"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
_, err := s3client.GetBucketOwnershipControls(ctx, &s3.GetBucketOwnershipControlsInput{
Bucket: getPtr(getBucketName()),
})
cancel()
if err := checkApiErr(err, s3err.GetAPIError(s3err.ErrNoSuchBucket)); err != nil {
return err
}
return nil
})
}
func GetBucketOwnershipControls_default_ownership(s *S3Conf) error {
testName := "GetBucketOwnershipControls_default_ownership"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
resp, err := s3client.GetBucketOwnershipControls(ctx, &s3.GetBucketOwnershipControlsInput{
Bucket: &bucket,
})
cancel()
if err != nil {
return err
}
if len(resp.OwnershipControls.Rules) != 1 {
return fmt.Errorf("expected ownership control rules length to be 1, instead got %v", len(resp.OwnershipControls.Rules))
}
if resp.OwnershipControls.Rules[0].ObjectOwnership != types.ObjectOwnershipBucketOwnerEnforced {
return fmt.Errorf("expected the bucket ownership to be %v, instead got %v", types.ObjectOwnershipBucketOwnerEnforced, resp.OwnershipControls.Rules[0].ObjectOwnership)
}
return nil
})
}
func GetBucketOwnershipControls_success(s *S3Conf) error {
testName := "GetBucketOwnershipControls_success"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
_, err := s3client.PutBucketOwnershipControls(ctx, &s3.PutBucketOwnershipControlsInput{
Bucket: &bucket,
OwnershipControls: &types.OwnershipControls{
Rules: []types.OwnershipControlsRule{
{
ObjectOwnership: types.ObjectOwnershipObjectWriter,
},
},
},
})
cancel()
if err != nil {
return err
}
ctx, cancel = context.WithTimeout(context.Background(), shortTimeout)
resp, err := s3client.GetBucketOwnershipControls(ctx, &s3.GetBucketOwnershipControlsInput{
Bucket: &bucket,
})
cancel()
if err != nil {
return err
}
if len(resp.OwnershipControls.Rules) != 1 {
return fmt.Errorf("expected ownership control rules length to be 1, instead got %v", len(resp.OwnershipControls.Rules))
}
if resp.OwnershipControls.Rules[0].ObjectOwnership != types.ObjectOwnershipObjectWriter {
return fmt.Errorf("expected the bucket ownership to be %v, instead got %v", types.ObjectOwnershipObjectWriter, resp.OwnershipControls.Rules[0].ObjectOwnership)
}
return nil
})
}
func DeleteBucketOwnershipControls_non_existing_bucket(s *S3Conf) error {
testName := "DeleteBucketOwnershipControls_non_existing_bucket"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
_, err := s3client.DeleteBucketOwnershipControls(ctx, &s3.DeleteBucketOwnershipControlsInput{
Bucket: getPtr(getBucketName()),
})
cancel()
if err := checkApiErr(err, s3err.GetAPIError(s3err.ErrNoSuchBucket)); err != nil {
return err
}
return nil
})
}
func DeleteBucketOwnershipControls_success(s *S3Conf) error {
testName := "DeleteBucketOwnershipControls_success"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
_, err := s3client.DeleteBucketOwnershipControls(ctx, &s3.DeleteBucketOwnershipControlsInput{
Bucket: &bucket,
})
cancel()
if err != nil {
return err
}
ctx, cancel = context.WithTimeout(context.Background(), shortTimeout)
_, err = s3client.GetBucketOwnershipControls(ctx, &s3.GetBucketOwnershipControlsInput{
Bucket: &bucket,
})
cancel()
if err := checkApiErr(err, s3err.GetAPIError(s3err.ErrOwnershipControlsNotFound)); err != nil {
return err
}
return nil
})
}
func PutBucketTagging_non_existing_bucket(s *S3Conf) error {
testName := "PutBucketTagging_non_existing_bucket"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
@@ -3031,6 +3286,17 @@ func GetObject_invalid_ranges(s *S3Conf) error {
return err
}
ctx, cancel = context.WithTimeout(context.Background(), shortTimeout)
_, err = s3client.GetObject(ctx, &s3.GetObjectInput{
Bucket: &bucket,
Key: &obj,
Range: getPtr("bytes=0-0"),
})
cancel()
if err := checkApiErr(err, s3err.GetAPIError(s3err.ErrInvalidRange)); err != nil {
return err
}
ctx, cancel = context.WithTimeout(context.Background(), shortTimeout)
resp, err := s3client.GetObject(ctx, &s3.GetObjectInput{
Bucket: &bucket,
@@ -3045,17 +3311,6 @@ func GetObject_invalid_ranges(s *S3Conf) error {
if *resp.ContentLength != dataLength-1500 {
return fmt.Errorf("expected content-length to be %v, instead got %v", dataLength-1500, *resp.ContentLength)
}
ctx, cancel = context.WithTimeout(context.Background(), shortTimeout)
_, err = s3client.GetObject(ctx, &s3.GetObjectInput{
Bucket: &bucket,
Key: &obj,
Range: getPtr("bytes=0-0"),
})
cancel()
if err := checkApiErr(err, s3err.GetAPIError(s3err.ErrInvalidRange)); err != nil {
return err
}
return nil
})
}
@@ -3164,7 +3419,7 @@ func GetObject_by_range_success(s *S3Conf) error {
return fmt.Errorf("expected accept range: %v, instead got: %v", rangeString, getString(out.AcceptRanges))
}
b, err := io.ReadAll(out.Body)
if err != nil {
if err != nil && !errors.Is(err, io.EOF) {
return err
}
@@ -3188,7 +3443,7 @@ func GetObject_by_range_success(s *S3Conf) error {
defer out.Body.Close()
b, err = io.ReadAll(out.Body)
if err != nil {
if err != nil && !errors.Is(err, io.EOF) {
return err
}
@@ -5893,6 +6148,23 @@ func PutBucketAcl_non_existing_bucket(s *S3Conf) error {
})
}
func PutBucketAcl_disabled(s *S3Conf) error {
testName := "PutBucketAcl_disabled"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
_, err := s3client.PutBucketAcl(ctx, &s3.PutBucketAclInput{
Bucket: &bucket,
ACL: types.BucketCannedACLPublicRead,
GrantRead: &s.awsID,
})
cancel()
if err := checkApiErr(err, s3err.GetAPIError(s3err.ErrAclNotSupported)); err != nil {
return err
}
return nil
})
}
func PutBucketAcl_invalid_acl_canned_and_acp(s *S3Conf) error {
testName := "PutBucketAcl_invalid_acl_canned_and_acp"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
@@ -5908,7 +6180,7 @@ func PutBucketAcl_invalid_acl_canned_and_acp(s *S3Conf) error {
}
return nil
})
}, withOwnership(types.ObjectOwnershipBucketOwnerPreferred))
}
func PutBucketAcl_invalid_acl_canned_and_grants(s *S3Conf) error {
@@ -5938,7 +6210,7 @@ func PutBucketAcl_invalid_acl_canned_and_grants(s *S3Conf) error {
}
return nil
})
}, withOwnership(types.ObjectOwnershipBucketOwnerPreferred))
}
func PutBucketAcl_invalid_acl_acp_and_grants(s *S3Conf) error {
@@ -5968,7 +6240,7 @@ func PutBucketAcl_invalid_acl_acp_and_grants(s *S3Conf) error {
}
return nil
})
}, withOwnership(types.ObjectOwnershipBucketOwnerPreferred))
}
func PutBucketAcl_invalid_owner(s *S3Conf) error {
@@ -5997,7 +6269,7 @@ func PutBucketAcl_invalid_owner(s *S3Conf) error {
}
return nil
})
}, withOwnership(types.ObjectOwnershipBucketOwnerPreferred))
}
func PutBucketAcl_invalid_owner_not_in_body(s *S3Conf) error {
@@ -6023,7 +6295,7 @@ func PutBucketAcl_invalid_owner_not_in_body(s *S3Conf) error {
}
return nil
})
}, withOwnership(types.ObjectOwnershipBucketOwnerPreferred))
}
func PutBucketAcl_success_access_denied(s *S3Conf) error {
@@ -6068,7 +6340,7 @@ func PutBucketAcl_success_access_denied(s *S3Conf) error {
}
return nil
})
}, withOwnership(types.ObjectOwnershipBucketOwnerPreferred))
}
func PutBucketAcl_success_canned_acl(s *S3Conf) error {
@@ -6100,7 +6372,7 @@ func PutBucketAcl_success_canned_acl(s *S3Conf) error {
}
return nil
})
}, withOwnership(types.ObjectOwnershipBucketOwnerPreferred))
}
func PutBucketAcl_success_acp(s *S3Conf) error {
@@ -6141,7 +6413,7 @@ func PutBucketAcl_success_acp(s *S3Conf) error {
}
return nil
})
}, withOwnership(types.ObjectOwnershipBucketOwnerPreferred))
}
func PutBucketAcl_success_grants(s *S3Conf) error {
@@ -6186,7 +6458,7 @@ func PutBucketAcl_success_grants(s *S3Conf) error {
}
return nil
})
}, withOwnership(types.ObjectOwnershipBucketOwnerPreferred))
}
func GetBucketAcl_non_existing_bucket(s *S3Conf) error {
@@ -6205,6 +6477,156 @@ func GetBucketAcl_non_existing_bucket(s *S3Conf) error {
})
}
func GetBucketAcl_translation_canned_public_read(s *S3Conf) error {
testName := "GetBucketAcl_translation_canned_public_read"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
grants := []types.Grant{
{
Grantee: &types.Grantee{
ID: &s.awsID,
Type: types.TypeCanonicalUser,
},
Permission: types.PermissionFullControl,
},
{
Grantee: &types.Grantee{
ID: getPtr("all-users"),
Type: types.TypeCanonicalUser,
},
Permission: types.PermissionRead,
},
}
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
_, err := s3client.PutBucketAcl(ctx, &s3.PutBucketAclInput{
Bucket: &bucket,
ACL: types.BucketCannedACLPublicRead,
})
cancel()
if err != nil {
return err
}
ctx, cancel = context.WithTimeout(context.Background(), shortTimeout)
out, err := s3client.GetBucketAcl(ctx, &s3.GetBucketAclInput{
Bucket: &bucket,
})
cancel()
if err != nil {
return err
}
if ok := compareGrants(out.Grants, grants); !ok {
return fmt.Errorf("expected grants to be %v, instead got %v", grants, out.Grants)
}
if *out.Owner.ID != s.awsID {
return fmt.Errorf("expected bucket owner to be %v, instead got %v", s.awsID, *out.Owner.ID)
}
return nil
}, withOwnership(types.ObjectOwnershipBucketOwnerPreferred))
}
func GetBucketAcl_translation_canned_public_read_write(s *S3Conf) error {
testName := "GetBucketAcl_translation_canned_public_read_write"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
grants := []types.Grant{
{
Grantee: &types.Grantee{
ID: &s.awsID,
Type: types.TypeCanonicalUser,
},
Permission: types.PermissionFullControl,
},
{
Grantee: &types.Grantee{
ID: getPtr("all-users"),
Type: types.TypeCanonicalUser,
},
Permission: types.PermissionRead,
},
{
Grantee: &types.Grantee{
ID: getPtr("all-users"),
Type: types.TypeCanonicalUser,
},
Permission: types.PermissionWrite,
},
}
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
_, err := s3client.PutBucketAcl(ctx, &s3.PutBucketAclInput{
Bucket: &bucket,
ACL: types.BucketCannedACLPublicReadWrite,
})
cancel()
if err != nil {
return err
}
ctx, cancel = context.WithTimeout(context.Background(), shortTimeout)
out, err := s3client.GetBucketAcl(ctx, &s3.GetBucketAclInput{
Bucket: &bucket,
})
cancel()
if err != nil {
return err
}
if ok := compareGrants(out.Grants, grants); !ok {
return fmt.Errorf("expected grants to be %v, instead got %v", grants, out.Grants)
}
if *out.Owner.ID != s.awsID {
return fmt.Errorf("expected bucket owner to be %v, instead got %v", s.awsID, *out.Owner.ID)
}
return nil
}, withOwnership(types.ObjectOwnershipBucketOwnerPreferred))
}
func GetBucketAcl_translation_canned_private(s *S3Conf) error {
testName := "GetBucketAcl_translation_canned_private"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
grants := []types.Grant{
{
Grantee: &types.Grantee{
ID: &s.awsID,
Type: types.TypeCanonicalUser,
},
Permission: types.PermissionFullControl,
},
}
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
_, err := s3client.PutBucketAcl(ctx, &s3.PutBucketAclInput{
Bucket: &bucket,
ACL: types.BucketCannedACLPrivate,
})
cancel()
if err != nil {
return err
}
ctx, cancel = context.WithTimeout(context.Background(), shortTimeout)
out, err := s3client.GetBucketAcl(ctx, &s3.GetBucketAclInput{
Bucket: &bucket,
})
cancel()
if err != nil {
return err
}
if ok := compareGrants(out.Grants, grants); !ok {
return fmt.Errorf("expected grants to be %v, instead got %v", grants, out.Grants)
}
if *out.Owner.ID != s.awsID {
return fmt.Errorf("expected bucket owner to be %v, instead got %v", s.awsID, *out.Owner.ID)
}
return nil
}, withOwnership(types.ObjectOwnershipBucketOwnerPreferred))
}
func GetBucketAcl_access_denied(s *S3Conf) error {
testName := "GetBucketAcl_access_denied"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
@@ -6291,6 +6713,15 @@ func GetBucketAcl_success(s *S3Conf) error {
return err
}
grants = append([]types.Grant{
{
Grantee: &types.Grantee{
ID: &s.awsID,
},
Permission: types.PermissionFullControl,
},
}, grants...)
if ok := compareGrants(out.Grants, grants); !ok {
return fmt.Errorf("expected grants to be %v, instead got %v", grants, out.Grants)
}
@@ -6299,7 +6730,7 @@ func GetBucketAcl_success(s *S3Conf) error {
}
return nil
})
}, withOwnership(types.ObjectOwnershipBucketOwnerPreferred))
}
func PutBucketPolicy_non_existing_bucket(s *S3Conf) error {

View File

@@ -66,6 +66,7 @@ func setup(s *S3Conf, bucket string, opts ...setupOpt) error {
_, err := s3client.CreateBucket(ctx, &s3.CreateBucketInput{
Bucket: &bucket,
ObjectLockEnabledForBucket: &cfg.LockEnabled,
ObjectOwnership: cfg.Ownership,
})
cancel()
return err
@@ -121,6 +122,7 @@ func teardown(s *S3Conf, bucket string) error {
type setupCfg struct {
LockEnabled bool
Ownership types.ObjectOwnership
}
type setupOpt func(*setupCfg)
@@ -128,6 +130,9 @@ type setupOpt func(*setupCfg)
func withLock() setupOpt {
return func(s *setupCfg) { s.LockEnabled = true }
}
func withOwnership(o types.ObjectOwnership) setupOpt {
return func(s *setupCfg) { s.Ownership = o }
}
func actionHandler(s *S3Conf, testName string, handler func(s3client *s3.Client, bucket string) error, opts ...setupOpt) error {
runF(testName)

View File

@@ -19,6 +19,7 @@ source ./tests/commands/get_object_legal_hold.sh
source ./tests/commands/get_object_lock_configuration.sh
source ./tests/commands/get_object_retention.sh
source ./tests/commands/get_object_tagging.sh
source ./tests/commands/list_multipart_uploads.sh
source ./tests/commands/list_object_versions.sh
source ./tests/commands/put_bucket_acl.sh
source ./tests/commands/put_bucket_policy.sh
@@ -246,17 +247,17 @@ export RUN_USERS=true
[[ "$(cat "$test_file_folder/$bucket_file-range")" == "9" ]] || fail "byte range not copied properly"
}
#@test "test_get_object_invalid_range" {
# bucket_file="bucket_file"
#
# create_test_files "$bucket_file" || local created=$?
# [[ $created -eq 0 ]] || fail "Error creating test files"
# setup_bucket "s3api" "$BUCKET_ONE_NAME" || local setup_result=$?
# [[ $setup_result -eq 0 ]] || fail "error setting up bucket"
# 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"
#}
@test "test_get_object_invalid_range" {
bucket_file="bucket_file"
create_test_files "$bucket_file" || local created=$?
[[ $created -eq 0 ]] || fail "Error creating test files"
setup_bucket "s3api" "$BUCKET_ONE_NAME" || local setup_result=$?
[[ $setup_result -eq 0 ]] || fail "error setting up bucket"
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"
}
@test "test_put_object" {
bucket_file="bucket_file"
@@ -333,46 +334,48 @@ export RUN_USERS=true
delete_bucket_or_contents "s3api" "$BUCKET_ONE_NAME"
}
@test "test_get_put_object_legal_hold" {
# bucket must be created with lock for legal hold
if [[ $RECREATE_BUCKETS == false ]]; then
return
fi
bucket_file="bucket_file"
username="ABCDEFG"
secret_key="HIJKLMN"
legal_hold_retention_setup "$username" "$secret_key" "$bucket_file"
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'"
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")
[[ $hold_status == "ON" ]] || fail "Status should be 'ON', is '$hold_status'"
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"
# shellcheck disable=SC2154
[[ $put_object_error == *"Object is WORM protected and cannot be overwritten"* ]] || fail "unexpected error message: $put_object_error"
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"
# 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" "$secret_key" || fail "error deleting object after removing legal hold"
delete_bucket_recursive "s3api" "$BUCKET_ONE_NAME"
}
#@test "test_get_put_object_legal_hold" {
# # bucket must be created with lock for legal hold
# if [[ $RECREATE_BUCKETS == false ]]; then
# return
# fi
#
# bucket_file="bucket_file"
# username="ABCDEFG"
# password="HIJKLMN"
#
# legal_hold_retention_setup "$username" "$password" "$bucket_file"
#
# 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'"
#
# 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'"
#
# 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
# # 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
# # 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"
#
# delete_bucket_recursive "s3api" "$BUCKET_ONE_NAME"
#}
#@test "test_get_put_object_retention" {
# # bucket must be created with lock for legal hold
@@ -419,66 +422,27 @@ export RUN_USERS=true
#}
legal_hold_retention_setup() {
if [[ $# -ne 3 ]]; then
log 2 "legal hold or retention setup requires username, secret key, bucket file"
return 1
fi
[[ $# -eq 3 ]] || fail "legal hold or retention setup requires username, secret key, bucket file"
delete_bucket_or_contents_if_exists "s3api" "$BUCKET_ONE_NAME" || fail "error deleting bucket, or checking for existence"
create_user_if_nonexistent "$1" "$2" "user" || fail "error creating user if nonexistent"
setup_user "$1" "$2" "user" || fail "error creating user if nonexistent"
create_test_files "$3" || fail "error creating test files"
#create_bucket "s3api" "$BUCKET_ONE_NAME" || fail "error creating bucket"
create_bucket_object_lock_enabled "$BUCKET_ONE_NAME" || fail "error creating bucket"
change_bucket_owner "$AWS_ACCESS_KEY_ID" "$AWS_SECRET_ACCESS_KEY" "$BUCKET_ONE_NAME" "$1" || fail "error changing bucket ownership"
put_object_with_user "s3api" "$test_file_folder/$3" "$BUCKET_ONE_NAME" "$3" "$AWS_ACCESS_KEY_ID" "$AWS_SECRET_ACCESS_KEY" || fail "failed to add object to bucket"
get_bucket_policy "s3api" "$BUCKET_ONE_NAME" || fail "error getting bucket policy"
log 5 "POLICY: $bucket_policy"
get_bucket_owner "$BUCKET_ONE_NAME"
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"
}
@test "test_put_bucket_acl" {
test_common_put_bucket_acl "s3api"
}
# test ability to retrieve object ACLs
#@test "test_get_object_acl" {
# object_one="test-file-one"
# setup_bucket "$BUCKET_ONE_NAME" || local created=$?
# [[ $created -eq 0 ]] || fail "Error creating bucket"
# create_test_files "$object_one" || local created=$?
# [[ $created -eq 0 ]] || fail "Error creating test file"
# put_object "$test_file_folder"/$object_one "$BUCKET_ONE_NAME"/"$object_one" || local result=$?
# [[ result -eq 0 ]] || fail "Error adding object one"
# get_object_acl "$BUCKET_ONE_NAME" "$object_one" || local result=$?
# [[ $result -eq 0 ]] || fail "Error retrieving acl"
# id=$(echo "$acl" | jq '.Owner.ID')
# [[ $id == '"'"$AWS_ACCESS_KEY_ID"'"' ]] || fail "Acl mismatch"
# delete_bucket_or_contents "$BUCKET_ONE_NAME"
#}
#@test "test_select_object_content" {
# bucket_file="bucket_file"
#
# create_test_files "$bucket_file" || local created=$?
# [[ $created -eq 0 ]] || fail "Error creating test files"
#
# printf "Field,Value\nSomething,Also Something" > "$test_file_folder/$bucket_file"
# cat "$test_file_folder/$bucket_file"
#
# setup_bucket "s3api" "$BUCKET_ONE_NAME" || local created=$?
# [[ $created -eq 0 ]] || fail "Error creating bucket"
# put_object "s3api" "$test_file_folder/$bucket_file" "$BUCKET_ONE_NAME" "$bucket_file" || local copy_result=$?
# [[ $copy_result -eq 0 ]] || fail "Failed to add object to bucket"
# select_object_content "$BUCKET_ONE_NAME" "$bucket_file" "select * from s3object limit 1" "SQL" "{\"CSV\": {}}" "{\"CSV\": {}}" "output.csv"
#}
#@test "test_get_set_versioning" {
# test_common_get_set_versioning "s3api"
#}
# test v1 s3api list objects command
@test "test-s3api-list-objects-v1" {
local object_one="test-file-one"
@@ -548,29 +512,25 @@ legal_hold_retention_setup() {
@test "test-multipart-upload-list-parts" {
local bucket_file="bucket-file"
create_test_files "$bucket_file" || local created=$?
[[ $created -eq 0 ]] || fail "Error creating test files"
create_test_files "$bucket_file" || fail "error creating test file"
dd if=/dev/urandom of="$test_file_folder/$bucket_file" bs=5M count=1 || fail "error creating test file"
setup_bucket "aws" "$BUCKET_ONE_NAME" || local result=$?
[[ $result -eq 0 ]] || fail "Failed to create bucket '$BUCKET_ONE_NAME'"
setup_bucket "aws" "$BUCKET_ONE_NAME" || fail "failed to create bucket '$BUCKET_ONE_NAME'"
list_parts "$BUCKET_ONE_NAME" "$bucket_file" "$test_file_folder"/"$bucket_file" 4 || list_result=$?
[[ list_result -eq 0 ]] || fail "Listing multipart upload parts failed"
list_parts "$BUCKET_ONE_NAME" "$bucket_file" "$test_file_folder"/"$bucket_file" 4 || fail "listing multipart upload parts failed"
declare -a parts_map
# shellcheck disable=SC2154
log 5 "parts: $parts"
for i in {0..3}; do
local part_number
local etag
part_number=$(echo "$parts" | jq ".[$i].PartNumber")
if [[ $part_number -eq "" ]]; then
echo "error: blank part number"
return 1
fi
etag=$(echo "$parts" | jq ".[$i].ETag")
if [[ $etag == "" ]]; then
echo "error: blank etag"
return 1
fi
# 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
@@ -579,12 +539,11 @@ legal_hold_retention_setup() {
for i in {0..3}; do
local part_number
local etag
part_number=$(echo "$listed_parts" | jq ".Parts[$i].PartNumber")
etag=$(echo "$listed_parts" | jq ".Parts[$i].ETag")
if [[ ${parts_map[$part_number]} != "$etag" ]]; then
echo "error: etags don't match (part number: $part_number, etags ${parts_map[$part_number]},$etag)"
return 1
fi
# 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
@@ -598,30 +557,25 @@ legal_hold_retention_setup() {
local bucket_file_two="bucket-file-two"
if [[ $RECREATE_BUCKETS == false ]]; then
abort_all_multipart_uploads "$BUCKET_ONE_NAME" || local abort_result=$?
[[ $abort_result -eq 0 ]] || fail "error aborting all uploads"
abort_all_multipart_uploads "$BUCKET_ONE_NAME" || fail "error aborting all uploads"
fi
create_test_files "$bucket_file_one" "$bucket_file_two" || local created=$?
[[ $created -eq 0 ]] || fail "Error creating test files"
setup_bucket "aws" "$BUCKET_ONE_NAME" || local result=$?
[[ $result -eq 0 ]] || fail "Failed to create bucket '$BUCKET_ONE_NAME'"
create_test_files "$bucket_file_one" "$bucket_file_two" || fail "error creating test files"
setup_bucket "aws" "$BUCKET_ONE_NAME" || fail "failed to create bucket '$BUCKET_ONE_NAME'"
list_multipart_uploads "$BUCKET_ONE_NAME" "$test_file_folder"/"$bucket_file_one" "$test_file_folder"/"$bucket_file_two" || fail "failed to list multipart uploads"
create_and_list_multipart_uploads "$BUCKET_ONE_NAME" "$test_file_folder"/"$bucket_file_one" "$test_file_folder"/"$bucket_file_two" || fail "failed to list multipart uploads"
local key_one
local key_two
log 5 "$uploads"
key_one=$(echo "$uploads" | jq '.Uploads[0].Key')
key_two=$(echo "$uploads" | jq '.Uploads[1].Key')
# shellcheck disable=SC2154
log 5 "Uploads: $uploads"
raw_uploads=$(echo "$uploads" | grep -v "InsecureRequestWarning")
key_one=$(echo "$raw_uploads" | jq -r '.Uploads[0].Key' 2>&1) || fail "error getting key one: $key_one"
key_two=$(echo "$raw_uploads" | jq -r '.Uploads[1].Key' 2>&1) || fail "error getting key two: $key_two"
key_one=${key_one//\"/}
key_two=${key_two//\"/}
if [[ "$test_file_folder/$bucket_file_one" != *"$key_one" ]]; then
fail "Key mismatch ($test_file_folder/$bucket_file_one, $key_one)"
fi
if [[ "$test_file_folder/$bucket_file_two" != *"$key_two" ]]; then
fail "Key mismatch ($test_file_folder/$bucket_file_two, $key_two)"
fi
[[ "$test_file_folder/$bucket_file_one" == *"$key_one" ]] || fail "Key mismatch ($test_file_folder/$bucket_file_one, $key_one)"
[[ "$test_file_folder/$bucket_file_two" == *"$key_two" ]] || fail "Key mismatch ($test_file_folder/$bucket_file_two, $key_two)"
delete_bucket_or_contents "aws" "$BUCKET_ONE_NAME"
delete_test_files "$bucket_file_one" "$bucket_file_two"
@@ -690,24 +644,20 @@ legal_hold_retention_setup() {
@test "test-list-objects-delimiter" {
folder_name="two"
object_name="three"
create_test_folder "$folder_name" || local created=$?
[[ $created -eq 0 ]] || fail "error creating folder"
create_test_files "$folder_name"/"$object_name" || created=$?
[[ $created -eq 0 ]] || fail "error creating file"
create_test_folder "$folder_name" || fail "error creating folder"
create_test_files "$folder_name"/"$object_name" || fail "error creating file"
setup_bucket "aws" "$BUCKET_ONE_NAME" || local setup_result=$?
[[ $setup_result -eq 0 ]] || fail "error setting up bucket"
setup_bucket "aws" "$BUCKET_ONE_NAME" || fail "error setting up bucket"
put_object "aws" "$test_file_folder/$folder_name/$object_name" "$BUCKET_ONE_NAME" "$folder_name/$object_name" || local copy_result=$?
[[ $copy_result -eq 0 ]] || fail "Failed to add object to bucket"
put_object "aws" "$test_file_folder/$folder_name/$object_name" "$BUCKET_ONE_NAME" "$folder_name/$object_name" || fail "failed to add object to bucket"
list_objects_s3api_v1 "$BUCKET_ONE_NAME" "/"
prefix=$(echo "${objects[@]}" | jq ".CommonPrefixes[0].Prefix")
[[ $prefix == "\""$folder_name/"\"" ]] || fail "prefix doesn't match (expected $prefix, actual $folder_name/)"
prefix=$(echo "${objects[@]}" | jq -r ".CommonPrefixes[0].Prefix" 2>&1) || fail "error getting object prefix from object list: $prefix"
[[ $prefix == "$folder_name/" ]] || fail "prefix doesn't match (expected $prefix, actual $folder_name/)"
list_objects_s3api_v1 "$BUCKET_ONE_NAME" "#"
key=$(echo "${objects[@]}" | jq ".Contents[0].Key")
[[ $key == "\""$folder_name/$object_name"\"" ]] || fail "prefix doesn't match (expected $prefix, actual $folder_name/)"
key=$(echo "${objects[@]}" | jq -r ".Contents[0].Key" 2>&1) || fail "error getting key from object list: $key"
[[ $key == "$folder_name/$object_name" ]] || fail "key doesn't match (expected $key, actual $folder_name/$object_name)"
delete_bucket_or_contents "aws" "$BUCKET_ONE_NAME"
delete_test_files $folder_name
@@ -800,10 +750,6 @@ EOF
action="s3:GetObject"
resource="arn:aws:s3:::$BUCKET_ONE_NAME/$test_file"
if user_exists "$username"; then
delete_user "$username" || fail "failed to delete user '$username'"
fi
setup_policy_with_single_statement "$test_file_folder/$policy_file" "2012-10-17" "$effect" "$principal" "$action" "$resource" || fail "failed to set up policy"
setup_bucket "s3api" "$BUCKET_ONE_NAME" || fail "error setting up bucket"
@@ -814,32 +760,7 @@ EOF
check_for_empty_policy "s3api" "$BUCKET_ONE_NAME" || fail "policy not empty after deletion"
fi
if put_bucket_policy "s3api" "$BUCKET_ONE_NAME" "$test_file_folder/$policy_file"; then
fail "put succeeded despite invalid username"
fi
[[ "$put_bucket_policy_error" == *"MalformedPolicy"* ]] || fail "invalid policy error: $put_bucket_policy_error"
# cat <<EOF > "$test_file_folder"/acl_file
#{
# "Grants": [
# {
# "Grantee": {
# "ID": "ABCDEFG",
# "Type": "CanonicalUser"
# },
# "Permission": "READ"
# }
# ],
# "Owner": {
# "ID": "$AWS_ACCESS_KEY_ID"
# }
#}
#EOF
#
#put_bucket_acl "s3api" "$BUCKET_ONE_NAME" "$test_file_folder/acl_file" || fail "error putting acl"
#put_bucket_canned_acl "$BUCKET_ONE_NAME" "public-read-write" || fail "error putting acl"
create_user "$username" "$password" "user" || fail "error creating user"
setup_user "$username" "$password" "user" || fail "error creating user"
if get_object_with_user "s3api" "$BUCKET_ONE_NAME" "$test_file" "$test_file_folder/$test_file-copy" "$username" "$password"; then
fail "get object with user succeeded despite lack of permissions"
fi
@@ -847,8 +768,6 @@ EOF
[[ "$get_object_error" == *"Access Denied"* ]] || fail "invalid get object error: $get_object_error"
put_bucket_policy "s3api" "$BUCKET_ONE_NAME" "$test_file_folder/$policy_file" || fail "error putting policy"
#get_bucket_policy "s3api" "$BUCKET_ONE_NAME" || fail "error getting bucket policy"
#log 5 "$bucket_policy"
get_object_with_user "s3api" "$BUCKET_ONE_NAME" "$test_file" "$test_file_folder/$test_file-copy" "$username" "$password" || fail "error getting object after permissions"
compare_files "$test_file_folder/$test_file" "$test_file_folder/$test_file-copy" || fail "files not equal"
delete_bucket_or_contents "aws" "$BUCKET_ONE_NAME"
@@ -875,10 +794,7 @@ EOF
action="s3:GetObject"
resource="arn:aws:s3:::$BUCKET_ONE_NAME/test_file"
if user_exists "$username"; then
delete_user "$username" || fail "failed to delete user '$username'"
fi
create_user "$username" "$password" "user" || fail "error creating user"
setup_user "$username" "$password" "user" || fail "error creating user"
setup_bucket "s3api" "$BUCKET_ONE_NAME" || fail "error setting up bucket"
setup_policy_with_single_statement "$test_file_folder/$policy_file" "dummy" "$effect" "$principal" "$action" "$resource" || fail "failed to set up policy"
@@ -916,10 +832,7 @@ EOF
action="s3:GetObject"
resource="arn:aws:s3:::$BUCKET_ONE_NAME/policy_file*"
if user_exists "$username"; then
delete_user "$username" || fail "failed to delete user '$username'"
fi
create_user "$username" "$password" "user" || fail "error creating user account"
setup_user "$username" "$password" "user" || fail "error creating user account"
setup_bucket "s3api" "$BUCKET_ONE_NAME" || fail "error setting up bucket"
setup_policy_with_single_statement "$test_file_folder/$policy_file" "dummy" "$effect" "$principal" "$action" "$resource" || fail "failed to set up policy"
@@ -959,10 +872,7 @@ EOF
action="s3:GetObject"
resource="arn:aws:s3:::$BUCKET_ONE_NAME/$test_folder/*"
if user_exists "$username"; then
delete_user "$username" || fail "failed to delete user '$username'"
fi
create_user "$username" "$password" "user" || fail "error creating user"
setup_user "$username" "$password" "user" || fail "error creating user"
setup_bucket "s3api" "$BUCKET_ONE_NAME" || fail "error setting up bucket"
setup_policy_with_single_statement "$test_file_folder/$policy_file" "dummy" "$effect" "$principal" "$action" "$resource" || fail "failed to set up policy"
@@ -1006,10 +916,7 @@ EOF
}
EOF
if user_exists "$username"; then
delete_user "$username" || fail "failed to delete user '$username'"
fi
create_user "$username" "$password" "user" || fail "error creating user"
setup_user "$username" "$password" "user" || fail "error creating user"
setup_bucket "s3api" "$BUCKET_ONE_NAME" || fail "error setting up bucket"
put_bucket_policy "s3api" "$BUCKET_ONE_NAME" "$test_file_folder/$policy_file" || fail "error putting policy"
put_object "s3api" "$test_file_folder/$test_file" "$BUCKET_ONE_NAME" "$test_file" || fail "error copying object to bucket"
@@ -1056,10 +963,7 @@ EOF
}
EOF
if user_exists "$username"; then
delete_user "$username" || fail "failed to delete user '$username'"
fi
create_user "$username" "$password" "user" || fail "error creating user"
setup_user "$username" "$password" "user" || fail "error creating user"
setup_bucket "s3api" "$BUCKET_ONE_NAME" || fail "error setting up bucket"
log 5 "Policy: $(cat "$test_file_folder/$policy_file")"
@@ -1096,10 +1000,7 @@ EOF
action="s3:PutObject"
resource="arn:aws:s3:::$BUCKET_ONE_NAME/$test_folder/*"
if user_exists "$username"; then
delete_user "$username" || fail "failed to delete user '$username'"
fi
create_user "$username" "$password" "user" || fail "error creating user"
setup_user "$username" "$password" "user" || fail "error creating user"
setup_bucket "s3api" "$BUCKET_ONE_NAME" || fail "error setting up bucket"
log 5 "Policy: $(cat "$test_file_folder/$policy_file")"
@@ -1110,11 +1011,220 @@ EOF
fi
[[ "$put_object_error" == *"Access Denied"* ]] || fail "invalid put object error: $put_object_error"
put_object_with_user "s3api" "$test_file_folder/$test_folder/$test_file" "$BUCKET_ONE_NAME" "$test_folder/$test_file" "$username" "$password" || fail "error putting file despite policy permissions"
if get_object_with_user "s3api" "$BUCKET_ONE_NAME" "$test_folder/$test_file" "$test_folder/$test_file-copy" "$username" "$password"; then
fail "able to get object without permissions"
fi
[[ "$get_object_error" == *"Access Denied"* ]] || fail "invalid get object error: $get_object_error"
download_and_compare_file "s3api" "$test_file_folder/$test_folder/$test_file" "$BUCKET_ONE_NAME" "$test_folder/$test_file" "$test_file_folder/$test_file-copy" || fail "files don't match"
delete_bucket_or_contents "aws" "$BUCKET_ONE_NAME"
delete_test_files "$test_folder/$test_file" "$test_file-copy" "$policy_file"
}
@test "test_policy_delete" {
# TODO (https://github.com/versity/versitygw/issues/637)
if [[ $RECREATE_BUCKETS == "false" ]]; then
return 0
fi
policy_file="policy_file"
test_file_one="test_file_one"
test_file_two="test_file_two"
username="ABCDEFG"
password="HIJKLMN"
create_test_files "$test_file_one" "$test_file_two" "$policy_file" || fail "error creating policy file, test files"
echo "$BATS_TEST_NAME" >> "$test_file_folder/$test_file_one"
echo "$BATS_TEST_NAME" >> "$test_file_folder/$test_file_two"
effect="Allow"
principal="$username"
action="s3:DeleteObject"
resource="arn:aws:s3:::$BUCKET_ONE_NAME/$test_file_two"
setup_user "$username" "$password" "user" || fail "error creating user"
setup_bucket "s3api" "$BUCKET_ONE_NAME" || fail "error setting up bucket"
setup_policy_with_single_statement "$test_file_folder/$policy_file" "dummy" "$effect" "$principal" "$action" "$resource" || fail "failed to set up policy"
log 5 "Policy: $(cat "$test_file_folder/$policy_file")"
put_bucket_policy "s3api" "$BUCKET_ONE_NAME" "$test_file_folder/$policy_file" || fail "error putting policy"
put_object "s3api" "$test_file_folder/$test_file_one" "$BUCKET_ONE_NAME" "$test_file_one" || fail "error copying object one"
put_object "s3api" "$test_file_folder/$test_file_two" "$BUCKET_ONE_NAME" "$test_file_two" || fail "error copying object two"
if delete_object_with_user "s3api" "$BUCKET_ONE_NAME" "$test_file_one" "$username" "$password"; then
fail "able to delete object despite lack of permissions"
fi
[[ "$delete_object_error" == *"Access Denied"* ]] || fail "invalid delete object error: $delete_object_error"
delete_object_with_user "s3api" "$BUCKET_ONE_NAME" "$test_file_two" "$username" "$password" || fail "error deleting object despite permissions"
delete_bucket_or_contents "aws" "$BUCKET_ONE_NAME"
delete_test_files "$test_file_one" "$test_file_two" "$policy_file"
}
@test "test_policy_get_bucket_policy" {
# TODO (https://github.com/versity/versitygw/issues/637)
if [[ $RECREATE_BUCKETS == "false" ]]; then
return 0
fi
policy_file="policy_file"
username="ABCDEFG"
password="HIJKLMN"
create_test_files "$policy_file" || fail "error creating policy file, test files"
effect="Allow"
principal="$username"
action="s3:GetBucketPolicy"
resource="arn:aws:s3:::$BUCKET_ONE_NAME"
setup_user "$username" "$password" "user" || fail "error creating user"
setup_bucket "s3api" "$BUCKET_ONE_NAME" || fail "error setting up bucket"
setup_policy_with_single_statement "$test_file_folder/$policy_file" "dummy" "$effect" "$principal" "$action" "$resource" || fail "failed to set up policy"
if get_bucket_policy_with_user "$BUCKET_ONE_NAME" "$username" "$password"; then
fail "able to retrieve bucket policy despite lack of permissions"
fi
put_bucket_policy "s3api" "$BUCKET_ONE_NAME" "$test_file_folder/$policy_file" || fail "error putting policy"
get_bucket_policy_with_user "$BUCKET_ONE_NAME" "$username" "$password" || fail "error getting bucket policy despite permissions"
# shellcheck disable=SC2154
echo "$bucket_policy" > "$test_file_folder/$policy_file-copy"
log 5 "ORIG: $(cat "$test_file_folder/$policy_file")"
log 5 "COPY: $(cat "$test_file_folder/$policy_file-copy")"
compare_files "$test_file_folder/$policy_file" "$test_file_folder/$policy_file-copy" || fail "policies not equal"
delete_bucket_or_contents "aws" "$BUCKET_ONE_NAME"
delete_test_files "$policy_file" "$policy_file-copy"
}
@test "test_policy_list_multipart_uploads" {
# TODO (https://github.com/versity/versitygw/issues/637)
if [[ $RECREATE_BUCKETS == "false" ]]; then
return 0
fi
policy_file="policy_file"
test_file="test_file"
username="ABCDEFG"
password="HIJKLMN"
create_test_files "$policy_file" || fail "error creating policy file, test files"
create_large_file "$test_file" || error creating file "$test_file"
effect="Allow"
principal="$username"
action="s3:ListBucketMultipartUploads"
resource="arn:aws:s3:::$BUCKET_ONE_NAME"
setup_user "$username" "$password" "user" || fail "error creating user"
setup_bucket "s3api" "$BUCKET_ONE_NAME" || fail "error setting up bucket"
setup_policy_with_single_statement "$test_file_folder/$policy_file" "dummy" "$effect" "$principal" "$action" "$resource" || fail "failed to set up policy"
create_multipart_upload "$BUCKET_ONE_NAME" "$test_file" || fail "error creating multipart upload"
if list_multipart_uploads_with_user "$BUCKET_ONE_NAME" "$username" "$password"; then
log 2 "able to list multipart uploads despite lack of permissions"
fi
# shellcheck disable=SC2154
[[ "$list_multipart_uploads_error" == *"Access Denied"* ]] || fail "invalid list multipart uploads error: $list_multipart_uploads_error"
put_bucket_policy "s3api" "$BUCKET_ONE_NAME" "$test_file_folder/$policy_file" || fail "error putting policy"
list_multipart_uploads_with_user "$BUCKET_ONE_NAME" "$username" "$password" || fail "error listing multipart uploads"
log 5 "$uploads"
upload_key=$(echo "$uploads" | grep -v "InsecureRequestWarning" | jq -r ".Uploads[0].Key" 2>&1) || fail "error parsing upload key from uploads message: $upload_key"
[[ $upload_key == "$test_file" ]] || fail "upload key doesn't match file marked as being uploaded"
delete_bucket_or_contents "aws" "$BUCKET_ONE_NAME"
delete_test_files "$policy_file" "$test_file"
}
@test "test_policy_put_bucket_policy" {
# TODO (https://github.com/versity/versitygw/issues/637)
if [[ $RECREATE_BUCKETS == "false" ]]; then
return 0
fi
policy_file="policy_file"
policy_file_two="policy_file_two"
username="ABCDEFG"
password="HIJKLMN"
create_test_files "$policy_file" || fail "error creating policy file, test files"
effect="Allow"
principal="$username"
action="s3:PutBucketPolicy"
resource="arn:aws:s3:::$BUCKET_ONE_NAME"
setup_user "$username" "$password" "user" || fail "error creating user"
setup_bucket "s3api" "$BUCKET_ONE_NAME" || fail "error setting up bucket"
setup_policy_with_single_statement "$test_file_folder/$policy_file" "dummy" "$effect" "$principal" "$action" "$resource" || fail "failed to set up policy"
if put_bucket_policy_with_user "$BUCKET_ONE_NAME" "$test_file_folder/$policy_file" "$username" "$password"; then
fail "able to retrieve bucket policy despite lack of permissions"
fi
put_bucket_policy "s3api" "$BUCKET_ONE_NAME" "$test_file_folder/$policy_file" || fail "error putting policy"
setup_policy_with_single_statement "$test_file_folder/$policy_file_two" "dummy" "$effect" "$principal" "s3:GetBucketPolicy" "$resource" || fail "failed to set up policy"
put_bucket_policy_with_user "$BUCKET_ONE_NAME" "$test_file_folder/$policy_file_two" "$username" "$password" || fail "error putting bucket policy despite permissions"
get_bucket_policy_with_user "$BUCKET_ONE_NAME" "$username" "$password" || fail "error getting bucket policy despite permissions"
# shellcheck disable=SC2154
echo "$bucket_policy" > "$test_file_folder/$policy_file-copy"
log 5 "ORIG: $(cat "$test_file_folder/$policy_file_two")"
log 5 "COPY: $(cat "$test_file_folder/$policy_file-copy")"
compare_files "$test_file_folder/$policy_file_two" "$test_file_folder/$policy_file-copy" || fail "policies not equal"
delete_bucket_or_contents "aws" "$BUCKET_ONE_NAME"
delete_test_files "$policy_file" "$policy_file_two" "$policy_file-copy"
}
@test "test_policy_delete_bucket_policy" {
# TODO (https://github.com/versity/versitygw/issues/637)
if [[ $RECREATE_BUCKETS == "false" ]]; then
return 0
fi
policy_file="policy_file"
username="ABCDEFG"
password="HIJKLMN"
create_test_files "$policy_file" || fail "error creating policy file, test files"
effect="Allow"
principal="$username"
action="s3:DeleteBucketPolicy"
resource="arn:aws:s3:::$BUCKET_ONE_NAME"
setup_user "$username" "$password" "user" || fail "error creating user"
setup_bucket "s3api" "$BUCKET_ONE_NAME" || fail "error setting up bucket"
if delete_bucket_policy_with_user "$BUCKET_ONE_NAME" "$username" "$password"; then
fail "able to delete bucket policy with user $username without right permissions"
fi
setup_policy_with_single_statement "$test_file_folder/$policy_file" "dummy" "$effect" "$principal" "$action" "$resource" || fail "failed to set up policy"
put_bucket_policy "s3api" "$BUCKET_ONE_NAME" "$test_file_folder/$policy_file" || fail "error putting policy"
delete_bucket_policy_with_user "$BUCKET_ONE_NAME" "$username" "$password" || fail "unable to delete bucket policy"
delete_bucket_or_contents "aws" "$BUCKET_ONE_NAME"
delete_test_files "$policy_file"
}
@test "test_policy_get_bucket_acl" {
# TODO (https://github.com/versity/versitygw/issues/637)
if [[ $RECREATE_BUCKETS == "false" ]]; then
return 0
fi
policy_file="policy_file"
username="ABCDEFG"
password="HIJKLMN"
create_test_files "$policy_file" || fail "error creating policy file, test files"
effect="Allow"
principal="$username"
action="s3:GetBucketAcl"
resource="arn:aws:s3:::$BUCKET_ONE_NAME"
setup_user "$username" "$password" "user" || fail "error creating user"
setup_bucket "s3api" "$BUCKET_ONE_NAME" || fail "error setting up bucket"
#put_bucket_canned_acl "$BUCKET_ONE_NAME" "private" || fail "error putting bucket canned ACL"
if get_bucket_acl_with_user "$BUCKET_ONE_NAME" "$username" "$password"; then
fail "user able to get bucket ACLs despite permissions"
fi
setup_policy_with_single_statement "$test_file_folder/$policy_file" "dummy" "$effect" "$principal" "$action" "$resource" || fail "failed to set up policy"
put_bucket_policy "s3api" "$BUCKET_ONE_NAME" "$test_file_folder/$policy_file" || fail "error putting policy"
get_bucket_acl_with_user "$BUCKET_ONE_NAME" "$username" "$password" || fail "error getting bucket ACL despite permissions"
}
# ensure that lists of files greater than a size of 1000 (pagination) are returned properly
#@test "test_list_objects_file_count" {
# test_common_list_objects_file_count "aws"
@@ -1145,15 +1255,18 @@ EOF
#}
@test "test_head_bucket" {
setup_bucket "aws" "$BUCKET_ONE_NAME" || local setup_result=$?
[[ $setup_result -eq 0 ]] || fail "error setting up bucket"
head_bucket "aws" "$BUCKET_ONE_NAME"
setup_bucket "aws" "$BUCKET_ONE_NAME" || fail "error setting up bucket"
head_bucket "aws" "$BUCKET_ONE_NAME" || fail "error getting bucket info"
log 5 "INFO: $bucket_info"
region=$(echo "$bucket_info" | grep -v "InsecureRequestWarning" | jq -r ".BucketRegion" 2>&1) || fail "error getting bucket region: $region"
[[ $region != "" ]] || fail "empty bucket region"
delete_bucket_or_contents "aws" "$BUCKET_ONE_NAME"
}
@test "test_head_bucket_invalid_name" {
head_bucket "aws" "" || local head_result=$?
[[ $head_result -ne 0 ]] || fail "able to get bucket info for invalid name"
if head_bucket "aws" ""; then
fail "able to get bucket info for invalid name"
fi
}
@test "test_head_bucket_doesnt_exist" {
@@ -1170,23 +1283,90 @@ EOF
test_key="x-test-data"
test_value="test-value"
create_test_files "$object_one" || local created=$?
[[ $created -eq 0 ]] || fail "Error creating test files"
create_test_files "$object_one" || fail "error creating test files"
setup_bucket "aws" "$BUCKET_ONE_NAME" || local setup_result=$?
[[ $setup_result -eq 0 ]] || fail "error setting up bucket"
setup_bucket "aws" "$BUCKET_ONE_NAME" || fail "error setting up bucket"
object="$test_file_folder"/"$object_one"
put_object_with_metadata "aws" "$object" "$BUCKET_ONE_NAME" "$object_one" "$test_key" "$test_value" || copy_result=$?
[[ $copy_result -eq 0 ]] || fail "Failed to add object to bucket"
object_exists "aws" "$BUCKET_ONE_NAME" "$object_one" || local exists_result_one=$?
[[ $exists_result_one -eq 0 ]] || fail "Object not added to bucket"
put_object_with_metadata "aws" "$object" "$BUCKET_ONE_NAME" "$object_one" "$test_key" "$test_value" || fail "failed to add object to bucket"
object_exists "aws" "$BUCKET_ONE_NAME" "$object_one" || fail "object not found after being added to bucket"
get_object_metadata "aws" "$BUCKET_ONE_NAME" "$object_one" || get_result=$?
[[ $get_result -eq 0 ]] || fail "error getting object metadata"
key=$(echo "$metadata" | jq 'keys[]')
value=$(echo "$metadata" | jq '.[]')
[[ $key == "\"$test_key\"" ]] || fail "keys doesn't match (expected $key, actual \"$test_key\")"
[[ $value == "\"$test_value\"" ]] || fail "values doesn't match (expected $value, actual \"$test_value\")"
get_object_metadata "aws" "$BUCKET_ONE_NAME" "$object_one" || fail "error getting object metadata"
key=$(echo "$metadata" | jq -r 'keys[]' 2>&1) || fail "error getting key from metadata: $key"
value=$(echo "$metadata" | jq -r '.[]' 2>&1) || fail "error getting value from metadata: $value"
[[ $key == "$test_key" ]] || fail "keys doesn't match (expected $key, actual \"$test_key\")"
[[ $value == "$test_value" ]] || fail "values doesn't match (expected $value, actual \"$test_value\")"
delete_bucket_or_contents "aws" "$BUCKET_ONE_NAME"
delete_test_files "$object_one"
}
@test "test_policy_abort_multipart_upload" {
policy_file="policy_file"
test_file="test_file"
username="ABCDEFG"
create_test_files "$policy_file" || fail "error creating policy file"
create_large_file "$test_file" || fail "error creating large file"
setup_bucket "s3api" "$BUCKET_ONE_NAME" || fail "error setting up bucket"
if [[ $DIRECT == "true" ]]; then
setup_user_direct "$username" "user" "$BUCKET_ONE_NAME" || fail "error setting up direct user $username"
principal="{\"AWS\": \"arn:aws:iam::$DIRECT_AWS_USER_ID:user/$username\"}"
# shellcheck disable=SC2154
username=$key_id
# shellcheck disable=SC2154
password=$secret_key
else
password="HIJLKMN"
setup_user "$username" "$password" "user" || fail "error setting up user $username"
principal="\"$username\""
fi
cat <<EOF > "$test_file_folder"/$policy_file
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": $principal,
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::$BUCKET_ONE_NAME/*"
},
{
"Effect": "Deny",
"Principal": $principal,
"Action": "s3:AbortMultipartUpload",
"Resource": "arn:aws:s3:::$BUCKET_ONE_NAME/*"
}
]
}
EOF
put_bucket_policy "s3api" "$BUCKET_ONE_NAME" "$test_file_folder/$policy_file" || fail "error putting first policy"
create_multipart_upload_with_user "$BUCKET_ONE_NAME" "$test_file" "$username" "$password" || fail "error creating multipart upload"
if abort_multipart_upload_with_user "$BUCKET_ONE_NAME" "$test_file" "$upload_id" "$username" "$password"; then
fail "abort multipart upload succeeded despite lack of permissions"
fi
# shellcheck disable=SC2154
[[ "$abort_multipart_upload_error" == *"AccessDenied"* ]] || fail "unexpected abort error: $abort_multipart_upload_error"
cat <<EOF > "$test_file_folder"/$policy_file
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": $principal,
"Action": "s3:AbortMultipartUpload",
"Resource": "arn:aws:s3:::$BUCKET_ONE_NAME/*"
}
]
}
EOF
put_bucket_policy "s3api" "$BUCKET_ONE_NAME" "$test_file_folder/$policy_file" || fail "error putting policy"
abort_multipart_upload_with_user "$BUCKET_ONE_NAME" "$test_file" "$upload_id" "$username" "$password" || fail "error aborting multipart upload despite permissions"
delete_bucket_or_contents "aws" "$BUCKET_ONE_NAME"
delete_test_files "$policy_file" "$test_file"
}

View File

@@ -47,14 +47,11 @@ test_common_create_delete_bucket() {
fail "create/delete bucket test requires command type"
fi
setup_bucket "$1" "$BUCKET_ONE_NAME" || local create_result=$?
[[ $create_result -eq 0 ]] || fail "Failed to create bucket"
setup_bucket "$1" "$BUCKET_ONE_NAME" || fail "failed to create bucket"
bucket_exists "$1" "$BUCKET_ONE_NAME" || local exists_three=$?
[[ $exists_three -eq 0 ]] || fail "Failed bucket existence check"
bucket_exists "$1" "$BUCKET_ONE_NAME" || fail "failed bucket existence check"
delete_bucket_or_contents "$1" "$BUCKET_ONE_NAME" || local delete_result_two=$?
[[ $delete_result_two -eq 0 ]] || fail "Failed to delete bucket"
delete_bucket_or_contents "$1" "$BUCKET_ONE_NAME" || fail "failed to delete bucket"
}
test_common_copy_object() {
@@ -435,21 +432,18 @@ test_common_get_bucket_location() {
test_common_put_bucket_acl() {
[[ $# -eq 1 ]] || fail "test common put bucket acl missing command type"
setup_bucket "$1" "$BUCKET_ONE_NAME" || fail "error creating bucket"
setup_bucket "$1" "$BUCKET_ONE_NAME" || fail "error creating bucket"
put_bucket_ownership_controls "$BUCKET_ONE_NAME" "BucketOwnerPreferred" || fail "error putting bucket ownership controls"
if ! user_exists "ABCDEFG"; then
create_user "ABCDEFG" "HIJKLMN" user || fail "error creating user"
fi
setup_user "ABCDEFG" "HIJKLMN" "user" || fail "error creating user"
get_bucket_acl "$1" "$BUCKET_ONE_NAME" || local result=$?
[[ $result -eq 0 ]] || fail "Error retrieving acl"
get_bucket_acl "$1" "$BUCKET_ONE_NAME" || fail "error retrieving acl"
log 5 "Initial ACLs: $acl"
id=$(echo "$acl" | grep -v "InsecureRequestWarning" | jq '.Owner.ID')
id=$(echo "$acl" | grep -v "InsecureRequestWarning" | jq '.Owner.ID' 2>&1) || fail "error getting ID: $id"
if [[ $id != '"'"$AWS_ACCESS_KEY_ID"'"' ]]; then
# in some cases, ID is canonical user ID rather than AWS_ACCESS_KEY_ID
canonical_id=$(aws --no-verify-ssl s3api list-buckets --query 'Owner.ID') || local list_result=$?
[[ $list_result -eq 0 ]] || fail "error getting canonical ID: $canonical_id"
# for direct, ID is canonical user ID rather than AWS_ACCESS_KEY_ID
canonical_id=$(aws --no-verify-ssl s3api list-buckets --query 'Owner.ID' 2>&1) || fail "error getting caononical ID: $canonical_id"
[[ $id == "$canonical_id" ]] || fail "acl ID doesn't match AWS key or canonical ID"
fi
@@ -480,12 +474,11 @@ EOF
put_bucket_acl "$1" "$BUCKET_ONE_NAME" "ABCDEFG" || fail "error putting first acl"
fi
get_bucket_acl "$1" "$BUCKET_ONE_NAME" || local result=$?
[[ $result -eq 0 ]] || fail "Error retrieving second acl"
get_bucket_acl "$1" "$BUCKET_ONE_NAME" || fail "error retrieving second ACL"
log 5 "Acls after 1st put: $acl"
public_grants=$(echo "$acl" | grep -v "InsecureRequestWarning" | jq -r '.Grants[0]')
permission=$(echo "$public_grants" | jq -r '.Permission')
public_grants=$(echo "$acl" | grep -v "InsecureRequestWarning" | jq -r '.Grants[1]' 2>&1) || fail "error getting public grants: $public_grants"
permission=$(echo "$public_grants" | jq -r '.Permission' 2>&1) || fail "error getting permission: $permission"
[[ $permission == "READ" ]] || fail "incorrect permission ($permission)"
cat <<EOF > "$test_file_folder"/"$acl_file"
@@ -505,17 +498,15 @@ cat <<EOF > "$test_file_folder"/"$acl_file"
}
EOF
put_bucket_acl "$1" "$BUCKET_ONE_NAME" "$test_file_folder"/"$acl_file" || local put_result=$?
[[ $put_result -eq 0 ]] || fail "Error putting second acl"
put_bucket_acl "$1" "$BUCKET_ONE_NAME" "$test_file_folder"/"$acl_file" || fail "error putting second acl"
get_bucket_acl "$1" "$BUCKET_ONE_NAME" || local result=$?
[[ $result -eq 0 ]] || fail "Error retrieving second acl"
get_bucket_acl "$1" "$BUCKET_ONE_NAME" || fail "error retrieving second ACL"
log 5 "Acls after 2nd put: $acl"
public_grants=$(echo "$acl" | grep -v "InsecureRequestWarning" | jq -r '.Grants')
public_grant_length=$(echo "$public_grants" | jq 'length')
[[ $public_grant_length -eq 1 ]] || fail "incorrect grant length for private ACL ($public_grant_length)"
permission=$(echo "$public_grants" | jq -r '.[0].Permission')
public_grants=$(echo "$acl" | grep -v "InsecureRequestWarning" | jq -r '.Grants' 2>&1) || fail "error retrieving public grants: $public_grants"
public_grant_length=$(echo "$public_grants" | jq -r 'length' 2>&1) || fail "Error retrieving public grant length: $public_grant_length"
[[ $public_grant_length -eq 2 ]] || fail "incorrect grant length for private ACL ($public_grant_length)"
permission=$(echo "$public_grants" | jq -r '.[0].Permission' 2>&1) || fail "Error retrieving permission: $permission"
[[ $permission == "FULL_CONTROL" ]] || fail "incorrect permission ($permission)"
delete_bucket_or_contents "$1" "$BUCKET_ONE_NAME"
@@ -526,48 +517,55 @@ test_common_get_put_delete_bucket_policy() {
policy_file="policy_file"
create_test_files "$policy_file" || local created=$?
[[ $created -eq 0 ]] || fail "Error creating policy file"
create_test_files "$policy_file" || fail "error creating policy file"
effect="Allow"
principal="*"
#principal="*"
if [[ $DIRECT == "true" ]]; then
principal="{\"AWS\": \"arn:aws:iam::$DIRECT_AWS_USER_ID:user/s3user\"}"
else
principal="\"*\""
fi
action="s3:GetObject"
resource="arn:aws:s3:::$BUCKET_ONE_NAME/*"
cat <<EOF > "$test_file_folder"/$policy_file
{
"Version": "2012-10-17",
"Statement": [
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "$effect",
"Principal": "$principal",
"Action": "$action",
"Resource": "$resource"
}
]
"Effect": "$effect",
"Principal": $principal,
"Action": "$action",
"Resource": "$resource"
}
]
}
EOF
log 5 "POLICY: $(cat "$test_file_folder/$policy_file")"
setup_bucket "$1" "$BUCKET_ONE_NAME" || local setup_result=$?
[[ $setup_result -eq 0 ]] || fail "error setting up bucket"
setup_bucket "$1" "$BUCKET_ONE_NAME" || fail "error setting up bucket"
check_for_empty_policy "$1" "$BUCKET_ONE_NAME" || check_result=$?
[[ $get_result -eq 0 ]] || fail "policy not empty"
check_for_empty_policy "$1" "$BUCKET_ONE_NAME" || fail "policy not empty"
put_bucket_policy "$1" "$BUCKET_ONE_NAME" "$test_file_folder"/"$policy_file" || put_result=$?
[[ $put_result -eq 0 ]] || fail "error putting bucket"
put_bucket_policy "$1" "$BUCKET_ONE_NAME" "$test_file_folder"/"$policy_file" || fail "error putting bucket policy"
get_bucket_policy "$1" "$BUCKET_ONE_NAME" || local get_result=$?
[[ $get_result -eq 0 ]] || fail "error getting bucket policy after setting"
get_bucket_policy "$1" "$BUCKET_ONE_NAME" || fail "error getting bucket policy after setting"
log 5 "$bucket_policy"
returned_effect=$(echo "$bucket_policy" | jq -r '.Statement[0].Effect')
# shellcheck disable=SC2154
log 5 "POLICY: $bucket_policy"
statement=$(echo "$bucket_policy" | jq -r '.Statement[0]' 2>&1) || fail "error getting statement value: $statement"
returned_effect=$(echo "$statement" | jq -r '.Effect' 2>&1) || fail "error getting effect: $returned_effect"
[[ $effect == "$returned_effect" ]] || fail "effect mismatch ($effect, $returned_effect)"
returned_principal=$(echo "$bucket_policy" | jq -r '.Statement[0].Principal')
[[ $principal == "$returned_principal" ]] || fail "principal mismatch ($principal, $returned_principal)"
returned_action=$(echo "$bucket_policy" | jq -r '.Statement[0].Action')
returned_principal=$(echo "$statement" | jq -r '.Principal')
if [[ -n $DIRECT ]] && arn=$(echo "$returned_principal" | jq -r '.AWS' 2>&1); then
[[ $arn == "arn:aws:iam::$DIRECT_AWS_USER_ID:user/s3user" ]] || fail "arn mismatch"
else
[[ $principal == "\"$returned_principal\"" ]] || fail "principal mismatch ($principal, $returned_principal)"
fi
returned_action=$(echo "$statement" | jq -r '.Action')
[[ $action == "$returned_action" ]] || fail "action mismatch ($action, $returned_action)"
returned_resource=$(echo "$bucket_policy" | jq -r '.Statement[0].Resource')
returned_resource=$(echo "$statement" | jq -r '.Resource')
[[ $resource == "$returned_resource" ]] || fail "resource mismatch ($resource, $returned_resource)"
delete_bucket_policy "$1" "$BUCKET_ONE_NAME" || delete_result=$?

View File

@@ -15,31 +15,21 @@ test_admin_user() {
admin_password="123456"
user_password="789012"
user_exists "$admin_username" || local admin_exists_result=$?
if [[ $admin_exists_result -eq 0 ]]; then
delete_user "$admin_username" || local delete_admin_result=$?
[[ $delete_admin_result -eq 0 ]] || fail "failed to delete admin user"
fi
create_user "$admin_username" "$admin_password" "admin" || create_admin_result=$?
[[ $create_admin_result -eq 0 ]] || fail "failed to create admin user"
setup_user "$admin_username" "$admin_password" "admin" || fail "error setting up admin user"
user_exists "$user_username" || local user_exists_result=$?
if [[ $user_exists_result -eq 0 ]]; then
delete_user "$user_username" || local delete_user_result=$?
[[ $delete_user_result -eq 0 ]] || fail "failed to delete user user"
if user_exists "$user_username"; then
delete_user "$user_username" || fail "failed to delete user '$user_username'"
fi
create_user_with_user "$admin_username" "$admin_password" "$user_username" "$user_password" "user"
create_user_with_user "$admin_username" "$admin_password" "$user_username" "$user_password" "user" || fail "failed to create user '$user_username'"
setup_bucket "aws" "$BUCKET_ONE_NAME" || local setup_result=$?
[[ $setup_result -eq 0 ]] || fail "error setting up bucket"
delete_bucket "aws" "versity-gwtest-admin-bucket" || local delete_result=$?
[[ $delete_result -eq 0 ]] || fail "error deleting bucket if it exists"
create_bucket_with_user "aws" "versity-gwtest-admin-bucket" "$admin_username" "$admin_password" || create_result_two=$?
[[ $create_result_two -eq 0 ]] || fail "error creating bucket with user"
setup_bucket "aws" "$BUCKET_ONE_NAME" || fail "error setting up bucket"
delete_bucket "aws" "versity-gwtest-admin-bucket" || fail "error deleting bucket if it exists"
create_bucket_with_user "aws" "versity-gwtest-admin-bucket" "$admin_username" "$admin_password" || fail "error creating bucket with admin user"
bucket_one_found=false
bucket_two_found=false
list_buckets_with_user "aws" "$admin_username" "$admin_password"
list_buckets_with_user "aws" "$admin_username" "$admin_password" || fail "error listing buckets with admin user"
# shellcheck disable=SC2154
for bucket in "${bucket_array[@]}"; do
if [ "$bucket" == "$BUCKET_ONE_NAME" ]; then
bucket_one_found=true
@@ -53,8 +43,7 @@ test_admin_user() {
if [ $bucket_one_found == false ] || [ $bucket_two_found == false ]; then
fail "not all expected buckets listed"
fi
change_bucket_owner "$admin_username" "$admin_password" "versity-gwtest-admin-bucket" "$user_username" || local change_result=$?
[[ $change_result -eq 0 ]] || fail "error changing bucket owner"
change_bucket_owner "$admin_username" "$admin_password" "versity-gwtest-admin-bucket" "$user_username" || fail "error changing bucket owner"
delete_bucket "aws" "versity-gwtest-admin-bucket"
delete_user "$user_username"
@@ -69,17 +58,11 @@ test_create_user_already_exists() {
username="ABCDEG"
password="123456"
user_exists "$username" || local exists_result=$?
if [[ $exists_result -eq 0 ]]; then
delete_user "$username" || local delete_result=$?
[[ $delete_result -eq 0 ]] || fail "failed to delete user '$username'"
setup_user "$username" "123456" "admin" || fail "error setting up user"
if create_user "$username" "123456" "admin"; then
fail "'user already exists' error not returned"
fi
create_user "$username" "123456" "admin" || local create_result=$?
[[ $create_result -eq 0 ]] || fail "error creating user"
create_user "$username" "123456" "admin" || local create_result=$?
[[ $create_result -eq 1 ]] || fail "'user already exists' error not returned"
delete_bucket "aws" "versity-gwtest-admin-bucket"
delete_user "$username"
}
@@ -92,31 +75,24 @@ test_user_user() {
username="ABCDEG"
password="123456"
user_exists "$username" || local exists_result=$?
if [[ $exists_result -eq 0 ]]; then
delete_user "$username" || local delete_result=$?
[[ $delete_result -eq 0 ]] || fail "failed to delete user '$username'"
fi
setup_user "$username" "$password" "user" || fail "error setting up user"
delete_bucket "aws" "versity-gwtest-user-bucket"
setup_bucket "aws" "$BUCKET_ONE_NAME" || fail "error setting up bucket '$BUCKET_ONE_NAME'"
create_user "$username" "123456" "user" || local create_result=$?
[[ $create_result -eq 0 ]] || fail "error creating user"
setup_bucket "aws" "$BUCKET_ONE_NAME" || local setup_result=$?
[[ $setup_result -eq 0 ]] || fail "error setting up bucket"
create_bucket_with_user "aws" "versity-gwtest-user-bucket" "$username" "$password" || create_result_two=$?
[[ $create_result_two -eq 1 ]] || fail "creating bucket with 'user' account failed to return error"
if create_bucket_with_user "aws" "versity-gwtest-user-bucket" "$username" "$password"; then
fail "creating bucket with 'user' account failed to return error"
fi
# shellcheck disable=SC2154
[[ $error == *"Access Denied"* ]] || fail "error message '$error' doesn't contain 'Access Denied'"
create_bucket "aws" "versity-gwtest-user-bucket" || create_result_three=$?
[[ $create_result_three -eq 0 ]] || fail "creating bucket account returned error"
create_bucket "aws" "versity-gwtest-user-bucket" || fail "error creating bucket"
change_bucket_owner "$AWS_ACCESS_KEY_ID" "$AWS_SECRET_ACCESS_KEY" "versity-gwtest-user-bucket" "$username" || local change_result=$?
[[ $change_result -eq 0 ]] || fail "error changing bucket owner"
change_bucket_owner "$username" "$password" "versity-gwtest-user-bucket" "admin" || local change_result_two=$?
[[ $change_result_two -eq 1 ]] || fail "user shouldn't be able to change bucket owner"
change_bucket_owner "$AWS_ACCESS_KEY_ID" "$AWS_SECRET_ACCESS_KEY" "versity-gwtest-user-bucket" "$username" || fail "error changing bucket owner"
if change_bucket_owner "$username" "$password" "versity-gwtest-user-bucket" "admin"; then
fail "user shouldn't be able to change bucket owner"
fi
list_buckets_with_user "aws" "$username" "$password"
list_buckets_with_user "aws" "$username" "$password" || fail "error listing buckets with user '$username'"
bucket_found=false
for bucket in "${bucket_array[@]}"; do
if [ "$bucket" == "$BUCKET_ONE_NAME" ]; then
@@ -141,22 +117,13 @@ test_userplus_operation() {
username="ABCDEG"
password="123456"
user_exists "$username" || local exists_result=$?
if [[ $exists_result -eq 0 ]]; then
delete_user "$username" || local delete_result=$?
[[ $delete_result -eq 0 ]] || fail "failed to delete user '$username'"
fi
delete_bucket "aws" "versity-gwtest-userplus-bucket"
setup_user "$username" "$password" "userplus" || fail "error creating user '$username'"
setup_bucket "aws" "$BUCKET_ONE_NAME" || fail "error setting up bucket '$BUCKET_ONE_NAME'"
create_user "$username" "123456" "userplus" || local create_result=$?
[[ $create_result -eq 0 ]] || fail "error creating user"
setup_bucket "aws" "$BUCKET_ONE_NAME" || local setup_result=$?
[[ $setup_result -eq 0 ]] || fail "error setting up bucket"
create_bucket_with_user "aws" "versity-gwtest-userplus-bucket" "$username" "$password" || fail "error creating bucket with user '$username'"
create_bucket_with_user "aws" "versity-gwtest-userplus-bucket" "$username" "$password" || create_result_two=$?
[[ $create_result_two -eq 0 ]] || fail "error creating bucket"
list_buckets_with_user "aws" "$username" "$password"
list_buckets_with_user "aws" "$username" "$password" || fail "error listing buckets with user '$username'"
bucket_found=false
for bucket in "${bucket_array[@]}"; do
if [ "$bucket" == "$BUCKET_ONE_NAME" ]; then
@@ -169,10 +136,10 @@ test_userplus_operation() {
fail "userplus-owned bucket not found in user list"
fi
change_bucket_owner "$username" "$password" "versity-gwtest-userplus-bucket" "admin" || local change_result_two=$?
[[ $change_result_two -eq 1 ]] || fail "userplus shouldn't be able to change bucket owner"
if change_bucket_owner "$username" "$password" "versity-gwtest-userplus-bucket" "admin"; then
fail "userplus shouldn't be able to change bucket owner"
fi
delete_bucket "aws" "versity-gwtest-admin-bucket"
delete_user "$username" || delete_result=$?
[[ $delete_result -eq 0 ]] || fail "error deleting user"
delete_user "$username"
}

View File

@@ -10,12 +10,14 @@ source ./tests/commands/create_bucket.sh
source ./tests/commands/delete_bucket.sh
source ./tests/commands/delete_bucket_policy.sh
source ./tests/commands/delete_object.sh
source ./tests/commands/get_bucket_ownership_controls.sh
source ./tests/commands/get_bucket_tagging.sh
source ./tests/commands/get_object_tagging.sh
source ./tests/commands/head_bucket.sh
source ./tests/commands/head_object.sh
source ./tests/commands/list_objects.sh
source ./tests/commands/put_bucket_acl.sh
source ./tests/commands/put_bucket_ownership_controls.sh
source ./tests/commands/upload_part_copy.sh
# recursively delete an AWS bucket
@@ -158,7 +160,12 @@ delete_bucket_or_contents() {
log 2 "error deleting bucket policies"
return 1
fi
if ! put_bucket_canned_acl "$2" "private"; then
if ! get_object_ownership_rule "$2"; then
log 2 "error getting object ownership rule"
return 1
fi
# shellcheck disable=SC2154
if [[ "$object_ownership_rule" != "BucketOwnerEnforced" ]] && ! put_bucket_canned_acl "$2" "private"; then
log 2 "error resetting bucket ACLs"
return 1
fi
@@ -209,8 +216,11 @@ setup_bucket() {
log 2 "bucket creation function requires command type, bucket name"
return 1
fi
delete_bucket_or_contents_if_exists "$1" "$2" || local delete_bucket_result=$?
if [[ $delete_bucket_result -ne 0 ]]; then
if [[ $1 == "s3cmd" ]]; then
log 5 "putting bucket ownership controls"
put_bucket_ownership_controls "$2" "BucketOwnerPreferred"
fi
if ! delete_bucket_or_contents_if_exists "$1" "$2"; then
log 2 "error deleting bucket, or checking for bucket existence"
return 1
fi
@@ -222,6 +232,10 @@ setup_bucket() {
return 1
fi
log 5 "bucket creation success"
if [[ $1 == "s3cmd" ]]; then
log 5 "putting bucket ownership controls"
put_bucket_ownership_controls "$2" "BucketOwnerPreferred" || fail "putting bucket ownership controls failed"
fi
else
log 5 "skipping bucket re-creation"
fi
@@ -656,14 +670,12 @@ multipart_upload_before_completion() {
return 1
fi
split_file "$3" "$4" || split_result=$?
if [[ $split_result -ne 0 ]]; then
if ! split_file "$3" "$4"; then
log 2 "error splitting file"
return 1
fi
create_multipart_upload "$1" "$2" || create_result=$?
if [[ $create_result -ne 0 ]]; then
if ! create_multipart_upload "$1" "$2"; then
log 2 "error creating multpart upload"
return 1
fi
@@ -671,8 +683,7 @@ multipart_upload_before_completion() {
parts="["
for ((i = 1; i <= $4; i++)); do
# shellcheck disable=SC2154
upload_part "$1" "$2" "$upload_id" "$3" "$i" || local upload_result=$?
if [[ $upload_result -ne 0 ]]; then
if ! upload_part "$1" "$2" "$upload_id" "$3" "$i"; then
echo "error uploading part $i"
return 1
fi
@@ -830,18 +841,20 @@ multipart_upload_with_params() {
# return 0 for success, 1 for failure
run_then_abort_multipart_upload() {
if [ $# -ne 4 ]; then
echo "run then abort multipart upload command missing bucket, key, file, and/or part count"
log 2 "run then abort multipart upload command missing bucket, key, file, and/or part count"
return 1
fi
multipart_upload_before_completion "$1" "$2" "$3" "$4" || result=$?
if [[ $result -ne 0 ]]; then
echo "error performing pre-completion multipart upload"
if ! multipart_upload_before_completion "$1" "$2" "$3" "$4"; then
log 2 "error performing pre-completion multipart upload"
return 1
fi
abort_multipart_upload "$1" "$2" "$upload_id"
return $?
if ! abort_multipart_upload "$1" "$2" "$upload_id"; then
log 2 "error aborting multipart upload"
return 1
fi
return 0
}
# copy a file to/from S3
@@ -867,19 +880,17 @@ copy_file() {
# export parts on success, return 1 for error
list_parts() {
if [ $# -ne 4 ]; then
echo "list multipart upload parts command missing bucket, key, file, and/or part count"
log 2 "list multipart upload parts command requires bucket, key, file, and part count"
return 1
fi
multipart_upload_before_completion "$1" "$2" "$3" "$4" || result=$?
if [[ $result -ne 0 ]]; then
echo "error performing pre-completion multipart upload"
if ! multipart_upload_before_completion "$1" "$2" "$3" "$4"; then
log 2 "error performing pre-completion multipart upload"
return 1
fi
listed_parts=$(aws --no-verify-ssl s3api list-parts --bucket "$1" --key "$2" --upload-id "$upload_id") || local listed=$?
if [[ $listed -ne 0 ]]; then
echo "Error aborting upload: $parts"
if ! listed_parts=$(aws --no-verify-ssl s3api list-parts --bucket "$1" --key "$2" --upload-id "$upload_id" 2>&1); then
log 2 "Error listing multipart upload parts: $listed_parts"
return 1
fi
export listed_parts
@@ -888,30 +899,27 @@ list_parts() {
# list unfinished multipart uploads
# params: bucket, key one, key two
# export current two uploads on success, return 1 for error
list_multipart_uploads() {
create_and_list_multipart_uploads() {
if [ $# -ne 3 ]; then
echo "list multipart uploads command requires bucket and two keys"
log 2 "list multipart uploads command requires bucket and two keys"
return 1
fi
create_multipart_upload "$1" "$2" || local create_result=$?
if [[ $create_result -ne 0 ]]; then
echo "error creating multpart upload"
if ! create_multipart_upload "$1" "$2"; then
log 2 "error creating multpart upload"
return 1
fi
create_multipart_upload "$1" "$3" || local create_result_two=$?
if [[ $create_result_two -ne 0 ]]; then
echo "error creating multpart upload two"
if ! create_multipart_upload "$1" "$3"; then
log 2 "error creating multpart upload two"
return 1
fi
uploads=$(aws --no-verify-ssl s3api list-multipart-uploads --bucket "$1") || local list_result=$?
if [[ $list_result -ne 0 ]]; then
echo "error listing uploads: $uploads"
if ! list_multipart_uploads "$1"; then
echo "error listing uploads"
return 1
fi
export uploads
return 0
}
multipart_upload_from_bucket() {

View File

@@ -1,6 +1,42 @@
#!/usr/bin/env bash
create_user() {
setup_user() {
if [[ $# -ne 3 ]]; then
log 2 "'setup user' command requires username, password, and role"
return 1
fi
if user_exists "$1"; then
if ! delete_user "$1"; then
log 2 "error deleting user '$1'"
return 1
fi
fi
if ! create_user_versitygw "$1" "$2" "$3"; then
log 2 "error creating user '$1'"
return 1
fi
return 0
}
setup_user_direct() {
if [[ $# -ne 3 ]]; then
log 2 "'setup user direct' command requires username, role, and bucket"
return 1
fi
if user_exists "$1"; then
if ! delete_user "$1"; then
log 2 "error deleting user '$1'"
return 1
fi
fi
if ! create_user_direct "$1" "$2" "$3"; then
log 2 "error creating user"
return 1
fi
return 0
}
create_user_versitygw() {
if [[ $# -ne 3 ]]; then
log 2 "create user command requires user ID, key, and role"
return 1
@@ -25,6 +61,70 @@ create_user_if_nonexistent() {
return $?
}
put_user_policy() {
if [[ $# -ne 3 ]]; then
log 2 "attaching user policy requires user ID, role, bucket name"
return 1
fi
if [[ -z "$test_file_folder" ]]; then
log 2 "no test folder defined"
return 1
fi
# TODO add other roles
if [[ $2 != "user" ]]; then
log 2 "role for '$2' not currently supported"
return 1
fi
cat <<EOF > "$test_file_folder"/user_policy_file
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "arn:aws:s3:::$3/*"
}
]
}
EOF
if ! error=$(aws iam put-user-policy --user-name "$1" --policy-name "UserPolicy" --policy-document "file://$test_file_folder/user_policy_file" 2>&1); then
log 2 "error putting user policy: $error"
return 1
fi
return 0
}
create_user_direct() {
if [[ $# -ne 3 ]]; then
log 2 "create user direct command requires desired username, role, bucket name"
return 1
fi
if ! error=$(aws iam create-user --user-name "$1" 2>&1); then
log 2 "error creating new user: $error"
return 1
fi
if ! put_user_policy "$1" "$2" "$3"; then
log 2 "error attaching user policy"
return 1
fi
if ! keys=$(aws iam create-access-key --user-name "$1" 2>&1); then
log 2 "error creating keys for new user: $keys"
return 1
fi
key_id=$(echo "$keys" | jq -r ".AccessKey.AccessKeyId")
export key_id
secret_key=$(echo "$keys" | jq -r ".AccessKey.SecretAccessKey")
export secret_key
# propagation delay occurs when user is added to IAM, so wait a few seconds
sleep 5
return 0
}
create_user_with_user() {
if [[ $# -ne 5 ]]; then
log 2 "create user with user command requires creator ID, key, and new user ID, key, and role"
@@ -37,7 +137,41 @@ create_user_with_user() {
return 0
}
list_users_direct() {
# AWS_ENDPOINT_URL of s3.amazonaws.com doesn't work here
if ! users=$(aws --profile="$AWS_PROFILE" iam list-users 2>&1); then
log 2 "error listing users via direct s3 call: $users"
return 1
fi
parsed_users=()
if ! users_list=$(echo "$users" | jq -r ".Users[].UserName" 2>&1); then
log 2 "error parsing users array: $users_list"
return 1
fi
while IFS= read -r line; do
parsed_users+=("$line")
done <<< "$users_list"
log 5 "parsed users: ${parsed_users[*]}"
export parsed_users
return 0
}
list_users() {
if [[ $DIRECT == "true" ]]; then
if ! list_users_direct; then
log 2 "error listing users via direct s3 call"
return 1
fi
return 0
fi
if ! list_users_versitygw; then
log 2 "error listing versitygw users"
return 1
fi
return 0
}
list_users_versitygw() {
users=$($VERSITY_EXE admin --allow-insecure --access "$AWS_ACCESS_KEY_ID" --secret "$AWS_SECRET_ACCESS_KEY" --endpoint-url "$AWS_ENDPOINT_URL" list-users) || local list_result=$?
if [[ $list_result -ne 0 ]]; then
echo "error listing users: $users"
@@ -53,15 +187,15 @@ list_users() {
user_exists() {
if [[ $# -ne 1 ]]; then
echo "user exists command requires username"
log 2 "user exists command requires username"
return 2
fi
list_users || local list_result=$?
if [[ $list_result -ne 0 ]]; then
echo "error listing user"
if ! list_users; then
log 2 "error listing user"
return 2
fi
for element in "${parsed_users[@]}"; do
log 5 "user: $element"
if [[ $element == "$1" ]]; then
return 0
fi
@@ -69,32 +203,109 @@ user_exists() {
return 1
}
delete_user_direct() {
if [[ $# -ne 1 ]]; then
log 2 "delete user direct command requires username"
return 1
fi
if ! policies=$(aws iam list-user-policies --user-name "$1" --query 'PolicyNames' --output text 2>&1); then
log 2 "error getting user policies: $error"
return 1
fi
for policy_name in $policies; do
if ! user_policy_delete_error=$(aws iam delete-user-policy --user-name "$1" --policy-name "$policy_name" 2>&1); then
log 2 "error deleting user policy: $user_policy_delete_error"
return 1
fi
done
if ! keys=$(aws iam list-access-keys --user-name "$1" 2>&1); then
log 2 "error getting keys: $keys"
return 1
fi
if ! key=$(echo "$keys" | jq -r ".AccessKeyMetadata[0].AccessKeyId" 2>&1); then
log 2 "error getting key ID: $key"
return 1
fi
if [[ $key != "null" ]]; then
if ! error=$(aws iam delete-access-key --user-name "$1" --access-key-id "$key" 2>&1); then
log 2 "error deleting access key: $error"
return 1
fi
fi
if ! error=$(aws --profile="$AWS_PROFILE" iam delete-user --user-name "$1" 2>&1); then
log 2 "error deleting user: $error"
return 1
fi
return 0
}
delete_user_versitygw() {
if [[ $# -ne 1 ]]; then
log 2 "delete user via versitygw command requires user ID or username"
return 1
fi
log 5 "$VERSITY_EXE admin --allow-insecure --access $AWS_ACCESS_KEY_ID --secret $AWS_SECRET_ACCESS_KEY --endpoint-url $AWS_ENDPOINT_URL delete-user --access $1"
if ! error=$($VERSITY_EXE admin --allow-insecure --access "$AWS_ACCESS_KEY_ID" --secret "$AWS_SECRET_ACCESS_KEY" --endpoint-url "$AWS_ENDPOINT_URL" delete-user --access "$1" 2>&1); then
log 2 "error deleting user: $error"
export error
return 1
fi
return 0
}
delete_user() {
if [[ $# -ne 1 ]]; then
echo "delete user command requires user ID"
return 1
fi
log 5 "$VERSITY_EXE admin --allow-insecure --access $AWS_ACCESS_KEY_ID --secret $AWS_SECRET_ACCESS_KEY --endpoint-url $AWS_ENDPOINT_URL delete-user --access $1"
error=$($VERSITY_EXE admin --allow-insecure --access "$AWS_ACCESS_KEY_ID" --secret "$AWS_SECRET_ACCESS_KEY" --endpoint-url "$AWS_ENDPOINT_URL" delete-user --access "$1") || local delete_result=$?
if [[ $delete_result -ne 0 ]]; then
echo "error deleting user: $error"
export error
log 2 "delete user command requires user ID"
return 1
fi
if [[ $DIRECT == "true" ]]; then
if ! delete_user_direct "$1"; then
log 2 "error deleting user direct via s3"
return 1
fi
log 5 "user '$1' deleted successfully"
return 0
fi
if ! delete_user_versitygw "$1"; then
log 2 "error deleting user via versitygw"
return 1
fi
}
change_bucket_owner() {
if [[ $# -ne 4 ]]; then
echo "change bucket owner command requires ID, key, bucket name, and new owner"
return 1
fi
error=$($VERSITY_EXE admin --allow-insecure --access "$1" --secret "$2" --endpoint-url "$AWS_ENDPOINT_URL" change-bucket-owner --bucket "$3" --owner "$4" 2>&1) || local change_result=$?
if [[ $change_result -ne 0 ]]; then
echo "error changing bucket owner: $error"
return 1
fi
return 0
echo "change bucket owner command requires ID, key, bucket name, and new owner"
return 1
fi
error=$($VERSITY_EXE admin --allow-insecure --access "$1" --secret "$2" --endpoint-url "$AWS_ENDPOINT_URL" change-bucket-owner --bucket "$3" --owner "$4" 2>&1) || local change_result=$?
if [[ $change_result -ne 0 ]]; then
echo "error changing bucket owner: $error"
return 1
fi
return 0
}
get_bucket_owner() {
if [[ $# -ne 1 ]]; then
log 2 "'get bucket owner' command requires bucket name"
return 1
fi
if ! buckets=$($VERSITY_EXE admin --allow-insecure --access "$AWS_ACCESS_KEY_ID" --secret "$AWS_SECRET_ACCESS_KEY" --endpoint-url "$AWS_ENDPOINT_URL" list-buckets 2>&1); then
log 2 "error listing buckets: $buckets"
return 1
fi
log 5 "BUCKET DATA: $buckets"
bucket_vals=$(echo "$buckets" | awk 'NR > 2')
while IFS= read -r line; do
log 5 "bucket line: $line"
bucket=$(echo "$line" | awk '{print $1}')
if [[ $bucket == "$1" ]]; then
bucket_owner=$(echo "$line" | awk '{print $2}')
export bucket_owner
return 0
fi
done <<< "$bucket_vals"
log 3 "bucket owner for bucket '$1' not found"
bucket_owner=
return 0
}