forked from TrueCloudLab/policy-engine
[#21] chain: Allow to return first match result
Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
This commit is contained in:
parent
1375e8f7fd
commit
8c673ee4f4
3 changed files with 84 additions and 0 deletions
|
@ -478,6 +478,7 @@ func TestProcessDenyFirst(t *testing.T) {
|
|||
|
||||
identityNativePolicy, err := ConvertToNativeChain(identityPolicy, mockResolver)
|
||||
require.NoError(t, err)
|
||||
identityNativePolicy.MatchType = chain.MatchTypeFirstMatch
|
||||
|
||||
resourceNativePolicy, err := ConvertToNativeChain(resourcePolicy, mockResolver)
|
||||
require.NoError(t, err)
|
||||
|
|
|
@ -12,10 +12,22 @@ import (
|
|||
// ID is the ID of rule chain.
|
||||
type ID string
|
||||
|
||||
// MatchType is the match type for chain rules.
|
||||
type MatchType uint8
|
||||
|
||||
const (
|
||||
// MatchTypeDenyPriority rejects the request if any `Deny` is specified.
|
||||
MatchTypeDenyPriority MatchType = 0
|
||||
// MatchTypeFirstMatch returns the first rule action matched to the request.
|
||||
MatchTypeFirstMatch MatchType = 1
|
||||
)
|
||||
|
||||
type Chain struct {
|
||||
ID ID
|
||||
|
||||
Rules []Rule
|
||||
|
||||
MatchType MatchType
|
||||
}
|
||||
|
||||
func (c *Chain) Bytes() []byte {
|
||||
|
@ -214,6 +226,17 @@ func (r *Rule) matchAll(obj resource.Request) (status Status, matched bool) {
|
|||
}
|
||||
|
||||
func (c *Chain) Match(req resource.Request) (status Status, matched bool) {
|
||||
switch c.MatchType {
|
||||
case MatchTypeDenyPriority:
|
||||
return c.denyPriority(req)
|
||||
case MatchTypeFirstMatch:
|
||||
return c.firstMatch(req)
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown MatchType %d", c.MatchType))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Chain) firstMatch(req resource.Request) (status Status, matched bool) {
|
||||
for i := range c.Rules {
|
||||
status, matched := c.Rules[i].Match(req)
|
||||
if matched {
|
||||
|
@ -222,3 +245,21 @@ func (c *Chain) Match(req resource.Request) (status Status, matched bool) {
|
|||
}
|
||||
return NoRuleFound, false
|
||||
}
|
||||
|
||||
func (c *Chain) denyPriority(req resource.Request) (status Status, matched bool) {
|
||||
var allowFound bool
|
||||
for i := range c.Rules {
|
||||
status, matched := c.Rules[i].Match(req)
|
||||
if !matched {
|
||||
continue
|
||||
}
|
||||
if status != Allow {
|
||||
return status, true
|
||||
}
|
||||
allowFound = true
|
||||
}
|
||||
if allowFound {
|
||||
return Allow, true
|
||||
}
|
||||
return NoRuleFound, false
|
||||
}
|
||||
|
|
|
@ -3,11 +3,14 @@ package chain
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/resource/testutil"
|
||||
"git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestEncodeDecode(t *testing.T) {
|
||||
expected := Chain{
|
||||
MatchType: MatchTypeFirstMatch,
|
||||
Rules: []Rule{
|
||||
{
|
||||
Status: Allow,
|
||||
|
@ -31,3 +34,42 @@ func TestEncodeDecode(t *testing.T) {
|
|||
require.NoError(t, actual.DecodeBytes(data))
|
||||
require.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestReturnFirstMatch(t *testing.T) {
|
||||
ch := Chain{
|
||||
Rules: []Rule{
|
||||
{
|
||||
Status: Allow,
|
||||
Actions: Actions{Names: []string{
|
||||
native.MethodPutObject,
|
||||
}},
|
||||
Resources: Resources{Names: []string{native.ResourceFormatRootContainers}},
|
||||
Condition: []Condition{},
|
||||
},
|
||||
{
|
||||
Status: AccessDenied,
|
||||
Actions: Actions{Names: []string{
|
||||
native.MethodPutObject,
|
||||
}},
|
||||
Resources: Resources{Names: []string{native.ResourceFormatRootContainers}},
|
||||
Condition: []Condition{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resource := testutil.NewResource(native.ResourceFormatRootContainers, nil)
|
||||
request := testutil.NewRequest(native.MethodPutObject, resource, nil)
|
||||
|
||||
t.Run("default match", func(t *testing.T) {
|
||||
st, found := ch.Match(request)
|
||||
require.True(t, found)
|
||||
require.Equal(t, AccessDenied, st)
|
||||
})
|
||||
|
||||
t.Run("return first match", func(t *testing.T) {
|
||||
ch.MatchType = MatchTypeFirstMatch
|
||||
st, found := ch.Match(request)
|
||||
require.True(t, found)
|
||||
require.Equal(t, Allow, st)
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue