219a3c5bd3
* add leadership transfer command * add RPC call test (flaky) * add missing import * add changelog * add command registration * Apply suggestions from code review Co-authored-by: Matt Keeler <mkeeler@users.noreply.github.com> * add the possibility of providing an id to raft leadership transfer. Add few tests. * delete old file from cherry pick * rename changelog filename to PR # * rename changelog and fix import * fix failing test * check for OperatorWrite Co-authored-by: Matt Keeler <mkeeler@users.noreply.github.com> * rename from leader-transfer to transfer-leader * remove version check and add test for operator read * move struct to operator.go * first pass * add code for leader transfer in the grpc backend and tests * wire the http endpoint to the new grpc endpoint * remove the RPC endpoint * remove non needed struct * fix naming * add mog glue to API * fix comment * remove dead code * fix linter error * change package name for proto file * remove error wrapping * fix failing test * add command registration * add grpc service mock tests * fix receiver to be pointer * use defined values Co-authored-by: Matt Keeler <mkeeler@users.noreply.github.com> * reuse MockAclAuthorizer * add documentation * remove usage of external.TokenFromContext * fix failing tests * fix proto generation * Apply suggestions from code review Co-authored-by: Jared Kirschner <85913323+jkirschner-hashicorp@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Jared Kirschner <85913323+jkirschner-hashicorp@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Jared Kirschner <85913323+jkirschner-hashicorp@users.noreply.github.com> * Apply suggestions from code review * add more context in doc for the reason * Apply suggestions from docs code review Co-authored-by: Jeff Boruszak <104028618+boruszak@users.noreply.github.com> * regenerate proto * fix linter errors Co-authored-by: github-team-consul-core <github-team-consul-core@hashicorp.com> Co-authored-by: Matt Keeler <mkeeler@users.noreply.github.com> Co-authored-by: Jared Kirschner <85913323+jkirschner-hashicorp@users.noreply.github.com> Co-authored-by: Jeff Boruszak <104028618+boruszak@users.noreply.github.com>
469 lines
8.5 KiB
Go
469 lines
8.5 KiB
Go
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: "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)
|
|
})
|
|
}
|
|
}
|