[#606] Keep eacl records order on conflict

Signed-off-by: Denis Kirillov <denis@nspcc.ru>
remotes/KirillovDenis/feature/192-lifecycle
Denis Kirillov 2022-09-06 10:43:04 +03:00 committed by Alex Vanin
parent ffd259671a
commit 4082cd6b54
3 changed files with 116 additions and 5 deletions

View File

@ -698,9 +698,10 @@ func mergeAst(parent, child *ast) (*ast, bool) {
var newOps []*astOperation
for _, astOp := range resource.Operations {
// get parent matched operations
ops := getAstOps(parentResource, astOp)
switch len(ops) {
case 2:
case 2: // parent contains different actions for the same child operation
// potential inconsistency
if groupGrantee := astOp.IsGroupGrantee(); groupGrantee {
// it is not likely (such state must be detected early)
@ -725,13 +726,12 @@ func mergeAst(parent, child *ast) (*ast, bool) {
if handleRemoveOperations(parentResource, astOp, opToDelete) {
updated = true
}
case 1:
case 1: // parent contains some action for the same child operation
if astOp.Action != ops[0].Action {
// potential inconsistency
if groupGrantee := astOp.IsGroupGrantee(); groupGrantee {
// inconsistency
removeAstOp(parentResource, groupGrantee, astOp.Op, ops[0].Action)
parentResource.Operations = append(parentResource.Operations, astOp)
ops[0].Action = astOp.Action
updated = true
continue
}
@ -746,7 +746,7 @@ func mergeAst(parent, child *ast) (*ast, bool) {
if handleAddOperations(parentResource, astOp, ops[0]) {
updated = true
}
case 0:
case 0: // parent doesn't contain actions for the same child operation
newOps = append(newOps, astOp)
updated = true
}

View File

@ -1,6 +1,7 @@
package handler
import (
"context"
"crypto/ecdsa"
"crypto/rand"
"crypto/sha256"
@ -12,9 +13,13 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neofs-s3-gw/api"
"github.com/nspcc-dev/neofs-s3-gw/api/data"
"github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
"github.com/nspcc-dev/neofs-sdk-go/bearer"
"github.com/nspcc-dev/neofs-sdk-go/eacl"
"github.com/nspcc-dev/neofs-sdk-go/object"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/nspcc-dev/neofs-sdk-go/session"
"github.com/stretchr/testify/require"
)
@ -1287,3 +1292,81 @@ func TestBucketAclToAst(t *testing.T) {
require.NoError(t, err)
require.Equal(t, expectedAst, actualAst)
}
func TestPutBucketACL(t *testing.T) {
tc := prepareHandlerContext(t)
bktName := "bucket-for-acl"
box := createAccessBox(t)
bktInfo := createBucket(t, tc, bktName, box)
header := map[string]string{api.AmzACL: "public-read"}
putBucketACL(t, tc, bktName, box, header)
header = map[string]string{api.AmzACL: "private"}
putBucketACL(t, tc, bktName, box, header)
checkLastRecords(t, tc, bktInfo, eacl.ActionDeny)
}
func checkLastRecords(t *testing.T, tc *handlerContext, bktInfo *data.BucketInfo, action eacl.Action) {
bktACL, err := tc.Layer().GetBucketACL(tc.Context(), bktInfo)
require.NoError(t, err)
length := len(bktACL.EACL.Records())
if length < 7 {
t.Fatalf("length of records is less than 7: '%d'", length)
}
for _, rec := range bktACL.EACL.Records()[length-7:] {
if rec.Action() != action || rec.Targets()[0].Role() != eacl.RoleOthers {
t.Fatalf("inavid last record: '%s', '%s', '%s',", rec.Action(), rec.Operation(), rec.Targets()[0].Role())
}
}
}
func createAccessBox(t *testing.T) *accessbox.Box {
key, err := keys.NewPrivateKey()
require.NoError(t, err)
var bearerToken bearer.Token
err = bearerToken.Sign(key.PrivateKey)
require.NoError(t, err)
tok := new(session.Container)
tok.ForVerb(session.VerbContainerSetEACL)
tok2 := new(session.Container)
tok2.ForVerb(session.VerbContainerPut)
box := &accessbox.Box{
Gate: &accessbox.GateData{
SessionTokens: []*session.Container{tok, tok2},
BearerToken: &bearerToken,
},
}
return box
}
func createBucket(t *testing.T, tc *handlerContext, bktName string, box *accessbox.Box) *data.BucketInfo {
w, r := prepareTestRequest(t, bktName, "", nil)
ctx := context.WithValue(r.Context(), api.BoxData, box)
r = r.WithContext(ctx)
tc.Handler().CreateBucketHandler(w, r)
assertStatus(t, w, http.StatusOK)
bktInfo, err := tc.Layer().GetBucketInfo(tc.Context(), bktName)
require.NoError(t, err)
return bktInfo
}
func putBucketACL(t *testing.T, tc *handlerContext, bktName string, box *accessbox.Box, header map[string]string) {
w, r := prepareTestRequest(t, bktName, "", nil)
for key, val := range header {
r.Header.Set(key, val)
}
ctx := context.WithValue(r.Context(), api.BoxData, box)
r = r.WithContext(ctx)
tc.Handler().PutBucketACLHandler(w, r)
assertStatus(t, w, http.StatusOK)
}

View File

@ -5,6 +5,7 @@ import (
"context"
"crypto/rand"
"crypto/sha256"
"errors"
"fmt"
"io"
"time"
@ -13,6 +14,7 @@ import (
"github.com/nspcc-dev/neofs-sdk-go/checksum"
"github.com/nspcc-dev/neofs-sdk-go/container"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
"github.com/nspcc-dev/neofs-sdk-go/eacl"
"github.com/nspcc-dev/neofs-sdk-go/object"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/nspcc-dev/neofs-sdk-go/session"
@ -24,6 +26,7 @@ type TestNeoFS struct {
objects map[string]*object.Object
containers map[string]*container.Container
eaclTables map[string]*eacl.Table
currentEpoch uint64
}
@ -31,6 +34,7 @@ func NewTestNeoFS() *TestNeoFS {
return &TestNeoFS{
objects: make(map[string]*object.Object),
containers: make(map[string]*container.Container),
eaclTables: make(map[string]*eacl.Table),
}
}
@ -232,3 +236,27 @@ func (t *TestNeoFS) AllObjects(cnrID cid.ID) []oid.ID {
return result
}
func (t *TestNeoFS) SetContainerEACL(_ context.Context, table eacl.Table, _ *session.Container) error {
cnrID, ok := table.CID()
if !ok {
return errors.New("invalid cid")
}
if _, ok = t.containers[cnrID.EncodeToString()]; !ok {
return errors.New("not found")
}
t.eaclTables[cnrID.EncodeToString()] = &table
return nil
}
func (t *TestNeoFS) ContainerEACL(_ context.Context, cnrID cid.ID) (*eacl.Table, error) {
table, ok := t.eaclTables[cnrID.EncodeToString()]
if !ok {
return nil, errors.New("not found")
}
return table, nil
}