diff --git a/api/handler/acl.go b/api/handler/acl.go index 66d2dd69..a90b8d3b 100644 --- a/api/handler/acl.go +++ b/api/handler/acl.go @@ -299,31 +299,31 @@ func (h *handler) encodeBucketCannedACL(ctx context.Context, bktInfo *data.Bucke DisplayName: ownerDisplayName, }} + granteeOwner := NewGrantee(acpCanonicalUser) + granteeOwner.ID = ownerEncodedID + granteeOwner.DisplayName = ownerDisplayName + res.AccessControlList = []*Grant{{ - Grantee: &Grantee{ - ID: ownerEncodedID, - DisplayName: ownerDisplayName, - Type: acpCanonicalUser, - }, + Grantee: granteeOwner, Permission: aclFullControl, }} switch settings.CannedACL { case basicACLPublic: + grantee := NewGrantee(acpGroup) + grantee.URI = allUsersGroup + res.AccessControlList = append(res.AccessControlList, &Grant{ - Grantee: &Grantee{ - URI: allUsersGroup, - Type: acpGroup, - }, + Grantee: grantee, Permission: aclWrite, }) fallthrough case basicACLReadOnly: + grantee := NewGrantee(acpGroup) + grantee.URI = allUsersGroup + res.AccessControlList = append(res.AccessControlList, &Grant{ - Grantee: &Grantee{ - URI: allUsersGroup, - Type: acpGroup, - }, + Grantee: grantee, Permission: aclRead, }) } diff --git a/api/handler/acl_test.go b/api/handler/acl_test.go index 1f8eefca..dad9d4dc 100644 --- a/api/handler/acl_test.go +++ b/api/handler/acl_test.go @@ -26,6 +26,7 @@ import ( oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session" engineiam "git.frostfs.info/TrueCloudLab/policy-engine/iam" + "git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/stretchr/testify/require" ) @@ -1308,13 +1309,98 @@ func TestPutBucketACL(t *testing.T) { bktInfo := createBucketOldACL(tc, bktName, box) header := map[string]string{api.AmzACL: "public-read"} - putBucketACL(t, tc, bktName, box, header) + putBucketACL(tc, bktName, box, header) header = map[string]string{api.AmzACL: "private"} - putBucketACL(t, tc, bktName, box, header) + putBucketACL(tc, bktName, box, header) checkLastRecords(t, tc, bktInfo, eacl.ActionDeny) } +func TestPutBucketAPE(t *testing.T) { + hc := prepareHandlerContext(t) + bktName := "bucket-for-acl-ape" + + info := createBucket(hc, bktName) + + _, err := hc.tp.ContainerEACL(hc.Context(), info.BktInfo.CID) + require.ErrorContains(t, err, "not found") + + chains, err := hc.h.ape.ListChains(engine.NamespaceTarget("")) + require.NoError(t, err) + require.Len(t, chains, 2) +} + +func TestPutBucketObjectACLErrorAPE(t *testing.T) { + hc := prepareHandlerContext(t) + bktName, objName := "bucket-for-acl-ape", "object" + + info := createBucket(hc, bktName) + putObject(hc, bktName, objName) + + aclBody := &AccessControlPolicy{} + putBucketACLAssertS3Error(hc, bktName, info.Box, nil, aclBody, s3errors.ErrAccessControlListNotSupported) + + putObjectACLAssertS3Error(hc, bktName, objName, info.Box, nil, aclBody, s3errors.ErrAccessControlListNotSupported) + getObjectACLAssertS3Error(hc, bktName, objName, s3errors.ErrAccessControlListNotSupported) +} + +func TestGetBucketACLAPE(t *testing.T) { + hc := prepareHandlerContext(t) + bktName := "bucket-for-acl-ape" + + info := createBucket(hc, bktName) + + aclRes := getBucketACL(hc, bktName) + checkPrivateBucketACL(t, aclRes, info.Key.PublicKey()) + + putBucketACL(hc, bktName, info.Box, map[string]string{api.AmzACL: basicACLPrivate}) + aclRes = getBucketACL(hc, bktName) + checkPrivateBucketACL(t, aclRes, info.Key.PublicKey()) + + putBucketACL(hc, bktName, info.Box, map[string]string{api.AmzACL: basicACLReadOnly}) + aclRes = getBucketACL(hc, bktName) + checkPublicReadBucketACL(t, aclRes, info.Key.PublicKey()) + + putBucketACL(hc, bktName, info.Box, map[string]string{api.AmzACL: basicACLPublic}) + aclRes = getBucketACL(hc, bktName) + checkPublicReadWriteBucketACL(t, aclRes, info.Key.PublicKey()) +} + +func checkPrivateBucketACL(t *testing.T, aclRes *AccessControlPolicy, ownerKey *keys.PublicKey) { + checkBucketACLOwner(t, aclRes, ownerKey, 1) +} + +func checkPublicReadBucketACL(t *testing.T, aclRes *AccessControlPolicy, ownerKey *keys.PublicKey) { + checkBucketACLOwner(t, aclRes, ownerKey, 2) + + require.Equal(t, allUsersGroup, aclRes.AccessControlList[1].Grantee.URI) + require.Equal(t, aclRead, aclRes.AccessControlList[1].Permission) +} + +func checkPublicReadWriteBucketACL(t *testing.T, aclRes *AccessControlPolicy, ownerKey *keys.PublicKey) { + checkBucketACLOwner(t, aclRes, ownerKey, 3) + + require.Equal(t, allUsersGroup, aclRes.AccessControlList[1].Grantee.URI) + require.Equal(t, aclWrite, aclRes.AccessControlList[1].Permission) + + require.Equal(t, allUsersGroup, aclRes.AccessControlList[2].Grantee.URI) + require.Equal(t, aclRead, aclRes.AccessControlList[2].Permission) +} + +func checkBucketACLOwner(t *testing.T, aclRes *AccessControlPolicy, ownerKey *keys.PublicKey, ln int) { + ownerIDStr := hex.EncodeToString(ownerKey.Bytes()) + ownerNameStr := ownerKey.Address() + + require.Equal(t, ownerIDStr, aclRes.Owner.ID) + require.Equal(t, ownerNameStr, aclRes.Owner.DisplayName) + + require.Len(t, aclRes.AccessControlList, ln) + + require.Equal(t, ownerIDStr, aclRes.AccessControlList[0].Grantee.ID) + require.Equal(t, ownerNameStr, aclRes.AccessControlList[0].Grantee.DisplayName) + require.Equal(t, aclFullControl, aclRes.AccessControlList[0].Permission) +} + func TestBucketPolicy(t *testing.T) { hc := prepareHandlerContext(t) bktName := "bucket-for-policy" @@ -1490,15 +1576,26 @@ func createAccessBox(t *testing.T) (*accessbox.Box, *keys.PrivateKey) { return box, key } -func createBucket(hc *handlerContext, bktName string) (*data.BucketInfo, *accessbox.Box) { - box, _ := createAccessBox(hc.t) +type createBucketInfo struct { + BktInfo *data.BucketInfo + Box *accessbox.Box + Key *keys.PrivateKey +} + +func createBucket(hc *handlerContext, bktName string) *createBucketInfo { + box, key := createAccessBox(hc.t) w := createBucketBase(hc, bktName, box) assertStatus(hc.t, w, http.StatusOK) bktInfo, err := hc.Layer().GetBucketInfo(hc.Context(), bktName) require.NoError(hc.t, err) - return bktInfo, box + + return &createBucketInfo{ + BktInfo: bktInfo, + Box: box, + Key: key, + } } func createBucketOldACL(hc *handlerContext, bktName string, box *accessbox.Box) *data.BucketInfo { @@ -1556,13 +1653,64 @@ func createBucketBase(hc *handlerContext, bktName string, box *accessbox.Box) *h return w } -func putBucketACL(t *testing.T, tc *handlerContext, bktName string, box *accessbox.Box, header map[string]string) { - w, r := prepareTestRequest(tc, bktName, "", nil) +func putBucketACL(hc *handlerContext, bktName string, box *accessbox.Box, header map[string]string) { + w := putBucketACLBase(hc, bktName, box, header, nil) + assertStatus(hc.t, w, http.StatusOK) +} + +func putBucketACLAssertS3Error(hc *handlerContext, bktName string, box *accessbox.Box, header map[string]string, body *AccessControlPolicy, code s3errors.ErrorCode) { + w := putBucketACLBase(hc, bktName, box, header, body) + assertS3Error(hc.t, w, s3errors.GetAPIError(code)) +} + +func putBucketACLBase(hc *handlerContext, bktName string, box *accessbox.Box, header map[string]string, body *AccessControlPolicy) *httptest.ResponseRecorder { + w, r := prepareTestRequest(hc, bktName, "", body) for key, val := range header { r.Header.Set(key, val) } ctx := middleware.SetBoxData(r.Context(), box) r = r.WithContext(ctx) - tc.Handler().PutBucketACLHandler(w, r) - assertStatus(t, w, http.StatusOK) + hc.Handler().PutBucketACLHandler(w, r) + return w +} + +func getBucketACL(hc *handlerContext, bktName string) *AccessControlPolicy { + w := getBucketACLBase(hc, bktName) + assertStatus(hc.t, w, http.StatusOK) + res := &AccessControlPolicy{} + parseTestResponse(hc.t, w, res) + return res +} + +func getBucketACLBase(hc *handlerContext, bktName string) *httptest.ResponseRecorder { + w, r := prepareTestRequest(hc, bktName, "", nil) + hc.Handler().GetBucketACLHandler(w, r) + return w +} + +func putObjectACLAssertS3Error(hc *handlerContext, bktName, objName string, box *accessbox.Box, header map[string]string, body *AccessControlPolicy, code s3errors.ErrorCode) { + w := putObjectACLBase(hc, bktName, objName, box, header, body) + assertS3Error(hc.t, w, s3errors.GetAPIError(code)) +} + +func putObjectACLBase(hc *handlerContext, bktName, objName string, box *accessbox.Box, header map[string]string, body *AccessControlPolicy) *httptest.ResponseRecorder { + w, r := prepareTestRequest(hc, bktName, objName, body) + for key, val := range header { + r.Header.Set(key, val) + } + ctx := middleware.SetBoxData(r.Context(), box) + r = r.WithContext(ctx) + hc.Handler().PutObjectACLHandler(w, r) + return w +} + +func getObjectACLAssertS3Error(hc *handlerContext, bktName, objName string, code s3errors.ErrorCode) { + w := getObjectACLBase(hc, bktName, objName) + assertS3Error(hc.t, w, s3errors.GetAPIError(code)) +} + +func getObjectACLBase(hc *handlerContext, bktName, objName string) *httptest.ResponseRecorder { + w, r := prepareTestRequest(hc, bktName, objName, nil) + hc.Handler().GetObjectACLHandler(w, r) + return w } diff --git a/api/handler/handlers_test.go b/api/handler/handlers_test.go index 26b6d384..ff082f68 100644 --- a/api/handler/handlers_test.go +++ b/api/handler/handlers_test.go @@ -266,8 +266,8 @@ func (a *apeMock) DeletePolicy(namespace string, cnrID cid.ID) error { } func createTestBucket(hc *handlerContext, bktName string) *data.BucketInfo { - bktInfo, _ := createBucket(hc, bktName) - return bktInfo + info := createBucket(hc, bktName) + return info.BktInfo } func createTestBucketWithLock(hc *handlerContext, bktName string, conf *data.ObjectLockConfiguration) *data.BucketInfo { diff --git a/api/handler/put_test.go b/api/handler/put_test.go index c195f145..a96c28ea 100644 --- a/api/handler/put_test.go +++ b/api/handler/put_test.go @@ -372,8 +372,8 @@ func TestCreateBucket(t *testing.T) { hc := prepareHandlerContext(t) bktName := "bkt-name" - _, box := createBucket(hc, bktName) - createBucketAssertS3Error(hc, bktName, box, s3errors.ErrBucketAlreadyOwnedByYou) + info := createBucket(hc, bktName) + createBucketAssertS3Error(hc, bktName, info.Box, s3errors.ErrBucketAlreadyOwnedByYou) box2, _ := createAccessBox(t) createBucketAssertS3Error(hc, bktName, box2, s3errors.ErrBucketAlreadyExists) diff --git a/internal/frostfs/frostfs.go b/internal/frostfs/frostfs.go index f541cd2a..95630aca 100644 --- a/internal/frostfs/frostfs.go +++ b/internal/frostfs/frostfs.go @@ -108,7 +108,7 @@ var basicACLZero acl.Basic // If prm.BasicACL is zero, 'eacl-public-read-write' is used. func (x *FrostFS) CreateContainer(ctx context.Context, prm layer.PrmContainerCreate) (*layer.ContainerCreateResult, error) { if prm.BasicACL == basicACLZero { - prm.BasicACL = acl.PublicRW + prm.BasicACL = acl.PublicRWExtended } var cnr container.Container