forked from TrueCloudLab/frostfs-node
[#1533] acl: Upgrade NeoFS SDK Go with refactored basic ACL
Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
parent
b13dca8052
commit
305dd7598f
15 changed files with 113 additions and 427 deletions
|
@ -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/common"
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
"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-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"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/container/acl"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/session"
|
"github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
subnetid "github.com/nspcc-dev/neofs-sdk-go/subnet/id"
|
subnetid "github.com/nspcc-dev/neofs-sdk-go/subnet/id"
|
||||||
|
@ -23,31 +23,6 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"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 (
|
var (
|
||||||
containerACL string
|
containerACL string
|
||||||
containerNonce string
|
containerNonce string
|
||||||
|
@ -80,8 +55,8 @@ It will be stored in sidechain when inner ring will accepts it.`,
|
||||||
attributes, err := parseAttributes(containerAttributes)
|
attributes, err := parseAttributes(containerAttributes)
|
||||||
common.ExitOnErr(cmd, "", err)
|
common.ExitOnErr(cmd, "", err)
|
||||||
|
|
||||||
basicACL, err := parseBasicACL(containerACL)
|
var basicACL acl.Basic
|
||||||
common.ExitOnErr(cmd, "", err)
|
common.ExitOnErr(cmd, "decode basic ACL string: %w", basicACL.DecodeString(containerACL))
|
||||||
|
|
||||||
nonce, err := parseNonce(containerNonce)
|
nonce, err := parseNonce(containerNonce)
|
||||||
common.ExitOnErr(cmd, "", err)
|
common.ExitOnErr(cmd, "", err)
|
||||||
|
@ -157,7 +132,9 @@ func initContainerCreateCmd() {
|
||||||
|
|
||||||
flags := createContainerCmd.Flags()
|
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.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.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")
|
flags.StringVarP(&containerNonce, "nonce", "n", "", "UUIDv4 nonce value for container")
|
||||||
|
@ -226,21 +203,6 @@ func parseAttributes(attributes []string) ([]container.Attribute, error) {
|
||||||
return result, nil
|
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) {
|
func parseNonce(nonce string) (uuid.UUID, error) {
|
||||||
if nonce == "" {
|
if nonce == "" {
|
||||||
result := uuid.New()
|
result := uuid.New()
|
||||||
|
|
|
@ -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/common"
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
"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-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"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/container/acl"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ func prettyPrintContainer(cmd *cobra.Command, cnr *container.Container, jsonEnco
|
||||||
cmd.Println("owner ID:", cnr.OwnerID())
|
cmd.Println("owner ID:", cnr.OwnerID())
|
||||||
|
|
||||||
basicACL := cnr.BasicACL()
|
basicACL := cnr.BasicACL()
|
||||||
prettyPrintBasicACL(cmd, acl.BasicACL(basicACL))
|
prettyPrintBasicACL(cmd, basicACL)
|
||||||
|
|
||||||
for _, attribute := range cnr.Attributes() {
|
for _, attribute := range cnr.Attributes() {
|
||||||
if attribute.Key() == container.AttributeTimestamp {
|
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) {
|
func prettyPrintBasicACL(cmd *cobra.Command, basicACL acl.Basic) {
|
||||||
cmd.Printf("basic ACL: %s", basicACL)
|
cmd.Printf("basic ACL: %s", basicACL.EncodeToString())
|
||||||
for k, v := range wellKnownBasicACL {
|
|
||||||
if v == basicACL {
|
var prettyName string
|
||||||
cmd.Printf(" (%s)\n", k)
|
|
||||||
return
|
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()
|
cmd.Println()
|
||||||
}
|
}
|
||||||
|
|
2
go.mod
2
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/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-api-go/v2 v2.12.3-0.20220621170933-dd233c3fbc84
|
||||||
github.com/nspcc-dev/neofs-contract v0.15.1
|
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/nspcc-dev/tzhash v1.5.2
|
||||||
github.com/panjf2000/ants/v2 v2.4.0
|
github.com/panjf2000/ants/v2 v2.4.0
|
||||||
github.com/paulmach/orb v0.2.2
|
github.com/paulmach/orb v0.2.2
|
||||||
|
|
BIN
go.sum
BIN
go.sum
Binary file not shown.
|
@ -52,12 +52,7 @@ func (cp *Processor) checkSetEACL(e container.SetEACL) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ACL extensions can be disabled by basic ACL, check it
|
// ACL extensions can be disabled by basic ACL, check it
|
||||||
basicACL := cnr.Value.BasicACL()
|
if !cnr.Value.BasicACL().Extendable() {
|
||||||
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 {
|
|
||||||
return errors.New("ACL extension disabled by container basic ACL")
|
return errors.New("ACL extension disabled by container basic ACL")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
eaclV2 "github.com/nspcc-dev/neofs-node/pkg/services/object/acl/eacl/v2"
|
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"
|
v2 "github.com/nspcc-dev/neofs-node/pkg/services/object/acl/v2"
|
||||||
bearerSDK "github.com/nspcc-dev/neofs-sdk-go/bearer"
|
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"
|
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
|
||||||
eaclSDK "github.com/nspcc-dev/neofs-sdk-go/eacl"
|
eaclSDK "github.com/nspcc-dev/neofs-sdk-go/eacl"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/user"
|
"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.
|
// CheckBasicACL is a main check function for basic ACL.
|
||||||
func (c *Checker) CheckBasicACL(info v2.RequestInfo) bool {
|
func (c *Checker) CheckBasicACL(info v2.RequestInfo) bool {
|
||||||
// check basic ACL permissions
|
// check basic ACL permissions
|
||||||
var checkFn func(eaclSDK.Operation) bool
|
return info.BasicACL().IsOpAllowed(info.Operation(), info.RequestRole())
|
||||||
|
|
||||||
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())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// StickyBitCheck validates owner field in the request if sticky bit is enabled.
|
// StickyBitCheck validates owner field in the request if sticky bit is enabled.
|
||||||
func (c *Checker) StickyBitCheck(info v2.RequestInfo, owner user.ID) bool {
|
func (c *Checker) StickyBitCheck(info v2.RequestInfo, owner user.ID) bool {
|
||||||
// According to NeoFS specification sticky bit has no effect on system nodes
|
// According to NeoFS specification sticky bit has no effect on system nodes
|
||||||
// for correct intra-container work with objects (in particular, replication).
|
// for correct intra-container work with objects (in particular, replication).
|
||||||
if info.RequestRole() == eaclSDK.RoleSystem {
|
if info.RequestRole() == acl.RoleContainer {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if !basicACLHelper(info.BasicACL()).Sticky() {
|
if !info.BasicACL().Sticky() {
|
||||||
return true
|
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.
|
// CheckEACL is a main check function for extended ACL.
|
||||||
func (c *Checker) CheckEACL(msg interface{}, reqInfo v2.RequestInfo) error {
|
func (c *Checker) CheckEACL(msg interface{}, reqInfo v2.RequestInfo) error {
|
||||||
if basicACLHelper(reqInfo.BasicACL()).Final() {
|
basicACL := reqInfo.BasicACL()
|
||||||
|
if !basicACL.Extendable() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// if bearer token is not allowed, then ignore it
|
// if bearer token is not allowed, then ignore it
|
||||||
if !basicACLHelper(reqInfo.BasicACL()).BearerAllowed(reqInfo.Operation()) {
|
if !basicACL.AllowedBearerRules(reqInfo.Operation()) {
|
||||||
reqInfo.CleanBearer()
|
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)
|
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).
|
action, _ := c.validator.CalculateAction(new(eaclSDK.ValidationUnit).
|
||||||
WithRole(reqInfo.RequestRole()).
|
WithRole(eaclRole).
|
||||||
WithOperation(reqInfo.Operation()).
|
WithOperation(eaclSDK.Operation(reqInfo.Operation())).
|
||||||
WithContainerID(&cnr).
|
WithContainerID(&cnr).
|
||||||
WithSenderKey(reqInfo.SenderKey()).
|
WithSenderKey(reqInfo.SenderKey()).
|
||||||
WithHeaderSource(hdrSrc).
|
WithHeaderSource(hdrSrc).
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/engine"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/engine"
|
||||||
v2 "github.com/nspcc-dev/neofs-node/pkg/services/object/acl/v2"
|
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"
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
eaclSDK "github.com/nspcc-dev/neofs-sdk-go/eacl"
|
eaclSDK "github.com/nspcc-dev/neofs-sdk-go/eacl"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/user"
|
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||||
|
@ -37,13 +38,14 @@ func TestStickyCheck(t *testing.T) {
|
||||||
var info v2.RequestInfo
|
var info v2.RequestInfo
|
||||||
|
|
||||||
info.SetSenderKey(make([]byte, 33)) // any non-empty key
|
info.SetSenderKey(make([]byte, 33)) // any non-empty key
|
||||||
info.SetRequestRole(eaclSDK.RoleSystem)
|
info.SetRequestRole(acl.RoleContainer)
|
||||||
|
|
||||||
setSticky(&info, true)
|
|
||||||
|
|
||||||
require.True(t, checker.StickyBitCheck(info, *usertest.ID()))
|
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()))
|
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) {
|
t.Run("owner ID and/or public key emptiness", func(t *testing.T) {
|
||||||
var info v2.RequestInfo
|
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) {
|
assertFn := func(isSticky, withKey, withOwner, expected bool) {
|
||||||
|
info := info
|
||||||
if isSticky {
|
if isSticky {
|
||||||
setSticky(&info, true)
|
var basicACL acl.Basic
|
||||||
} else {
|
basicACL.MakeSticky()
|
||||||
setSticky(&info, false)
|
|
||||||
|
info.SetBasicACL(basicACL)
|
||||||
}
|
}
|
||||||
|
|
||||||
if withKey {
|
if withKey {
|
||||||
|
@ -84,15 +88,3 @@ func TestStickyCheck(t *testing.T) {
|
||||||
assertFn(false, true, true, true)
|
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))
|
|
||||||
}
|
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -7,8 +7,8 @@ import (
|
||||||
|
|
||||||
core "github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
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"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/container/acl"
|
||||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
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"
|
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
@ -20,8 +20,7 @@ type senderClassifier struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type classifyResult struct {
|
type classifyResult struct {
|
||||||
role eaclSDK.Role
|
role acl.Role
|
||||||
isIR bool
|
|
||||||
key []byte
|
key []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,8 +45,7 @@ func (c senderClassifier) classify(
|
||||||
// if request owner is the same as container owner, return RoleUser
|
// if request owner is the same as container owner, return RoleUser
|
||||||
if ownerID.Equals(*ownerCnr) {
|
if ownerID.Equals(*ownerCnr) {
|
||||||
return &classifyResult{
|
return &classifyResult{
|
||||||
role: eaclSDK.RoleUser,
|
role: acl.RoleOwner,
|
||||||
isIR: false,
|
|
||||||
key: ownerKeyInBytes,
|
key: ownerKeyInBytes,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -59,8 +57,7 @@ func (c senderClassifier) classify(
|
||||||
zap.String("error", err.Error()))
|
zap.String("error", err.Error()))
|
||||||
} else if isInnerRingNode {
|
} else if isInnerRingNode {
|
||||||
return &classifyResult{
|
return &classifyResult{
|
||||||
role: eaclSDK.RoleSystem,
|
role: acl.RoleInnerRing,
|
||||||
isIR: true,
|
|
||||||
key: ownerKeyInBytes,
|
key: ownerKeyInBytes,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -77,15 +74,14 @@ func (c senderClassifier) classify(
|
||||||
zap.String("error", err.Error()))
|
zap.String("error", err.Error()))
|
||||||
} else if isContainerNode {
|
} else if isContainerNode {
|
||||||
return &classifyResult{
|
return &classifyResult{
|
||||||
role: eaclSDK.RoleSystem,
|
role: acl.RoleContainer,
|
||||||
isIR: false,
|
|
||||||
key: ownerKeyInBytes,
|
key: ownerKeyInBytes,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// if none of above, return RoleOthers
|
// if none of above, return RoleOthers
|
||||||
return &classifyResult{
|
return &classifyResult{
|
||||||
role: eaclSDK.RoleOthers,
|
role: acl.RoleOthers,
|
||||||
key: ownerKeyInBytes,
|
key: ownerKeyInBytes,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,6 @@ var (
|
||||||
// ErrMalformedRequest is returned when request contains
|
// ErrMalformedRequest is returned when request contains
|
||||||
// invalid data.
|
// invalid data.
|
||||||
ErrMalformedRequest = errors.New("malformed request")
|
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 is returned when session token verb doesn't include necessary operation.
|
||||||
ErrInvalidVerb = errors.New("session token verb is invalid")
|
ErrInvalidVerb = errors.New("session token verb is invalid")
|
||||||
)
|
)
|
||||||
|
|
|
@ -7,8 +7,8 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
sessionV2 "github.com/nspcc-dev/neofs-api-go/v2/session"
|
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/bearer"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/container/acl"
|
||||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
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"
|
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
||||||
sessionSDK "github.com/nspcc-dev/neofs-sdk-go/session"
|
sessionSDK "github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/user"
|
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||||
|
@ -17,10 +17,9 @@ import (
|
||||||
// RequestInfo groups parsed version-independent (from SDK library)
|
// RequestInfo groups parsed version-independent (from SDK library)
|
||||||
// request information and raw API request.
|
// request information and raw API request.
|
||||||
type RequestInfo struct {
|
type RequestInfo struct {
|
||||||
basicACL uint32
|
basicACL acl.Basic
|
||||||
requestRole eaclSDK.Role
|
requestRole acl.Role
|
||||||
isInnerRing bool
|
operation acl.Op // put, get, head, etc.
|
||||||
operation eaclSDK.Operation // put, get, head, etc.
|
|
||||||
cnrOwner user.ID // container owner
|
cnrOwner user.ID // container owner
|
||||||
|
|
||||||
idCnr cid.ID
|
idCnr cid.ID
|
||||||
|
@ -36,11 +35,11 @@ type RequestInfo struct {
|
||||||
srcRequest interface{}
|
srcRequest interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RequestInfo) SetBasicACL(basicACL uint32) {
|
func (r *RequestInfo) SetBasicACL(basicACL acl.Basic) {
|
||||||
r.basicACL = basicACL
|
r.basicACL = basicACL
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RequestInfo) SetRequestRole(requestRole eaclSDK.Role) {
|
func (r *RequestInfo) SetRequestRole(requestRole acl.Role) {
|
||||||
r.requestRole = requestRole
|
r.requestRole = requestRole
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,13 +77,8 @@ func (r RequestInfo) Bearer() *bearer.Token {
|
||||||
return r.bearer
|
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.
|
// BasicACL returns basic ACL of the container.
|
||||||
func (r RequestInfo) BasicACL() uint32 {
|
func (r RequestInfo) BasicACL() acl.Basic {
|
||||||
return r.basicACL
|
return r.basicACL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,12 +88,12 @@ func (r RequestInfo) SenderKey() []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Operation returns request's operation.
|
// Operation returns request's operation.
|
||||||
func (r RequestInfo) Operation() eaclSDK.Operation {
|
func (r RequestInfo) Operation() acl.Op {
|
||||||
return r.operation
|
return r.operation
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequestRole returns request sender's role.
|
// RequestRole returns request sender's role.
|
||||||
func (r RequestInfo) RequestRole() eaclSDK.Role {
|
func (r RequestInfo) RequestRole() acl.Role {
|
||||||
return r.requestRole
|
return r.requestRole
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,8 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
"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/core/netmap"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object"
|
"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"
|
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"
|
sessionSDK "github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/user"
|
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
@ -130,7 +130,7 @@ func (b Service) Get(request *objectV2.GetRequest, stream object.GetObjectStream
|
||||||
src: request,
|
src: request,
|
||||||
}
|
}
|
||||||
|
|
||||||
reqInfo, err := b.findRequestInfo(req, cnr, eaclSDK.OperationGet)
|
reqInfo, err := b.findRequestInfo(req, cnr, acl.OpObjectGet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -189,7 +189,7 @@ func (b Service) Head(
|
||||||
src: request,
|
src: request,
|
||||||
}
|
}
|
||||||
|
|
||||||
reqInfo, err := b.findRequestInfo(req, cnr, eaclSDK.OperationHead)
|
reqInfo, err := b.findRequestInfo(req, cnr, acl.OpObjectHead)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -240,7 +240,7 @@ func (b Service) Search(request *objectV2.SearchRequest, stream object.SearchStr
|
||||||
src: request,
|
src: request,
|
||||||
}
|
}
|
||||||
|
|
||||||
reqInfo, err := b.findRequestInfo(req, id, eaclSDK.OperationSearch)
|
reqInfo, err := b.findRequestInfo(req, id, acl.OpObjectSearch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -288,7 +288,7 @@ func (b Service) Delete(
|
||||||
src: request,
|
src: request,
|
||||||
}
|
}
|
||||||
|
|
||||||
reqInfo, err := b.findRequestInfo(req, cnr, eaclSDK.OperationDelete)
|
reqInfo, err := b.findRequestInfo(req, cnr, acl.OpObjectDelete)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -332,7 +332,7 @@ func (b Service) GetRange(request *objectV2.GetRangeRequest, stream object.GetOb
|
||||||
src: request,
|
src: request,
|
||||||
}
|
}
|
||||||
|
|
||||||
reqInfo, err := b.findRequestInfo(req, cnr, eaclSDK.OperationRange)
|
reqInfo, err := b.findRequestInfo(req, cnr, acl.OpObjectRange)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -381,7 +381,7 @@ func (b Service) GetRangeHash(
|
||||||
src: request,
|
src: request,
|
||||||
}
|
}
|
||||||
|
|
||||||
reqInfo, err := b.findRequestInfo(req, cnr, eaclSDK.OperationRangeHash)
|
reqInfo, err := b.findRequestInfo(req, cnr, acl.OpObjectHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -450,7 +450,7 @@ func (p putStreamBasicChecker) Send(request *objectV2.PutRequest) error {
|
||||||
src: request,
|
src: request,
|
||||||
}
|
}
|
||||||
|
|
||||||
reqInfo, err := p.source.findRequestInfo(req, cnr, eaclSDK.OperationPut)
|
reqInfo, err := p.source.findRequestInfo(req, cnr, acl.OpObjectPut)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -502,7 +502,7 @@ func (g *searchStreamBasicChecker) Send(resp *objectV2.SearchResponse) error {
|
||||||
return g.SearchStream.Send(resp)
|
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
|
cnr, err := b.containers.Get(idCnr) // fetch actual container
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return info, err
|
return info, err
|
||||||
|
@ -531,13 +531,8 @@ func (b Service) findRequestInfo(req MetaWithToken, idCnr cid.ID, op eaclSDK.Ope
|
||||||
return info, err
|
return info, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if res.role == eaclSDK.RoleUnknown {
|
|
||||||
return info, ErrUnknownRole
|
|
||||||
}
|
|
||||||
|
|
||||||
info.basicACL = cnr.Value.BasicACL()
|
info.basicACL = cnr.Value.BasicACL()
|
||||||
info.requestRole = res.role
|
info.requestRole = res.role
|
||||||
info.isInnerRing = res.isIR
|
|
||||||
info.operation = op
|
info.operation = op
|
||||||
info.cnrOwner = *cnr.Value.OwnerID()
|
info.cnrOwner = *cnr.Value.OwnerID()
|
||||||
info.idCnr = idCnr
|
info.idCnr = idCnr
|
||||||
|
|
|
@ -11,8 +11,8 @@ import (
|
||||||
refsV2 "github.com/nspcc-dev/neofs-api-go/v2/refs"
|
refsV2 "github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||||
sessionV2 "github.com/nspcc-dev/neofs-api-go/v2/session"
|
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/bearer"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/container/acl"
|
||||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
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"
|
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
||||||
sessionSDK "github.com/nspcc-dev/neofs-sdk-go/session"
|
sessionSDK "github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/user"
|
"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.
|
// 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
|
//nolint:exhaustive
|
||||||
switch op {
|
switch op {
|
||||||
case eaclSDK.OperationPut:
|
case acl.OpObjectPut:
|
||||||
return tok.AssertVerb(sessionSDK.VerbObjectPut, sessionSDK.VerbObjectDelete)
|
return tok.AssertVerb(sessionSDK.VerbObjectPut, sessionSDK.VerbObjectDelete)
|
||||||
case eaclSDK.OperationDelete:
|
case acl.OpObjectDelete:
|
||||||
return tok.AssertVerb(sessionSDK.VerbObjectDelete)
|
return tok.AssertVerb(sessionSDK.VerbObjectDelete)
|
||||||
case eaclSDK.OperationGet:
|
case acl.OpObjectGet:
|
||||||
return tok.AssertVerb(sessionSDK.VerbObjectGet)
|
return tok.AssertVerb(sessionSDK.VerbObjectGet)
|
||||||
case eaclSDK.OperationHead:
|
case acl.OpObjectHead:
|
||||||
return tok.AssertVerb(
|
return tok.AssertVerb(
|
||||||
sessionSDK.VerbObjectHead,
|
sessionSDK.VerbObjectHead,
|
||||||
sessionSDK.VerbObjectGet,
|
sessionSDK.VerbObjectGet,
|
||||||
sessionSDK.VerbObjectDelete,
|
sessionSDK.VerbObjectDelete,
|
||||||
sessionSDK.VerbObjectRange,
|
sessionSDK.VerbObjectRange,
|
||||||
sessionSDK.VerbObjectRangeHash)
|
sessionSDK.VerbObjectRangeHash)
|
||||||
case eaclSDK.OperationSearch:
|
case acl.OpObjectSearch:
|
||||||
return tok.AssertVerb(sessionSDK.VerbObjectSearch, sessionSDK.VerbObjectDelete)
|
return tok.AssertVerb(sessionSDK.VerbObjectSearch, sessionSDK.VerbObjectDelete)
|
||||||
case eaclSDK.OperationRange:
|
case acl.OpObjectRange:
|
||||||
return tok.AssertVerb(sessionSDK.VerbObjectRange, sessionSDK.VerbObjectRangeHash)
|
return tok.AssertVerb(sessionSDK.VerbObjectRange, sessionSDK.VerbObjectRangeHash)
|
||||||
case eaclSDK.OperationRangeHash:
|
case acl.OpObjectHash:
|
||||||
return tok.AssertVerb(sessionSDK.VerbObjectRangeHash)
|
return tok.AssertVerb(sessionSDK.VerbObjectRangeHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-api-go/v2/acl"
|
"github.com/nspcc-dev/neofs-api-go/v2/acl"
|
||||||
"github.com/nspcc-dev/neofs-api-go/v2/session"
|
"github.com/nspcc-dev/neofs-api-go/v2/session"
|
||||||
bearertest "github.com/nspcc-dev/neofs-sdk-go/bearer/test"
|
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"
|
sessionSDK "github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
sessiontest "github.com/nspcc-dev/neofs-sdk-go/session/test"
|
sessiontest "github.com/nspcc-dev/neofs-sdk-go/session/test"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -59,20 +59,20 @@ func testGenerateMetaHeader(depth uint32, b *acl.BearerToken, s *session.Token)
|
||||||
|
|
||||||
func TestIsVerbCompatible(t *testing.T) {
|
func TestIsVerbCompatible(t *testing.T) {
|
||||||
// Source: https://nspcc.ru/upload/neofs-spec-latest.pdf#page=28
|
// Source: https://nspcc.ru/upload/neofs-spec-latest.pdf#page=28
|
||||||
table := map[eacl.Operation][]sessionSDK.ObjectVerb{
|
table := map[aclsdk.Op][]sessionSDK.ObjectVerb{
|
||||||
eacl.OperationPut: {sessionSDK.VerbObjectPut, sessionSDK.VerbObjectDelete},
|
aclsdk.OpObjectPut: {sessionSDK.VerbObjectPut, sessionSDK.VerbObjectDelete},
|
||||||
eacl.OperationDelete: {sessionSDK.VerbObjectDelete},
|
aclsdk.OpObjectDelete: {sessionSDK.VerbObjectDelete},
|
||||||
eacl.OperationGet: {sessionSDK.VerbObjectGet},
|
aclsdk.OpObjectGet: {sessionSDK.VerbObjectGet},
|
||||||
eacl.OperationHead: {
|
aclsdk.OpObjectHead: {
|
||||||
sessionSDK.VerbObjectHead,
|
sessionSDK.VerbObjectHead,
|
||||||
sessionSDK.VerbObjectGet,
|
sessionSDK.VerbObjectGet,
|
||||||
sessionSDK.VerbObjectDelete,
|
sessionSDK.VerbObjectDelete,
|
||||||
sessionSDK.VerbObjectRange,
|
sessionSDK.VerbObjectRange,
|
||||||
sessionSDK.VerbObjectRangeHash,
|
sessionSDK.VerbObjectRangeHash,
|
||||||
},
|
},
|
||||||
eacl.OperationRange: {sessionSDK.VerbObjectRange, sessionSDK.VerbObjectRangeHash},
|
aclsdk.OpObjectRange: {sessionSDK.VerbObjectRange, sessionSDK.VerbObjectRangeHash},
|
||||||
eacl.OperationRangeHash: {sessionSDK.VerbObjectRangeHash},
|
aclsdk.OpObjectHash: {sessionSDK.VerbObjectRangeHash},
|
||||||
eacl.OperationSearch: {sessionSDK.VerbObjectSearch, sessionSDK.VerbObjectDelete},
|
aclsdk.OpObjectSearch: {sessionSDK.VerbObjectSearch, sessionSDK.VerbObjectDelete},
|
||||||
}
|
}
|
||||||
|
|
||||||
verbs := []sessionSDK.ObjectVerb{
|
verbs := []sessionSDK.ObjectVerb{
|
||||||
|
|
Loading…
Reference in a new issue