// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package acl
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
)
func TestACL_Enforce ( t * testing . T ) {
type testCase struct {
method string
resource Resource
segment string
access string
ret EnforcementDecision
err string
}
testName := func ( t testCase ) string {
if t . segment != "" {
return fmt . Sprintf ( "%s/%s/%s/%s" , t . resource , t . segment , t . access , t . ret . String ( ) )
}
return fmt . Sprintf ( "%s/%s/%s" , t . resource , t . access , t . ret . String ( ) )
}
cases := [ ] testCase {
{
method : "ACLRead" ,
resource : ResourceACL ,
access : "read" ,
ret : Deny ,
} ,
{
method : "ACLRead" ,
resource : ResourceACL ,
access : "read" ,
ret : Allow ,
} ,
{
method : "ACLWrite" ,
resource : ResourceACL ,
access : "write" ,
ret : Deny ,
} ,
{
method : "ACLWrite" ,
resource : ResourceACL ,
access : "write" ,
ret : Allow ,
} ,
{
resource : ResourceACL ,
access : "list" ,
ret : Deny ,
err : "Invalid access level" ,
} ,
{
method : "OperatorRead" ,
resource : ResourceOperator ,
access : "read" ,
ret : Deny ,
} ,
{
method : "OperatorRead" ,
resource : ResourceOperator ,
access : "read" ,
ret : Allow ,
} ,
{
method : "OperatorWrite" ,
resource : ResourceOperator ,
access : "write" ,
ret : Deny ,
} ,
{
method : "OperatorWrite" ,
resource : ResourceOperator ,
access : "write" ,
ret : Allow ,
} ,
{
resource : ResourceOperator ,
access : "list" ,
ret : Deny ,
err : "Invalid access level" ,
} ,
{
method : "KeyringRead" ,
resource : ResourceKeyring ,
access : "read" ,
ret : Deny ,
} ,
{
method : "KeyringRead" ,
resource : ResourceKeyring ,
access : "read" ,
ret : Allow ,
} ,
{
method : "KeyringWrite" ,
resource : ResourceKeyring ,
access : "write" ,
ret : Deny ,
} ,
{
method : "KeyringWrite" ,
resource : ResourceKeyring ,
access : "write" ,
ret : Allow ,
} ,
{
resource : ResourceKeyring ,
access : "list" ,
ret : Deny ,
err : "Invalid access level" ,
} ,
{
method : "AgentRead" ,
resource : ResourceAgent ,
segment : "foo" ,
access : "read" ,
ret : Deny ,
} ,
{
method : "AgentRead" ,
resource : ResourceAgent ,
segment : "foo" ,
access : "read" ,
ret : Allow ,
} ,
{
method : "AgentWrite" ,
resource : ResourceAgent ,
segment : "foo" ,
access : "write" ,
ret : Deny ,
} ,
{
method : "AgentWrite" ,
resource : ResourceAgent ,
segment : "foo" ,
access : "write" ,
ret : Allow ,
} ,
{
resource : ResourceAgent ,
segment : "foo" ,
access : "list" ,
ret : Deny ,
err : "Invalid access level" ,
} ,
{
method : "EventRead" ,
resource : ResourceEvent ,
segment : "foo" ,
access : "read" ,
ret : Deny ,
} ,
{
method : "EventRead" ,
resource : ResourceEvent ,
segment : "foo" ,
access : "read" ,
ret : Allow ,
} ,
{
method : "EventWrite" ,
resource : ResourceEvent ,
segment : "foo" ,
access : "write" ,
ret : Deny ,
} ,
{
method : "EventWrite" ,
resource : ResourceEvent ,
segment : "foo" ,
access : "write" ,
ret : Allow ,
} ,
{
resource : ResourceEvent ,
segment : "foo" ,
access : "list" ,
ret : Deny ,
err : "Invalid access level" ,
} ,
{
method : "IdentityRead" ,
resource : ResourceIdentity ,
segment : "foo" ,
access : "read" ,
ret : Deny ,
} ,
{
method : "IdentityRead" ,
resource : ResourceIdentity ,
segment : "foo" ,
access : "read" ,
ret : Allow ,
} ,
{
method : "IdentityWrite" ,
resource : ResourceIdentity ,
segment : "foo" ,
access : "write" ,
ret : Deny ,
} ,
{
method : "IdentityWrite" ,
resource : ResourceIdentity ,
segment : "foo" ,
access : "write" ,
ret : Allow ,
} ,
{
method : "IntentionRead" ,
resource : ResourceIntention ,
segment : "foo" ,
access : "read" ,
ret : Deny ,
} ,
{
method : "IntentionRead" ,
resource : ResourceIntention ,
segment : "foo" ,
access : "read" ,
ret : Allow ,
} ,
{
method : "IntentionWrite" ,
resource : ResourceIntention ,
segment : "foo" ,
access : "write" ,
ret : Deny ,
} ,
{
method : "IntentionWrite" ,
resource : ResourceIntention ,
segment : "foo" ,
access : "write" ,
ret : Allow ,
} ,
{
resource : ResourceIntention ,
segment : "foo" ,
access : "list" ,
ret : Deny ,
err : "Invalid access level" ,
} ,
{
method : "NodeRead" ,
resource : ResourceNode ,
segment : "foo" ,
access : "read" ,
ret : Deny ,
} ,
{
method : "NodeRead" ,
resource : ResourceNode ,
segment : "foo" ,
access : "read" ,
ret : Allow ,
} ,
{
method : "NodeWrite" ,
resource : ResourceNode ,
segment : "foo" ,
access : "write" ,
ret : Deny ,
} ,
{
method : "NodeWrite" ,
resource : ResourceNode ,
segment : "foo" ,
access : "write" ,
ret : Allow ,
} ,
{
resource : ResourceNode ,
segment : "foo" ,
access : "list" ,
ret : Deny ,
err : "Invalid access level" ,
} ,
{
method : "PeeringRead" ,
resource : ResourcePeering ,
access : "read" ,
ret : Allow ,
} ,
{
method : "PeeringRead" ,
resource : ResourcePeering ,
access : "read" ,
ret : Deny ,
} ,
{
method : "PeeringWrite" ,
resource : ResourcePeering ,
access : "write" ,
ret : Allow ,
} ,
{
method : "PeeringWrite" ,
resource : ResourcePeering ,
access : "write" ,
ret : Deny ,
} ,
{
method : "PreparedQueryRead" ,
resource : ResourceQuery ,
segment : "foo" ,
access : "read" ,
ret : Deny ,
} ,
{
method : "PreparedQueryRead" ,
resource : ResourceQuery ,
segment : "foo" ,
access : "read" ,
ret : Allow ,
} ,
{
method : "PreparedQueryWrite" ,
resource : ResourceQuery ,
segment : "foo" ,
access : "write" ,
ret : Deny ,
} ,
{
method : "PreparedQueryWrite" ,
resource : ResourceQuery ,
segment : "foo" ,
access : "write" ,
ret : Allow ,
} ,
{
resource : ResourceQuery ,
segment : "foo" ,
access : "list" ,
ret : Deny ,
err : "Invalid access level" ,
} ,
{
method : "ServiceRead" ,
resource : ResourceService ,
segment : "foo" ,
access : "read" ,
ret : Deny ,
} ,
{
method : "ServiceRead" ,
resource : ResourceService ,
segment : "foo" ,
access : "read" ,
ret : Allow ,
} ,
{
method : "ServiceWrite" ,
resource : ResourceService ,
segment : "foo" ,
access : "write" ,
ret : Deny ,
} ,
{
method : "ServiceWrite" ,
resource : ResourceService ,
segment : "foo" ,
access : "write" ,
ret : Allow ,
} ,
{
resource : ResourceSession ,
segment : "foo" ,
access : "list" ,
ret : Deny ,
err : "Invalid access level" ,
} ,
{
method : "SessionRead" ,
resource : ResourceSession ,
segment : "foo" ,
access : "read" ,
ret : Deny ,
} ,
{
method : "SessionRead" ,
resource : ResourceSession ,
segment : "foo" ,
access : "read" ,
ret : Allow ,
} ,
{
method : "SessionWrite" ,
resource : ResourceSession ,
segment : "foo" ,
access : "write" ,
ret : Deny ,
} ,
{
method : "SessionWrite" ,
resource : ResourceSession ,
segment : "foo" ,
access : "write" ,
ret : Allow ,
} ,
{
resource : ResourceSession ,
segment : "foo" ,
access : "list" ,
ret : Deny ,
err : "Invalid access level" ,
} ,
{
method : "KeyRead" ,
resource : ResourceKey ,
segment : "foo" ,
access : "read" ,
ret : Deny ,
} ,
{
method : "KeyRead" ,
resource : ResourceKey ,
segment : "foo" ,
access : "read" ,
ret : Allow ,
} ,
{
method : "KeyWrite" ,
resource : ResourceKey ,
segment : "foo" ,
access : "write" ,
ret : Deny ,
} ,
{
method : "KeyWrite" ,
resource : ResourceKey ,
segment : "foo" ,
access : "write" ,
ret : Allow ,
} ,
{
method : "KeyList" ,
resource : ResourceKey ,
segment : "foo" ,
access : "list" ,
ret : Deny ,
} ,
{
method : "KeyList" ,
resource : ResourceKey ,
segment : "foo" ,
access : "list" ,
ret : Allow ,
} ,
{
resource : ResourceKey ,
segment : "foo" ,
access : "deny" ,
ret : Deny ,
err : "Invalid access level" ,
} ,
{
resource : "not-a-real-resource" ,
access : "read" ,
ret : Deny ,
err : "Invalid ACL resource requested:" ,
} ,
}
for _ , tcase := range cases {
t . Run ( testName ( tcase ) , func ( t * testing . T ) {
m := & MockAuthorizer { }
if tcase . err == "" {
var nilCtx * AuthorizerContext
if tcase . segment != "" {
m . On ( tcase . method , tcase . segment , nilCtx ) . Return ( tcase . ret )
} else {
m . On ( tcase . method , nilCtx ) . Return ( tcase . ret )
}
}
ret , err := Enforce ( m , tcase . resource , tcase . segment , tcase . access , nil )
if tcase . err == "" {
require . NoError ( t , err )
} else {
require . Error ( t , err )
require . Contains ( t , err . Error ( ) , tcase . err )
}
require . Equal ( t , tcase . ret , ret )
m . AssertExpectations ( t )
} )
}
}