forked from TrueCloudLab/frostfs-api-go
[#217] pkg/eacl: Change interface for working with keys on Target and Record
In previous implementation Target provided Keys/SetKeys methods which allowed working with ECDSA keys. There was also a bug in the NewTargetFromV2 function when the binary key differed in format from the ECDSA key. New BinaryKeys/SetBinaryKeys methods work with binary keys. To work with ECDSA keys added functions TargetECDSAKeys/SetTargetECDSAKeys. Old methods are left and marked deprecated. Type Record provided an interface for adding a Target by Role and a list of ECDSA keys. New SetTargets method allows to set the list of Target's, AddTarget function allows to add a single Target. AddFormedTarget works like old AddTarget method, which is now deprecated. Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
parent
2a94fdc5e7
commit
c01024b553
4 changed files with 134 additions and 43 deletions
|
@ -26,6 +26,11 @@ func (r Record) Targets() []*Target {
|
||||||
return r.targets
|
return r.targets
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetTargets sets list of target subjects to apply ACL rule to.
|
||||||
|
func (r *Record) SetTargets(targets ...*Target) {
|
||||||
|
r.targets = targets
|
||||||
|
}
|
||||||
|
|
||||||
// Filters returns list of filters to match and see if rule is applicable.
|
// Filters returns list of filters to match and see if rule is applicable.
|
||||||
func (r Record) Filters() []*Filter {
|
func (r Record) Filters() []*Filter {
|
||||||
return r.filters
|
return r.filters
|
||||||
|
@ -52,17 +57,25 @@ func (r *Record) SetAction(action Action) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddTarget adds target subject with specified Role and key list.
|
// AddTarget adds target subject with specified Role and key list.
|
||||||
|
//
|
||||||
|
// Deprecated: use AddFormedTarget instead.
|
||||||
func (r *Record) AddTarget(role Role, keys ...ecdsa.PublicKey) {
|
func (r *Record) AddTarget(role Role, keys ...ecdsa.PublicKey) {
|
||||||
t := &Target{
|
AddFormedTarget(r, role, keys...)
|
||||||
role: role,
|
|
||||||
keys: make([]ecdsa.PublicKey, 0, len(keys)),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range keys {
|
// AddRecordTarget adds single Target to the Record.
|
||||||
t.keys = append(t.keys, keys[i])
|
func AddRecordTarget(r *Record, t *Target) {
|
||||||
|
r.SetTargets(append(r.Targets(), t)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
r.targets = 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)...)
|
||||||
|
|
||||||
|
AddRecordTarget(r, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Record) addFilter(from FilterHeaderType, m Match, keyTyp filterKeyType, key string, val fmt.Stringer) {
|
func (r *Record) addFilter(from FilterHeaderType, m Match, keyTyp filterKeyType, key string, val fmt.Stringer) {
|
||||||
|
|
|
@ -15,7 +15,10 @@ func TestRecord(t *testing.T) {
|
||||||
record.SetAction(ActionAllow)
|
record.SetAction(ActionAllow)
|
||||||
record.AddFilter(HeaderFromRequest, MatchStringEqual, "A", "B")
|
record.AddFilter(HeaderFromRequest, MatchStringEqual, "A", "B")
|
||||||
record.AddFilter(HeaderFromRequest, MatchStringNotEqual, "C", "D")
|
record.AddFilter(HeaderFromRequest, MatchStringNotEqual, "C", "D")
|
||||||
record.AddTarget(RoleSystem)
|
|
||||||
|
target := NewTarget()
|
||||||
|
target.SetRole(RoleSystem)
|
||||||
|
AddRecordTarget(record, target)
|
||||||
|
|
||||||
v2 := record.ToV2()
|
v2 := record.ToV2()
|
||||||
require.NotNil(t, v2)
|
require.NotNil(t, v2)
|
||||||
|
@ -38,8 +41,11 @@ func TestRecord(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRecord_AddTarget(t *testing.T) {
|
func TestAddFormedTarget(t *testing.T) {
|
||||||
targets := []*Target{
|
items := []struct {
|
||||||
|
role Role
|
||||||
|
keys []ecdsa.PublicKey
|
||||||
|
}{
|
||||||
{
|
{
|
||||||
role: RoleUnknown,
|
role: RoleUnknown,
|
||||||
keys: []ecdsa.PublicKey{test.DecodeKey(1).PublicKey},
|
keys: []ecdsa.PublicKey{test.DecodeKey(1).PublicKey},
|
||||||
|
@ -50,12 +56,26 @@ func TestRecord_AddTarget(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
targets := make([]*Target, 0, len(items))
|
||||||
|
|
||||||
r := NewRecord()
|
r := NewRecord()
|
||||||
for _, target := range targets {
|
|
||||||
r.AddTarget(target.Role(), target.Keys()...)
|
for _, item := range items {
|
||||||
|
tgt := NewTarget()
|
||||||
|
tgt.SetRole(item.role)
|
||||||
|
SetTargetECDSAKeys(tgt, ecdsaKeysToPtrs(item.keys)...)
|
||||||
|
|
||||||
|
targets = append(targets, tgt)
|
||||||
|
|
||||||
|
AddFormedTarget(r, item.role, item.keys...)
|
||||||
}
|
}
|
||||||
|
|
||||||
require.Equal(t, targets, r.Targets())
|
tgts := r.Targets()
|
||||||
|
require.Len(t, tgts, len(targets))
|
||||||
|
|
||||||
|
for _, tgt := range targets {
|
||||||
|
require.Contains(t, tgts, tgt)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRecord_AddFilter(t *testing.T) {
|
func TestRecord_AddFilter(t *testing.T) {
|
||||||
|
@ -77,7 +97,7 @@ func TestRecordEncoding(t *testing.T) {
|
||||||
r.SetOperation(OperationHead)
|
r.SetOperation(OperationHead)
|
||||||
r.SetAction(ActionDeny)
|
r.SetAction(ActionDeny)
|
||||||
r.AddObjectAttributeFilter(MatchStringEqual, "key", "value")
|
r.AddObjectAttributeFilter(MatchStringEqual, "key", "value")
|
||||||
r.AddTarget(RoleSystem, test.DecodeKey(-1).PublicKey)
|
AddFormedTarget(r, RoleSystem, test.DecodeKey(-1).PublicKey)
|
||||||
|
|
||||||
t.Run("binary", func(t *testing.T) {
|
t.Run("binary", func(t *testing.T) {
|
||||||
data, err := r.Marshal()
|
data, err := r.Marshal()
|
||||||
|
|
|
@ -13,17 +13,88 @@ import (
|
||||||
// Target is compatible with v2 acl.EACLRecord.Target message.
|
// Target is compatible with v2 acl.EACLRecord.Target message.
|
||||||
type Target struct {
|
type Target struct {
|
||||||
role Role
|
role Role
|
||||||
keys []ecdsa.PublicKey
|
keys [][]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetKeys sets list of public keys to identify target subject.
|
func ecdsaKeysToPtrs(keys []ecdsa.PublicKey) []*ecdsa.PublicKey {
|
||||||
|
keysPtr := make([]*ecdsa.PublicKey, len(keys))
|
||||||
|
|
||||||
|
for i := range keys {
|
||||||
|
keysPtr[i] = &keys[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
return keysPtr
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetKeys sets list of ECDSA public keys to identify target subject.
|
||||||
|
//
|
||||||
|
// Deprecated: use SetTargetECDSAKeys instead.
|
||||||
func (t *Target) SetKeys(keys ...ecdsa.PublicKey) {
|
func (t *Target) SetKeys(keys ...ecdsa.PublicKey) {
|
||||||
|
SetTargetECDSAKeys(t, ecdsaKeysToPtrs(keys)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keys returns list of ECDSA public keys to identify target subject.
|
||||||
|
// If some key has a different format, it is ignored.
|
||||||
|
//
|
||||||
|
// Deprecated: use TargetECDSAKeys instead.
|
||||||
|
func (t *Target) Keys() []ecdsa.PublicKey {
|
||||||
|
keysPtr := TargetECDSAKeys(t)
|
||||||
|
keys := make([]ecdsa.PublicKey, 0, len(keysPtr))
|
||||||
|
|
||||||
|
for i := range keysPtr {
|
||||||
|
if keysPtr[i] != nil {
|
||||||
|
keys = append(keys, *keysPtr[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
|
// BinaryKeys returns list of public keys to identify
|
||||||
|
// target subject in a binary format.
|
||||||
|
func (t *Target) BinaryKeys() [][]byte {
|
||||||
|
return t.keys
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBinaryKeys sets list of binary public keys to identify
|
||||||
|
// target subject.
|
||||||
|
func (t *Target) SetBinaryKeys(keys [][]byte) {
|
||||||
t.keys = keys
|
t.keys = keys
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keys returns list of public keys to identify target subject.
|
// SetTargetECDSAKeys converts ECDSA public keys to a binary
|
||||||
func (t Target) Keys() []ecdsa.PublicKey {
|
// format and stores them in Target.
|
||||||
return t.keys
|
func SetTargetECDSAKeys(t *Target, keys ...*ecdsa.PublicKey) {
|
||||||
|
binKeys := t.BinaryKeys()
|
||||||
|
ln := len(keys)
|
||||||
|
|
||||||
|
if cap(binKeys) >= ln {
|
||||||
|
binKeys = binKeys[:0]
|
||||||
|
} else {
|
||||||
|
binKeys = make([][]byte, 0, ln)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < ln; i++ {
|
||||||
|
binKeys = append(binKeys, crypto.MarshalPublicKey(keys[i]))
|
||||||
|
}
|
||||||
|
|
||||||
|
t.SetBinaryKeys(binKeys)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TargetECDSAKeys interprets binary public keys of Target
|
||||||
|
// as ECDSA public keys. If any key has a different format,
|
||||||
|
// the corresponding element will be nil.
|
||||||
|
func TargetECDSAKeys(t *Target) []*ecdsa.PublicKey {
|
||||||
|
binKeys := t.BinaryKeys()
|
||||||
|
ln := len(binKeys)
|
||||||
|
|
||||||
|
keys := make([]*ecdsa.PublicKey, ln)
|
||||||
|
|
||||||
|
for i := 0; i < ln; i++ {
|
||||||
|
keys[i] = crypto.UnmarshalPublicKey(binKeys[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return keys
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetRole sets target subject's role class.
|
// SetRole sets target subject's role class.
|
||||||
|
@ -38,16 +109,10 @@ func (t Target) Role() Role {
|
||||||
|
|
||||||
// ToV2 converts Target to v2 acl.EACLRecord.Target message.
|
// ToV2 converts Target to v2 acl.EACLRecord.Target message.
|
||||||
func (t *Target) ToV2() *v2acl.Target {
|
func (t *Target) ToV2() *v2acl.Target {
|
||||||
keys := make([][]byte, 0, len(t.keys))
|
|
||||||
for i := range t.keys {
|
|
||||||
key := crypto.MarshalPublicKey(&t.keys[i])
|
|
||||||
keys = append(keys, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
target := new(v2acl.Target)
|
target := new(v2acl.Target)
|
||||||
|
|
||||||
target.SetRole(t.role.ToV2())
|
target.SetRole(t.role.ToV2())
|
||||||
target.SetKeys(keys)
|
target.SetKeys(t.keys)
|
||||||
|
|
||||||
return target
|
return target
|
||||||
}
|
}
|
||||||
|
@ -66,13 +131,7 @@ func NewTargetFromV2(target *v2acl.Target) *Target {
|
||||||
}
|
}
|
||||||
|
|
||||||
t.role = RoleFromV2(target.GetRole())
|
t.role = RoleFromV2(target.GetRole())
|
||||||
v2keys := target.GetKeys()
|
t.keys = target.GetKeys()
|
||||||
t.keys = make([]ecdsa.PublicKey, 0, len(v2keys))
|
|
||||||
|
|
||||||
for i := range v2keys {
|
|
||||||
key := crypto.UnmarshalPublicKey(v2keys[i])
|
|
||||||
t.keys = append(t.keys, *key)
|
|
||||||
}
|
|
||||||
|
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,22 +11,21 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTarget(t *testing.T) {
|
func TestTarget(t *testing.T) {
|
||||||
keys := []ecdsa.PublicKey{
|
keys := []*ecdsa.PublicKey{
|
||||||
test.DecodeKey(1).PublicKey,
|
&test.DecodeKey(1).PublicKey,
|
||||||
test.DecodeKey(2).PublicKey,
|
&test.DecodeKey(2).PublicKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
target := &Target{
|
target := NewTarget()
|
||||||
role: RoleSystem,
|
target.SetRole(RoleSystem)
|
||||||
keys: keys,
|
SetTargetECDSAKeys(target, keys...)
|
||||||
}
|
|
||||||
|
|
||||||
v2 := target.ToV2()
|
v2 := target.ToV2()
|
||||||
require.NotNil(t, v2)
|
require.NotNil(t, v2)
|
||||||
require.Equal(t, v2acl.RoleSystem, v2.GetRole())
|
require.Equal(t, v2acl.RoleSystem, v2.GetRole())
|
||||||
require.Len(t, v2.GetKeys(), len(keys))
|
require.Len(t, v2.GetKeys(), len(keys))
|
||||||
for i, key := range v2.GetKeys() {
|
for i, key := range v2.GetKeys() {
|
||||||
require.Equal(t, key, crypto.MarshalPublicKey(&keys[i]))
|
require.Equal(t, key, crypto.MarshalPublicKey(keys[i]))
|
||||||
}
|
}
|
||||||
|
|
||||||
newTarget := NewTargetFromV2(v2)
|
newTarget := NewTargetFromV2(v2)
|
||||||
|
@ -40,7 +39,7 @@ func TestTarget(t *testing.T) {
|
||||||
func TestTargetEncoding(t *testing.T) {
|
func TestTargetEncoding(t *testing.T) {
|
||||||
tar := NewTarget()
|
tar := NewTarget()
|
||||||
tar.SetRole(RoleSystem)
|
tar.SetRole(RoleSystem)
|
||||||
tar.SetKeys(test.DecodeKey(-1).PublicKey)
|
SetTargetECDSAKeys(tar, &test.DecodeKey(-1).PublicKey)
|
||||||
|
|
||||||
t.Run("binary", func(t *testing.T) {
|
t.Run("binary", func(t *testing.T) {
|
||||||
data, err := tar.Marshal()
|
data, err := tar.Marshal()
|
||||||
|
|
Loading…
Reference in a new issue