forked from TrueCloudLab/frostfs-s3-gw
[#606] Keep eacl records order on conflict
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
ffd259671a
commit
4082cd6b54
3 changed files with 116 additions and 5 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue