frostfs-node/lib/acl/basic.go
alexvanin dadfd90dcd Initial commit
Initial public review release v0.10.0
2020-07-10 17:45:00 +03:00

179 lines
4.7 KiB
Go

package acl
import (
"github.com/nspcc-dev/neofs-api-go/acl"
"github.com/nspcc-dev/neofs-api-go/object"
"github.com/nspcc-dev/neofs-node/internal"
)
type (
// BasicChecker is an interface of the basic ACL control tool.
BasicChecker interface {
// Action returns true if request is allowed for this target.
Action(uint32, object.RequestType, acl.Target) (bool, error)
// Bearer returns true if bearer token is allowed for this request.
Bearer(uint32, object.RequestType) (bool, error)
// Extended returns true if extended ACL is allowed for this.
Extended(uint32) bool
// Sticky returns true if sticky bit is set.
Sticky(uint32) bool
}
// BasicACLChecker performs basic ACL check.
BasicACLChecker struct{}
// MaskedBasicACLChecker performs all basic ACL checks, but applying
// mask on ACL first. It is useful, when some bits must be always
// set or unset.
MaskedBasicACLChecker struct {
BasicACLChecker
andMask uint32
orMask uint32
}
nibble struct {
value uint32
}
)
const (
errUnknownRequest = internal.Error("unknown request type")
errUnknownTarget = internal.Error("unknown target type")
)
const (
aclFinalBit = 0x10000000 // 29th bit
aclStickyBit = 0x20000000 // 30th bit
nibbleBBit = 0x1
nibbleOBit = 0x2
nibbleSBit = 0x4
nibbleUBit = 0x8
// DefaultAndFilter is a default AND mask of basic ACL value of container.
DefaultAndFilter = 0xFFFFFFFF
)
var (
nibbleOffset = map[object.RequestType]uint32{
object.RequestGet: 0,
object.RequestHead: 1 * 4,
object.RequestPut: 2 * 4,
object.RequestDelete: 3 * 4,
object.RequestSearch: 4 * 4,
object.RequestRange: 5 * 4,
object.RequestRangeHash: 6 * 4,
}
)
// Action returns true if request is allowed for target.
func (c *BasicACLChecker) Action(rule uint32, req object.RequestType, t acl.Target) (bool, error) {
n, err := fetchNibble(rule, req)
if err != nil {
return false, err
}
switch t {
case acl.Target_User:
return n.U(), nil
case acl.Target_System:
return n.S(), nil
case acl.Target_Others:
return n.O(), nil
default:
return false, errUnknownTarget
}
}
// Bearer returns true if bearer token is allowed to use for this request
// as source of extended ACL.
func (c *BasicACLChecker) Bearer(rule uint32, req object.RequestType) (bool, error) {
n, err := fetchNibble(rule, req)
if err != nil {
return false, err
}
return n.B(), nil
}
// Extended returns true if extended ACL stored in the container are allowed
// to use.
func (c *BasicACLChecker) Extended(rule uint32) bool {
return rule&aclFinalBit != aclFinalBit
}
// Sticky returns true if container is not allowed to store objects with
// owners different from request owner.
func (c *BasicACLChecker) Sticky(rule uint32) bool {
return rule&aclStickyBit == aclStickyBit
}
func fetchNibble(rule uint32, req object.RequestType) (*nibble, error) {
offset, ok := nibbleOffset[req]
if !ok {
return nil, errUnknownRequest
}
return &nibble{value: (rule >> offset) & 0xf}, nil
}
// B returns true if `Bearer` bit set in the nibble.
func (n *nibble) B() bool { return n.value&nibbleBBit == nibbleBBit }
// O returns true if `Others` bit set in the nibble.
func (n *nibble) O() bool { return n.value&nibbleOBit == nibbleOBit }
// S returns true if `System` bit set in the nibble.
func (n *nibble) S() bool { return n.value&nibbleSBit == nibbleSBit }
// U returns true if `User` bit set in the nibble.
func (n *nibble) U() bool { return n.value&nibbleUBit == nibbleUBit }
// NewMaskedBasicACLChecker returns BasicChecker that applies predefined
// bit mask on basic ACL value.
func NewMaskedBasicACLChecker(or, and uint32) BasicChecker {
return MaskedBasicACLChecker{
BasicACLChecker: BasicACLChecker{},
andMask: and,
orMask: or,
}
}
// Action returns true if request is allowed for target.
func (c MaskedBasicACLChecker) Action(rule uint32, req object.RequestType, t acl.Target) (bool, error) {
rule |= c.orMask
rule &= c.andMask
return c.BasicACLChecker.Action(rule, req, t)
}
// Bearer returns true if bearer token is allowed to use for this request
// as source of extended ACL.
func (c MaskedBasicACLChecker) Bearer(rule uint32, req object.RequestType) (bool, error) {
rule |= c.orMask
rule &= c.andMask
return c.BasicACLChecker.Bearer(rule, req)
}
// Extended returns true if extended ACL stored in the container are allowed
// to use.
func (c MaskedBasicACLChecker) Extended(rule uint32) bool {
rule |= c.orMask
rule &= c.andMask
return c.BasicACLChecker.Extended(rule)
}
// Sticky returns true if container is not allowed to store objects with
// owners different from request owner.
func (c MaskedBasicACLChecker) Sticky(rule uint32) bool {
rule |= c.orMask
rule &= c.andMask
return c.BasicACLChecker.Sticky(rule)
}