2020-09-10 14:51:58 +00:00
|
|
|
package eacl
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/ecdsa"
|
2020-10-27 17:20:01 +00:00
|
|
|
"fmt"
|
2020-09-10 14:51:58 +00:00
|
|
|
|
2020-10-27 17:20:01 +00:00
|
|
|
"github.com/nspcc-dev/neofs-api-go/pkg"
|
2021-05-24 16:42:36 +00:00
|
|
|
cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id"
|
2021-08-25 11:11:35 +00:00
|
|
|
"github.com/nspcc-dev/neofs-api-go/pkg/object"
|
2020-10-27 17:20:01 +00:00
|
|
|
"github.com/nspcc-dev/neofs-api-go/pkg/owner"
|
2020-09-10 14:51:58 +00:00
|
|
|
v2acl "github.com/nspcc-dev/neofs-api-go/v2/acl"
|
|
|
|
)
|
|
|
|
|
2020-11-16 14:24:06 +00:00
|
|
|
// Record of the EACL rule, that defines EACL action, targets for this action,
|
|
|
|
// object service operation and filters for request headers.
|
|
|
|
//
|
|
|
|
// Record is compatible with v2 acl.EACLRecord message.
|
|
|
|
type Record struct {
|
|
|
|
action Action
|
|
|
|
operation Operation
|
|
|
|
filters []*Filter
|
|
|
|
targets []*Target
|
|
|
|
}
|
2020-09-10 14:51:58 +00:00
|
|
|
|
2020-11-16 14:24:06 +00:00
|
|
|
// Targets returns list of target subjects to apply ACL rule to.
|
|
|
|
func (r Record) Targets() []*Target {
|
2020-09-10 14:51:58 +00:00
|
|
|
return r.targets
|
|
|
|
}
|
|
|
|
|
2020-12-01 06:39:35 +00:00
|
|
|
// SetTargets sets list of target subjects to apply ACL rule to.
|
|
|
|
func (r *Record) SetTargets(targets ...*Target) {
|
|
|
|
r.targets = targets
|
|
|
|
}
|
|
|
|
|
2020-11-16 14:24:06 +00:00
|
|
|
// Filters returns list of filters to match and see if rule is applicable.
|
|
|
|
func (r Record) Filters() []*Filter {
|
2020-09-10 14:51:58 +00:00
|
|
|
return r.filters
|
|
|
|
}
|
|
|
|
|
2020-11-16 14:24:06 +00:00
|
|
|
// Operation returns NeoFS request verb to match.
|
2020-09-10 14:51:58 +00:00
|
|
|
func (r Record) Operation() Operation {
|
|
|
|
return r.operation
|
|
|
|
}
|
|
|
|
|
2020-11-16 14:24:06 +00:00
|
|
|
// SetOperation sets NeoFS request verb to match.
|
2020-09-10 14:51:58 +00:00
|
|
|
func (r *Record) SetOperation(operation Operation) {
|
|
|
|
r.operation = operation
|
|
|
|
}
|
|
|
|
|
2020-11-16 14:24:06 +00:00
|
|
|
// Action returns rule execution result.
|
2020-09-10 14:51:58 +00:00
|
|
|
func (r Record) Action() Action {
|
|
|
|
return r.action
|
|
|
|
}
|
|
|
|
|
2020-11-16 14:24:06 +00:00
|
|
|
// SetAction sets rule execution result.
|
2020-09-10 14:51:58 +00:00
|
|
|
func (r *Record) SetAction(action Action) {
|
|
|
|
r.action = action
|
|
|
|
}
|
|
|
|
|
2020-11-16 14:24:06 +00:00
|
|
|
// AddTarget adds target subject with specified Role and key list.
|
2020-12-01 06:39:35 +00:00
|
|
|
//
|
|
|
|
// Deprecated: use AddFormedTarget instead.
|
2020-09-10 14:51:58 +00:00
|
|
|
func (r *Record) AddTarget(role Role, keys ...ecdsa.PublicKey) {
|
2020-12-01 06:39:35 +00:00
|
|
|
AddFormedTarget(r, role, keys...)
|
|
|
|
}
|
2020-09-10 14:51:58 +00:00
|
|
|
|
2020-12-01 06:39:35 +00:00
|
|
|
// AddRecordTarget adds single Target to the Record.
|
|
|
|
func AddRecordTarget(r *Record, t *Target) {
|
|
|
|
r.SetTargets(append(r.Targets(), t)...)
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddFormedTarget forms Target with specified Role and list of
|
|
|
|
// ECDSA public keys and adds it to the Record.
|
|
|
|
func AddFormedTarget(r *Record, role Role, keys ...ecdsa.PublicKey) {
|
|
|
|
t := NewTarget()
|
|
|
|
t.SetRole(role)
|
|
|
|
SetTargetECDSAKeys(t, ecdsaKeysToPtrs(keys)...)
|
2020-09-10 14:51:58 +00:00
|
|
|
|
2020-12-01 06:39:35 +00:00
|
|
|
AddRecordTarget(r, t)
|
2020-09-10 14:51:58 +00:00
|
|
|
}
|
|
|
|
|
2020-10-27 17:20:01 +00:00
|
|
|
func (r *Record) addFilter(from FilterHeaderType, m Match, keyTyp filterKeyType, key string, val fmt.Stringer) {
|
2020-11-16 14:24:06 +00:00
|
|
|
filter := &Filter{
|
2020-10-27 17:20:01 +00:00
|
|
|
from: from,
|
|
|
|
key: filterKey{
|
|
|
|
typ: keyTyp,
|
|
|
|
str: key,
|
|
|
|
},
|
|
|
|
matcher: m,
|
|
|
|
value: val,
|
2020-09-10 14:51:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
r.filters = append(r.filters, filter)
|
|
|
|
}
|
|
|
|
|
2020-10-27 17:20:01 +00:00
|
|
|
func (r *Record) addObjectFilter(m Match, keyTyp filterKeyType, key string, val fmt.Stringer) {
|
|
|
|
r.addFilter(HeaderFromObject, m, keyTyp, key, val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Record) addObjectReservedFilter(m Match, typ filterKeyType, val fmt.Stringer) {
|
|
|
|
r.addObjectFilter(m, typ, "", val)
|
|
|
|
}
|
|
|
|
|
2020-11-16 14:24:06 +00:00
|
|
|
// AddFilter adds generic filter.
|
2020-10-27 17:20:01 +00:00
|
|
|
func (r *Record) AddFilter(from FilterHeaderType, matcher Match, name, value string) {
|
|
|
|
r.addFilter(from, matcher, 0, name, staticStringer(value))
|
|
|
|
}
|
|
|
|
|
2020-11-16 14:24:06 +00:00
|
|
|
// AddObjectAttributeFilter adds filter by object attribute.
|
2020-10-27 17:20:01 +00:00
|
|
|
func (r *Record) AddObjectAttributeFilter(m Match, key, value string) {
|
|
|
|
r.addObjectFilter(m, 0, key, staticStringer(value))
|
|
|
|
}
|
|
|
|
|
2020-11-16 14:24:06 +00:00
|
|
|
// AddObjectVersionFilter adds filter by object version.
|
2020-10-27 17:20:01 +00:00
|
|
|
func (r *Record) AddObjectVersionFilter(m Match, v *pkg.Version) {
|
|
|
|
r.addObjectReservedFilter(m, fKeyObjVersion, v)
|
|
|
|
}
|
|
|
|
|
2021-08-25 11:11:35 +00:00
|
|
|
// AddObjectIDFilter adds filter by object ID.
|
|
|
|
func (r *Record) AddObjectIDFilter(m Match, id *object.ID) {
|
|
|
|
r.addObjectReservedFilter(m, fKeyObjID, id)
|
|
|
|
}
|
|
|
|
|
2020-11-16 14:24:06 +00:00
|
|
|
// AddObjectContainerIDFilter adds filter by object container ID.
|
2021-05-24 16:42:36 +00:00
|
|
|
func (r *Record) AddObjectContainerIDFilter(m Match, id *cid.ID) {
|
2020-10-27 17:20:01 +00:00
|
|
|
r.addObjectReservedFilter(m, fKeyObjContainerID, id)
|
|
|
|
}
|
|
|
|
|
2020-11-16 14:24:06 +00:00
|
|
|
// AddObjectOwnerIDFilter adds filter by object owner ID.
|
2020-10-27 17:20:01 +00:00
|
|
|
func (r *Record) AddObjectOwnerIDFilter(m Match, id *owner.ID) {
|
|
|
|
r.addObjectReservedFilter(m, fKeyObjOwnerID, id)
|
|
|
|
}
|
|
|
|
|
2021-08-25 11:11:35 +00:00
|
|
|
// AddObjectCreationEpoch adds filter by object creation epoch.
|
|
|
|
func (r *Record) AddObjectCreationEpoch(m Match, epoch uint64) {
|
|
|
|
r.addObjectReservedFilter(m, fKeyObjCreationEpoch, u64Stringer(epoch))
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddObjectPayloadLengthFilter adds filter by object payload length.
|
|
|
|
func (r *Record) AddObjectPayloadLengthFilter(m Match, size uint64) {
|
|
|
|
r.addObjectReservedFilter(m, fKeyObjPayloadLength, u64Stringer(size))
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddObjectPayloadHashFilter adds filter by object payload hash value.
|
|
|
|
func (r *Record) AddObjectPayloadHashFilter(m Match, h *pkg.Checksum) {
|
|
|
|
r.addObjectReservedFilter(m, fKeyObjPayloadHash, h)
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddObjectTypeFilter adds filter by object type.
|
|
|
|
func (r *Record) AddObjectTypeFilter(m Match, t object.Type) {
|
|
|
|
r.addObjectReservedFilter(m, fKeyObjType, t)
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddObjectHomomorphicHashFilter adds filter by object payload homomorphic hash value.
|
|
|
|
func (r *Record) AddObjectHomomorphicHashFilter(m Match, h *pkg.Checksum) {
|
|
|
|
r.addObjectReservedFilter(m, fKeyObjHomomorphicHash, h)
|
|
|
|
}
|
2020-10-27 17:20:01 +00:00
|
|
|
|
2020-11-16 14:24:06 +00:00
|
|
|
// ToV2 converts Record to v2 acl.EACLRecord message.
|
2021-05-27 11:35:49 +00:00
|
|
|
//
|
|
|
|
// Nil Record converts to nil.
|
2020-09-10 14:51:58 +00:00
|
|
|
func (r *Record) ToV2() *v2acl.Record {
|
2021-05-27 11:35:49 +00:00
|
|
|
if r == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-05-27 11:42:12 +00:00
|
|
|
v2 := new(v2acl.Record)
|
|
|
|
|
|
|
|
if r.targets != nil {
|
|
|
|
targets := make([]*v2acl.Target, 0, len(r.targets))
|
|
|
|
for _, target := range r.targets {
|
|
|
|
targets = append(targets, target.ToV2())
|
|
|
|
}
|
2020-09-10 14:51:58 +00:00
|
|
|
|
2021-05-27 11:42:12 +00:00
|
|
|
v2.SetTargets(targets)
|
2020-09-10 14:51:58 +00:00
|
|
|
}
|
|
|
|
|
2021-05-27 11:42:12 +00:00
|
|
|
if r.filters != nil {
|
|
|
|
filters := make([]*v2acl.HeaderFilter, 0, len(r.filters))
|
|
|
|
for _, filter := range r.filters {
|
|
|
|
filters = append(filters, filter.ToV2())
|
|
|
|
}
|
|
|
|
|
|
|
|
v2.SetFilters(filters)
|
|
|
|
}
|
2020-09-10 14:51:58 +00:00
|
|
|
|
|
|
|
v2.SetAction(r.action.ToV2())
|
|
|
|
v2.SetOperation(r.operation.ToV2())
|
|
|
|
|
|
|
|
return v2
|
|
|
|
}
|
|
|
|
|
2020-11-16 14:24:06 +00:00
|
|
|
// NewRecord creates and returns blank Record instance.
|
2021-05-27 11:36:45 +00:00
|
|
|
//
|
|
|
|
// Defaults:
|
|
|
|
// - action: ActionUnknown;
|
|
|
|
// - operation: OperationUnknown;
|
|
|
|
// - targets: nil,
|
|
|
|
// - filters: nil.
|
2020-09-10 14:51:58 +00:00
|
|
|
func NewRecord() *Record {
|
|
|
|
return new(Record)
|
|
|
|
}
|
|
|
|
|
2020-11-16 14:24:06 +00:00
|
|
|
// CreateRecord creates, initializes with parameters and returns Record instance.
|
2020-09-10 14:51:58 +00:00
|
|
|
func CreateRecord(action Action, operation Operation) *Record {
|
|
|
|
r := NewRecord()
|
|
|
|
r.action = action
|
|
|
|
r.operation = operation
|
2020-11-16 14:24:06 +00:00
|
|
|
r.targets = []*Target{}
|
|
|
|
r.filters = []*Filter{}
|
2020-09-10 14:51:58 +00:00
|
|
|
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
2020-11-16 14:24:06 +00:00
|
|
|
// NewRecordFromV2 converts v2 acl.EACLRecord message to Record.
|
2020-09-10 14:51:58 +00:00
|
|
|
func NewRecordFromV2(record *v2acl.Record) *Record {
|
|
|
|
r := NewRecord()
|
|
|
|
|
|
|
|
if record == nil {
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
|
|
|
r.action = ActionFromV2(record.GetAction())
|
|
|
|
r.operation = OperationFromV2(record.GetOperation())
|
|
|
|
|
|
|
|
v2targets := record.GetTargets()
|
|
|
|
v2filters := record.GetFilters()
|
|
|
|
|
2020-11-16 14:24:06 +00:00
|
|
|
r.targets = make([]*Target, 0, len(v2targets))
|
2020-09-10 14:51:58 +00:00
|
|
|
for i := range v2targets {
|
2020-11-16 14:24:06 +00:00
|
|
|
r.targets = append(r.targets, NewTargetFromV2(v2targets[i]))
|
2020-09-10 14:51:58 +00:00
|
|
|
}
|
|
|
|
|
2020-11-16 14:24:06 +00:00
|
|
|
r.filters = make([]*Filter, 0, len(v2filters))
|
2020-09-10 14:51:58 +00:00
|
|
|
for i := range v2filters {
|
2020-11-16 14:24:06 +00:00
|
|
|
r.filters = append(r.filters, NewFilterFromV2(v2filters[i]))
|
2020-09-10 14:51:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return r
|
|
|
|
}
|
2020-11-13 11:48:19 +00:00
|
|
|
|
|
|
|
// Marshal marshals Record into a protobuf binary form.
|
|
|
|
//
|
|
|
|
// Buffer is allocated when the argument is empty.
|
|
|
|
// Otherwise, the first buffer is used.
|
|
|
|
func (r *Record) Marshal(b ...[]byte) ([]byte, error) {
|
|
|
|
var buf []byte
|
|
|
|
if len(b) > 0 {
|
|
|
|
buf = b[0]
|
|
|
|
}
|
|
|
|
|
|
|
|
return r.ToV2().
|
|
|
|
StableMarshal(buf)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unmarshal unmarshals protobuf binary representation of Record.
|
|
|
|
func (r *Record) Unmarshal(data []byte) error {
|
|
|
|
fV2 := new(v2acl.Record)
|
|
|
|
if err := fV2.Unmarshal(data); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
*r = *NewRecordFromV2(fV2)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// MarshalJSON encodes Record to protobuf JSON format.
|
|
|
|
func (r *Record) MarshalJSON() ([]byte, error) {
|
|
|
|
return r.ToV2().
|
|
|
|
MarshalJSON()
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalJSON decodes Record from protobuf JSON format.
|
|
|
|
func (r *Record) UnmarshalJSON(data []byte) error {
|
|
|
|
tV2 := new(v2acl.Record)
|
|
|
|
if err := tV2.UnmarshalJSON(data); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
*r = *NewRecordFromV2(tV2)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|