forked from TrueCloudLab/policy-engine
[#33] pkg/chain: Support CondSliceContains condition
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
parent
b82544b0fe
commit
06e9c91014
6 changed files with 91 additions and 0 deletions
1
go.mod
1
go.mod
|
@ -6,6 +6,7 @@ require (
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.18.1-0.20231129062201-a1b61d394958
|
git.frostfs.info/TrueCloudLab/frostfs-contract v0.18.1-0.20231129062201-a1b61d394958
|
||||||
github.com/nspcc-dev/neo-go v0.103.0
|
github.com/nspcc-dev/neo-go v0.103.0
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.8.4
|
||||||
|
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -31,6 +31,8 @@ github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74/go.mod h1
|
||||||
go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
|
go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
|
||||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||||
|
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
|
||||||
|
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
|
|
|
@ -50,6 +50,9 @@ const (
|
||||||
CondArnLike string = "ArnLike"
|
CondArnLike string = "ArnLike"
|
||||||
CondArnNotEquals string = "ArnNotEquals"
|
CondArnNotEquals string = "ArnNotEquals"
|
||||||
CondArnNotLike string = "ArnNotLike"
|
CondArnNotLike string = "ArnNotLike"
|
||||||
|
|
||||||
|
// Custom condition operators.
|
||||||
|
CondSliceContains string = "SliceContains"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -191,6 +194,8 @@ func getConditionTypeAndConverter(op string) (chain.ConditionType, convertFuncti
|
||||||
return chain.CondStringLike, noConvertFunction, nil
|
return chain.CondStringLike, noConvertFunction, nil
|
||||||
case op == CondNotIPAddress:
|
case op == CondNotIPAddress:
|
||||||
return chain.CondStringNotLike, noConvertFunction, nil
|
return chain.CondStringNotLike, noConvertFunction, nil
|
||||||
|
case op == CondSliceContains:
|
||||||
|
return chain.CondSliceContains, noConvertFunction, nil
|
||||||
default:
|
default:
|
||||||
return 0, nil, fmt.Errorf("unsupported condition operator: '%s'", op)
|
return 0, nil, fmt.Errorf("unsupported condition operator: '%s'", op)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/resource"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/resource"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/util"
|
"git.frostfs.info/TrueCloudLab/policy-engine/util"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ID is the ID of rule chain.
|
// ID is the ID of rule chain.
|
||||||
|
@ -103,6 +104,8 @@ const (
|
||||||
CondNumericLessThanEquals
|
CondNumericLessThanEquals
|
||||||
CondNumericGreaterThan
|
CondNumericGreaterThan
|
||||||
CondNumericGreaterThanEquals
|
CondNumericGreaterThanEquals
|
||||||
|
|
||||||
|
CondSliceContains
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c ConditionType) String() string {
|
func (c ConditionType) String() string {
|
||||||
|
@ -139,11 +142,21 @@ func (c ConditionType) String() string {
|
||||||
return "NumericGreaterThan"
|
return "NumericGreaterThan"
|
||||||
case CondNumericGreaterThanEquals:
|
case CondNumericGreaterThanEquals:
|
||||||
return "NumericGreaterThanEquals"
|
return "NumericGreaterThanEquals"
|
||||||
|
case CondSliceContains:
|
||||||
|
return "SliceContains"
|
||||||
default:
|
default:
|
||||||
return "unknown condition type"
|
return "unknown condition type"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const condSliceContainsDelimiter = "\x00"
|
||||||
|
|
||||||
|
// FormCondSliceContainsValue builds value for ObjectResource or ObjectRequest property
|
||||||
|
// that can be matched by CondSliceContains condition.
|
||||||
|
func FormCondSliceContainsValue(values []string) string {
|
||||||
|
return strings.Join(values, condSliceContainsDelimiter)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Condition) Match(req resource.Request) bool {
|
func (c *Condition) Match(req resource.Request) bool {
|
||||||
var val string
|
var val string
|
||||||
switch c.Object {
|
switch c.Object {
|
||||||
|
@ -178,6 +191,8 @@ func (c *Condition) Match(req resource.Request) bool {
|
||||||
return val > c.Value
|
return val > c.Value
|
||||||
case CondStringGreaterThanEquals:
|
case CondStringGreaterThanEquals:
|
||||||
return val >= c.Value
|
return val >= c.Value
|
||||||
|
case CondSliceContains:
|
||||||
|
return slices.Contains(strings.Split(val, condSliceContainsDelimiter), c.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/resource/testutil"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/resource/testutil"
|
||||||
|
"git.frostfs.info/TrueCloudLab/policy-engine/schema/common"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
|
"git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -73,3 +74,65 @@ func TestReturnFirstMatch(t *testing.T) {
|
||||||
require.Equal(t, Allow, st)
|
require.Equal(t, Allow, st)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCondSliceContainsMatch(t *testing.T) {
|
||||||
|
propKey := common.PropertyKeyFrostFSIDGroupID
|
||||||
|
groupID := "1"
|
||||||
|
|
||||||
|
ch := Chain{Rules: []Rule{{
|
||||||
|
Status: Allow,
|
||||||
|
Actions: Actions{Names: []string{native.MethodPutObject}},
|
||||||
|
Resources: Resources{Names: []string{native.ResourceFormatRootContainers}},
|
||||||
|
Condition: []Condition{{
|
||||||
|
Op: CondSliceContains,
|
||||||
|
Object: ObjectRequest,
|
||||||
|
Key: propKey,
|
||||||
|
Value: groupID,
|
||||||
|
}},
|
||||||
|
}}}
|
||||||
|
|
||||||
|
for _, tc := range []struct {
|
||||||
|
name string
|
||||||
|
value string
|
||||||
|
status Status
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "simple value",
|
||||||
|
value: groupID,
|
||||||
|
status: Allow,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "simple value by func",
|
||||||
|
value: FormCondSliceContainsValue([]string{groupID}),
|
||||||
|
status: Allow,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple values by func",
|
||||||
|
value: FormCondSliceContainsValue([]string{groupID, "2", "3"}),
|
||||||
|
status: Allow,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "simple mismatched",
|
||||||
|
value: "3",
|
||||||
|
status: NoRuleFound,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple mismatched",
|
||||||
|
value: FormCondSliceContainsValue([]string{"11", "12"}),
|
||||||
|
status: NoRuleFound,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "comma correct handling mismatched",
|
||||||
|
value: "1,11",
|
||||||
|
status: NoRuleFound,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
resource := testutil.NewResource(native.ResourceFormatRootContainers, nil)
|
||||||
|
request := testutil.NewRequest(native.MethodPutObject, resource, map[string]string{propKey: tc.value})
|
||||||
|
|
||||||
|
st, _ := ch.Match(request)
|
||||||
|
require.Equal(t, tc.status.String(), st.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
5
schema/common/consts.go
Normal file
5
schema/common/consts.go
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
const (
|
||||||
|
PropertyKeyFrostFSIDGroupID = "frostfsid:groupID"
|
||||||
|
)
|
Loading…
Reference in a new issue