[#1533] acl: Upgrade NeoFS SDK Go with refactored basic ACL

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
Leonard Lyubich 2022-06-17 16:40:51 +03:00 committed by fyrchik
parent b13dca8052
commit 305dd7598f
15 changed files with 115 additions and 429 deletions

View file

@ -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()

View file

@ -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()
}

2
go.mod
View file

@ -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

4
go.sum
View file

@ -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=

View file

@ -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")
}

View file

@ -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).

View file

@ -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))
}

View file

@ -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)
}
}

View file

@ -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))
}
}
})
}

View file

@ -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
}

View file

@ -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")
)

View file

@ -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
}

View file

@ -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

View file

@ -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)
}

View file

@ -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{