From f83ff628fb19bdf1dc624c8c57b0de32c3ae9697 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Tue, 5 Oct 2021 15:24:04 +0300 Subject: [PATCH] [#36] eacl: add eACL table to `ValidationUnit` Improve SDK usability a bit: 1. Replace bearer and storage with a single eACL table. This way caller can implement it's own behaviour for missing eACL. 2. Remove logging. SDK library shouldn't be dependent on a specific logger. Signed-off-by: Evgenii Stratonikov --- eacl/opts.go | 34 ------------------------ eacl/types.go | 26 +++--------------- eacl/validator.go | 49 +++------------------------------- eacl/validator_test.go | 60 ++++++++++++++++-------------------------- 4 files changed, 28 insertions(+), 141 deletions(-) delete mode 100644 eacl/opts.go diff --git a/eacl/opts.go b/eacl/opts.go deleted file mode 100644 index 530fa76..0000000 --- a/eacl/opts.go +++ /dev/null @@ -1,34 +0,0 @@ -package eacl - -import ( - "go.uber.org/zap" -) - -// Option represents Validator option. -type Option func(*cfg) - -type cfg struct { - logger *zap.Logger - - storage Source -} - -func defaultCfg() *cfg { - return &cfg{ - logger: zap.L(), - } -} - -// WithLogger configures the Validator to use logger v. -func WithLogger(v *zap.Logger) Option { - return func(c *cfg) { - c.logger = v - } -} - -// WithEACLSource configures the validator to use v as eACL source. -func WithEACLSource(v Source) Option { - return func(c *cfg) { - c.storage = v - } -} diff --git a/eacl/types.go b/eacl/types.go index 10abdd5..2655413 100644 --- a/eacl/types.go +++ b/eacl/types.go @@ -1,25 +1,9 @@ package eacl import ( - "errors" - - bearer "github.com/nspcc-dev/neofs-api-go/v2/acl" cid "github.com/nspcc-dev/neofs-sdk-go/container/id" ) -// Source is the interface that wraps -// basic methods of extended ACL table source. -type Source interface { - // GetEACL reads the table from the source by identifier. - // It returns any error encountered. - // - // GetEACL must return exactly one non-nil value. - // - // Must return pkg/core/container.ErrEACLNotFound if requested - // eACL table is not in source. - GetEACL(*cid.ID) (*Table, error) -} - // Header is an interface of string key-value header. type Header interface { Key() string @@ -49,13 +33,9 @@ type ValidationUnit struct { key []byte - bearer *bearer.BearerToken + table *Table } -// ErrEACLNotFound is returned by eACL storage implementations when -// requested eACL table is not in storage. -var ErrEACLNotFound = errors.New("extended ACL table is not set for this container") - // WithContainerID configures ValidationUnit to use v as request's container ID. func (u *ValidationUnit) WithContainerID(v *cid.ID) *ValidationUnit { if u != nil { @@ -102,9 +82,9 @@ func (u *ValidationUnit) WithSenderKey(v []byte) *ValidationUnit { } // WithBearerToken configures ValidationUnit to use v as request's bearer token. -func (u *ValidationUnit) WithBearerToken(bearer *bearer.BearerToken) *ValidationUnit { +func (u *ValidationUnit) WithEACLTable(table *Table) *ValidationUnit { if u != nil { - u.bearer = bearer + u.table = table } return u diff --git a/eacl/validator.go b/eacl/validator.go index c14c6d7..1c09dea 100644 --- a/eacl/validator.go +++ b/eacl/validator.go @@ -2,29 +2,17 @@ package eacl import ( "bytes" - "errors" - - "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 } // 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, - } +func NewValidator() *Validator { + return &Validator{} } // CalculateAction calculates action on the request according @@ -33,40 +21,9 @@ func NewValidator(opts ...Option) *Validator { // 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, -// ActionUnknown is returned. -// // If no matching table entry is found, ActionAllow is returned. func (v *Validator) CalculateAction(unit *ValidationUnit) Action { - var ( - err error - table *Table - ) - - if unit.bearer != nil { - table = 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, ErrEACLNotFound) { - return ActionAllow - } - - v.logger.Error("could not get eACL table", - zap.String("error", err.Error()), - ) - - return ActionUnknown - } - } - - return tableAction(unit, table) -} - -// tableAction calculates action on the request based on the eACL rules. -func tableAction(unit *ValidationUnit, table *Table) Action { - for _, record := range table.Records() { + for _, record := range unit.table.Records() { // check type of operation if record.Operation() != unit.op { continue diff --git a/eacl/validator_test.go b/eacl/validator_test.go index 4c4e822..1f0749d 100644 --- a/eacl/validator_test.go +++ b/eacl/validator_test.go @@ -4,9 +4,7 @@ import ( "math/rand" "testing" - cid "github.com/nspcc-dev/neofs-sdk-go/container/id" "github.com/stretchr/testify/require" - "go.uber.org/zap/zaptest" ) func TestFilterMatch(t *testing.T) { @@ -26,8 +24,8 @@ func TestFilterMatch(t *testing.T) { tb.AddRecord(newRecord(ActionAllow, OperationUnknown, tgt)) - v := newValidator(t, tb) - vu := newValidationUnit(RoleOthers, nil) + v := NewValidator() + vu := newValidationUnit(RoleOthers, nil, tb) hs := headers{} vu.hdrSrc = &hs @@ -55,8 +53,8 @@ func TestFilterMatch(t *testing.T) { tb.AddRecord(r) tb.AddRecord(newRecord(ActionAllow, OperationUnknown, tgt)) - v := newValidator(t, tb) - vu := newValidationUnit(RoleOthers, nil) + v := NewValidator() + vu := newValidationUnit(RoleOthers, nil, tb) hs := headers{} vu.hdrSrc = &hs @@ -82,8 +80,8 @@ func TestFilterMatch(t *testing.T) { tb.AddRecord(newRecord(ActionDeny, OperationUnknown, tgt)) - v := newValidator(t, tb) - vu := newValidationUnit(RoleOthers, nil) + v := NewValidator() + vu := newValidationUnit(RoleOthers, nil, tb) hs := headers{} vu.hdrSrc = &hs @@ -104,8 +102,8 @@ func TestFilterMatch(t *testing.T) { tb.AddRecord(r) tb.AddRecord(newRecord(ActionDeny, OperationUnknown, tgt)) - v := newValidator(t, tb) - vu := newValidationUnit(RoleOthers, nil) + v := NewValidator() + vu := newValidationUnit(RoleOthers, nil, tb) hs := headers{} vu.hdrSrc = &hs @@ -125,8 +123,8 @@ func TestOperationMatch(t *testing.T) { tb.AddRecord(newRecord(ActionDeny, OperationPut, tgt)) tb.AddRecord(newRecord(ActionAllow, OperationGet, tgt)) - v := newValidator(t, tb) - vu := newValidationUnit(RoleOthers, nil) + v := NewValidator() + vu := newValidationUnit(RoleOthers, nil, tb) vu.op = OperationPut require.Equal(t, ActionDeny, v.CalculateAction(vu)) @@ -140,8 +138,8 @@ func TestOperationMatch(t *testing.T) { tb.AddRecord(newRecord(ActionDeny, OperationUnknown, tgt)) tb.AddRecord(newRecord(ActionAllow, OperationGet, tgt)) - v := newValidator(t, tb) - vu := newValidationUnit(RoleOthers, nil) + v := NewValidator() + vu := newValidationUnit(RoleOthers, nil, tb) // TODO discuss if both next tests should result in DENY vu.op = OperationPut @@ -165,19 +163,19 @@ func TestTargetMatches(t *testing.T) { r := NewRecord() r.SetTargets(tgt1, tgt2) - u := newValidationUnit(RoleUser, pubs[0]) + u := newValidationUnit(RoleUser, pubs[0], nil) require.True(t, targetMatches(u, r)) - u = newValidationUnit(RoleUser, pubs[2]) + u = newValidationUnit(RoleUser, pubs[2], nil) require.False(t, targetMatches(u, r)) - u = newValidationUnit(RoleUnknown, pubs[1]) + u = newValidationUnit(RoleUnknown, pubs[1], nil) require.True(t, targetMatches(u, r)) - u = newValidationUnit(RoleOthers, pubs[2]) + u = newValidationUnit(RoleOthers, pubs[2], nil) require.True(t, targetMatches(u, r)) - u = newValidationUnit(RoleSystem, pubs[2]) + u = newValidationUnit(RoleSystem, pubs[2], nil) require.False(t, targetMatches(u, r)) } @@ -234,23 +232,9 @@ func newRecord(a Action, op Operation, tgt ...*Target) *Record { return r } -type dummySource struct { - tb *Table -} - -func (d dummySource) GetEACL(*cid.ID) (*Table, error) { - return d.tb, nil -} - -func newValidator(t *testing.T, tb *Table) *Validator { - return NewValidator( - WithLogger(zaptest.NewLogger(t)), - WithEACLSource(dummySource{tb})) -} - -func newValidationUnit(role Role, key []byte) *ValidationUnit { - return &ValidationUnit{ - role: role, - key: key, - } +func newValidationUnit(role Role, key []byte, table *Table) *ValidationUnit { + return new(ValidationUnit). + WithRole(role). + WithSenderKey(key). + WithEACLTable(table) }