forked from TrueCloudLab/frostfs-node
dadfd90dcd
Initial public review release v0.10.0
94 lines
2.4 KiB
Go
94 lines
2.4 KiB
Go
package acl
|
|
|
|
import (
|
|
"bytes"
|
|
|
|
"github.com/nspcc-dev/neofs-api-go/acl"
|
|
)
|
|
|
|
// RequestInfo is an interface of request information needed for extended ACL check.
|
|
type RequestInfo interface {
|
|
TypedHeaderSource
|
|
|
|
// Must return the binary representation of request initiator's key.
|
|
Key() []byte
|
|
|
|
// Must return true if request corresponds to operation type.
|
|
TypeOf(acl.OperationType) bool
|
|
|
|
// Must return true if request has passed target.
|
|
TargetOf(acl.Target) bool
|
|
}
|
|
|
|
// ExtendedACLChecker is an interface of extended ACL checking tool.
|
|
type ExtendedACLChecker interface {
|
|
// Must return an action according to the results of applying the ACL table rules to request.
|
|
//
|
|
// Must return ActionUndefined if it is unable to explicitly calculate the action.
|
|
Action(acl.ExtendedACLTable, RequestInfo) acl.ExtendedACLAction
|
|
}
|
|
|
|
type extendedACLChecker struct{}
|
|
|
|
// NewExtendedACLChecker creates a new extended ACL checking tool and returns ExtendedACLChecker interface.
|
|
func NewExtendedACLChecker() ExtendedACLChecker {
|
|
return new(extendedACLChecker)
|
|
}
|
|
|
|
// Action returns an action for passed request based on information about it and ACL table.
|
|
//
|
|
// Returns action of the first suitable table record, or ActionUndefined in the absence thereof.
|
|
//
|
|
// If passed ExtendedACLTable is nil, ActionUndefined returns.
|
|
// If passed RequestInfo is nil, ActionUndefined returns.
|
|
func (s extendedACLChecker) Action(table acl.ExtendedACLTable, req RequestInfo) acl.ExtendedACLAction {
|
|
if table == nil {
|
|
return acl.ActionUndefined
|
|
} else if req == nil {
|
|
return acl.ActionUndefined
|
|
}
|
|
|
|
for _, record := range table.Records() {
|
|
// check type of operation
|
|
if !req.TypeOf(record.OperationType()) {
|
|
continue
|
|
}
|
|
|
|
// check target
|
|
if !targetMatches(req, record.TargetList()) {
|
|
continue
|
|
}
|
|
|
|
// check headers
|
|
switch MatchFilters(req, record.HeaderFilters()) {
|
|
case mResUndefined:
|
|
// headers of some type could not be composed => allow
|
|
return acl.ActionAllow
|
|
case mResMatch:
|
|
return record.Action()
|
|
}
|
|
}
|
|
|
|
return acl.ActionAllow
|
|
}
|
|
|
|
// returns true if one of ExtendedACLTarget has suitable target OR suitable public key.
|
|
func targetMatches(req RequestInfo, list []acl.ExtendedACLTarget) bool {
|
|
rKey := req.Key()
|
|
|
|
for _, target := range list {
|
|
// check public key match
|
|
for _, key := range target.KeyList() {
|
|
if bytes.Equal(key, rKey) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
// check target group match
|
|
if req.TargetOf(target.Target()) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|