frostfs-node/pkg/services/object/acl/basic_helper.go
Alex Vanin 6f841e319d [#180] Make separate basic ACL check for inner ring requests
Signed-off-by: Alex Vanin <alexey@nspcc.ru>
2020-11-19 15:17:18 +03:00

195 lines
5.2 KiB
Go

package acl
import (
"github.com/nspcc-dev/neofs-api-go/pkg/acl/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:
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)
}
}