From 305dd7598f8e2887f9f19cc7bad862e34eff9d45 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Fri, 17 Jun 2022 16:40:51 +0300 Subject: [PATCH] [#1533] acl: Upgrade NeoFS SDK Go with refactored basic ACL Signed-off-by: Leonard Lyubich --- cmd/neofs-cli/modules/container/create.go | 50 +---- cmd/neofs-cli/modules/container/get.go | 38 +++- go.mod | 2 +- go.sum | 4 +- .../processors/container/process_eacl.go | 7 +- pkg/services/object/acl/acl.go | 45 ++-- pkg/services/object/acl/acl_test.go | 32 ++- pkg/services/object/acl/basic_helper.go | 193 ------------------ pkg/services/object/acl/basic_helper_test.go | 70 ------- pkg/services/object/acl/v2/classifier.go | 16 +- pkg/services/object/acl/v2/errors.go | 2 - pkg/services/object/acl/v2/request.go | 26 +-- pkg/services/object/acl/v2/service.go | 23 +-- pkg/services/object/acl/v2/util.go | 18 +- pkg/services/object/acl/v2/util_test.go | 18 +- 15 files changed, 115 insertions(+), 429 deletions(-) delete mode 100644 pkg/services/object/acl/basic_helper.go delete mode 100644 pkg/services/object/acl/basic_helper_test.go diff --git a/cmd/neofs-cli/modules/container/create.go b/cmd/neofs-cli/modules/container/create.go index 3a9c0dd1e..f86862e7b 100644 --- a/cmd/neofs-cli/modules/container/create.go +++ b/cmd/neofs-cli/modules/container/create.go @@ -13,8 +13,8 @@ import ( "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key" - "github.com/nspcc-dev/neofs-sdk-go/acl" "github.com/nspcc-dev/neofs-sdk-go/container" + "github.com/nspcc-dev/neofs-sdk-go/container/acl" "github.com/nspcc-dev/neofs-sdk-go/netmap" "github.com/nspcc-dev/neofs-sdk-go/session" subnetid "github.com/nspcc-dev/neofs-sdk-go/subnet/id" @@ -23,31 +23,6 @@ import ( "github.com/spf13/cobra" ) -// keywords of predefined basic ACL values -const ( - basicACLPrivate = "private" - basicACLReadOnly = "public-read" - basicACLPublic = "public-read-write" - basicACLAppend = "public-append" - - basicACLNoFinalPrivate = "eacl-private" - basicACLNoFinalReadOnly = "eacl-public-read" - basicACLNoFinalPublic = "eacl-public-read-write" - basicACLNoFinalAppend = "eacl-public-append" -) - -var wellKnownBasicACL = map[string]acl.BasicACL{ - basicACLPublic: acl.PublicBasicRule, - basicACLPrivate: acl.PrivateBasicRule, - basicACLReadOnly: acl.ReadOnlyBasicRule, - basicACLAppend: acl.PublicAppendRule, - - basicACLNoFinalPublic: acl.EACLPublicBasicRule, - basicACLNoFinalPrivate: acl.EACLPrivateBasicRule, - basicACLNoFinalReadOnly: acl.EACLReadOnlyBasicRule, - basicACLNoFinalAppend: acl.EACLPublicAppendRule, -} - var ( containerACL string containerNonce string @@ -80,8 +55,8 @@ It will be stored in sidechain when inner ring will accepts it.`, attributes, err := parseAttributes(containerAttributes) common.ExitOnErr(cmd, "", err) - basicACL, err := parseBasicACL(containerACL) - common.ExitOnErr(cmd, "", err) + var basicACL acl.Basic + common.ExitOnErr(cmd, "decode basic ACL string: %w", basicACL.DecodeString(containerACL)) nonce, err := parseNonce(containerNonce) common.ExitOnErr(cmd, "", err) @@ -157,7 +132,9 @@ func initContainerCreateCmd() { flags := createContainerCmd.Flags() - flags.StringVar(&containerACL, "basic-acl", basicACLPrivate, fmt.Sprintf("hex encoded basic ACL value or keywords like '%s', '%s', '%s'", basicACLPublic, basicACLPrivate, basicACLNoFinalReadOnly)) + flags.StringVar(&containerACL, "basic-acl", acl.NamePrivate, fmt.Sprintf("hex encoded basic ACL value or keywords like '%s', '%s', '%s'", + acl.NamePublicRW, acl.NamePrivate, acl.NamePublicROExtended, + )) flags.StringVarP(&containerPolicy, "policy", "p", "", "QL-encoded or JSON-encoded placement policy or path to file with it") flags.StringSliceVarP(&containerAttributes, "attributes", "a", nil, "comma separated pairs of container attributes in form of Key1=Value1,Key2=Value2") flags.StringVarP(&containerNonce, "nonce", "n", "", "UUIDv4 nonce value for container") @@ -226,21 +203,6 @@ func parseAttributes(attributes []string) ([]container.Attribute, error) { return result, nil } -func parseBasicACL(basicACL string) (acl.BasicACL, error) { - if value, ok := wellKnownBasicACL[basicACL]; ok { - return value, nil - } - - basicACL = strings.Trim(strings.ToLower(basicACL), "0x") - - value, err := strconv.ParseUint(basicACL, 16, 32) - if err != nil { - return 0, fmt.Errorf("can't parse basic ACL: %s", basicACL) - } - - return acl.BasicACL(value), nil -} - func parseNonce(nonce string) (uuid.UUID, error) { if nonce == "" { result := uuid.New() diff --git a/cmd/neofs-cli/modules/container/get.go b/cmd/neofs-cli/modules/container/get.go index 6386b41eb..1bbc071a8 100644 --- a/cmd/neofs-cli/modules/container/get.go +++ b/cmd/neofs-cli/modules/container/get.go @@ -9,8 +9,8 @@ import ( "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags" "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key" - "github.com/nspcc-dev/neofs-sdk-go/acl" "github.com/nspcc-dev/neofs-sdk-go/container" + "github.com/nspcc-dev/neofs-sdk-go/container/acl" "github.com/spf13/cobra" ) @@ -120,7 +120,7 @@ func prettyPrintContainer(cmd *cobra.Command, cnr *container.Container, jsonEnco cmd.Println("owner ID:", cnr.OwnerID()) basicACL := cnr.BasicACL() - prettyPrintBasicACL(cmd, acl.BasicACL(basicACL)) + prettyPrintBasicACL(cmd, basicACL) for _, attribute := range cnr.Attributes() { if attribute.Key() == container.AttributeTimestamp { @@ -152,13 +152,33 @@ func prettyPrintContainer(cmd *cobra.Command, cnr *container.Container, jsonEnco } } -func prettyPrintBasicACL(cmd *cobra.Command, basicACL acl.BasicACL) { - cmd.Printf("basic ACL: %s", basicACL) - for k, v := range wellKnownBasicACL { - if v == basicACL { - cmd.Printf(" (%s)\n", k) - return - } +func prettyPrintBasicACL(cmd *cobra.Command, basicACL acl.Basic) { + cmd.Printf("basic ACL: %s", basicACL.EncodeToString()) + + var prettyName string + + switch basicACL { + case acl.Private: + prettyName = acl.NamePrivate + case acl.PrivateExtended: + prettyName = acl.NamePrivateExtended + case acl.PublicRO: + prettyName = acl.NamePublicRO + case acl.PublicROExtended: + prettyName = acl.NamePublicROExtended + case acl.PublicRW: + prettyName = acl.NamePublicRW + case acl.PublicRWExtended: + prettyName = acl.NamePublicRWExtended + case acl.PublicAppend: + prettyName = acl.NamePublicAppend + case acl.PublicAppendExtended: + prettyName = acl.NamePublicAppendExtended } + + if prettyName != "" { + cmd.Printf(" (%s)", prettyName) + } + cmd.Println() } diff --git a/go.mod b/go.mod index bb8533eb4..051d0d336 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220601120906-3bec6657f5c5 // indirect github.com/nspcc-dev/neofs-api-go/v2 v2.12.3-0.20220621170933-dd233c3fbc84 github.com/nspcc-dev/neofs-contract v0.15.1 - github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.4.0.20220622125136-af7e20073bc6 + github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.4.0.20220623080532-aa5ee1dcde1c github.com/nspcc-dev/tzhash v1.5.2 github.com/panjf2000/ants/v2 v2.4.0 github.com/paulmach/orb v0.2.2 diff --git a/go.sum b/go.sum index 03bd1e2a4..0877a207d 100644 --- a/go.sum +++ b/go.sum @@ -409,8 +409,8 @@ github.com/nspcc-dev/neofs-crypto v0.3.0 h1:zlr3pgoxuzrmGCxc5W8dGVfA9Rro8diFvVnB github.com/nspcc-dev/neofs-crypto v0.3.0/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw= github.com/nspcc-dev/neofs-sdk-go v0.0.0-20211201182451-a5b61c4f6477/go.mod h1:dfMtQWmBHYpl9Dez23TGtIUKiFvCIxUZq/CkSIhEpz4= github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659/go.mod h1:/jay1lr3w7NQd/VDBkEhkJmDmyPNsu4W+QV2obsUV40= -github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.4.0.20220622125136-af7e20073bc6 h1:SrD9Qo8Knh5B08WC3XD5GKqt2tiG4ToCm+gc5BPQKxY= -github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.4.0.20220622125136-af7e20073bc6/go.mod h1:EpzpilARa1/7Pgtn8qB/iXXyvC1AIzhlm8mbU+S52MU= +github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.4.0.20220623080532-aa5ee1dcde1c h1:1kYefIk0WdUZJPsZ5HXN7hdNgsb3gEP+/AVMS6lxUzI= +github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.4.0.20220623080532-aa5ee1dcde1c/go.mod h1:EpzpilARa1/7Pgtn8qB/iXXyvC1AIzhlm8mbU+S52MU= github.com/nspcc-dev/rfc6979 v0.1.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso= github.com/nspcc-dev/rfc6979 v0.2.0 h1:3e1WNxrN60/6N0DW7+UYisLeZJyfqZTNOjeV/toYvOE= github.com/nspcc-dev/rfc6979 v0.2.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso= diff --git a/pkg/innerring/processors/container/process_eacl.go b/pkg/innerring/processors/container/process_eacl.go index 747218ee7..b8c9e4d19 100644 --- a/pkg/innerring/processors/container/process_eacl.go +++ b/pkg/innerring/processors/container/process_eacl.go @@ -52,12 +52,7 @@ func (cp *Processor) checkSetEACL(e container.SetEACL) error { } // ACL extensions can be disabled by basic ACL, check it - basicACL := cnr.Value.BasicACL() - const finalBitMask = 1 << 28 - - // Temp solution: NeoFS SDK is going to provide convenient interface to do this soon. - // This place won't be missed since BasicACL() signature will be changed. - if basicACL&finalBitMask == finalBitMask { + if !cnr.Value.BasicACL().Extendable() { return errors.New("ACL extension disabled by container basic ACL") } diff --git a/pkg/services/object/acl/acl.go b/pkg/services/object/acl/acl.go index c14551b21..69458527a 100644 --- a/pkg/services/object/acl/acl.go +++ b/pkg/services/object/acl/acl.go @@ -14,6 +14,7 @@ import ( eaclV2 "github.com/nspcc-dev/neofs-node/pkg/services/object/acl/eacl/v2" v2 "github.com/nspcc-dev/neofs-node/pkg/services/object/acl/v2" bearerSDK "github.com/nspcc-dev/neofs-sdk-go/bearer" + "github.com/nspcc-dev/neofs-sdk-go/container/acl" neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa" eaclSDK "github.com/nspcc-dev/neofs-sdk-go/eacl" "github.com/nspcc-dev/neofs-sdk-go/user" @@ -91,35 +92,18 @@ func NewChecker(prm *CheckerPrm) *Checker { // CheckBasicACL is a main check function for basic ACL. func (c *Checker) CheckBasicACL(info v2.RequestInfo) bool { // check basic ACL permissions - var checkFn func(eaclSDK.Operation) bool - - switch info.RequestRole() { - case eaclSDK.RoleUser: - checkFn = basicACLHelper(info.BasicACL()).UserAllowed - case eaclSDK.RoleSystem: - checkFn = basicACLHelper(info.BasicACL()).SystemAllowed - if info.IsInnerRing() { - checkFn = basicACLHelper(info.BasicACL()).InnerRingAllowed - } - case eaclSDK.RoleOthers: - checkFn = basicACLHelper(info.BasicACL()).OthersAllowed - default: - // log there - return false - } - - return checkFn(info.Operation()) + return info.BasicACL().IsOpAllowed(info.Operation(), info.RequestRole()) } // StickyBitCheck validates owner field in the request if sticky bit is enabled. func (c *Checker) StickyBitCheck(info v2.RequestInfo, owner user.ID) bool { // According to NeoFS specification sticky bit has no effect on system nodes // for correct intra-container work with objects (in particular, replication). - if info.RequestRole() == eaclSDK.RoleSystem { + if info.RequestRole() == acl.RoleContainer { return true } - if !basicACLHelper(info.BasicACL()).Sticky() { + if !info.BasicACL().Sticky() { return true } @@ -134,12 +118,13 @@ func (c *Checker) StickyBitCheck(info v2.RequestInfo, owner user.ID) bool { // CheckEACL is a main check function for extended ACL. func (c *Checker) CheckEACL(msg interface{}, reqInfo v2.RequestInfo) error { - if basicACLHelper(reqInfo.BasicACL()).Final() { + basicACL := reqInfo.BasicACL() + if !basicACL.Extendable() { return nil } // if bearer token is not allowed, then ignore it - if !basicACLHelper(reqInfo.BasicACL()).BearerAllowed(reqInfo.Operation()) { + if !basicACL.AllowedBearerRules(reqInfo.Operation()) { reqInfo.CleanBearer() } @@ -190,9 +175,21 @@ func (c *Checker) CheckEACL(msg interface{}, reqInfo v2.RequestInfo) error { return fmt.Errorf("can't parse headers: %w", err) } + var eaclRole eaclSDK.Role + switch op := reqInfo.RequestRole(); op { + default: + eaclRole = eaclSDK.Role(op) + case acl.RoleOwner: + eaclRole = eaclSDK.RoleUser + case acl.RoleInnerRing, acl.RoleContainer: + eaclRole = eaclSDK.RoleSystem + case acl.RoleOthers: + eaclRole = eaclSDK.RoleOthers + } + action, _ := c.validator.CalculateAction(new(eaclSDK.ValidationUnit). - WithRole(reqInfo.RequestRole()). - WithOperation(reqInfo.Operation()). + WithRole(eaclRole). + WithOperation(eaclSDK.Operation(reqInfo.Operation())). WithContainerID(&cnr). WithSenderKey(reqInfo.SenderKey()). WithHeaderSource(hdrSrc). diff --git a/pkg/services/object/acl/acl_test.go b/pkg/services/object/acl/acl_test.go index f31263d69..a0de5e6f1 100644 --- a/pkg/services/object/acl/acl_test.go +++ b/pkg/services/object/acl/acl_test.go @@ -6,6 +6,7 @@ import ( "github.com/nspcc-dev/neofs-node/pkg/core/container" "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/engine" v2 "github.com/nspcc-dev/neofs-node/pkg/services/object/acl/v2" + "github.com/nspcc-dev/neofs-sdk-go/container/acl" cid "github.com/nspcc-dev/neofs-sdk-go/container/id" eaclSDK "github.com/nspcc-dev/neofs-sdk-go/eacl" "github.com/nspcc-dev/neofs-sdk-go/user" @@ -37,13 +38,14 @@ func TestStickyCheck(t *testing.T) { var info v2.RequestInfo info.SetSenderKey(make([]byte, 33)) // any non-empty key - info.SetRequestRole(eaclSDK.RoleSystem) - - setSticky(&info, true) + info.SetRequestRole(acl.RoleContainer) require.True(t, checker.StickyBitCheck(info, *usertest.ID())) - setSticky(&info, false) + var basicACL acl.Basic + basicACL.MakeSticky() + + info.SetBasicACL(basicACL) require.True(t, checker.StickyBitCheck(info, *usertest.ID())) }) @@ -51,13 +53,15 @@ func TestStickyCheck(t *testing.T) { t.Run("owner ID and/or public key emptiness", func(t *testing.T) { var info v2.RequestInfo - info.SetRequestRole(eaclSDK.RoleOthers) // should be non-system role + info.SetRequestRole(acl.RoleOthers) // should be non-system role assertFn := func(isSticky, withKey, withOwner, expected bool) { + info := info if isSticky { - setSticky(&info, true) - } else { - setSticky(&info, false) + var basicACL acl.Basic + basicACL.MakeSticky() + + info.SetBasicACL(basicACL) } if withKey { @@ -84,15 +88,3 @@ func TestStickyCheck(t *testing.T) { assertFn(false, true, true, true) }) } - -func setSticky(req *v2.RequestInfo, enabled bool) { - bh := basicACLHelper(req.BasicACL()) - - if enabled { - bh.SetSticky() - } else { - bh.ResetSticky() - } - - req.SetBasicACL(uint32(bh)) -} diff --git a/pkg/services/object/acl/basic_helper.go b/pkg/services/object/acl/basic_helper.go deleted file mode 100644 index ba3bae1e2..000000000 --- a/pkg/services/object/acl/basic_helper.go +++ /dev/null @@ -1,193 +0,0 @@ -package acl - -import ( - "github.com/nspcc-dev/neofs-sdk-go/eacl" -) - -// wrapper around basic ACL to provide easy access to basic ACL fields -type basicACLHelper uint32 - -const ( - reservedBitNumber = 2 // first left bits are reserved - stickyBitPos = reservedBitNumber // X-bit after reserved bits - finalBitPos = stickyBitPos + 1 // F-bit after X-bit -) - -const ( - opOffset = finalBitPos + 1 // offset of operation bits - bitsPerOp = 4 // number of bits per operation - opNumber = 7 // number of operation bit sections -) - -const ( - bitUser uint8 = iota - bitSystem - bitOthers - bitBearer -) - -const leftACLBitPos = opOffset + bitsPerOp*opNumber - 1 - -var order = map[eacl.Operation]uint8{ - eacl.OperationRangeHash: 0, - eacl.OperationRange: 1, - eacl.OperationSearch: 2, - eacl.OperationDelete: 3, - eacl.OperationPut: 4, - eacl.OperationHead: 5, - eacl.OperationGet: 6, -} - -// returns true if n-th left bit is set (starting at 0). -func isLeftBitSet(value basicACLHelper, n uint8) bool { - bitMask := basicACLHelper(1 << (leftACLBitPos - n)) - return bitMask != 0 && value&bitMask == bitMask -} - -// sets n-th left bit (starting at 0). -func setLeftBit(value *basicACLHelper, n uint8) { - *value |= basicACLHelper(1 << (leftACLBitPos - n)) -} - -// resets n-th left bit (starting at 0). -func resetLeftBit(value *basicACLHelper, n uint8) { - *value &= ^basicACLHelper(1 << (leftACLBitPos - n)) -} - -// Final returns true if final option is enabled in ACL. -func (a basicACLHelper) Final() bool { - return isLeftBitSet(a, finalBitPos) -} - -// SetFinal enables final option in ACL. -func (a *basicACLHelper) SetFinal() { - setLeftBit(a, finalBitPos) -} - -// ResetFinal disables final option in ACL. -func (a *basicACLHelper) ResetFinal() { - resetLeftBit(a, finalBitPos) -} - -// Sticky returns true if sticky option is enabled in ACL. -func (a basicACLHelper) Sticky() bool { - return isLeftBitSet(a, stickyBitPos) -} - -// SetSticky enables the sticky option in ACL. -func (a *basicACLHelper) SetSticky() { - setLeftBit(a, stickyBitPos) -} - -// ResetSticky disables the sticky option in ACL. -func (a *basicACLHelper) ResetSticky() { - resetLeftBit(a, stickyBitPos) -} - -// UserAllowed returns true if user allowed the n-th operation in ACL. -func (a basicACLHelper) UserAllowed(op eacl.Operation) bool { - if n, ok := order[op]; ok { - return isLeftBitSet(a, opOffset+n*bitsPerOp+bitUser) - } - return false -} - -// AllowUser allows user the n-th operation in ACL. -func (a *basicACLHelper) AllowUser(op eacl.Operation) { - if n, ok := order[op]; ok { - setLeftBit(a, opOffset+n*bitsPerOp+bitUser) - } -} - -// ForbidUser forbids user the n-th operation in ACL. -func (a *basicACLHelper) ForbidUser(op eacl.Operation) { - if n, ok := order[op]; ok { - resetLeftBit(a, opOffset+n*bitsPerOp+bitUser) - } -} - -// SystemAllowed returns true if System group allowed the n-th operation is set in ACL. -func (a basicACLHelper) SystemAllowed(op eacl.Operation) bool { - if op != eacl.OperationDelete && op != eacl.OperationRange { - return true - } - - if n, ok := order[op]; ok { - return isLeftBitSet(a, opOffset+n*bitsPerOp+bitSystem) - } - - return false -} - -// InnerRingAllowed returns true if the operation is allowed by ACL for -// InnerRing nodes, as part of System group. -func (a basicACLHelper) InnerRingAllowed(op eacl.Operation) bool { - switch op { - case eacl.OperationSearch, eacl.OperationRangeHash, eacl.OperationHead, eacl.OperationGet: - return true - default: - if n, ok := order[op]; ok { - return isLeftBitSet(a, opOffset+n*bitsPerOp+bitSystem) - } - - return false - } -} - -// AllowSystem allows System group the n-th operation in ACL. -func (a *basicACLHelper) AllowSystem(op eacl.Operation) { - if n, ok := order[op]; ok { - setLeftBit(a, opOffset+n*bitsPerOp+bitSystem) - } -} - -// ForbidSystem forbids System group the n-th operation in ACL. -func (a *basicACLHelper) ForbidSystem(op eacl.Operation) { - if n, ok := order[op]; ok { - resetLeftBit(a, opOffset+n*bitsPerOp+bitSystem) - } -} - -// OthersAllowed returns true if Others group allowed the n-th operation is set in ACL. -func (a basicACLHelper) OthersAllowed(op eacl.Operation) bool { - if n, ok := order[op]; ok { - return isLeftBitSet(a, opOffset+n*bitsPerOp+bitOthers) - } - return false -} - -// AllowOthers allows Others group the n-th operation in ACL. -func (a *basicACLHelper) AllowOthers(op eacl.Operation) { - if n, ok := order[op]; ok { - setLeftBit(a, opOffset+n*bitsPerOp+bitOthers) - } -} - -// ForbidOthers forbids Others group the n-th operation in ACL. -func (a *basicACLHelper) ForbidOthers(op eacl.Operation) { - if n, ok := order[op]; ok { - resetLeftBit(a, opOffset+n*bitsPerOp+bitOthers) - } -} - -// BearerAllowed returns true if Bearer token usage is allowed for n-th operation in ACL. -func (a basicACLHelper) BearerAllowed(op eacl.Operation) bool { - if n, ok := order[op]; ok { - return isLeftBitSet(a, opOffset+n*bitsPerOp+bitBearer) - } - return false -} - -// AllowBearer allows Bearer token usage for n-th operation in ACL. -func (a *basicACLHelper) AllowBearer(op eacl.Operation) { - if n, ok := order[op]; ok { - setLeftBit(a, opOffset+n*bitsPerOp+bitBearer) - } -} - -// ForbidBearer forbids Bearer token usage for n-th operation in ACL. -func (a *basicACLHelper) ForbidBearer(op eacl.Operation) { - if n, ok := order[op]; ok { - resetLeftBit(a, opOffset+n*bitsPerOp+bitBearer) - } -} diff --git a/pkg/services/object/acl/basic_helper_test.go b/pkg/services/object/acl/basic_helper_test.go deleted file mode 100644 index ded0041ba..000000000 --- a/pkg/services/object/acl/basic_helper_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package acl - -import ( - "testing" - - "github.com/nspcc-dev/neofs-sdk-go/eacl" - "github.com/stretchr/testify/require" -) - -// from neofs-api basic ACL specification -const ( - privateContainer uint32 = 0x1C8C8CCC - publicContainerWithSticky uint32 = 0x3FFFFFFF - readonlyContainer uint32 = 0x1FFFCCFF -) - -var ( - allOperations = []eacl.Operation{ - eacl.OperationGet, eacl.OperationPut, eacl.OperationDelete, - eacl.OperationHead, eacl.OperationSearch, eacl.OperationRange, - eacl.OperationRangeHash, - } -) - -func TestDefaultBasicACLs(t *testing.T) { - t.Run("private", func(t *testing.T) { - r := basicACLHelper(privateContainer) - - require.False(t, r.Sticky()) - - for _, op := range allOperations { - require.True(t, r.UserAllowed(op)) - require.False(t, r.OthersAllowed(op)) - if op == eacl.OperationDelete || op == eacl.OperationRange { - require.False(t, r.SystemAllowed(op)) - } else { - require.True(t, r.SystemAllowed(op)) - } - } - }) - - t.Run("public with sticky", func(t *testing.T) { - r := basicACLHelper(publicContainerWithSticky) - - require.True(t, r.Sticky()) - - for _, op := range allOperations { - require.True(t, r.UserAllowed(op)) - require.True(t, r.OthersAllowed(op)) - require.True(t, r.SystemAllowed(op)) - } - }) - - t.Run("read only", func(t *testing.T) { - r := basicACLHelper(readonlyContainer) - - require.False(t, r.Sticky()) - - for _, op := range allOperations { - require.True(t, r.UserAllowed(op)) - require.True(t, r.SystemAllowed(op)) - - if op == eacl.OperationDelete || op == eacl.OperationPut { - require.False(t, r.OthersAllowed(op)) - } else { - require.True(t, r.OthersAllowed(op)) - } - } - }) -} diff --git a/pkg/services/object/acl/v2/classifier.go b/pkg/services/object/acl/v2/classifier.go index 13d114f8a..99fe2a593 100644 --- a/pkg/services/object/acl/v2/classifier.go +++ b/pkg/services/object/acl/v2/classifier.go @@ -7,8 +7,8 @@ import ( core "github.com/nspcc-dev/neofs-node/pkg/core/netmap" "github.com/nspcc-dev/neofs-sdk-go/container" + "github.com/nspcc-dev/neofs-sdk-go/container/acl" cid "github.com/nspcc-dev/neofs-sdk-go/container/id" - eaclSDK "github.com/nspcc-dev/neofs-sdk-go/eacl" "github.com/nspcc-dev/neofs-sdk-go/netmap" "go.uber.org/zap" ) @@ -20,8 +20,7 @@ type senderClassifier struct { } type classifyResult struct { - role eaclSDK.Role - isIR bool + role acl.Role key []byte } @@ -46,8 +45,7 @@ func (c senderClassifier) classify( // if request owner is the same as container owner, return RoleUser if ownerID.Equals(*ownerCnr) { return &classifyResult{ - role: eaclSDK.RoleUser, - isIR: false, + role: acl.RoleOwner, key: ownerKeyInBytes, }, nil } @@ -59,8 +57,7 @@ func (c senderClassifier) classify( zap.String("error", err.Error())) } else if isInnerRingNode { return &classifyResult{ - role: eaclSDK.RoleSystem, - isIR: true, + role: acl.RoleInnerRing, key: ownerKeyInBytes, }, nil } @@ -77,15 +74,14 @@ func (c senderClassifier) classify( zap.String("error", err.Error())) } else if isContainerNode { return &classifyResult{ - role: eaclSDK.RoleSystem, - isIR: false, + role: acl.RoleContainer, key: ownerKeyInBytes, }, nil } // if none of above, return RoleOthers return &classifyResult{ - role: eaclSDK.RoleOthers, + role: acl.RoleOthers, key: ownerKeyInBytes, }, nil } diff --git a/pkg/services/object/acl/v2/errors.go b/pkg/services/object/acl/v2/errors.go index 249db466e..651673116 100644 --- a/pkg/services/object/acl/v2/errors.go +++ b/pkg/services/object/acl/v2/errors.go @@ -11,8 +11,6 @@ var ( // ErrMalformedRequest is returned when request contains // invalid data. ErrMalformedRequest = errors.New("malformed request") - // ErrUnknownRole is returned when role of the sender is unknown. - ErrUnknownRole = errors.New("can't classify request sender") // ErrInvalidVerb is returned when session token verb doesn't include necessary operation. ErrInvalidVerb = errors.New("session token verb is invalid") ) diff --git a/pkg/services/object/acl/v2/request.go b/pkg/services/object/acl/v2/request.go index a136c9d5b..7eaf9bd09 100644 --- a/pkg/services/object/acl/v2/request.go +++ b/pkg/services/object/acl/v2/request.go @@ -7,8 +7,8 @@ import ( "github.com/nspcc-dev/neo-go/pkg/crypto/keys" sessionV2 "github.com/nspcc-dev/neofs-api-go/v2/session" "github.com/nspcc-dev/neofs-sdk-go/bearer" + "github.com/nspcc-dev/neofs-sdk-go/container/acl" cid "github.com/nspcc-dev/neofs-sdk-go/container/id" - eaclSDK "github.com/nspcc-dev/neofs-sdk-go/eacl" oid "github.com/nspcc-dev/neofs-sdk-go/object/id" sessionSDK "github.com/nspcc-dev/neofs-sdk-go/session" "github.com/nspcc-dev/neofs-sdk-go/user" @@ -17,11 +17,10 @@ import ( // RequestInfo groups parsed version-independent (from SDK library) // request information and raw API request. type RequestInfo struct { - basicACL uint32 - requestRole eaclSDK.Role - isInnerRing bool - operation eaclSDK.Operation // put, get, head, etc. - cnrOwner user.ID // container owner + basicACL acl.Basic + requestRole acl.Role + operation acl.Op // put, get, head, etc. + cnrOwner user.ID // container owner idCnr cid.ID @@ -36,11 +35,11 @@ type RequestInfo struct { srcRequest interface{} } -func (r *RequestInfo) SetBasicACL(basicACL uint32) { +func (r *RequestInfo) SetBasicACL(basicACL acl.Basic) { r.basicACL = basicACL } -func (r *RequestInfo) SetRequestRole(requestRole eaclSDK.Role) { +func (r *RequestInfo) SetRequestRole(requestRole acl.Role) { r.requestRole = requestRole } @@ -78,13 +77,8 @@ func (r RequestInfo) Bearer() *bearer.Token { return r.bearer } -// IsInnerRing specifies if request was made by inner ring. -func (r RequestInfo) IsInnerRing() bool { - return r.isInnerRing -} - // BasicACL returns basic ACL of the container. -func (r RequestInfo) BasicACL() uint32 { +func (r RequestInfo) BasicACL() acl.Basic { return r.basicACL } @@ -94,12 +88,12 @@ func (r RequestInfo) SenderKey() []byte { } // Operation returns request's operation. -func (r RequestInfo) Operation() eaclSDK.Operation { +func (r RequestInfo) Operation() acl.Op { return r.operation } // RequestRole returns request sender's role. -func (r RequestInfo) RequestRole() eaclSDK.Role { +func (r RequestInfo) RequestRole() acl.Role { return r.requestRole } diff --git a/pkg/services/object/acl/v2/service.go b/pkg/services/object/acl/v2/service.go index ec5894d75..ac3a8931c 100644 --- a/pkg/services/object/acl/v2/service.go +++ b/pkg/services/object/acl/v2/service.go @@ -9,8 +9,8 @@ import ( "github.com/nspcc-dev/neofs-node/pkg/core/container" "github.com/nspcc-dev/neofs-node/pkg/core/netmap" "github.com/nspcc-dev/neofs-node/pkg/services/object" + "github.com/nspcc-dev/neofs-sdk-go/container/acl" cid "github.com/nspcc-dev/neofs-sdk-go/container/id" - eaclSDK "github.com/nspcc-dev/neofs-sdk-go/eacl" sessionSDK "github.com/nspcc-dev/neofs-sdk-go/session" "github.com/nspcc-dev/neofs-sdk-go/user" "go.uber.org/zap" @@ -130,7 +130,7 @@ func (b Service) Get(request *objectV2.GetRequest, stream object.GetObjectStream src: request, } - reqInfo, err := b.findRequestInfo(req, cnr, eaclSDK.OperationGet) + reqInfo, err := b.findRequestInfo(req, cnr, acl.OpObjectGet) if err != nil { return err } @@ -189,7 +189,7 @@ func (b Service) Head( src: request, } - reqInfo, err := b.findRequestInfo(req, cnr, eaclSDK.OperationHead) + reqInfo, err := b.findRequestInfo(req, cnr, acl.OpObjectHead) if err != nil { return nil, err } @@ -240,7 +240,7 @@ func (b Service) Search(request *objectV2.SearchRequest, stream object.SearchStr src: request, } - reqInfo, err := b.findRequestInfo(req, id, eaclSDK.OperationSearch) + reqInfo, err := b.findRequestInfo(req, id, acl.OpObjectSearch) if err != nil { return err } @@ -288,7 +288,7 @@ func (b Service) Delete( src: request, } - reqInfo, err := b.findRequestInfo(req, cnr, eaclSDK.OperationDelete) + reqInfo, err := b.findRequestInfo(req, cnr, acl.OpObjectDelete) if err != nil { return nil, err } @@ -332,7 +332,7 @@ func (b Service) GetRange(request *objectV2.GetRangeRequest, stream object.GetOb src: request, } - reqInfo, err := b.findRequestInfo(req, cnr, eaclSDK.OperationRange) + reqInfo, err := b.findRequestInfo(req, cnr, acl.OpObjectRange) if err != nil { return err } @@ -381,7 +381,7 @@ func (b Service) GetRangeHash( src: request, } - reqInfo, err := b.findRequestInfo(req, cnr, eaclSDK.OperationRangeHash) + reqInfo, err := b.findRequestInfo(req, cnr, acl.OpObjectHash) if err != nil { return nil, err } @@ -450,7 +450,7 @@ func (p putStreamBasicChecker) Send(request *objectV2.PutRequest) error { src: request, } - reqInfo, err := p.source.findRequestInfo(req, cnr, eaclSDK.OperationPut) + reqInfo, err := p.source.findRequestInfo(req, cnr, acl.OpObjectPut) if err != nil { return err } @@ -502,7 +502,7 @@ func (g *searchStreamBasicChecker) Send(resp *objectV2.SearchResponse) error { return g.SearchStream.Send(resp) } -func (b Service) findRequestInfo(req MetaWithToken, idCnr cid.ID, op eaclSDK.Operation) (info RequestInfo, err error) { +func (b Service) findRequestInfo(req MetaWithToken, idCnr cid.ID, op acl.Op) (info RequestInfo, err error) { cnr, err := b.containers.Get(idCnr) // fetch actual container if err != nil { return info, err @@ -531,13 +531,8 @@ func (b Service) findRequestInfo(req MetaWithToken, idCnr cid.ID, op eaclSDK.Ope return info, err } - if res.role == eaclSDK.RoleUnknown { - return info, ErrUnknownRole - } - info.basicACL = cnr.Value.BasicACL() info.requestRole = res.role - info.isInnerRing = res.isIR info.operation = op info.cnrOwner = *cnr.Value.OwnerID() info.idCnr = idCnr diff --git a/pkg/services/object/acl/v2/util.go b/pkg/services/object/acl/v2/util.go index 706ede4e5..3d2797c22 100644 --- a/pkg/services/object/acl/v2/util.go +++ b/pkg/services/object/acl/v2/util.go @@ -11,8 +11,8 @@ import ( refsV2 "github.com/nspcc-dev/neofs-api-go/v2/refs" sessionV2 "github.com/nspcc-dev/neofs-api-go/v2/session" "github.com/nspcc-dev/neofs-sdk-go/bearer" + "github.com/nspcc-dev/neofs-sdk-go/container/acl" cid "github.com/nspcc-dev/neofs-sdk-go/container/id" - eaclSDK "github.com/nspcc-dev/neofs-sdk-go/eacl" oid "github.com/nspcc-dev/neofs-sdk-go/object/id" sessionSDK "github.com/nspcc-dev/neofs-sdk-go/session" "github.com/nspcc-dev/neofs-sdk-go/user" @@ -205,27 +205,27 @@ func isOwnerFromKey(id user.ID, key *keys.PublicKey) bool { } // assertVerb checks that token verb corresponds to op. -func assertVerb(tok sessionSDK.Object, op eaclSDK.Operation) bool { +func assertVerb(tok sessionSDK.Object, op acl.Op) bool { //nolint:exhaustive switch op { - case eaclSDK.OperationPut: + case acl.OpObjectPut: return tok.AssertVerb(sessionSDK.VerbObjectPut, sessionSDK.VerbObjectDelete) - case eaclSDK.OperationDelete: + case acl.OpObjectDelete: return tok.AssertVerb(sessionSDK.VerbObjectDelete) - case eaclSDK.OperationGet: + case acl.OpObjectGet: return tok.AssertVerb(sessionSDK.VerbObjectGet) - case eaclSDK.OperationHead: + case acl.OpObjectHead: return tok.AssertVerb( sessionSDK.VerbObjectHead, sessionSDK.VerbObjectGet, sessionSDK.VerbObjectDelete, sessionSDK.VerbObjectRange, sessionSDK.VerbObjectRangeHash) - case eaclSDK.OperationSearch: + case acl.OpObjectSearch: return tok.AssertVerb(sessionSDK.VerbObjectSearch, sessionSDK.VerbObjectDelete) - case eaclSDK.OperationRange: + case acl.OpObjectRange: return tok.AssertVerb(sessionSDK.VerbObjectRange, sessionSDK.VerbObjectRangeHash) - case eaclSDK.OperationRangeHash: + case acl.OpObjectHash: return tok.AssertVerb(sessionSDK.VerbObjectRangeHash) } diff --git a/pkg/services/object/acl/v2/util_test.go b/pkg/services/object/acl/v2/util_test.go index 15321d8b8..792114f0d 100644 --- a/pkg/services/object/acl/v2/util_test.go +++ b/pkg/services/object/acl/v2/util_test.go @@ -9,7 +9,7 @@ import ( "github.com/nspcc-dev/neofs-api-go/v2/acl" "github.com/nspcc-dev/neofs-api-go/v2/session" bearertest "github.com/nspcc-dev/neofs-sdk-go/bearer/test" - "github.com/nspcc-dev/neofs-sdk-go/eacl" + aclsdk "github.com/nspcc-dev/neofs-sdk-go/container/acl" sessionSDK "github.com/nspcc-dev/neofs-sdk-go/session" sessiontest "github.com/nspcc-dev/neofs-sdk-go/session/test" "github.com/stretchr/testify/require" @@ -59,20 +59,20 @@ func testGenerateMetaHeader(depth uint32, b *acl.BearerToken, s *session.Token) func TestIsVerbCompatible(t *testing.T) { // Source: https://nspcc.ru/upload/neofs-spec-latest.pdf#page=28 - table := map[eacl.Operation][]sessionSDK.ObjectVerb{ - eacl.OperationPut: {sessionSDK.VerbObjectPut, sessionSDK.VerbObjectDelete}, - eacl.OperationDelete: {sessionSDK.VerbObjectDelete}, - eacl.OperationGet: {sessionSDK.VerbObjectGet}, - eacl.OperationHead: { + table := map[aclsdk.Op][]sessionSDK.ObjectVerb{ + aclsdk.OpObjectPut: {sessionSDK.VerbObjectPut, sessionSDK.VerbObjectDelete}, + aclsdk.OpObjectDelete: {sessionSDK.VerbObjectDelete}, + aclsdk.OpObjectGet: {sessionSDK.VerbObjectGet}, + aclsdk.OpObjectHead: { sessionSDK.VerbObjectHead, sessionSDK.VerbObjectGet, sessionSDK.VerbObjectDelete, sessionSDK.VerbObjectRange, sessionSDK.VerbObjectRangeHash, }, - eacl.OperationRange: {sessionSDK.VerbObjectRange, sessionSDK.VerbObjectRangeHash}, - eacl.OperationRangeHash: {sessionSDK.VerbObjectRangeHash}, - eacl.OperationSearch: {sessionSDK.VerbObjectSearch, sessionSDK.VerbObjectDelete}, + aclsdk.OpObjectRange: {sessionSDK.VerbObjectRange, sessionSDK.VerbObjectRangeHash}, + aclsdk.OpObjectHash: {sessionSDK.VerbObjectRangeHash}, + aclsdk.OpObjectSearch: {sessionSDK.VerbObjectSearch, sessionSDK.VerbObjectDelete}, } verbs := []sessionSDK.ObjectVerb{