From 2427c67171c13fcaaf517d62d4f4848bec1d976d Mon Sep 17 00:00:00 2001 From: Ben McClelland Date: Fri, 16 Jun 2023 16:47:05 -0700 Subject: [PATCH] refactor ACLs to separate out ACL logic from backend --- backend/auth/acl.go | 149 ++++++++++++++++++---- backend/auth/iam.go | 15 +++ backend/backend.go | 9 +- backend/backend_moq_test.go | 33 ++--- backend/backend_test.go | 3 +- backend/posix/posix.go | 152 +++------------------- s3api/controllers/backend_moq_test.go | 33 ++--- s3api/controllers/base.go | 175 +++++++++++++++++++++----- s3api/controllers/base_test.go | 88 +++++++++---- 9 files changed, 411 insertions(+), 246 deletions(-) diff --git a/backend/auth/acl.go b/backend/auth/acl.go index 168e3cd0..d9630336 100644 --- a/backend/auth/acl.go +++ b/backend/auth/acl.go @@ -18,9 +18,10 @@ import ( "encoding/json" "fmt" "os" + "strings" + "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/aws/aws-sdk-go-v2/service/s3/types" - "github.com/pkg/xattr" "github.com/versity/versitygw/s3err" ) @@ -44,39 +45,143 @@ type AccessControlList struct { Grants []types.Grant } -type ACLService interface { - VerifyACL(bucket, access string, permission types.Permission, isRoot bool) error - IsAdmin(access string, isRoot bool) error +func ParseACL(data []byte) (ACL, error) { + var acl ACL + if err := json.Unmarshal(data, &acl); err != nil { + return acl, fmt.Errorf("parse acl: %w", err) + } + return acl, nil } -type ACLServiceUnsupported struct{} +func ParseACLOutput(data []byte) (GetBucketAclOutput, error) { + var acl ACL + if err := json.Unmarshal(data, &acl); err != nil { + return GetBucketAclOutput{}, fmt.Errorf("parse acl: %w", err) + } -var _ ACLService = &ACLServiceUnsupported{} + grants := []types.Grant{} -func (ACLServiceUnsupported) VerifyACL(bucket, access string, permission types.Permission, isRoot bool) error { - var ACL ACL + for _, elem := range acl.Grantees { + acs := elem.Access + grants = append(grants, types.Grant{Grantee: &types.Grantee{ID: &acs}, Permission: elem.Permission}) + } + return GetBucketAclOutput{ + Owner: &types.Owner{ + ID: &acl.Owner, + }, + AccessControlList: AccessControlList{ + Grants: grants, + }, + }, nil +} + +func UpdateACL(input *s3.PutBucketAclInput, acl ACL, iam IAMConfig) error { + if acl.Owner != *input.AccessControlPolicy.Owner.ID { + return s3err.GetAPIError(s3err.ErrAccessDenied) + } + + // if the ACL is specified, set the ACL, else replace the grantees + if input.ACL != "" { + acl.ACL = input.ACL + acl.Grantees = []Grantee{} + return nil + } + + grantees := []Grantee{} + + fullControlList, readList, readACPList, writeList, writeACPList := []string{}, []string{}, []string{}, []string{}, []string{} + + if *input.GrantFullControl != "" { + fullControlList = splitUnique(*input.GrantFullControl, ",") + fmt.Println(fullControlList) + for _, str := range fullControlList { + grantees = append(grantees, Grantee{Access: str, Permission: "FULL_CONTROL"}) + } + } + if *input.GrantRead != "" { + readList = splitUnique(*input.GrantRead, ",") + for _, str := range readList { + grantees = append(grantees, Grantee{Access: str, Permission: "READ"}) + } + } + if *input.GrantReadACP != "" { + readACPList = splitUnique(*input.GrantReadACP, ",") + for _, str := range readACPList { + grantees = append(grantees, Grantee{Access: str, Permission: "READ_ACP"}) + } + } + if *input.GrantWrite != "" { + writeList = splitUnique(*input.GrantWrite, ",") + for _, str := range writeList { + grantees = append(grantees, Grantee{Access: str, Permission: "WRITE"}) + } + } + if *input.GrantWriteACP != "" { + writeACPList = splitUnique(*input.GrantWriteACP, ",") + for _, str := range writeACPList { + grantees = append(grantees, Grantee{Access: str, Permission: "WRITE_ACP"}) + } + } + + accs := append(append(append(append(fullControlList, readList...), writeACPList...), readACPList...), writeList...) + + // Check if the specified accounts exist + accList, err := checkIfAccountsExist(accs, iam) + if err != nil { + return err + } + if len(accList) > 0 { + return fmt.Errorf("accounts does not exist: %s", strings.Join(accList, ", ")) + } + + acl.Grantees = grantees + acl.ACL = "" + + return nil +} + +func checkIfAccountsExist(accs []string, iam IAMConfig) ([]string, error) { + result := []string{} + + for _, acc := range accs { + _, ok := iam.AccessAccounts[acc] + if !ok { + result = append(result, acc) + } + } + return result, nil +} + +func splitUnique(s, divider string) []string { + elements := strings.Split(s, divider) + uniqueElements := make(map[string]bool) + result := make([]string, 0, len(elements)) + + for _, element := range elements { + if _, ok := uniqueElements[element]; !ok { + result = append(result, element) + uniqueElements[element] = true + } + } + + return result +} + +func VerifyACL(acl ACL, bucket, access string, permission types.Permission, isRoot bool) error { if isRoot { return nil } - acl, err := xattr.Get(bucket, "user.acl") - if err != nil { - return fmt.Errorf("get acl: %w", err) - } - - if err := json.Unmarshal(acl, &ACL); err != nil { - return fmt.Errorf("parse acl: %w", err) - } - if ACL.Owner == access { + if acl.Owner == access { return nil } - if ACL.ACL != "" { - if (permission == "READ" || permission == "READ_ACP") && (ACL.ACL != "public-read" && ACL.ACL != "public-read-write") { + 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" { + if (permission == "WRITE" || permission == "WRITE_ACP") && acl.ACL != "public-read-write" { return s3err.GetAPIError(s3err.ErrAccessDenied) } @@ -87,7 +192,7 @@ func (ACLServiceUnsupported) VerifyACL(bucket, access string, permission types.P isFound := false - for _, grt := range ACL.Grantees { + for _, grt := range acl.Grantees { if grt == grantee || grt == granteeFullCtrl { isFound = true break @@ -102,7 +207,7 @@ func (ACLServiceUnsupported) VerifyACL(bucket, access string, permission types.P return s3err.GetAPIError(s3err.ErrAccessDenied) } -func (ACLServiceUnsupported) IsAdmin(access string, isRoot bool) error { +func IsAdmin(access string, isRoot bool) error { var data IAMConfig if isRoot { diff --git a/backend/auth/iam.go b/backend/auth/iam.go index c3b8fbfe..a6bf53ec 100644 --- a/backend/auth/iam.go +++ b/backend/auth/iam.go @@ -108,6 +108,21 @@ func (IAMServiceUnsupported) GetIAMConfig() (*IAMConfig, error) { return nil, s3err.GetAPIError(s3err.ErrNotImplemented) } +func GetIAMConfig() (*IAMConfig, error) { + var data IAMConfig + + file, err := os.ReadFile("users.json") + if err != nil { + return nil, fmt.Errorf("unable to read config file: %w", err) + } + + if err := json.Unmarshal(file, &data); err != nil { + return nil, err + } + + return &data, nil +} + func (s IAMServiceUnsupported) CreateAccount(access string, account *Account) error { var data IAMConfig diff --git a/backend/backend.go b/backend/backend.go index 18b8801f..18f53426 100644 --- a/backend/backend.go +++ b/backend/backend.go @@ -20,7 +20,6 @@ import ( "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/aws/aws-sdk-go-v2/service/s3/types" - "github.com/versity/versitygw/backend/auth" "github.com/versity/versitygw/s3err" "github.com/versity/versitygw/s3response" ) @@ -33,9 +32,9 @@ type Backend interface { ListBuckets() (s3response.ListAllMyBucketsResult, error) HeadBucket(bucket string) (*s3.HeadBucketOutput, error) - GetBucketAcl(bucket string) (*auth.GetBucketAclOutput, error) + GetBucketAcl(bucket string) ([]byte, error) PutBucket(bucket, owner string) error - PutBucketAcl(*s3.PutBucketAclInput) error + PutBucketAcl(bucket string, data []byte) error DeleteBucket(bucket string) error CreateMultipartUpload(*s3.CreateMultipartUploadInput) (*s3.CreateMultipartUploadOutput, error) @@ -79,7 +78,7 @@ func (BackendUnsupported) String() string { func (BackendUnsupported) ListBuckets() (s3response.ListAllMyBucketsResult, error) { return s3response.ListAllMyBucketsResult{}, s3err.GetAPIError(s3err.ErrNotImplemented) } -func (BackendUnsupported) PutBucketAcl(*s3.PutBucketAclInput) error { +func (BackendUnsupported) PutBucketAcl(bucket string, data []byte) error { return s3err.GetAPIError(s3err.ErrNotImplemented) } func (BackendUnsupported) PutObjectAcl(*s3.PutObjectAclInput) error { @@ -91,7 +90,7 @@ func (BackendUnsupported) RestoreObject(bucket, object string, restoreRequest *s func (BackendUnsupported) UploadPartCopy(*s3.UploadPartCopyInput) (*s3.UploadPartCopyOutput, error) { return nil, s3err.GetAPIError(s3err.ErrNotImplemented) } -func (BackendUnsupported) GetBucketAcl(bucket string) (*auth.GetBucketAclOutput, error) { +func (BackendUnsupported) GetBucketAcl(bucket string) ([]byte, error) { return nil, s3err.GetAPIError(s3err.ErrNotImplemented) } func (BackendUnsupported) HeadBucket(bucket string) (*s3.HeadBucketOutput, error) { diff --git a/backend/backend_moq_test.go b/backend/backend_moq_test.go index 8a27eb4c..d8cc9a45 100644 --- a/backend/backend_moq_test.go +++ b/backend/backend_moq_test.go @@ -6,7 +6,6 @@ package backend import ( "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/aws/aws-sdk-go-v2/service/s3/types" - "github.com/versity/versitygw/backend/auth" "github.com/versity/versitygw/s3response" "io" "sync" @@ -46,7 +45,7 @@ var _ Backend = &BackendMock{} // DeleteObjectsFunc: func(bucket string, objects *s3.DeleteObjectsInput) error { // panic("mock out the DeleteObjects method") // }, -// GetBucketAclFunc: func(bucket string) (*auth.GetBucketAclOutput, error) { +// GetBucketAclFunc: func(bucket string) ([]byte, error) { // panic("mock out the GetBucketAcl method") // }, // GetObjectFunc: func(bucket string, object string, acceptRange string, writer io.Writer) (*s3.GetObjectOutput, error) { @@ -85,7 +84,7 @@ var _ Backend = &BackendMock{} // PutBucketFunc: func(bucket string, owner string) error { // panic("mock out the PutBucket method") // }, -// PutBucketAclFunc: func(putBucketAclInput *s3.PutBucketAclInput) error { +// PutBucketAclFunc: func(bucket string, data []byte) error { // panic("mock out the PutBucketAcl method") // }, // PutObjectFunc: func(putObjectInput *s3.PutObjectInput) (string, error) { @@ -147,7 +146,7 @@ type BackendMock struct { DeleteObjectsFunc func(bucket string, objects *s3.DeleteObjectsInput) error // GetBucketAclFunc mocks the GetBucketAcl method. - GetBucketAclFunc func(bucket string) (*auth.GetBucketAclOutput, error) + GetBucketAclFunc func(bucket string) ([]byte, error) // GetObjectFunc mocks the GetObject method. GetObjectFunc func(bucket string, object string, acceptRange string, writer io.Writer) (*s3.GetObjectOutput, error) @@ -186,7 +185,7 @@ type BackendMock struct { PutBucketFunc func(bucket string, owner string) error // PutBucketAclFunc mocks the PutBucketAcl method. - PutBucketAclFunc func(putBucketAclInput *s3.PutBucketAclInput) error + PutBucketAclFunc func(bucket string, data []byte) error // PutObjectFunc mocks the PutObject method. PutObjectFunc func(putObjectInput *s3.PutObjectInput) (string, error) @@ -390,8 +389,10 @@ type BackendMock struct { } // PutBucketAcl holds details about calls to the PutBucketAcl method. PutBucketAcl []struct { - // PutBucketAclInput is the putBucketAclInput argument value. - PutBucketAclInput *s3.PutBucketAclInput + // Bucket is the bucket argument value. + Bucket string + // Data is the data argument value. + Data []byte } // PutObject holds details about calls to the PutObject method. PutObject []struct { @@ -797,7 +798,7 @@ func (mock *BackendMock) DeleteObjectsCalls() []struct { } // GetBucketAcl calls GetBucketAclFunc. -func (mock *BackendMock) GetBucketAcl(bucket string) (*auth.GetBucketAclOutput, error) { +func (mock *BackendMock) GetBucketAcl(bucket string) ([]byte, error) { if mock.GetBucketAclFunc == nil { panic("BackendMock.GetBucketAclFunc: method is nil but Backend.GetBucketAcl was just called") } @@ -1292,19 +1293,21 @@ func (mock *BackendMock) PutBucketCalls() []struct { } // PutBucketAcl calls PutBucketAclFunc. -func (mock *BackendMock) PutBucketAcl(putBucketAclInput *s3.PutBucketAclInput) error { +func (mock *BackendMock) PutBucketAcl(bucket string, data []byte) error { if mock.PutBucketAclFunc == nil { panic("BackendMock.PutBucketAclFunc: method is nil but Backend.PutBucketAcl was just called") } callInfo := struct { - PutBucketAclInput *s3.PutBucketAclInput + Bucket string + Data []byte }{ - PutBucketAclInput: putBucketAclInput, + Bucket: bucket, + Data: data, } mock.lockPutBucketAcl.Lock() mock.calls.PutBucketAcl = append(mock.calls.PutBucketAcl, callInfo) mock.lockPutBucketAcl.Unlock() - return mock.PutBucketAclFunc(putBucketAclInput) + return mock.PutBucketAclFunc(bucket, data) } // PutBucketAclCalls gets all the calls that were made to PutBucketAcl. @@ -1312,10 +1315,12 @@ func (mock *BackendMock) PutBucketAcl(putBucketAclInput *s3.PutBucketAclInput) e // // len(mockedBackend.PutBucketAclCalls()) func (mock *BackendMock) PutBucketAclCalls() []struct { - PutBucketAclInput *s3.PutBucketAclInput + Bucket string + Data []byte } { var calls []struct { - PutBucketAclInput *s3.PutBucketAclInput + Bucket string + Data []byte } mock.lockPutBucketAcl.RLock() calls = mock.calls.PutBucketAcl diff --git a/backend/backend_test.go b/backend/backend_test.go index fa187dd6..f696b74a 100644 --- a/backend/backend_test.go +++ b/backend/backend_test.go @@ -19,7 +19,6 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/service/s3" - "github.com/versity/versitygw/backend/auth" "github.com/versity/versitygw/s3err" "github.com/versity/versitygw/s3response" ) @@ -122,7 +121,7 @@ func TestBackend_GetBucketAcl(t *testing.T) { tests = append(tests, test{ name: "get bucket acl error", c: &BackendMock{ - GetBucketAclFunc: func(bucket string) (*auth.GetBucketAclOutput, error) { + GetBucketAclFunc: func(bucket string) ([]byte, error) { return nil, s3err.GetAPIError(s3err.ErrNotImplemented) }, }, diff --git a/backend/posix/posix.go b/backend/posix/posix.go index 35048f06..b8ee76b1 100644 --- a/backend/posix/posix.go +++ b/backend/posix/posix.go @@ -1080,115 +1080,36 @@ func (p *Posix) ListObjectsV2(bucket, prefix, marker, delim string, maxkeys int) }, nil } -func (p *Posix) PutBucketAcl(input *s3.PutBucketAclInput) error { - var ACL auth.ACL - acl, err := xattr.Get(*input.Bucket, "user.acl") +func (p *Posix) PutBucketAcl(bucket string, data []byte) error { + _, err := os.Stat(bucket) + if errors.Is(err, fs.ErrNotExist) { + return s3err.GetAPIError(s3err.ErrNoSuchBucket) + } if err != nil { - return fmt.Errorf("get acl: %w", err) + return fmt.Errorf("stat bucket: %w", err) } - if err := json.Unmarshal(acl, &ACL); err != nil { - return fmt.Errorf("parse acl: %w", err) - } - - if ACL.Owner != *input.AccessControlPolicy.Owner.ID { - return s3err.GetAPIError(s3err.ErrAccessDenied) - } - - // if the ACL is specified, set the ACL, else replace the grantees - if input.ACL != "" { - ACL.ACL = input.ACL - ACL.Grantees = []auth.Grantee{} - } else { - grantees := []auth.Grantee{} - - fullControlList, readList, readACPList, writeList, writeACPList := []string{}, []string{}, []string{}, []string{}, []string{} - - if *input.GrantFullControl != "" { - fullControlList = splitUnique(*input.GrantFullControl, ",") - fmt.Println(fullControlList) - for _, str := range fullControlList { - grantees = append(grantees, auth.Grantee{Access: str, Permission: "FULL_CONTROL"}) - } - } - if *input.GrantRead != "" { - readList = splitUnique(*input.GrantRead, ",") - for _, str := range readList { - grantees = append(grantees, auth.Grantee{Access: str, Permission: "READ"}) - } - } - if *input.GrantReadACP != "" { - readACPList = splitUnique(*input.GrantReadACP, ",") - for _, str := range readACPList { - grantees = append(grantees, auth.Grantee{Access: str, Permission: "READ_ACP"}) - } - } - if *input.GrantWrite != "" { - writeList = splitUnique(*input.GrantWrite, ",") - for _, str := range writeList { - grantees = append(grantees, auth.Grantee{Access: str, Permission: "WRITE"}) - } - } - if *input.GrantWriteACP != "" { - writeACPList = splitUnique(*input.GrantWriteACP, ",") - for _, str := range writeACPList { - grantees = append(grantees, auth.Grantee{Access: str, Permission: "WRITE_ACP"}) - } - } - - accs := append(append(append(append(fullControlList, readList...), writeACPList...), readACPList...), writeList...) - - // Check if the specified accounts exist - accList, err := checkIfAccountsExist(accs) - if err != nil { - return err - } - if len(accList) > 0 { - return fmt.Errorf("accounts does not exist: %s", strings.Join(accList, ", ")) - } - - ACL.Grantees = grantees - ACL.ACL = "" - } - - ACLJson, err := json.Marshal(ACL) - if err != nil { - return fmt.Errorf("parsing error: %w", err) - } - - if err := xattr.Set(*input.Bucket, "user.acl", ACLJson); err != nil { + if err := xattr.Set(bucket, "user.acl", data); err != nil { return fmt.Errorf("set acl: %w", err) } return nil } -func (p *Posix) GetBucketAcl(bucket string) (*auth.GetBucketAclOutput, error) { - var ACL auth.ACL - acl, err := xattr.Get(bucket, "user.acl") +func (p *Posix) GetBucketAcl(bucket string) ([]byte, error) { + _, err := os.Stat(bucket) + if errors.Is(err, fs.ErrNotExist) { + return nil, s3err.GetAPIError(s3err.ErrNoSuchBucket) + } + if err != nil { + return nil, fmt.Errorf("stat bucket: %w", err) + } + + b, err := xattr.Get(bucket, "user.acl") if err != nil { return nil, fmt.Errorf("get acl: %w", err) } - - if err := json.Unmarshal(acl, &ACL); err != nil { - return nil, fmt.Errorf("parse acl: %w", err) - } - - grants := []types.Grant{} - - for _, elem := range ACL.Grantees { - acs := elem.Access - grants = append(grants, types.Grant{Grantee: &types.Grantee{ID: &acs}, Permission: elem.Permission}) - } - - return &auth.GetBucketAclOutput{ - Owner: &types.Owner{ - ID: &ACL.Owner, - }, - AccessControlList: auth.AccessControlList{ - Grants: grants, - }, - }, nil + return b, nil } func (p *Posix) GetTags(bucket, object string) (map[string]string, error) { @@ -1277,40 +1198,3 @@ func isNoAttr(err error) bool { } return false } - -func checkIfAccountsExist(accs []string) ([]string, error) { - var data auth.IAMConfig - result := []string{} - - file, err := os.ReadFile("users.json") - if err != nil { - return []string{}, fmt.Errorf("unable to read config file: %w", err) - } - - if err := json.Unmarshal(file, &data); err != nil { - return []string{}, err - } - - for _, acc := range accs { - _, ok := data.AccessAccounts[acc] - if !ok { - result = append(result, acc) - } - } - return result, nil -} - -func splitUnique(s, divider string) []string { - elements := strings.Split(s, divider) - uniqueElements := make(map[string]bool) - result := make([]string, 0, len(elements)) - - for _, element := range elements { - if _, ok := uniqueElements[element]; !ok { - result = append(result, element) - uniqueElements[element] = true - } - } - - return result -} diff --git a/s3api/controllers/backend_moq_test.go b/s3api/controllers/backend_moq_test.go index 8f03d225..39adc7a6 100644 --- a/s3api/controllers/backend_moq_test.go +++ b/s3api/controllers/backend_moq_test.go @@ -7,7 +7,6 @@ import ( "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/backend/auth" "github.com/versity/versitygw/s3response" "io" "sync" @@ -47,7 +46,7 @@ var _ backend.Backend = &BackendMock{} // DeleteObjectsFunc: func(bucket string, objects *s3.DeleteObjectsInput) error { // panic("mock out the DeleteObjects method") // }, -// GetBucketAclFunc: func(bucket string) (*auth.GetBucketAclOutput, error) { +// GetBucketAclFunc: func(bucket string) ([]byte, error) { // panic("mock out the GetBucketAcl method") // }, // GetObjectFunc: func(bucket string, object string, acceptRange string, writer io.Writer) (*s3.GetObjectOutput, error) { @@ -86,7 +85,7 @@ var _ backend.Backend = &BackendMock{} // PutBucketFunc: func(bucket string, owner string) error { // panic("mock out the PutBucket method") // }, -// PutBucketAclFunc: func(putBucketAclInput *s3.PutBucketAclInput) error { +// PutBucketAclFunc: func(bucket string, data []byte) error { // panic("mock out the PutBucketAcl method") // }, // PutObjectFunc: func(putObjectInput *s3.PutObjectInput) (string, error) { @@ -148,7 +147,7 @@ type BackendMock struct { DeleteObjectsFunc func(bucket string, objects *s3.DeleteObjectsInput) error // GetBucketAclFunc mocks the GetBucketAcl method. - GetBucketAclFunc func(bucket string) (*auth.GetBucketAclOutput, error) + GetBucketAclFunc func(bucket string) ([]byte, error) // GetObjectFunc mocks the GetObject method. GetObjectFunc func(bucket string, object string, acceptRange string, writer io.Writer) (*s3.GetObjectOutput, error) @@ -187,7 +186,7 @@ type BackendMock struct { PutBucketFunc func(bucket string, owner string) error // PutBucketAclFunc mocks the PutBucketAcl method. - PutBucketAclFunc func(putBucketAclInput *s3.PutBucketAclInput) error + PutBucketAclFunc func(bucket string, data []byte) error // PutObjectFunc mocks the PutObject method. PutObjectFunc func(putObjectInput *s3.PutObjectInput) (string, error) @@ -391,8 +390,10 @@ type BackendMock struct { } // PutBucketAcl holds details about calls to the PutBucketAcl method. PutBucketAcl []struct { - // PutBucketAclInput is the putBucketAclInput argument value. - PutBucketAclInput *s3.PutBucketAclInput + // Bucket is the bucket argument value. + Bucket string + // Data is the data argument value. + Data []byte } // PutObject holds details about calls to the PutObject method. PutObject []struct { @@ -798,7 +799,7 @@ func (mock *BackendMock) DeleteObjectsCalls() []struct { } // GetBucketAcl calls GetBucketAclFunc. -func (mock *BackendMock) GetBucketAcl(bucket string) (*auth.GetBucketAclOutput, error) { +func (mock *BackendMock) GetBucketAcl(bucket string) ([]byte, error) { if mock.GetBucketAclFunc == nil { panic("BackendMock.GetBucketAclFunc: method is nil but Backend.GetBucketAcl was just called") } @@ -1293,19 +1294,21 @@ func (mock *BackendMock) PutBucketCalls() []struct { } // PutBucketAcl calls PutBucketAclFunc. -func (mock *BackendMock) PutBucketAcl(putBucketAclInput *s3.PutBucketAclInput) error { +func (mock *BackendMock) PutBucketAcl(bucket string, data []byte) error { if mock.PutBucketAclFunc == nil { panic("BackendMock.PutBucketAclFunc: method is nil but Backend.PutBucketAcl was just called") } callInfo := struct { - PutBucketAclInput *s3.PutBucketAclInput + Bucket string + Data []byte }{ - PutBucketAclInput: putBucketAclInput, + Bucket: bucket, + Data: data, } mock.lockPutBucketAcl.Lock() mock.calls.PutBucketAcl = append(mock.calls.PutBucketAcl, callInfo) mock.lockPutBucketAcl.Unlock() - return mock.PutBucketAclFunc(putBucketAclInput) + return mock.PutBucketAclFunc(bucket, data) } // PutBucketAclCalls gets all the calls that were made to PutBucketAcl. @@ -1313,10 +1316,12 @@ func (mock *BackendMock) PutBucketAcl(putBucketAclInput *s3.PutBucketAclInput) e // // len(mockedBackend.PutBucketAclCalls()) func (mock *BackendMock) PutBucketAclCalls() []struct { - PutBucketAclInput *s3.PutBucketAclInput + Bucket string + Data []byte } { var calls []struct { - PutBucketAclInput *s3.PutBucketAclInput + Bucket string + Data []byte } mock.lockPutBucketAcl.RLock() calls = mock.calls.PutBucketAcl diff --git a/s3api/controllers/base.go b/s3api/controllers/base.go index 9d32cc58..9116d1fd 100644 --- a/s3api/controllers/base.go +++ b/s3api/controllers/base.go @@ -36,17 +36,16 @@ import ( ) type S3ApiController struct { - be backend.Backend - acl auth.ACLService + be backend.Backend } func New(be backend.Backend) S3ApiController { - return S3ApiController{be: be, acl: auth.ACLServiceUnsupported{}} + return S3ApiController{be: be} } func (c S3ApiController) ListBuckets(ctx *fiber.Ctx) error { access, isRoot := ctx.Locals("access").(string), ctx.Locals("isRoot").(bool) - if err := c.acl.IsAdmin(access, isRoot); err != nil { + if err := auth.IsAdmin(access, isRoot); err != nil { return SendXMLResponse(ctx, nil, err) } res, err := c.be.ListBuckets() @@ -67,6 +66,16 @@ func (c S3ApiController) GetActions(ctx *fiber.Ctx) error { key = strings.Join([]string{key, keyEnd}, "/") } + data, err := c.be.GetBucketAcl(bucket) + if err != nil { + return SendResponse(ctx, err) + } + + parsedAcl, err := auth.ParseACL(data) + if err != nil { + return SendResponse(ctx, err) + } + if uploadId != "" { if maxParts < 0 || (maxParts == 0 && ctx.Query("max-parts") != "") { return SendResponse(ctx, s3err.GetAPIError(s3err.ErrInvalidMaxParts)) @@ -75,7 +84,7 @@ func (c S3ApiController) GetActions(ctx *fiber.Ctx) error { return SendResponse(ctx, s3err.GetAPIError(s3err.ErrInvalidPartNumberMarker)) } - if err := c.acl.VerifyACL(bucket, access, "READ", isRoot); err != nil { + if err := auth.VerifyACL(parsedAcl, bucket, access, "READ", isRoot); err != nil { return SendXMLResponse(ctx, nil, err) } @@ -84,7 +93,7 @@ func (c S3ApiController) GetActions(ctx *fiber.Ctx) error { } if ctx.Request().URI().QueryArgs().Has("acl") { - if err := c.acl.VerifyACL(bucket, access, "READ_ACP", isRoot); err != nil { + if err := auth.VerifyACL(parsedAcl, bucket, access, "READ_ACP", isRoot); err != nil { return SendXMLResponse(ctx, nil, err) } res, err := c.be.GetObjectAcl(bucket, key) @@ -92,14 +101,14 @@ func (c S3ApiController) GetActions(ctx *fiber.Ctx) error { } if attrs := ctx.Get("X-Amz-Object-Attributes"); attrs != "" { - if err := c.acl.VerifyACL(bucket, access, "READ", isRoot); err != nil { + if err := auth.VerifyACL(parsedAcl, bucket, access, "READ", isRoot); err != nil { return SendXMLResponse(ctx, nil, err) } res, err := c.be.GetObjectAttributes(bucket, key, strings.Split(attrs, ",")) return SendXMLResponse(ctx, res, err) } - if err := c.acl.VerifyACL(bucket, access, "READ_ACP", isRoot); err != nil { + if err := auth.VerifyACL(parsedAcl, bucket, access, "READ_ACP", isRoot); err != nil { return SendResponse(ctx, err) } @@ -157,16 +166,27 @@ func (c S3ApiController) ListActions(ctx *fiber.Ctx) error { access := ctx.Locals("access").(string) isRoot := ctx.Locals("isRoot").(bool) + data, err := c.be.GetBucketAcl(bucket) + if err != nil { + return SendResponse(ctx, err) + } + + parsedAcl, err := auth.ParseACL(data) + if err != nil { + return SendResponse(ctx, err) + } + if ctx.Request().URI().QueryArgs().Has("acl") { - if err := c.acl.VerifyACL(bucket, access, "READ_ACP", isRoot); err != nil { + if err := auth.VerifyACL(parsedAcl, bucket, access, "READ_ACP", isRoot); err != nil { return SendXMLResponse(ctx, nil, err) } - res, err := c.be.GetBucketAcl(ctx.Params("bucket")) + + res, err := auth.ParseACLOutput(data) return SendXMLResponse(ctx, res, err) } if ctx.Request().URI().QueryArgs().Has("uploads") { - if err := c.acl.VerifyACL(bucket, access, "READ", isRoot); err != nil { + if err := auth.VerifyACL(parsedAcl, bucket, access, "READ", isRoot); err != nil { return SendXMLResponse(ctx, nil, err) } res, err := c.be.ListMultipartUploads(&s3.ListMultipartUploadsInput{Bucket: aws.String(ctx.Params("bucket"))}) @@ -174,14 +194,14 @@ func (c S3ApiController) ListActions(ctx *fiber.Ctx) error { } if ctx.QueryInt("list-type") == 2 { - if err := c.acl.VerifyACL(bucket, access, "READ", isRoot); err != nil { + if err := auth.VerifyACL(parsedAcl, bucket, access, "READ", isRoot); err != nil { return SendXMLResponse(ctx, nil, err) } res, err := c.be.ListObjectsV2(bucket, prefix, marker, delimiter, maxkeys) return SendXMLResponse(ctx, res, err) } - if err := c.acl.VerifyACL(bucket, access, "READ", isRoot); err != nil { + if err := auth.VerifyACL(parsedAcl, bucket, access, "READ", isRoot); err != nil { return SendXMLResponse(ctx, nil, err) } @@ -212,11 +232,21 @@ func (c S3ApiController) PutBucketActions(ctx *fiber.Ctx) error { return errors.New("wrong api call") } - if err := c.acl.VerifyACL(bucket, access, "WRITE_ACP", isRoot); err != nil { + data, err := c.be.GetBucketAcl(bucket) + if err != nil { return SendResponse(ctx, err) } - err := c.be.PutBucketAcl(&s3.PutBucketAclInput{ + parsedAcl, err := auth.ParseACL(data) + if err != nil { + return SendResponse(ctx, err) + } + + if err := auth.VerifyACL(parsedAcl, bucket, access, "WRITE_ACP", isRoot); err != nil { + return SendResponse(ctx, err) + } + + input := &s3.PutBucketAclInput{ Bucket: &bucket, ACL: types.BucketCannedACL(acl), GrantFullControl: &grantFullControl, @@ -225,8 +255,14 @@ func (c S3ApiController) PutBucketActions(ctx *fiber.Ctx) error { GrantWrite: &granWrite, GrantWriteACP: &grantWriteACP, AccessControlPolicy: &types.AccessControlPolicy{Owner: &types.Owner{ID: &access}}, - }) + } + iam, err := auth.GetIAMConfig() + if err != nil { + return SendResponse(ctx, err) + } + + err = auth.UpdateACL(input, parsedAcl, *iam) return SendResponse(ctx, err) } @@ -280,13 +316,23 @@ func (c S3ApiController) PutActions(ctx *fiber.Ctx) error { } } + data, err := c.be.GetBucketAcl(bucket) + if err != nil { + return SendResponse(ctx, err) + } + + parsedAcl, err := auth.ParseACL(data) + if err != nil { + return SendResponse(ctx, err) + } + if uploadId != "" && partNumberStr != "" { partNumber := ctx.QueryInt("partNumber", -1) if partNumber < 1 { return SendResponse(ctx, s3err.GetAPIError(s3err.ErrInvalidPart)) } - if err := c.acl.VerifyACL(bucket, access, "WRITE", isRoot); err != nil { + if err := auth.VerifyACL(parsedAcl, bucket, access, "WRITE", isRoot); err != nil { return SendResponse(ctx, err) } @@ -302,7 +348,7 @@ func (c S3ApiController) PutActions(ctx *fiber.Ctx) error { return errors.New("wrong api call") } - if err := c.acl.VerifyACL(bucket, access, "WRITE_ACP", isRoot); err != nil { + if err := auth.VerifyACL(parsedAcl, bucket, access, "WRITE_ACP", isRoot); err != nil { return SendResponse(ctx, err) } @@ -325,7 +371,7 @@ func (c S3ApiController) PutActions(ctx *fiber.Ctx) error { copySourceSplit := strings.Split(copySource, "/") srcBucket, srcObject := copySourceSplit[0], copySourceSplit[1:] - if err := c.acl.VerifyACL(bucket, access, "WRITE", isRoot); err != nil { + if err := auth.VerifyACL(parsedAcl, bucket, access, "WRITE", isRoot); err != nil { return SendXMLResponse(ctx, nil, err) } @@ -335,7 +381,7 @@ func (c S3ApiController) PutActions(ctx *fiber.Ctx) error { metadata := utils.GetUserMetaData(&ctx.Request().Header) - if err := c.acl.VerifyACL(bucket, access, "WRITE", isRoot); err != nil { + if err := auth.VerifyACL(parsedAcl, bucket, access, "WRITE", isRoot); err != nil { return SendResponse(ctx, err) } @@ -352,10 +398,22 @@ func (c S3ApiController) PutActions(ctx *fiber.Ctx) error { func (c S3ApiController) DeleteBucket(ctx *fiber.Ctx) error { bucket, access, isRoot := ctx.Params("bucket"), ctx.Locals("access").(string), ctx.Locals("isRoot").(bool) - if err := c.acl.VerifyACL(bucket, access, "WRITE", isRoot); err != nil { + + data, err := c.be.GetBucketAcl(bucket) + if err != nil { return SendResponse(ctx, err) } - err := c.be.DeleteBucket(bucket) + + parsedAcl, err := auth.ParseACL(data) + if err != nil { + return SendResponse(ctx, err) + } + + if err := auth.VerifyACL(parsedAcl, bucket, access, "WRITE", isRoot); err != nil { + return SendResponse(ctx, err) + } + + err = c.be.DeleteBucket(bucket) return SendResponse(ctx, err) } @@ -367,11 +425,21 @@ func (c S3ApiController) DeleteObjects(ctx *fiber.Ctx) error { return errors.New("wrong api call") } - if err := c.acl.VerifyACL(bucket, access, "WRITE", isRoot); err != nil { + data, err := c.be.GetBucketAcl(bucket) + if err != nil { return SendResponse(ctx, err) } - err := c.be.DeleteObjects(bucket, &s3.DeleteObjectsInput{Delete: &dObj}) + parsedAcl, err := auth.ParseACL(data) + if err != nil { + return SendResponse(ctx, err) + } + + if err := auth.VerifyACL(parsedAcl, bucket, access, "WRITE", isRoot); err != nil { + return SendResponse(ctx, err) + } + + err = c.be.DeleteObjects(bucket, &s3.DeleteObjectsInput{Delete: &dObj}) return SendResponse(ctx, err) } @@ -387,10 +455,20 @@ func (c S3ApiController) DeleteActions(ctx *fiber.Ctx) error { key = strings.Join([]string{key, keyEnd}, "/") } + data, err := c.be.GetBucketAcl(bucket) + if err != nil { + return SendResponse(ctx, err) + } + + parsedAcl, err := auth.ParseACL(data) + if err != nil { + return SendResponse(ctx, err) + } + if uploadId != "" { expectedBucketOwner, requestPayer := ctx.Get("X-Amz-Expected-Bucket-Owner"), ctx.Get("X-Amz-Request-Payer") - if err := c.acl.VerifyACL(bucket, access, "WRITE", isRoot); err != nil { + if err := auth.VerifyACL(parsedAcl, bucket, access, "WRITE", isRoot); err != nil { return SendResponse(ctx, err) } @@ -404,21 +482,32 @@ func (c S3ApiController) DeleteActions(ctx *fiber.Ctx) error { return SendResponse(ctx, err) } - if err := c.acl.VerifyACL(bucket, access, "WRITE", isRoot); err != nil { + if err := auth.VerifyACL(parsedAcl, bucket, access, "WRITE", isRoot); err != nil { return SendResponse(ctx, err) } - err := c.be.DeleteObject(bucket, key) + err = c.be.DeleteObject(bucket, key) return SendResponse(ctx, err) } func (c S3ApiController) HeadBucket(ctx *fiber.Ctx) error { bucket, access, isRoot := ctx.Params("bucket"), ctx.Locals("access").(string), ctx.Locals("isRoot").(bool) - if err := c.acl.VerifyACL(bucket, access, "READ", isRoot); err != nil { + + data, err := c.be.GetBucketAcl(bucket) + if err != nil { return SendResponse(ctx, err) } - _, err := c.be.HeadBucket(bucket) + parsedAcl, err := auth.ParseACL(data) + if err != nil { + return SendResponse(ctx, err) + } + + if err := auth.VerifyACL(parsedAcl, bucket, access, "READ", isRoot); err != nil { + return SendResponse(ctx, err) + } + + _, err = c.be.HeadBucket(bucket) // TODO: set bucket response headers return SendResponse(ctx, err) } @@ -435,7 +524,17 @@ func (c S3ApiController) HeadObject(ctx *fiber.Ctx) error { key = strings.Join([]string{key, keyEnd}, "/") } - if err := c.acl.VerifyACL(bucket, access, "READ", isRoot); err != nil { + data, err := c.be.GetBucketAcl(bucket) + if err != nil { + return SendResponse(ctx, err) + } + + parsedAcl, err := auth.ParseACL(data) + if err != nil { + return SendResponse(ctx, err) + } + + if err := auth.VerifyACL(parsedAcl, bucket, access, "READ", isRoot); err != nil { return SendResponse(ctx, err) } @@ -490,6 +589,16 @@ func (c S3ApiController) CreateActions(ctx *fiber.Ctx) error { key = strings.Join([]string{key, keyEnd}, "/") } + data, err := c.be.GetBucketAcl(bucket) + if err != nil { + return SendResponse(ctx, err) + } + + parsedAcl, err := auth.ParseACL(data) + if err != nil { + return SendResponse(ctx, err) + } + var restoreRequest s3.RestoreObjectInput if ctx.Request().URI().QueryArgs().Has("restore") { xmlErr := xml.Unmarshal(ctx.Body(), &restoreRequest) @@ -497,7 +606,7 @@ func (c S3ApiController) CreateActions(ctx *fiber.Ctx) error { return errors.New("wrong api call") } - if err := c.acl.VerifyACL(bucket, access, "WRITE", isRoot); err != nil { + if err := auth.VerifyACL(parsedAcl, bucket, access, "WRITE", isRoot); err != nil { return SendResponse(ctx, err) } @@ -514,7 +623,7 @@ func (c S3ApiController) CreateActions(ctx *fiber.Ctx) error { return errors.New("wrong api call") } - if err := c.acl.VerifyACL(bucket, access, "WRITE", isRoot); err != nil { + if err := auth.VerifyACL(parsedAcl, bucket, access, "WRITE", isRoot); err != nil { return SendXMLResponse(ctx, nil, err) } @@ -522,7 +631,7 @@ func (c S3ApiController) CreateActions(ctx *fiber.Ctx) error { return SendXMLResponse(ctx, res, err) } - if err := c.acl.VerifyACL(bucket, access, "WRITE", isRoot); err != nil { + if err := auth.VerifyACL(parsedAcl, bucket, access, "WRITE", isRoot); err != nil { return SendXMLResponse(ctx, nil, err) } diff --git a/s3api/controllers/base_test.go b/s3api/controllers/base_test.go index 229c84ab..d1be9ab7 100644 --- a/s3api/controllers/base_test.go +++ b/s3api/controllers/base_test.go @@ -15,6 +15,7 @@ package controllers import ( + "encoding/json" "io" "net/http" "net/http/httptest" @@ -33,13 +34,25 @@ import ( "github.com/versity/versitygw/s3response" ) +var ( + acl auth.ACL + acldata []byte +) + +func init() { + var err error + acldata, err = json.Marshal(acl) + if err != nil { + panic(err) + } +} + func TestNew(t *testing.T) { type args struct { be backend.Backend } be := backend.BackendUnsupported{} - acl := auth.ACLServiceUnsupported{} tests := []struct { name string @@ -52,8 +65,7 @@ func TestNew(t *testing.T) { be: be, }, want: S3ApiController{ - be: be, - acl: acl, + be: be, }, }, } @@ -74,11 +86,13 @@ func TestS3ApiController_ListBuckets(t *testing.T) { app := fiber.New() s3ApiController := S3ApiController{ be: &BackendMock{ + GetBucketAclFunc: func(bucket string) ([]byte, error) { + return acldata, nil + }, ListBucketsFunc: func() (s3response.ListAllMyBucketsResult, error) { return s3response.ListAllMyBucketsResult{}, nil }, }, - acl: auth.ACLServiceUnsupported{}, } app.Use(func(ctx *fiber.Ctx) error { @@ -92,11 +106,13 @@ func TestS3ApiController_ListBuckets(t *testing.T) { appErr := fiber.New() s3ApiControllerErr := S3ApiController{ be: &BackendMock{ + GetBucketAclFunc: func(bucket string) ([]byte, error) { + return acldata, nil + }, ListBucketsFunc: func() (s3response.ListAllMyBucketsResult, error) { return s3response.ListAllMyBucketsResult{}, s3err.GetAPIError(s3err.ErrMethodNotAllowed) }, }, - acl: auth.ACLServiceUnsupported{}, } appErr.Use(func(ctx *fiber.Ctx) error { @@ -155,6 +171,9 @@ func TestS3ApiController_GetActions(t *testing.T) { app := fiber.New() s3ApiController := S3ApiController{ be: &BackendMock{ + GetBucketAclFunc: func(bucket string) ([]byte, error) { + return acldata, nil + }, ListObjectPartsFunc: func(bucket, object, uploadID string, partNumberMarker int, maxParts int) (s3response.ListPartsResponse, error) { return s3response.ListPartsResponse{}, nil }, @@ -168,7 +187,6 @@ func TestS3ApiController_GetActions(t *testing.T) { return &s3.GetObjectOutput{Metadata: nil}, nil }, }, - acl: &auth.ACLServiceUnsupported{}, } app.Use(func(ctx *fiber.Ctx) error { ctx.Locals("access", "valid access") @@ -265,8 +283,8 @@ func TestS3ApiController_ListActions(t *testing.T) { app := fiber.New() s3ApiController := S3ApiController{ be: &BackendMock{ - GetBucketAclFunc: func(bucket string) (*auth.GetBucketAclOutput, error) { - return nil, nil + GetBucketAclFunc: func(bucket string) ([]byte, error) { + return acldata, nil }, ListMultipartUploadsFunc: func(output *s3.ListMultipartUploadsInput) (s3response.ListMultipartUploadsResponse, error) { return s3response.ListMultipartUploadsResponse{}, nil @@ -278,7 +296,6 @@ func TestS3ApiController_ListActions(t *testing.T) { return &s3.ListObjectsOutput{}, nil }, }, - acl: auth.ACLServiceUnsupported{}, } app.Use(func(ctx *fiber.Ctx) error { @@ -292,11 +309,13 @@ func TestS3ApiController_ListActions(t *testing.T) { //Error case s3ApiControllerError := S3ApiController{ be: &BackendMock{ + GetBucketAclFunc: func(bucket string) ([]byte, error) { + return acldata, nil + }, ListObjectsFunc: func(bucket, prefix, marker, delim string, maxkeys int) (*s3.ListObjectsOutput, error) { return nil, s3err.GetAPIError(s3err.ErrNotImplemented) }, }, - acl: auth.ACLServiceUnsupported{}, } appError := fiber.New() appError.Use(func(ctx *fiber.Ctx) error { @@ -382,14 +401,16 @@ func TestS3ApiController_PutBucketActions(t *testing.T) { app := fiber.New() s3ApiController := S3ApiController{ be: &BackendMock{ - PutBucketAclFunc: func(*s3.PutBucketAclInput) error { + GetBucketAclFunc: func(bucket string) ([]byte, error) { + return acldata, nil + }, + PutBucketAclFunc: func(string, []byte) error { return nil }, PutBucketFunc: func(bucket, owner string) error { return nil }, }, - acl: auth.ACLServiceUnsupported{}, } // Mock ctx.Locals app.Use(func(ctx *fiber.Ctx) error { @@ -464,6 +485,9 @@ func TestS3ApiController_PutActions(t *testing.T) { app := fiber.New() s3ApiController := S3ApiController{ be: &BackendMock{ + GetBucketAclFunc: func(bucket string) ([]byte, error) { + return acldata, nil + }, UploadPartCopyFunc: func(*s3.UploadPartCopyInput) (*s3.UploadPartCopyOutput, error) { return &s3.UploadPartCopyOutput{}, nil }, @@ -477,7 +501,6 @@ func TestS3ApiController_PutActions(t *testing.T) { return "Hey", nil }, }, - acl: auth.ACLServiceUnsupported{}, } app.Use(func(ctx *fiber.Ctx) error { ctx.Locals("access", "valid access") @@ -602,11 +625,13 @@ func TestS3ApiController_DeleteBucket(t *testing.T) { app := fiber.New() s3ApiController := S3ApiController{ be: &BackendMock{ + GetBucketAclFunc: func(bucket string) ([]byte, error) { + return acldata, nil + }, DeleteBucketFunc: func(bucket string) error { return nil }, }, - acl: auth.ACLServiceUnsupported{}, } app.Use(func(ctx *fiber.Ctx) error { @@ -622,11 +647,13 @@ func TestS3ApiController_DeleteBucket(t *testing.T) { s3ApiControllerErr := S3ApiController{ be: &BackendMock{ + GetBucketAclFunc: func(bucket string) ([]byte, error) { + return acldata, nil + }, DeleteBucketFunc: func(bucket string) error { return s3err.GetAPIError(48) }, }, - acl: auth.ACLServiceUnsupported{}, } appErr.Use(func(ctx *fiber.Ctx) error { @@ -683,11 +710,13 @@ func TestS3ApiController_DeleteObjects(t *testing.T) { app := fiber.New() s3ApiController := S3ApiController{ be: &BackendMock{ + GetBucketAclFunc: func(bucket string) ([]byte, error) { + return acldata, nil + }, DeleteObjectsFunc: func(bucket string, objects *s3.DeleteObjectsInput) error { return nil }, }, - acl: auth.ACLServiceUnsupported{}, } app.Use(func(ctx *fiber.Ctx) error { @@ -750,6 +779,9 @@ func TestS3ApiController_DeleteActions(t *testing.T) { app := fiber.New() s3ApiController := S3ApiController{ be: &BackendMock{ + GetBucketAclFunc: func(bucket string) ([]byte, error) { + return acldata, nil + }, DeleteObjectFunc: func(bucket, object string) error { return nil }, @@ -757,7 +789,6 @@ func TestS3ApiController_DeleteActions(t *testing.T) { return nil }, }, - acl: auth.ACLServiceUnsupported{}, } app.Use(func(ctx *fiber.Ctx) error { @@ -771,6 +802,9 @@ func TestS3ApiController_DeleteActions(t *testing.T) { appErr := fiber.New() s3ApiControllerErr := S3ApiController{be: &BackendMock{ + GetBucketAclFunc: func(bucket string) ([]byte, error) { + return acldata, nil + }, DeleteObjectFunc: func(bucket, object string) error { return s3err.GetAPIError(7) }, @@ -839,11 +873,13 @@ func TestS3ApiController_HeadBucket(t *testing.T) { app := fiber.New() s3ApiController := S3ApiController{ be: &BackendMock{ + GetBucketAclFunc: func(bucket string) ([]byte, error) { + return acldata, nil + }, HeadBucketFunc: func(bucket string) (*s3.HeadBucketOutput, error) { return &s3.HeadBucketOutput{}, nil }, }, - acl: auth.ACLServiceUnsupported{}, } app.Use(func(ctx *fiber.Ctx) error { @@ -858,11 +894,13 @@ func TestS3ApiController_HeadBucket(t *testing.T) { appErr := fiber.New() s3ApiControllerErr := S3ApiController{be: &BackendMock{ + GetBucketAclFunc: func(bucket string) ([]byte, error) { + return acldata, nil + }, HeadBucketFunc: func(bucket string) (*s3.HeadBucketOutput, error) { return nil, s3err.GetAPIError(3) }, }, - acl: auth.ACLServiceUnsupported{}, } appErr.Use(func(ctx *fiber.Ctx) error { @@ -927,6 +965,9 @@ func TestS3ApiController_HeadObject(t *testing.T) { s3ApiController := S3ApiController{ be: &BackendMock{ + GetBucketAclFunc: func(bucket string) ([]byte, error) { + return acldata, nil + }, HeadObjectFunc: func(bucket, object string) (*s3.HeadObjectOutput, error) { return &s3.HeadObjectOutput{ ContentEncoding: &contentEncoding, @@ -937,7 +978,6 @@ func TestS3ApiController_HeadObject(t *testing.T) { }, nil }, }, - acl: auth.ACLServiceUnsupported{}, } app.Use(func(ctx *fiber.Ctx) error { @@ -952,11 +992,13 @@ func TestS3ApiController_HeadObject(t *testing.T) { s3ApiControllerErr := S3ApiController{ be: &BackendMock{ + GetBucketAclFunc: func(bucket string) ([]byte, error) { + return acldata, nil + }, HeadObjectFunc: func(bucket, object string) (*s3.HeadObjectOutput, error) { return nil, s3err.GetAPIError(42) }, }, - acl: auth.ACLServiceUnsupported{}, } appErr.Use(func(ctx *fiber.Ctx) error { @@ -1012,6 +1054,9 @@ func TestS3ApiController_CreateActions(t *testing.T) { app := fiber.New() s3ApiController := S3ApiController{ be: &BackendMock{ + GetBucketAclFunc: func(bucket string) ([]byte, error) { + return acldata, nil + }, RestoreObjectFunc: func(bucket, object string, restoreRequest *s3.RestoreObjectInput) error { return nil }, @@ -1022,7 +1067,6 @@ func TestS3ApiController_CreateActions(t *testing.T) { return &s3.CreateMultipartUploadOutput{}, nil }, }, - acl: auth.ACLServiceUnsupported{}, } app.Use(func(ctx *fiber.Ctx) error {