[#1096] eacl: Use validator from SDK

Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
This commit is contained in:
Pavel Karpy 2022-01-20 12:45:58 +03:00 committed by Alex Vanin
parent 759421ebbf
commit ed156cd738
12 changed files with 61 additions and 413 deletions

View file

@ -20,7 +20,6 @@ import (
objectTransportGRPC "github.com/nspcc-dev/neofs-node/pkg/network/transport/object/grpc" objectTransportGRPC "github.com/nspcc-dev/neofs-node/pkg/network/transport/object/grpc"
objectService "github.com/nspcc-dev/neofs-node/pkg/services/object" objectService "github.com/nspcc-dev/neofs-node/pkg/services/object"
"github.com/nspcc-dev/neofs-node/pkg/services/object/acl" "github.com/nspcc-dev/neofs-node/pkg/services/object/acl"
"github.com/nspcc-dev/neofs-node/pkg/services/object/acl/eacl"
deletesvc "github.com/nspcc-dev/neofs-node/pkg/services/object/delete" deletesvc "github.com/nspcc-dev/neofs-node/pkg/services/object/delete"
deletesvcV2 "github.com/nspcc-dev/neofs-node/pkg/services/object/delete/v2" deletesvcV2 "github.com/nspcc-dev/neofs-node/pkg/services/object/delete/v2"
getsvc "github.com/nspcc-dev/neofs-node/pkg/services/object/get" getsvc "github.com/nspcc-dev/neofs-node/pkg/services/object/get"
@ -365,10 +364,7 @@ func initObjectService(c *cfg) {
), ),
acl.WithNextService(splitSvc), acl.WithNextService(splitSvc),
acl.WithLocalStorage(ls), acl.WithLocalStorage(ls),
acl.WithEACLValidatorOptions( acl.WithEACLSource(c.cfgObject.eaclSource),
eacl.WithEACLSource(c.cfgObject.eaclSource),
eacl.WithLogger(c.log),
),
acl.WithNetmapState(c.cfgNetmap.state), acl.WithNetmapState(c.cfgNetmap.state),
) )

4
go.mod
View file

@ -12,8 +12,8 @@ require (
github.com/multiformats/go-multiaddr v0.4.0 github.com/multiformats/go-multiaddr v0.4.0
github.com/nspcc-dev/hrw v1.0.9 github.com/nspcc-dev/hrw v1.0.9
github.com/nspcc-dev/neo-go v0.98.0 github.com/nspcc-dev/neo-go v0.98.0
github.com/nspcc-dev/neofs-api-go/v2 v2.11.1 github.com/nspcc-dev/neofs-api-go/v2 v2.11.2-0.20220114101721-227a871a04ac
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659 github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220119080627-f83ff628fb19
github.com/nspcc-dev/tzhash v1.4.0 github.com/nspcc-dev/tzhash v1.4.0
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

8
go.sum
View file

@ -364,15 +364,15 @@ github.com/nspcc-dev/neo-go v0.73.1-pre.0.20200303142215-f5a1b928ce09/go.mod h1:
github.com/nspcc-dev/neo-go v0.98.0 h1:yyW4sgY88/pLf0949qmgfkQXzRKC3CI/WyhqXNnwMd8= github.com/nspcc-dev/neo-go v0.98.0 h1:yyW4sgY88/pLf0949qmgfkQXzRKC3CI/WyhqXNnwMd8=
github.com/nspcc-dev/neo-go v0.98.0/go.mod h1:E3cc1x6RXSXrJb2nDWXTXjnXk3rIqVN8YdFyWv+FrqM= github.com/nspcc-dev/neo-go v0.98.0/go.mod h1:E3cc1x6RXSXrJb2nDWXTXjnXk3rIqVN8YdFyWv+FrqM=
github.com/nspcc-dev/neofs-api-go/v2 v2.11.0-pre.0.20211201134523-3604d96f3fe1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs= github.com/nspcc-dev/neofs-api-go/v2 v2.11.0-pre.0.20211201134523-3604d96f3fe1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs=
github.com/nspcc-dev/neofs-api-go/v2 v2.11.1 h1:SVqc523pZsSaS9vnPS1mm3VV6b6xY0gvdA0uYJ/GWZQ= github.com/nspcc-dev/neofs-api-go/v2 v2.11.2-0.20220114101721-227a871a04ac h1:65C4z7pybLT2HjtY96abZj6kbgVp34AbrApn5DD+ZxY=
github.com/nspcc-dev/neofs-api-go/v2 v2.11.1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs= github.com/nspcc-dev/neofs-api-go/v2 v2.11.2-0.20220114101721-227a871a04ac/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs=
github.com/nspcc-dev/neofs-crypto v0.2.0/go.mod h1:F/96fUzPM3wR+UGsPi3faVNmFlA9KAEAUQR7dMxZmNA= github.com/nspcc-dev/neofs-crypto v0.2.0/go.mod h1:F/96fUzPM3wR+UGsPi3faVNmFlA9KAEAUQR7dMxZmNA=
github.com/nspcc-dev/neofs-crypto v0.2.3/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw= github.com/nspcc-dev/neofs-crypto v0.2.3/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw=
github.com/nspcc-dev/neofs-crypto v0.3.0 h1:zlr3pgoxuzrmGCxc5W8dGVfA9Rro8diFvVnBg0L4ifM= github.com/nspcc-dev/neofs-crypto v0.3.0 h1:zlr3pgoxuzrmGCxc5W8dGVfA9Rro8diFvVnBg0L4ifM=
github.com/nspcc-dev/neofs-crypto v0.3.0/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw= 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-20211201182451-a5b61c4f6477/go.mod h1:dfMtQWmBHYpl9Dez23TGtIUKiFvCIxUZq/CkSIhEpz4=
github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220113123743-7f3162110659 h1:rpMCoRa7expLc9gMiOP724gz6YSykZzmMALR/CmiwnU= github.com/nspcc-dev/neofs-sdk-go v0.0.0-20220119080627-f83ff628fb19 h1:VuOztHAvvu0ZK7ng6EillhlEunHy34TQr5/13k0fSUU=
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 v0.0.0-20220119080627-f83ff628fb19/go.mod h1:fhs4v6uts7bEgwYP05NXbAQlQ0YhK4WVjJRKQKFKBxY=
github.com/nspcc-dev/rfc6979 v0.1.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso= 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 h1:3e1WNxrN60/6N0DW7+UYisLeZJyfqZTNOjeV/toYvOE=
github.com/nspcc-dev/rfc6979 v0.2.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso= github.com/nspcc-dev/rfc6979 v0.2.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso=

View file

@ -12,6 +12,7 @@ import (
"github.com/nspcc-dev/neofs-api-go/v2/refs" "github.com/nspcc-dev/neofs-api-go/v2/refs"
"github.com/nspcc-dev/neofs-api-go/v2/session" "github.com/nspcc-dev/neofs-api-go/v2/session"
v2signature "github.com/nspcc-dev/neofs-api-go/v2/signature" v2signature "github.com/nspcc-dev/neofs-api-go/v2/signature"
"github.com/nspcc-dev/neofs-node/pkg/core/container"
core "github.com/nspcc-dev/neofs-node/pkg/core/container" core "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/local_object_storage/engine" "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/engine"
@ -95,9 +96,9 @@ type cfg struct {
} }
type eACLCfg struct { type eACLCfg struct {
eACLOpts []eacl.Option eaclSource eacl.Source
eACL *eacl.Validator eACL *acl.Validator
localStorage *engine.StorageEngine localStorage *engine.StorageEngine
@ -130,7 +131,7 @@ func New(opts ...Option) Service {
opts[i](cfg) opts[i](cfg)
} }
cfg.eACL = eacl.NewValidator(cfg.eACLOpts...) cfg.eACL = acl.NewValidator()
return Service{ return Service{
cfg: cfg, cfg: cfg,
@ -610,6 +611,20 @@ func eACLCheck(msg interface{}, reqInfo requestInfo, cfg *eACLCfg) bool {
reqInfo.bearer = nil reqInfo.bearer = nil
} }
var (
table *acl.Table
err error
)
if reqInfo.bearer == nil {
table, err = cfg.eaclSource.GetEACL(reqInfo.cid)
if err != nil {
return errors.Is(err, container.ErrEACLNotFound)
}
} else {
table = acl.NewTableFromV2(reqInfo.bearer.GetBody().GetEACL())
}
// if bearer token is not present, isValidBearer returns true // if bearer token is not present, isValidBearer returns true
if !isValidBearer(reqInfo, cfg.state) { if !isValidBearer(reqInfo, cfg.state) {
return false return false
@ -637,7 +652,7 @@ func eACLCheck(msg interface{}, reqInfo requestInfo, cfg *eACLCfg) bool {
) )
} }
action := cfg.eACL.CalculateAction(new(eacl.ValidationUnit). action := cfg.eACL.CalculateAction(new(acl.ValidationUnit).
WithRole(reqInfo.requestRole). WithRole(reqInfo.requestRole).
WithOperation(reqInfo.operation). WithOperation(reqInfo.operation).
WithContainerID(reqInfo.cid). WithContainerID(reqInfo.cid).
@ -645,7 +660,7 @@ func eACLCheck(msg interface{}, reqInfo requestInfo, cfg *eACLCfg) bool {
WithHeaderSource( WithHeaderSource(
eaclV2.NewMessageHeaderSource(hdrSrcOpts...), eaclV2.NewMessageHeaderSource(hdrSrcOpts...),
). ).
WithBearerToken(reqInfo.bearer), WithEACLTable(table),
) )
return action == acl.ActionAllow return action == acl.ActionAllow

View file

@ -1,17 +0,0 @@
package eacl
import (
"github.com/nspcc-dev/neofs-node/pkg/util/logger"
)
func WithLogger(v *logger.Logger) Option {
return func(c *cfg) {
c.logger = v
}
}
func WithEACLSource(v Source) Option {
return func(c *cfg) {
c.storage = v
}
}

View file

@ -1,7 +1,6 @@
package eacl package eacl
import ( import (
bearer "github.com/nspcc-dev/neofs-api-go/v2/acl"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id" cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
"github.com/nspcc-dev/neofs-sdk-go/eacl" "github.com/nspcc-dev/neofs-sdk-go/eacl"
) )
@ -18,83 +17,3 @@ type Source interface {
// eACL table is not in source. // eACL table is not in source.
GetEACL(*cid.ID) (*eacl.Table, error) GetEACL(*cid.ID) (*eacl.Table, error)
} }
// Header is an interface of string key-value header.
type Header interface {
Key() string
Value() string
}
// TypedHeaderSource is the interface that wraps
// method for selecting typed headers by type.
type TypedHeaderSource interface {
// HeadersOfType returns the list of key-value headers
// of particular type.
//
// It returns any problem encountered through the boolean
// false value.
HeadersOfType(eacl.FilterHeaderType) ([]Header, bool)
}
// ValidationUnit represents unit of check for Validator.
type ValidationUnit struct {
cid *cid.ID
role eacl.Role
op eacl.Operation
hdrSrc TypedHeaderSource
key []byte
bearer *bearer.BearerToken
}
func (u *ValidationUnit) WithContainerID(v *cid.ID) *ValidationUnit {
if u != nil {
u.cid = v
}
return u
}
func (u *ValidationUnit) WithRole(v eacl.Role) *ValidationUnit {
if u != nil {
u.role = v
}
return u
}
func (u *ValidationUnit) WithOperation(v eacl.Operation) *ValidationUnit {
if u != nil {
u.op = v
}
return u
}
func (u *ValidationUnit) WithHeaderSource(v TypedHeaderSource) *ValidationUnit {
if u != nil {
u.hdrSrc = v
}
return u
}
func (u *ValidationUnit) WithSenderKey(v []byte) *ValidationUnit {
if u != nil {
u.key = v
}
return u
}
func (u *ValidationUnit) WithBearerToken(bearer *bearer.BearerToken) *ValidationUnit {
if u != nil {
u.bearer = bearer
}
return u
}

View file

@ -10,10 +10,8 @@ import (
objectV2 "github.com/nspcc-dev/neofs-api-go/v2/object" objectV2 "github.com/nspcc-dev/neofs-api-go/v2/object"
"github.com/nspcc-dev/neofs-api-go/v2/session" "github.com/nspcc-dev/neofs-api-go/v2/session"
"github.com/nspcc-dev/neofs-node/pkg/core/object" "github.com/nspcc-dev/neofs-node/pkg/core/object"
eacl2 "github.com/nspcc-dev/neofs-node/pkg/services/object/acl/eacl"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test" cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
"github.com/nspcc-dev/neofs-sdk-go/eacl" eaclSDK "github.com/nspcc-dev/neofs-sdk-go/eacl"
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object" objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -26,20 +24,6 @@ type testLocalStorage struct {
obj *object.Object obj *object.Object
} }
type testEACLStorage struct {
t *testing.T
expCID *cid.ID
table *eacl.Table
}
func (s *testEACLStorage) GetEACL(id *cid.ID) (*eacl.Table, error) {
require.True(s.t, s.expCID.Equal(id))
return s.table, nil
}
func (s *testLocalStorage) Head(addr *objectSDK.Address) (*object.Object, error) { func (s *testLocalStorage) Head(addr *objectSDK.Address) (*object.Object, error) {
require.True(s.t, addr.ContainerID().Equal(addr.ContainerID()) && addr.ObjectID().Equal(addr.ObjectID())) require.True(s.t, addr.ContainerID().Equal(addr.ContainerID()) && addr.ObjectID().Equal(addr.ObjectID()))
@ -109,18 +93,18 @@ func TestHeadRequest(t *testing.T) {
attr.SetValue(attrVal) attr.SetValue(attrVal)
obj.SetAttributes(attr) obj.SetAttributes(attr)
table := new(eacl.Table) table := new(eaclSDK.Table)
priv, err := keys.NewPrivateKey() priv, err := keys.NewPrivateKey()
require.NoError(t, err) require.NoError(t, err)
senderKey := priv.PublicKey() senderKey := priv.PublicKey()
r := eacl.NewRecord() r := eaclSDK.NewRecord()
r.SetOperation(eacl.OperationHead) r.SetOperation(eaclSDK.OperationHead)
r.SetAction(eacl.ActionDeny) r.SetAction(eaclSDK.ActionDeny)
r.AddFilter(eacl.HeaderFromObject, eacl.MatchStringEqual, attrKey, attrVal) r.AddFilter(eaclSDK.HeaderFromObject, eaclSDK.MatchStringEqual, attrKey, attrVal)
r.AddFilter(eacl.HeaderFromRequest, eacl.MatchStringEqual, xKey, xVal) r.AddFilter(eaclSDK.HeaderFromRequest, eaclSDK.MatchStringEqual, xKey, xVal)
eacl.AddFormedTarget(r, eacl.RoleUnknown, (ecdsa.PublicKey)(*senderKey)) eaclSDK.AddFormedTarget(r, eaclSDK.RoleUnknown, (ecdsa.PublicKey)(*senderKey))
table.AddRecord(r) table.AddRecord(r)
@ -131,36 +115,29 @@ func TestHeadRequest(t *testing.T) {
} }
cid := addr.ContainerID() cid := addr.ContainerID()
unit := new(eacl2.ValidationUnit). unit := new(eaclSDK.ValidationUnit).
WithContainerID(cid). WithContainerID(cid).
WithOperation(eacl.OperationHead). WithOperation(eaclSDK.OperationHead).
WithSenderKey(senderKey.Bytes()). WithSenderKey(senderKey.Bytes()).
WithHeaderSource( WithHeaderSource(
NewMessageHeaderSource( NewMessageHeaderSource(
WithObjectStorage(lStorage), WithObjectStorage(lStorage),
WithServiceRequest(req), WithServiceRequest(req),
), ),
) ).
WithEACLTable(table)
eStorage := &testEACLStorage{ validator := eaclSDK.NewValidator()
t: t,
expCID: cid,
table: table,
}
validator := eacl2.NewValidator( require.Equal(t, eaclSDK.ActionDeny, validator.CalculateAction(unit))
eacl2.WithEACLSource(eStorage),
)
require.Equal(t, eacl.ActionDeny, validator.CalculateAction(unit))
meta.SetXHeaders(nil) meta.SetXHeaders(nil)
require.Equal(t, eacl.ActionAllow, validator.CalculateAction(unit)) require.Equal(t, eaclSDK.ActionAllow, validator.CalculateAction(unit))
meta.SetXHeaders(xHdrs) meta.SetXHeaders(xHdrs)
obj.SetAttributes(nil) obj.SetAttributes(nil)
require.Equal(t, eacl.ActionAllow, validator.CalculateAction(unit)) require.Equal(t, eaclSDK.ActionAllow, validator.CalculateAction(unit))
} }

View file

@ -8,7 +8,6 @@ import (
"github.com/nspcc-dev/neofs-api-go/v2/refs" "github.com/nspcc-dev/neofs-api-go/v2/refs"
"github.com/nspcc-dev/neofs-api-go/v2/session" "github.com/nspcc-dev/neofs-api-go/v2/session"
"github.com/nspcc-dev/neofs-node/pkg/core/object" "github.com/nspcc-dev/neofs-node/pkg/core/object"
"github.com/nspcc-dev/neofs-node/pkg/services/object/acl/eacl"
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"
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object" objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
@ -47,7 +46,7 @@ func defaultCfg() *cfg {
} }
} }
func NewMessageHeaderSource(opts ...Option) eacl.TypedHeaderSource { func NewMessageHeaderSource(opts ...Option) eaclSDK.TypedHeaderSource {
cfg := defaultCfg() cfg := defaultCfg()
for i := range opts { for i := range opts {
@ -59,7 +58,7 @@ func NewMessageHeaderSource(opts ...Option) eacl.TypedHeaderSource {
} }
} }
func (h *headerSource) HeadersOfType(typ eaclSDK.FilterHeaderType) ([]eacl.Header, bool) { func (h *headerSource) HeadersOfType(typ eaclSDK.FilterHeaderType) ([]eaclSDK.Header, bool) {
switch typ { switch typ {
default: default:
return nil, true return nil, true
@ -70,10 +69,10 @@ func (h *headerSource) HeadersOfType(typ eaclSDK.FilterHeaderType) ([]eacl.Heade
} }
} }
func requestHeaders(msg xHeaderSource) []eacl.Header { func requestHeaders(msg xHeaderSource) []eaclSDK.Header {
xHdrs := msg.GetXHeaders() xHdrs := msg.GetXHeaders()
res := make([]eacl.Header, 0, len(xHdrs)) res := make([]eaclSDK.Header, 0, len(xHdrs))
for i := range xHdrs { for i := range xHdrs {
res = append(res, sessionSDK.NewXHeaderFromV2(xHdrs[i])) res = append(res, sessionSDK.NewXHeaderFromV2(xHdrs[i]))
@ -82,7 +81,7 @@ func requestHeaders(msg xHeaderSource) []eacl.Header {
return res return res
} }
func (h *headerSource) objectHeaders() ([]eacl.Header, bool) { func (h *headerSource) objectHeaders() ([]eaclSDK.Header, bool) {
var addr *objectSDK.Address var addr *objectSDK.Address
if h.addr != nil { if h.addr != nil {
addr = objectSDK.NewAddressFromV2(h.addr) addr = objectSDK.NewAddressFromV2(h.addr)
@ -119,7 +118,7 @@ func (h *headerSource) objectHeaders() ([]eacl.Header, bool) {
return hs, true return hs, true
} }
case *objectV2.SearchRequest: case *objectV2.SearchRequest:
return []eacl.Header{cidHeader( return []eaclSDK.Header{cidHeader(
cid.NewFromV2( cid.NewFromV2(
req.GetBody().GetContainerID()), req.GetBody().GetContainerID()),
)}, true )}, true
@ -165,7 +164,7 @@ func (h *headerSource) objectHeaders() ([]eacl.Header, bool) {
return nil, true return nil, true
} }
func (h *headerSource) localObjectHeaders(addrV2 *refs.Address) ([]eacl.Header, bool) { func (h *headerSource) localObjectHeaders(addrV2 *refs.Address) ([]eaclSDK.Header, bool) {
addr := objectSDK.NewAddressFromV2(addrV2) addr := objectSDK.NewAddressFromV2(addrV2)
obj, err := h.storage.Head(addr) obj, err := h.storage.Head(addr)
@ -176,22 +175,22 @@ func (h *headerSource) localObjectHeaders(addrV2 *refs.Address) ([]eacl.Header,
return addressHeaders(addr), false return addressHeaders(addr), false
} }
func cidHeader(cid *cid.ID) eacl.Header { func cidHeader(cid *cid.ID) eaclSDK.Header {
return &sysObjHdr{ return &sysObjHdr{
k: acl.FilterObjectContainerID, k: acl.FilterObjectContainerID,
v: cidValue(cid), v: cidValue(cid),
} }
} }
func oidHeader(oid *objectSDK.ID) eacl.Header { func oidHeader(oid *objectSDK.ID) eaclSDK.Header {
return &sysObjHdr{ return &sysObjHdr{
k: acl.FilterObjectID, k: acl.FilterObjectID,
v: idValue(oid), v: idValue(oid),
} }
} }
func addressHeaders(addr *objectSDK.Address) []eacl.Header { func addressHeaders(addr *objectSDK.Address) []eaclSDK.Header {
res := make([]eacl.Header, 1, 2) res := make([]eaclSDK.Header, 1, 2)
res[0] = cidHeader(addr.ContainerID()) res[0] = cidHeader(addr.ContainerID())
if oid := addr.ObjectID(); oid != nil { if oid := addr.ObjectID(); oid != nil {

View file

@ -5,8 +5,8 @@ import (
"github.com/nspcc-dev/neofs-api-go/v2/acl" "github.com/nspcc-dev/neofs-api-go/v2/acl"
"github.com/nspcc-dev/neofs-node/pkg/core/object" "github.com/nspcc-dev/neofs-node/pkg/core/object"
"github.com/nspcc-dev/neofs-node/pkg/services/object/acl/eacl"
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"
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object" objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
"github.com/nspcc-dev/neofs-sdk-go/owner" "github.com/nspcc-dev/neofs-sdk-go/owner"
) )
@ -39,9 +39,9 @@ func u64Value(v uint64) string {
return strconv.FormatUint(v, 10) return strconv.FormatUint(v, 10)
} }
func headersFromObject(obj *object.Object, addr *objectSDK.Address) []eacl.Header { func headersFromObject(obj *object.Object, addr *objectSDK.Address) []eaclSDK.Header {
// TODO: optimize allocs // TODO: optimize allocs
res := make([]eacl.Header, 0) res := make([]eaclSDK.Header, 0)
for ; obj != nil; obj = obj.GetParent() { for ; obj != nil; obj = obj.GetParent() {
res = append(res, res = append(res,
@ -85,7 +85,7 @@ func headersFromObject(obj *object.Object, addr *objectSDK.Address) []eacl.Heade
) )
attrs := obj.Attributes() attrs := obj.Attributes()
hs := make([]eacl.Header, 0, len(attrs)) hs := make([]eaclSDK.Header, 0, len(attrs))
for i := range attrs { for i := range attrs {
hs = append(hs, attrs[i]) hs = append(hs, attrs[i])

View file

@ -1,189 +0,0 @@
package eacl
import (
"bytes"
"errors"
"github.com/nspcc-dev/neofs-node/pkg/core/container"
"github.com/nspcc-dev/neofs-node/pkg/util/logger"
"github.com/nspcc-dev/neofs-sdk-go/eacl"
"go.uber.org/zap"
)
// Validator is a tool that calculates
// the action on a request according
// to the extended ACL rule table.
type Validator struct {
*cfg
}
// Option represents Validator option.
type Option func(*cfg)
type cfg struct {
logger *logger.Logger
storage Source
}
func defaultCfg() *cfg {
return &cfg{
logger: zap.L(),
}
}
// NewValidator creates and initializes a new Validator using options.
func NewValidator(opts ...Option) *Validator {
cfg := defaultCfg()
for i := range opts {
opts[i](cfg)
}
return &Validator{
cfg: cfg,
}
}
// CalculateAction calculates action on the request according
// to its information represented in ValidationUnit.
//
// The action is calculated according to the application of
// eACL table of rules to the request.
//
// If the eACL table is not available at the time of the call,
// eacl.ActionUnknown is returned.
//
// If no matching table entry is found, ActionAllow is returned.
func (v *Validator) CalculateAction(unit *ValidationUnit) eacl.Action {
var (
err error
table *eacl.Table
)
if unit.bearer != nil {
table = eacl.NewTableFromV2(unit.bearer.GetBody().GetEACL())
} else {
// get eACL table by container ID
table, err = v.storage.GetEACL(unit.cid)
if err != nil {
if errors.Is(err, container.ErrEACLNotFound) {
return eacl.ActionAllow
}
v.logger.Error("could not get eACL table",
zap.String("error", err.Error()),
)
return eacl.ActionUnknown
}
}
return tableAction(unit, table)
}
// calculates action on the request based on the eACL rules.
func tableAction(unit *ValidationUnit, table *eacl.Table) eacl.Action {
for _, record := range table.Records() {
// check type of operation
if record.Operation() != unit.op {
continue
}
// check target
if !targetMatches(unit, record) {
continue
}
// check headers
switch val := matchFilters(unit.hdrSrc, record.Filters()); {
case val < 0:
// headers of some type could not be composed => allow
return eacl.ActionAllow
case val == 0:
return record.Action()
}
}
return eacl.ActionAllow
}
// returns:
// - positive value if no matching header is found for at least one filter;
// - zero if at least one suitable header is found for all filters;
// - negative value if the headers of at least one filter cannot be obtained.
func matchFilters(hdrSrc TypedHeaderSource, filters []*eacl.Filter) int {
matched := 0
for _, filter := range filters {
headers, ok := hdrSrc.HeadersOfType(filter.From())
if !ok {
return -1
}
// get headers of filtering type
for _, header := range headers {
// prevent NPE
if header == nil {
continue
}
// check header name
if header.Key() != filter.Key() {
continue
}
// get match function
matchFn, ok := mMatchFns[filter.Matcher()]
if !ok {
continue
}
// check match
if !matchFn(header, filter) {
continue
}
// increment match counter
matched++
break
}
}
return len(filters) - matched
}
// returns true if one of ExtendedACLTarget has
// suitable target OR suitable public key.
func targetMatches(unit *ValidationUnit, record *eacl.Record) bool {
for _, target := range record.Targets() {
// check public key match
if pubs := target.BinaryKeys(); len(pubs) != 0 {
for _, key := range pubs {
if bytes.Equal(key, unit.key) {
return true
}
}
continue
}
// check target group match
if unit.role == target.Role() {
return true
}
}
return false
}
// Maps match type to corresponding function.
var mMatchFns = map[eacl.Match]func(Header, *eacl.Filter) bool{
eacl.MatchStringEqual: func(header Header, filter *eacl.Filter) bool {
return header.Value() == filter.Value()
},
eacl.MatchStringNotEqual: func(header Header, filter *eacl.Filter) bool {
return header.Value() != filter.Value()
},
}

View file

@ -1,52 +0,0 @@
package eacl
import (
"math/rand"
"testing"
"github.com/nspcc-dev/neofs-sdk-go/eacl"
"github.com/stretchr/testify/require"
)
func TestTargetMatches(t *testing.T) {
pubs := make([][]byte, 3)
for i := range pubs {
pubs[i] = make([]byte, 33)
pubs[i][0] = 0x02
_, err := rand.Read(pubs[i][1:])
require.NoError(t, err)
}
tgt1 := eacl.NewTarget()
tgt1.SetBinaryKeys(pubs[0:2])
tgt1.SetRole(eacl.RoleUser)
tgt2 := eacl.NewTarget()
tgt2.SetRole(eacl.RoleOthers)
r := eacl.NewRecord()
r.SetTargets(tgt1, tgt2)
u := newValidationUnit(eacl.RoleUser, pubs[0])
require.True(t, targetMatches(u, r))
u = newValidationUnit(eacl.RoleUser, pubs[2])
require.False(t, targetMatches(u, r))
u = newValidationUnit(eacl.RoleUnknown, pubs[1])
require.True(t, targetMatches(u, r))
u = newValidationUnit(eacl.RoleOthers, pubs[2])
require.True(t, targetMatches(u, r))
u = newValidationUnit(eacl.RoleSystem, pubs[2])
require.False(t, targetMatches(u, r))
}
func newValidationUnit(role eacl.Role, key []byte) *ValidationUnit {
return &ValidationUnit{
role: role,
key: key,
}
}

View file

@ -29,10 +29,10 @@ func WithNextService(v objectSvc.ServiceServer) Option {
} }
} }
// WithEACLValidatorOptions returns options to set eACL validator options. // WithEACLSource returns options to set eACL table source.
func WithEACLValidatorOptions(v ...eacl.Option) Option { func WithEACLSource(v eacl.Source) Option {
return func(c *cfg) { return func(c *cfg) {
c.eACLOpts = v c.eACLCfg.eaclSource = v
} }
} }