feat: Implemented GetBucketACL, PutBucketACL posix functions, fixed authentication middleware signed headers bug

This commit is contained in:
jonaustin09
2023-06-14 22:39:27 +04:00
parent 1bcdf948ba
commit 21f0fea5a7
9 changed files with 227 additions and 160 deletions
+28
View File
@@ -0,0 +1,28 @@
// Copyright 2023 Versity Software
// This file is licensed under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package auth
import "github.com/aws/aws-sdk-go-v2/service/s3/types"
type ACL struct {
ACL types.BucketCannedACL
Owner string
Grantees []Grantee
}
type Grantee struct {
Permission types.Permission
Access string
}
+2 -2
View File
@@ -33,7 +33,7 @@ type Backend interface {
ListBuckets() (*s3.ListBucketsOutput, error)
HeadBucket(bucket string) (*s3.HeadBucketOutput, error)
GetBucketAcl(bucket string) (*s3.GetBucketAclOutput, error)
PutBucket(bucket string) error
PutBucket(bucket, owner string) error
PutBucketAcl(*s3.PutBucketAclInput) error
DeleteBucket(bucket string) error
@@ -96,7 +96,7 @@ func (BackendUnsupported) GetBucketAcl(bucket string) (*s3.GetBucketAclOutput, e
func (BackendUnsupported) HeadBucket(bucket string) (*s3.HeadBucketOutput, error) {
return nil, s3err.GetAPIError(s3err.ErrNotImplemented)
}
func (BackendUnsupported) PutBucket(bucket string) error {
func (BackendUnsupported) PutBucket(bucket, owner string) error {
return s3err.GetAPIError(s3err.ErrNotImplemented)
}
func (BackendUnsupported) DeleteBucket(bucket string) error {
+10 -66
View File
@@ -81,7 +81,7 @@ var _ Backend = &BackendMock{}
// ListObjectsV2Func: func(bucket string, prefix string, marker string, delim string, maxkeys int) (*s3.ListObjectsV2Output, error) {
// panic("mock out the ListObjectsV2 method")
// },
// PutBucketFunc: func(bucket string) error {
// PutBucketFunc: func(bucket string, owner string) error {
// panic("mock out the PutBucket method")
// },
// PutBucketAclFunc: func(putBucketAclInput *s3.PutBucketAclInput) error {
@@ -111,9 +111,6 @@ var _ Backend = &BackendMock{}
// StringFunc: func() string {
// panic("mock out the String method")
// },
// UploadPartFunc: func(bucket string, object string, uploadId string, Body io.ReadSeeker) (*s3.UploadPartOutput, error) {
// panic("mock out the UploadPart method")
// },
// UploadPartCopyFunc: func(uploadPartCopyInput *s3.UploadPartCopyInput) (*s3.UploadPartCopyOutput, error) {
// panic("mock out the UploadPartCopy method")
// },
@@ -185,7 +182,7 @@ type BackendMock struct {
ListObjectsV2Func func(bucket string, prefix string, marker string, delim string, maxkeys int) (*s3.ListObjectsV2Output, error)
// PutBucketFunc mocks the PutBucket method.
PutBucketFunc func(bucket string) error
PutBucketFunc func(bucket string, owner string) error
// PutBucketAclFunc mocks the PutBucketAcl method.
PutBucketAclFunc func(putBucketAclInput *s3.PutBucketAclInput) error
@@ -214,9 +211,6 @@ type BackendMock struct {
// StringFunc mocks the String method.
StringFunc func() string
// UploadPartFunc mocks the UploadPart method.
UploadPartFunc func(bucket string, object string, uploadId string, Body io.ReadSeeker) (*s3.UploadPartOutput, error)
// UploadPartCopyFunc mocks the UploadPartCopy method.
UploadPartCopyFunc func(uploadPartCopyInput *s3.UploadPartCopyInput) (*s3.UploadPartCopyOutput, error)
@@ -390,6 +384,8 @@ type BackendMock struct {
PutBucket []struct {
// Bucket is the bucket argument value.
Bucket string
// Owner is the owner argument value.
Owner string
}
// PutBucketAcl holds details about calls to the PutBucketAcl method.
PutBucketAcl []struct {
@@ -452,17 +448,6 @@ type BackendMock struct {
// String holds details about calls to the String method.
String []struct {
}
// UploadPart holds details about calls to the UploadPart method.
UploadPart []struct {
// Bucket is the bucket argument value.
Bucket string
// Object is the object argument value.
Object string
// UploadId is the uploadId argument value.
UploadId string
// Body is the Body argument value.
Body io.ReadSeeker
}
// UploadPartCopy holds details about calls to the UploadPartCopy method.
UploadPartCopy []struct {
// UploadPartCopyInput is the uploadPartCopyInput argument value.
@@ -499,7 +484,6 @@ type BackendMock struct {
lockSetTags sync.RWMutex
lockShutdown sync.RWMutex
lockString sync.RWMutex
lockUploadPart sync.RWMutex
lockUploadPartCopy sync.RWMutex
}
@@ -1271,19 +1255,21 @@ func (mock *BackendMock) ListObjectsV2Calls() []struct {
}
// PutBucket calls PutBucketFunc.
func (mock *BackendMock) PutBucket(bucket string) error {
func (mock *BackendMock) PutBucket(bucket string, owner string) error {
if mock.PutBucketFunc == nil {
panic("BackendMock.PutBucketFunc: method is nil but Backend.PutBucket was just called")
}
callInfo := struct {
Bucket string
Owner string
}{
Bucket: bucket,
Owner: owner,
}
mock.lockPutBucket.Lock()
mock.calls.PutBucket = append(mock.calls.PutBucket, callInfo)
mock.lockPutBucket.Unlock()
return mock.PutBucketFunc(bucket)
return mock.PutBucketFunc(bucket, owner)
}
// PutBucketCalls gets all the calls that were made to PutBucket.
@@ -1292,9 +1278,11 @@ func (mock *BackendMock) PutBucket(bucket string) error {
// len(mockedBackend.PutBucketCalls())
func (mock *BackendMock) PutBucketCalls() []struct {
Bucket string
Owner string
} {
var calls []struct {
Bucket string
Owner string
}
mock.lockPutBucket.RLock()
calls = mock.calls.PutBucket
@@ -1620,50 +1608,6 @@ func (mock *BackendMock) StringCalls() []struct {
return calls
}
// UploadPart calls UploadPartFunc.
func (mock *BackendMock) UploadPart(bucket string, object string, uploadId string, Body io.ReadSeeker) (*s3.UploadPartOutput, error) {
if mock.UploadPartFunc == nil {
panic("BackendMock.UploadPartFunc: method is nil but Backend.UploadPart was just called")
}
callInfo := struct {
Bucket string
Object string
UploadId string
Body io.ReadSeeker
}{
Bucket: bucket,
Object: object,
UploadId: uploadId,
Body: Body,
}
mock.lockUploadPart.Lock()
mock.calls.UploadPart = append(mock.calls.UploadPart, callInfo)
mock.lockUploadPart.Unlock()
return mock.UploadPartFunc(bucket, object, uploadId, Body)
}
// UploadPartCalls gets all the calls that were made to UploadPart.
// Check the length with:
//
// len(mockedBackend.UploadPartCalls())
func (mock *BackendMock) UploadPartCalls() []struct {
Bucket string
Object string
UploadId string
Body io.ReadSeeker
} {
var calls []struct {
Bucket string
Object string
UploadId string
Body io.ReadSeeker
}
mock.lockUploadPart.RLock()
calls = mock.calls.UploadPart
mock.lockUploadPart.RUnlock()
return calls
}
// UploadPartCopy calls UploadPartCopyFunc.
func (mock *BackendMock) UploadPartCopy(uploadPartCopyInput *s3.UploadPartCopyInput) (*s3.UploadPartCopyOutput, error) {
if mock.UploadPartCopyFunc == nil {
+12 -9
View File
@@ -140,8 +140,9 @@ func TestBackend_GetBucketAcl(t *testing.T) {
}
func TestBackend_PutBucket(t *testing.T) {
type args struct {
ctx context.Context
bucketName string
ctx context.Context
bucketName string
bucketOwner string
}
type test struct {
name string
@@ -153,31 +154,33 @@ func TestBackend_PutBucket(t *testing.T) {
tests = append(tests, test{
name: "put bucket ",
c: &BackendMock{
PutBucketFunc: func(bucket string) error {
PutBucketFunc: func(bucket, owner string) error {
return s3err.GetAPIError(0)
},
},
args: args{
ctx: context.Background(),
bucketName: "b1",
ctx: context.Background(),
bucketName: "b1",
bucketOwner: "owner",
},
wantErr: false,
}, test{
name: "put bucket error",
c: &BackendMock{
PutBucketFunc: func(bucket string) error {
PutBucketFunc: func(bucket, owner string) error {
return s3err.GetAPIError(s3err.ErrNotImplemented)
},
},
args: args{
ctx: context.Background(),
bucketName: "b2",
ctx: context.Background(),
bucketName: "b2",
bucketOwner: "owner",
},
wantErr: true,
})
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := tt.c.PutBucket(tt.args.bucketName); (err.(s3err.APIError).Code != "") != tt.wantErr {
if err := tt.c.PutBucket(tt.args.bucketName, tt.args.bucketOwner); (err.(s3err.APIError).Code != "") != tt.wantErr {
t.Errorf("Backend.PutBucket() error = %v, wantErr %v", err, tt.wantErr)
}
})
+148 -1
View File
@@ -35,6 +35,7 @@ import (
"github.com/google/uuid"
"github.com/pkg/xattr"
"github.com/versity/versitygw/backend"
"github.com/versity/versitygw/backend/auth"
"github.com/versity/versitygw/s3err"
"github.com/versity/versitygw/s3response"
)
@@ -121,7 +122,7 @@ func (p *Posix) HeadBucket(bucket string) (*s3.HeadBucketOutput, error) {
return &s3.HeadBucketOutput{}, nil
}
func (p *Posix) PutBucket(bucket string) error {
func (p *Posix) PutBucket(bucket string, owner string) error {
err := os.Mkdir(bucket, 0777)
if err != nil && os.IsExist(err) {
return s3err.GetAPIError(s3err.ErrBucketAlreadyExists)
@@ -130,6 +131,16 @@ func (p *Posix) PutBucket(bucket string) error {
return fmt.Errorf("mkdir bucket: %w", err)
}
acl := auth.ACL{ACL: "private", Owner: owner, Grantees: []auth.Grantee{}}
jsonACL, err := json.Marshal(acl)
if err != nil {
return fmt.Errorf("marshal acl: %w", err)
}
if err := xattr.Set(bucket, "user.acl", jsonACL); err != nil {
return fmt.Errorf("set acl: %w", err)
}
return nil
}
@@ -1088,6 +1099,120 @@ 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")
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 != *input.AccessControlPolicy.Owner.ID {
return s3err.GetAPIError(s3err.ErrAccessDenied)
}
grantees := []auth.Grantee{}
fullControlList, readList, readACPList, writeList, writeACPList := []string{}, []string{}, []string{}, []string{}, []string{}
if *input.GrantFullControl != "" {
fullControlList = strings.Split(*input.GrantFullControl, ",")
for _, str := range fullControlList {
grantees = append(grantees, auth.Grantee{Access: str, Permission: "FULL_CONTROL"})
}
}
if *input.GrantRead != "" {
readList = strings.Split(*input.GrantRead, ",")
for _, str := range readList {
grantees = append(grantees, auth.Grantee{Access: str, Permission: "READ"})
}
}
if *input.GrantReadACP != "" {
readACPList = strings.Split(*input.GrantReadACP, ",")
for _, str := range readACPList {
grantees = append(grantees, auth.Grantee{Access: str, Permission: "READ_ACP"})
}
}
if *input.GrantWrite != "" {
writeList = strings.Split(*input.GrantWrite, ",")
for _, str := range writeList {
grantees = append(grantees, auth.Grantee{Access: str, Permission: "WRITE"})
}
}
if *input.GrantWriteACP != "" {
writeACPList = strings.Split(*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...)
accList, err := checkIfAccountsExist(accs)
if err != nil {
return err
}
if len(accList) > 0 {
return fmt.Errorf("Accounts does not exist: %s", strings.Join(accList, ", "))
}
for _, elem := range grantees {
doesContain := false
for _, grantee := range ACL.Grantees {
if elem == grantee {
doesContain = true
break
}
}
if !doesContain {
ACL.Grantees = append(ACL.Grantees, elem)
}
}
if input.ACL != "" {
ACL.ACL = input.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 {
return fmt.Errorf("set acl: %w", err)
}
return nil
}
func (p *Posix) GetBucketAcl(bucket string) (*s3.GetBucketAclOutput, error) {
var ACL auth.ACL
acl, 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 {
grants = append(grants, types.Grant{Grantee: &types.Grantee{ID: &elem.Access}, Permission: elem.Permission})
}
return &s3.GetBucketAclOutput{
Owner: &types.Owner{
ID: &ACL.Owner,
},
Grants: grants,
}, nil
}
func (p *Posix) GetTags(bucket, object string) (map[string]string, error) {
_, err := os.Stat(bucket)
if errors.Is(err, fs.ErrNotExist) {
@@ -1174,3 +1299,25 @@ 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
}
+10 -66
View File
@@ -82,7 +82,7 @@ var _ backend.Backend = &BackendMock{}
// ListObjectsV2Func: func(bucket string, prefix string, marker string, delim string, maxkeys int) (*s3.ListObjectsV2Output, error) {
// panic("mock out the ListObjectsV2 method")
// },
// PutBucketFunc: func(bucket string) error {
// PutBucketFunc: func(bucket string, owner string) error {
// panic("mock out the PutBucket method")
// },
// PutBucketAclFunc: func(putBucketAclInput *s3.PutBucketAclInput) error {
@@ -112,9 +112,6 @@ var _ backend.Backend = &BackendMock{}
// StringFunc: func() string {
// panic("mock out the String method")
// },
// UploadPartFunc: func(bucket string, object string, uploadId string, Body io.ReadSeeker) (*s3.UploadPartOutput, error) {
// panic("mock out the UploadPart method")
// },
// UploadPartCopyFunc: func(uploadPartCopyInput *s3.UploadPartCopyInput) (*s3.UploadPartCopyOutput, error) {
// panic("mock out the UploadPartCopy method")
// },
@@ -186,7 +183,7 @@ type BackendMock struct {
ListObjectsV2Func func(bucket string, prefix string, marker string, delim string, maxkeys int) (*s3.ListObjectsV2Output, error)
// PutBucketFunc mocks the PutBucket method.
PutBucketFunc func(bucket string) error
PutBucketFunc func(bucket string, owner string) error
// PutBucketAclFunc mocks the PutBucketAcl method.
PutBucketAclFunc func(putBucketAclInput *s3.PutBucketAclInput) error
@@ -215,9 +212,6 @@ type BackendMock struct {
// StringFunc mocks the String method.
StringFunc func() string
// UploadPartFunc mocks the UploadPart method.
UploadPartFunc func(bucket string, object string, uploadId string, Body io.ReadSeeker) (*s3.UploadPartOutput, error)
// UploadPartCopyFunc mocks the UploadPartCopy method.
UploadPartCopyFunc func(uploadPartCopyInput *s3.UploadPartCopyInput) (*s3.UploadPartCopyOutput, error)
@@ -391,6 +385,8 @@ type BackendMock struct {
PutBucket []struct {
// Bucket is the bucket argument value.
Bucket string
// Owner is the owner argument value.
Owner string
}
// PutBucketAcl holds details about calls to the PutBucketAcl method.
PutBucketAcl []struct {
@@ -453,17 +449,6 @@ type BackendMock struct {
// String holds details about calls to the String method.
String []struct {
}
// UploadPart holds details about calls to the UploadPart method.
UploadPart []struct {
// Bucket is the bucket argument value.
Bucket string
// Object is the object argument value.
Object string
// UploadId is the uploadId argument value.
UploadId string
// Body is the Body argument value.
Body io.ReadSeeker
}
// UploadPartCopy holds details about calls to the UploadPartCopy method.
UploadPartCopy []struct {
// UploadPartCopyInput is the uploadPartCopyInput argument value.
@@ -500,7 +485,6 @@ type BackendMock struct {
lockSetTags sync.RWMutex
lockShutdown sync.RWMutex
lockString sync.RWMutex
lockUploadPart sync.RWMutex
lockUploadPartCopy sync.RWMutex
}
@@ -1272,19 +1256,21 @@ func (mock *BackendMock) ListObjectsV2Calls() []struct {
}
// PutBucket calls PutBucketFunc.
func (mock *BackendMock) PutBucket(bucket string) error {
func (mock *BackendMock) PutBucket(bucket string, owner string) error {
if mock.PutBucketFunc == nil {
panic("BackendMock.PutBucketFunc: method is nil but Backend.PutBucket was just called")
}
callInfo := struct {
Bucket string
Owner string
}{
Bucket: bucket,
Owner: owner,
}
mock.lockPutBucket.Lock()
mock.calls.PutBucket = append(mock.calls.PutBucket, callInfo)
mock.lockPutBucket.Unlock()
return mock.PutBucketFunc(bucket)
return mock.PutBucketFunc(bucket, owner)
}
// PutBucketCalls gets all the calls that were made to PutBucket.
@@ -1293,9 +1279,11 @@ func (mock *BackendMock) PutBucket(bucket string) error {
// len(mockedBackend.PutBucketCalls())
func (mock *BackendMock) PutBucketCalls() []struct {
Bucket string
Owner string
} {
var calls []struct {
Bucket string
Owner string
}
mock.lockPutBucket.RLock()
calls = mock.calls.PutBucket
@@ -1621,50 +1609,6 @@ func (mock *BackendMock) StringCalls() []struct {
return calls
}
// UploadPart calls UploadPartFunc.
func (mock *BackendMock) UploadPart(bucket string, object string, uploadId string, Body io.ReadSeeker) (*s3.UploadPartOutput, error) {
if mock.UploadPartFunc == nil {
panic("BackendMock.UploadPartFunc: method is nil but Backend.UploadPart was just called")
}
callInfo := struct {
Bucket string
Object string
UploadId string
Body io.ReadSeeker
}{
Bucket: bucket,
Object: object,
UploadId: uploadId,
Body: Body,
}
mock.lockUploadPart.Lock()
mock.calls.UploadPart = append(mock.calls.UploadPart, callInfo)
mock.lockUploadPart.Unlock()
return mock.UploadPartFunc(bucket, object, uploadId, Body)
}
// UploadPartCalls gets all the calls that were made to UploadPart.
// Check the length with:
//
// len(mockedBackend.UploadPartCalls())
func (mock *BackendMock) UploadPartCalls() []struct {
Bucket string
Object string
UploadId string
Body io.ReadSeeker
} {
var calls []struct {
Bucket string
Object string
UploadId string
Body io.ReadSeeker
}
mock.lockUploadPart.RLock()
calls = mock.calls.UploadPart
mock.lockUploadPart.RUnlock()
return calls
}
// UploadPartCopy calls UploadPartCopyFunc.
func (mock *BackendMock) UploadPartCopy(uploadPartCopyInput *s3.UploadPartCopyInput) (*s3.UploadPartCopyOutput, error) {
if mock.UploadPartCopyFunc == nil {
+13 -10
View File
@@ -152,15 +152,17 @@ func (c S3ApiController) ListActions(ctx *fiber.Ctx) error {
}
func (c S3ApiController) PutBucketActions(ctx *fiber.Ctx) error {
bucket, acl, grantFullControl, grantRead, grantReadACP, granWrite, grantWriteACP :=
bucket, acl, grantFullControl, grantRead, grantReadACP, granWrite, grantWriteACP, access :=
ctx.Params("bucket"),
ctx.Get("X-Amz-Acl"),
ctx.Get("X-Amz-Grant-Full-Control"),
ctx.Get("X-Amz-Grant-Read"),
ctx.Get("X-Amz-Grant-Read-Acp"),
ctx.Get("X-Amz-Grant-Write"),
ctx.Get("X-Amz-Grant-Write-Acp")
ctx.Get("X-Amz-Grant-Write-Acp"),
ctx.Locals("access")
owner := access.(string)
grants := grantFullControl + grantRead + grantReadACP + granWrite + grantWriteACP
if grants != "" || acl != "" {
@@ -168,19 +170,20 @@ func (c S3ApiController) PutBucketActions(ctx *fiber.Ctx) error {
return errors.New("wrong api call")
}
err := c.be.PutBucketAcl(&s3.PutBucketAclInput{
Bucket: &bucket,
ACL: types.BucketCannedACL(acl),
GrantFullControl: &grantFullControl,
GrantRead: &grantRead,
GrantReadACP: &grantReadACP,
GrantWrite: &granWrite,
GrantWriteACP: &grantWriteACP,
Bucket: &bucket,
ACL: types.BucketCannedACL(acl),
GrantFullControl: &grantFullControl,
GrantRead: &grantRead,
GrantReadACP: &grantReadACP,
GrantWrite: &granWrite,
GrantWriteACP: &grantWriteACP,
AccessControlPolicy: &types.AccessControlPolicy{Owner: &types.Owner{ID: &owner}},
})
return SendResponse(ctx, err)
}
err := c.be.PutBucket(bucket)
err := c.be.PutBucket(bucket, owner)
return SendResponse(ctx, err)
}
+2 -5
View File
@@ -232,7 +232,7 @@ func TestS3ApiController_ListActions(t *testing.T) {
app := fiber.New()
s3ApiController := S3ApiController{be: &BackendMock{
GetBucketAclFunc: func(bucket string) (*s3.GetBucketAclOutput, error) {
return &s3.GetBucketAclOutput{}, nil
return nil, nil
},
ListMultipartUploadsFunc: func(output *s3.ListMultipartUploadsInput) (s3response.ListMultipartUploadsResponse, error) {
return s3response.ListMultipartUploadsResponse{}, nil
@@ -333,7 +333,7 @@ func TestS3ApiController_PutBucketActions(t *testing.T) {
PutBucketAclFunc: func(*s3.PutBucketAclInput) error {
return nil
},
PutBucketFunc: func(bucket string) error {
PutBucketFunc: func(bucket, owner string) error {
return nil
},
}}
@@ -406,9 +406,6 @@ func TestS3ApiController_PutActions(t *testing.T) {
UploadPartCopyFunc: func(*s3.UploadPartCopyInput) (*s3.UploadPartCopyOutput, error) {
return &s3.UploadPartCopyOutput{}, nil
},
UploadPartFunc: func(bucket, object, uploadId string, Body io.ReadSeeker) (*s3.UploadPartOutput, error) {
return &s3.UploadPartOutput{}, nil
},
PutObjectAclFunc: func(*s3.PutObjectAclInput) error {
return nil
},
+2 -1
View File
@@ -68,7 +68,7 @@ func VerifyV4Signature(root RootUserConfig, iam auth.IAMService, debug bool) fib
return controllers.SendResponse(ctx, s3err.GetAPIError(s3err.ErrCredMalformed))
}
signHdrKv := strings.Split(authParts[2], "=")
signHdrKv := strings.Split(authParts[2][:len(authParts[2])-1], "=")
if len(signHdrKv) != 2 {
return controllers.SendResponse(ctx, s3err.GetAPIError(s3err.ErrCredMalformed))
}
@@ -135,6 +135,7 @@ func VerifyV4Signature(root RootUserConfig, iam auth.IAMService, debug bool) fib
}
ctx.Locals("role", account.Role)
ctx.Locals("access", creds[0])
return ctx.Next()
}