2015-01-06 18:40:00 +00:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
2018-10-25 15:09:46 +00:00
|
|
|
"strings"
|
2015-01-06 18:40:00 +00:00
|
|
|
"testing"
|
Add fields to the /acl/auth-methods endpoint. (#9741)
* A GET of the /acl/auth-method/:name endpoint returns the fields
MaxTokenTTL and TokenLocality, while a LIST (/acl/auth-methods) does
not.
The list command returns a filtered subset of the full set. This is
somewhat deliberate, so that secrets aren't shown, but the TTL and
Locality fields aren't (IMO) security critical, and it is useful for
the front end to be able to show them.
For consistency these changes mirror the 'omit empty' and string
representation choices made for the GET call.
This includes changes to the gRPC and API code in the client.
The new output looks similar to this
curl 'http://localhost:8500/v1/acl/auth-methods' | jq '.'
{
"MaxTokenTTL": "8m20s",
"Name": "minikube-ttl-local2",
"Type": "kubernetes",
"Description": "minikube auth method",
"TokenLocality": "local",
"CreateIndex": 530,
"ModifyIndex": 530,
"Namespace": "default"
}
]
Signed-off-by: Mark Anderson <manderson@hashicorp.com>
* Add changelog
Signed-off-by: Mark Anderson <manderson@hashicorp.com>
2021-02-17 16:16:57 +00:00
|
|
|
"time"
|
2018-10-25 15:09:46 +00:00
|
|
|
|
2019-03-27 12:54:56 +00:00
|
|
|
"github.com/hashicorp/consul/sdk/testutil/retry"
|
2018-10-25 15:09:46 +00:00
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
2015-01-06 18:40:00 +00:00
|
|
|
)
|
|
|
|
|
2017-08-03 00:05:18 +00:00
|
|
|
func TestAPI_ACLBootstrap(t *testing.T) {
|
|
|
|
// TODO (slackpad) We currently can't inject the version, and the
|
|
|
|
// version in the binary depends on Git tags, so we can't reliably
|
|
|
|
// test this until we are just running an agent in-process here and
|
|
|
|
// have full control over the config.
|
|
|
|
}
|
|
|
|
|
2017-06-30 21:05:02 +00:00
|
|
|
func TestAPI_ACLCreateDestroy(t *testing.T) {
|
2015-05-08 17:27:24 +00:00
|
|
|
t.Parallel()
|
2015-06-13 21:51:30 +00:00
|
|
|
c, s := makeACLClient(t)
|
2015-03-03 02:18:38 +00:00
|
|
|
defer s.Stop()
|
2018-12-12 20:09:42 +00:00
|
|
|
s.WaitForSerfCheck(t)
|
2015-01-06 23:26:50 +00:00
|
|
|
|
2015-01-06 18:40:00 +00:00
|
|
|
acl := c.ACL()
|
|
|
|
|
|
|
|
ae := ACLEntry{
|
|
|
|
Name: "API test",
|
|
|
|
Type: ACLClientType,
|
|
|
|
Rules: `key "" { policy = "deny" }`,
|
|
|
|
}
|
|
|
|
|
|
|
|
id, wm, err := acl.Create(&ae, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if wm.RequestTime == 0 {
|
|
|
|
t.Fatalf("bad: %v", wm)
|
|
|
|
}
|
|
|
|
|
|
|
|
if id == "" {
|
|
|
|
t.Fatalf("invalid: %v", id)
|
|
|
|
}
|
|
|
|
|
|
|
|
ae2, _, err := acl.Info(id, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if ae2.Name != ae.Name || ae2.Type != ae.Type || ae2.Rules != ae.Rules {
|
|
|
|
t.Fatalf("Bad: %#v", ae2)
|
|
|
|
}
|
|
|
|
|
|
|
|
wm, err = acl.Destroy(id, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if wm.RequestTime == 0 {
|
|
|
|
t.Fatalf("bad: %v", wm)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-30 21:05:02 +00:00
|
|
|
func TestAPI_ACLCloneDestroy(t *testing.T) {
|
2015-05-08 17:27:24 +00:00
|
|
|
t.Parallel()
|
2015-06-13 21:51:30 +00:00
|
|
|
c, s := makeACLClient(t)
|
2015-03-03 02:18:38 +00:00
|
|
|
defer s.Stop()
|
2015-01-06 23:26:50 +00:00
|
|
|
|
2015-01-06 18:40:00 +00:00
|
|
|
acl := c.ACL()
|
|
|
|
|
2015-06-13 21:51:30 +00:00
|
|
|
id, wm, err := acl.Clone(c.config.Token, nil)
|
2015-01-06 18:40:00 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if wm.RequestTime == 0 {
|
|
|
|
t.Fatalf("bad: %v", wm)
|
|
|
|
}
|
|
|
|
|
|
|
|
if id == "" {
|
|
|
|
t.Fatalf("invalid: %v", id)
|
|
|
|
}
|
|
|
|
|
|
|
|
wm, err = acl.Destroy(id, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if wm.RequestTime == 0 {
|
|
|
|
t.Fatalf("bad: %v", wm)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-30 21:05:02 +00:00
|
|
|
func TestAPI_ACLInfo(t *testing.T) {
|
2015-05-08 17:27:24 +00:00
|
|
|
t.Parallel()
|
2015-06-13 21:51:30 +00:00
|
|
|
c, s := makeACLClient(t)
|
2015-03-03 02:18:38 +00:00
|
|
|
defer s.Stop()
|
2015-01-06 23:26:50 +00:00
|
|
|
|
2015-01-06 18:40:00 +00:00
|
|
|
acl := c.ACL()
|
|
|
|
|
2015-06-13 21:51:30 +00:00
|
|
|
ae, qm, err := acl.Info(c.config.Token, nil)
|
2015-01-06 18:40:00 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if qm.LastIndex == 0 {
|
|
|
|
t.Fatalf("bad: %v", qm)
|
|
|
|
}
|
|
|
|
if !qm.KnownLeader {
|
|
|
|
t.Fatalf("bad: %v", qm)
|
|
|
|
}
|
|
|
|
|
2015-06-13 21:51:30 +00:00
|
|
|
if ae == nil || ae.ID != c.config.Token || ae.Type != ACLManagementType {
|
2015-01-06 18:40:00 +00:00
|
|
|
t.Fatalf("bad: %#v", ae)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-30 21:05:02 +00:00
|
|
|
func TestAPI_ACLList(t *testing.T) {
|
2015-05-08 17:27:24 +00:00
|
|
|
t.Parallel()
|
2015-06-13 21:51:30 +00:00
|
|
|
c, s := makeACLClient(t)
|
2015-03-03 02:18:38 +00:00
|
|
|
defer s.Stop()
|
2015-01-06 23:26:50 +00:00
|
|
|
|
2015-01-06 18:40:00 +00:00
|
|
|
acl := c.ACL()
|
|
|
|
|
|
|
|
acls, qm, err := acl.List(nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
2018-10-19 16:04:07 +00:00
|
|
|
// anon token is a new token
|
|
|
|
if len(acls) < 1 {
|
2015-01-06 18:40:00 +00:00
|
|
|
t.Fatalf("bad: %v", acls)
|
|
|
|
}
|
|
|
|
|
|
|
|
if qm.LastIndex == 0 {
|
|
|
|
t.Fatalf("bad: %v", qm)
|
|
|
|
}
|
|
|
|
if !qm.KnownLeader {
|
|
|
|
t.Fatalf("bad: %v", qm)
|
|
|
|
}
|
|
|
|
}
|
2017-04-24 21:39:50 +00:00
|
|
|
|
2017-06-30 21:05:02 +00:00
|
|
|
func TestAPI_ACLReplication(t *testing.T) {
|
2017-04-24 21:39:50 +00:00
|
|
|
t.Parallel()
|
|
|
|
c, s := makeACLClient(t)
|
|
|
|
defer s.Stop()
|
|
|
|
|
|
|
|
acl := c.ACL()
|
|
|
|
|
|
|
|
repl, qm, err := acl.Replication(nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if repl == nil {
|
|
|
|
t.Fatalf("bad: %v", repl)
|
|
|
|
}
|
|
|
|
|
|
|
|
if repl.Running {
|
|
|
|
t.Fatal("bad: repl should not be running")
|
|
|
|
}
|
|
|
|
|
|
|
|
if repl.Enabled {
|
|
|
|
t.Fatal("bad: repl should not be enabled")
|
|
|
|
}
|
|
|
|
|
|
|
|
if qm.RequestTime == 0 {
|
|
|
|
t.Fatalf("bad: %v", qm)
|
|
|
|
}
|
|
|
|
}
|
2018-10-25 15:09:46 +00:00
|
|
|
|
|
|
|
func TestAPI_ACLPolicy_CreateReadDelete(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
c, s := makeACLClient(t)
|
|
|
|
defer s.Stop()
|
|
|
|
|
|
|
|
acl := c.ACL()
|
|
|
|
|
|
|
|
created, wm, err := acl.PolicyCreate(&ACLPolicy{
|
|
|
|
Name: "test-policy",
|
|
|
|
Description: "test-policy description",
|
|
|
|
Rules: `node_prefix "" { policy = "read" }`,
|
|
|
|
Datacenters: []string{"dc1"},
|
|
|
|
}, nil)
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, created)
|
|
|
|
require.NotEqual(t, "", created.ID)
|
|
|
|
require.NotEqual(t, 0, wm.RequestTime)
|
|
|
|
|
|
|
|
read, qm, err := acl.PolicyRead(created.ID, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotEqual(t, 0, qm.LastIndex)
|
|
|
|
require.True(t, qm.KnownLeader)
|
|
|
|
|
|
|
|
require.Equal(t, created, read)
|
|
|
|
|
|
|
|
wm, err = acl.PolicyDelete(created.ID, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotEqual(t, 0, wm.RequestTime)
|
|
|
|
|
|
|
|
read, _, err = acl.PolicyRead(created.ID, nil)
|
|
|
|
require.Nil(t, read)
|
|
|
|
require.Error(t, err)
|
|
|
|
}
|
|
|
|
|
2020-03-25 14:34:24 +00:00
|
|
|
func TestAPI_ACLPolicy_CreateReadByNameDelete(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
c, s := makeACLClient(t)
|
|
|
|
defer s.Stop()
|
|
|
|
|
|
|
|
acl := c.ACL()
|
|
|
|
|
|
|
|
created, wm, err := acl.PolicyCreate(&ACLPolicy{
|
|
|
|
Name: "test-policy",
|
|
|
|
Description: "test-policy description",
|
|
|
|
Rules: `node_prefix "" { policy = "read" }`,
|
|
|
|
Datacenters: []string{"dc1"},
|
|
|
|
}, nil)
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, created)
|
|
|
|
require.NotEqual(t, "", created.ID)
|
|
|
|
require.NotEqual(t, 0, wm.RequestTime)
|
|
|
|
|
|
|
|
read, qm, err := acl.PolicyReadByName(created.Name, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotEqual(t, 0, qm.LastIndex)
|
|
|
|
require.True(t, qm.KnownLeader)
|
|
|
|
|
|
|
|
require.Equal(t, created, read)
|
|
|
|
|
|
|
|
wm, err = acl.PolicyDelete(created.ID, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotEqual(t, 0, wm.RequestTime)
|
|
|
|
|
|
|
|
read, _, err = acl.PolicyRead(created.ID, nil)
|
|
|
|
require.Nil(t, read)
|
|
|
|
require.Error(t, err)
|
|
|
|
}
|
|
|
|
|
2018-10-25 15:09:46 +00:00
|
|
|
func TestAPI_ACLPolicy_CreateUpdate(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
c, s := makeACLClient(t)
|
|
|
|
defer s.Stop()
|
|
|
|
|
|
|
|
acl := c.ACL()
|
|
|
|
|
|
|
|
created, _, err := acl.PolicyCreate(&ACLPolicy{
|
|
|
|
Name: "test-policy",
|
|
|
|
Description: "test-policy description",
|
|
|
|
Rules: `node_prefix "" { policy = "read" }`,
|
|
|
|
Datacenters: []string{"dc1"},
|
|
|
|
}, nil)
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, created)
|
|
|
|
require.NotEqual(t, "", created.ID)
|
|
|
|
|
|
|
|
read, _, err := acl.PolicyRead(created.ID, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, created, read)
|
|
|
|
|
|
|
|
read.Rules += ` service_prefix "" { policy = "read" }`
|
|
|
|
read.Datacenters = nil
|
|
|
|
|
|
|
|
updated, wm, err := acl.PolicyUpdate(read, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, created.ID, updated.ID)
|
|
|
|
require.Equal(t, created.Description, updated.Description)
|
|
|
|
require.Equal(t, read.Rules, updated.Rules)
|
|
|
|
require.Equal(t, created.CreateIndex, updated.CreateIndex)
|
|
|
|
require.NotEqual(t, created.ModifyIndex, updated.ModifyIndex)
|
|
|
|
require.Nil(t, updated.Datacenters)
|
|
|
|
require.NotEqual(t, 0, wm.RequestTime)
|
|
|
|
|
|
|
|
updated_read, _, err := acl.PolicyRead(created.ID, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, updated, updated_read)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAPI_ACLPolicy_List(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
c, s := makeACLClient(t)
|
|
|
|
defer s.Stop()
|
|
|
|
|
|
|
|
acl := c.ACL()
|
|
|
|
|
|
|
|
created1, _, err := acl.PolicyCreate(&ACLPolicy{
|
|
|
|
Name: "policy1",
|
|
|
|
Description: "policy1 description",
|
|
|
|
Rules: `node_prefix "" { policy = "read" }`,
|
|
|
|
Datacenters: []string{"dc1"},
|
|
|
|
}, nil)
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, created1)
|
|
|
|
require.NotEqual(t, "", created1.ID)
|
|
|
|
|
|
|
|
created2, _, err := acl.PolicyCreate(&ACLPolicy{
|
|
|
|
Name: "policy2",
|
|
|
|
Description: "policy2 description",
|
|
|
|
Rules: `service "app" { policy = "write" }`,
|
|
|
|
Datacenters: []string{"dc1", "dc2"},
|
|
|
|
}, nil)
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, created2)
|
|
|
|
require.NotEqual(t, "", created2.ID)
|
|
|
|
|
|
|
|
created3, _, err := acl.PolicyCreate(&ACLPolicy{
|
|
|
|
Name: "policy3",
|
|
|
|
Description: "policy3 description",
|
|
|
|
Rules: `acl = "read"`,
|
|
|
|
}, nil)
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, created3)
|
|
|
|
require.NotEqual(t, "", created3.ID)
|
|
|
|
|
|
|
|
policies, qm, err := acl.PolicyList(nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, policies, 4)
|
|
|
|
require.NotEqual(t, 0, qm.LastIndex)
|
|
|
|
require.True(t, qm.KnownLeader)
|
|
|
|
|
|
|
|
policyMap := make(map[string]*ACLPolicyListEntry)
|
|
|
|
for _, policy := range policies {
|
|
|
|
policyMap[policy.ID] = policy
|
|
|
|
}
|
|
|
|
|
|
|
|
policy1, ok := policyMap[created1.ID]
|
|
|
|
require.True(t, ok)
|
|
|
|
require.NotNil(t, policy1)
|
|
|
|
require.Equal(t, created1.Name, policy1.Name)
|
|
|
|
require.Equal(t, created1.Description, policy1.Description)
|
|
|
|
require.Equal(t, created1.CreateIndex, policy1.CreateIndex)
|
|
|
|
require.Equal(t, created1.ModifyIndex, policy1.ModifyIndex)
|
|
|
|
require.Equal(t, created1.Hash, policy1.Hash)
|
|
|
|
require.ElementsMatch(t, created1.Datacenters, policy1.Datacenters)
|
|
|
|
|
|
|
|
policy2, ok := policyMap[created2.ID]
|
|
|
|
require.True(t, ok)
|
|
|
|
require.NotNil(t, policy2)
|
|
|
|
require.Equal(t, created2.Name, policy2.Name)
|
|
|
|
require.Equal(t, created2.Description, policy2.Description)
|
|
|
|
require.Equal(t, created2.CreateIndex, policy2.CreateIndex)
|
|
|
|
require.Equal(t, created2.ModifyIndex, policy2.ModifyIndex)
|
|
|
|
require.Equal(t, created2.Hash, policy2.Hash)
|
|
|
|
require.ElementsMatch(t, created2.Datacenters, policy2.Datacenters)
|
|
|
|
|
|
|
|
policy3, ok := policyMap[created3.ID]
|
|
|
|
require.True(t, ok)
|
|
|
|
require.NotNil(t, policy3)
|
|
|
|
require.Equal(t, created3.Name, policy3.Name)
|
|
|
|
require.Equal(t, created3.Description, policy3.Description)
|
|
|
|
require.Equal(t, created3.CreateIndex, policy3.CreateIndex)
|
|
|
|
require.Equal(t, created3.ModifyIndex, policy3.ModifyIndex)
|
|
|
|
require.Equal(t, created3.Hash, policy3.Hash)
|
|
|
|
require.ElementsMatch(t, created3.Datacenters, policy3.Datacenters)
|
|
|
|
|
|
|
|
// make sure the 4th policy is the global management
|
|
|
|
policy4, ok := policyMap["00000000-0000-0000-0000-000000000001"]
|
|
|
|
require.True(t, ok)
|
|
|
|
require.NotNil(t, policy4)
|
|
|
|
}
|
|
|
|
|
|
|
|
func prepTokenPolicies(t *testing.T, acl *ACL) (policies []*ACLPolicy) {
|
|
|
|
policy, _, err := acl.PolicyCreate(&ACLPolicy{
|
|
|
|
Name: "one",
|
|
|
|
Description: "one description",
|
|
|
|
Rules: `acl = "read"`,
|
|
|
|
Datacenters: []string{"dc1", "dc2"},
|
|
|
|
}, nil)
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, policy)
|
|
|
|
policies = append(policies, policy)
|
|
|
|
|
|
|
|
policy, _, err = acl.PolicyCreate(&ACLPolicy{
|
|
|
|
Name: "two",
|
|
|
|
Description: "two description",
|
|
|
|
Rules: `node_prefix "" { policy = "read" }`,
|
|
|
|
Datacenters: []string{"dc1", "dc2"},
|
|
|
|
}, nil)
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, policy)
|
|
|
|
policies = append(policies, policy)
|
|
|
|
|
|
|
|
policy, _, err = acl.PolicyCreate(&ACLPolicy{
|
|
|
|
Name: "three",
|
|
|
|
Description: "three description",
|
|
|
|
Rules: `service_prefix "" { policy = "read" }`,
|
|
|
|
}, nil)
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, policy)
|
|
|
|
policies = append(policies, policy)
|
|
|
|
|
|
|
|
policy, _, err = acl.PolicyCreate(&ACLPolicy{
|
|
|
|
Name: "four",
|
|
|
|
Description: "four description",
|
|
|
|
Rules: `agent "foo" { policy = "write" }`,
|
|
|
|
}, nil)
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, policy)
|
|
|
|
policies = append(policies, policy)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAPI_ACLToken_CreateReadDelete(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
c, s := makeACLClient(t)
|
|
|
|
defer s.Stop()
|
|
|
|
|
|
|
|
acl := c.ACL()
|
|
|
|
|
|
|
|
policies := prepTokenPolicies(t, acl)
|
|
|
|
|
|
|
|
created, wm, err := acl.TokenCreate(&ACLToken{
|
|
|
|
Description: "token created",
|
|
|
|
Policies: []*ACLTokenPolicyLink{
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2018-10-25 15:09:46 +00:00
|
|
|
ID: policies[0].ID,
|
|
|
|
},
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2018-10-25 15:09:46 +00:00
|
|
|
ID: policies[1].ID,
|
|
|
|
},
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2018-10-25 15:09:46 +00:00
|
|
|
Name: policies[2].Name,
|
|
|
|
},
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2018-10-25 15:09:46 +00:00
|
|
|
Name: policies[3].Name,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}, nil)
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, created)
|
|
|
|
require.NotEqual(t, "", created.AccessorID)
|
|
|
|
require.NotEqual(t, "", created.SecretID)
|
|
|
|
require.NotEqual(t, 0, wm.RequestTime)
|
|
|
|
|
|
|
|
read, qm, err := acl.TokenRead(created.AccessorID, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, created, read)
|
|
|
|
require.NotEqual(t, 0, qm.LastIndex)
|
|
|
|
require.True(t, qm.KnownLeader)
|
|
|
|
|
|
|
|
acl.c.config.Token = created.SecretID
|
|
|
|
self, _, err := acl.TokenReadSelf(nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, created, self)
|
|
|
|
acl.c.config.Token = "root"
|
|
|
|
|
|
|
|
_, err = acl.TokenDelete(created.AccessorID, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
read, _, err = acl.TokenRead(created.AccessorID, nil)
|
|
|
|
require.Nil(t, read)
|
|
|
|
require.Error(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAPI_ACLToken_CreateUpdate(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
c, s := makeACLClient(t)
|
|
|
|
defer s.Stop()
|
|
|
|
|
|
|
|
acl := c.ACL()
|
|
|
|
|
|
|
|
policies := prepTokenPolicies(t, acl)
|
|
|
|
|
|
|
|
created, _, err := acl.TokenCreate(&ACLToken{
|
|
|
|
Description: "token created",
|
|
|
|
Policies: []*ACLTokenPolicyLink{
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2018-10-25 15:09:46 +00:00
|
|
|
ID: policies[0].ID,
|
|
|
|
},
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2018-10-25 15:09:46 +00:00
|
|
|
Name: policies[2].Name,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}, nil)
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, created)
|
|
|
|
require.NotEqual(t, "", created.AccessorID)
|
|
|
|
require.NotEqual(t, "", created.SecretID)
|
|
|
|
|
|
|
|
read, _, err := acl.TokenRead(created.AccessorID, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, created, read)
|
|
|
|
|
|
|
|
read.Policies = append(read.Policies, &ACLTokenPolicyLink{ID: policies[1].ID})
|
|
|
|
read.Policies = append(read.Policies, &ACLTokenPolicyLink{Name: policies[2].Name})
|
|
|
|
|
|
|
|
expectedPolicies := []*ACLTokenPolicyLink{
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2018-10-25 15:09:46 +00:00
|
|
|
ID: policies[0].ID,
|
|
|
|
Name: policies[0].Name,
|
|
|
|
},
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2018-10-25 15:09:46 +00:00
|
|
|
ID: policies[1].ID,
|
|
|
|
Name: policies[1].Name,
|
|
|
|
},
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2018-10-25 15:09:46 +00:00
|
|
|
ID: policies[2].ID,
|
|
|
|
Name: policies[2].Name,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
updated, wm, err := acl.TokenUpdate(read, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, created.AccessorID, updated.AccessorID)
|
|
|
|
require.Equal(t, created.SecretID, updated.SecretID)
|
|
|
|
require.Equal(t, created.Description, updated.Description)
|
|
|
|
require.Equal(t, created.CreateIndex, updated.CreateIndex)
|
|
|
|
require.NotEqual(t, created.ModifyIndex, updated.ModifyIndex)
|
|
|
|
require.ElementsMatch(t, expectedPolicies, updated.Policies)
|
|
|
|
require.NotEqual(t, 0, wm.RequestTime)
|
|
|
|
|
|
|
|
updated_read, _, err := acl.TokenRead(created.AccessorID, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, updated, updated_read)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAPI_ACLToken_List(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
c, s := makeACLClient(t)
|
|
|
|
defer s.Stop()
|
|
|
|
|
|
|
|
acl := c.ACL()
|
2019-02-22 18:42:09 +00:00
|
|
|
s.WaitForSerfCheck(t)
|
2018-10-25 15:09:46 +00:00
|
|
|
|
|
|
|
policies := prepTokenPolicies(t, acl)
|
|
|
|
|
|
|
|
created1, _, err := acl.TokenCreate(&ACLToken{
|
|
|
|
Description: "token created1",
|
|
|
|
Policies: []*ACLTokenPolicyLink{
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2018-10-25 15:09:46 +00:00
|
|
|
ID: policies[0].ID,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}, nil)
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, created1)
|
|
|
|
require.NotEqual(t, "", created1.AccessorID)
|
|
|
|
require.NotEqual(t, "", created1.SecretID)
|
|
|
|
|
|
|
|
created2, _, err := acl.TokenCreate(&ACLToken{
|
|
|
|
Description: "token created2",
|
|
|
|
Policies: []*ACLTokenPolicyLink{
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2018-10-25 15:09:46 +00:00
|
|
|
ID: policies[1].ID,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}, nil)
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, created2)
|
|
|
|
require.NotEqual(t, "", created2.AccessorID)
|
|
|
|
require.NotEqual(t, "", created2.SecretID)
|
|
|
|
|
|
|
|
created3, _, err := acl.TokenCreate(&ACLToken{
|
|
|
|
Description: "token created3",
|
|
|
|
Policies: []*ACLTokenPolicyLink{
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2018-10-25 15:09:46 +00:00
|
|
|
ID: policies[2].ID,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}, nil)
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, created3)
|
|
|
|
require.NotEqual(t, "", created3.AccessorID)
|
|
|
|
require.NotEqual(t, "", created3.SecretID)
|
|
|
|
|
|
|
|
tokens, qm, err := acl.TokenList(nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
// 3 + anon + master
|
|
|
|
require.Len(t, tokens, 5)
|
|
|
|
require.NotEqual(t, 0, qm.LastIndex)
|
|
|
|
require.True(t, qm.KnownLeader)
|
|
|
|
|
|
|
|
tokenMap := make(map[string]*ACLTokenListEntry)
|
|
|
|
for _, token := range tokens {
|
|
|
|
tokenMap[token.AccessorID] = token
|
|
|
|
}
|
|
|
|
|
|
|
|
token1, ok := tokenMap[created1.AccessorID]
|
|
|
|
require.True(t, ok)
|
|
|
|
require.NotNil(t, token1)
|
2021-07-08 22:13:08 +00:00
|
|
|
require.Equal(t, created1.SecretID, token1.SecretID)
|
2018-10-25 15:09:46 +00:00
|
|
|
require.Equal(t, created1.Description, token1.Description)
|
|
|
|
require.Equal(t, created1.CreateIndex, token1.CreateIndex)
|
|
|
|
require.Equal(t, created1.ModifyIndex, token1.ModifyIndex)
|
|
|
|
require.Equal(t, created1.Hash, token1.Hash)
|
|
|
|
require.ElementsMatch(t, created1.Policies, token1.Policies)
|
|
|
|
|
|
|
|
token2, ok := tokenMap[created2.AccessorID]
|
|
|
|
require.True(t, ok)
|
|
|
|
require.NotNil(t, token2)
|
2021-07-08 22:13:08 +00:00
|
|
|
require.Equal(t, created2.SecretID, token2.SecretID)
|
2018-10-25 15:09:46 +00:00
|
|
|
require.Equal(t, created2.Description, token2.Description)
|
|
|
|
require.Equal(t, created2.CreateIndex, token2.CreateIndex)
|
|
|
|
require.Equal(t, created2.ModifyIndex, token2.ModifyIndex)
|
|
|
|
require.Equal(t, created2.Hash, token2.Hash)
|
|
|
|
require.ElementsMatch(t, created2.Policies, token2.Policies)
|
|
|
|
|
|
|
|
token3, ok := tokenMap[created3.AccessorID]
|
|
|
|
require.True(t, ok)
|
|
|
|
require.NotNil(t, token3)
|
2021-07-08 22:13:08 +00:00
|
|
|
require.Equal(t, created3.SecretID, token3.SecretID)
|
2018-10-25 15:09:46 +00:00
|
|
|
require.Equal(t, created3.Description, token3.Description)
|
|
|
|
require.Equal(t, created3.CreateIndex, token3.CreateIndex)
|
|
|
|
require.Equal(t, created3.ModifyIndex, token3.ModifyIndex)
|
|
|
|
require.Equal(t, created3.Hash, token3.Hash)
|
|
|
|
require.ElementsMatch(t, created3.Policies, token3.Policies)
|
|
|
|
|
|
|
|
// make sure the there is an anon token
|
|
|
|
token4, ok := tokenMap["00000000-0000-0000-0000-000000000002"]
|
|
|
|
require.True(t, ok)
|
|
|
|
require.NotNil(t, token4)
|
|
|
|
|
|
|
|
// ensure the 5th token is the root master token
|
|
|
|
root, _, err := acl.TokenReadSelf(nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, root)
|
|
|
|
token5, ok := tokenMap[root.AccessorID]
|
|
|
|
require.True(t, ok)
|
|
|
|
require.NotNil(t, token5)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAPI_ACLToken_Clone(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
c, s := makeACLClient(t)
|
|
|
|
defer s.Stop()
|
|
|
|
|
|
|
|
acl := c.ACL()
|
|
|
|
|
|
|
|
master, _, err := acl.TokenReadSelf(nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, master)
|
|
|
|
|
|
|
|
cloned, _, err := acl.TokenClone(master.AccessorID, "cloned", nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, cloned)
|
|
|
|
require.NotEqual(t, master.AccessorID, cloned.AccessorID)
|
|
|
|
require.NotEqual(t, master.SecretID, cloned.SecretID)
|
|
|
|
require.Equal(t, "cloned", cloned.Description)
|
|
|
|
require.ElementsMatch(t, master.Policies, cloned.Policies)
|
|
|
|
|
|
|
|
read, _, err := acl.TokenRead(cloned.AccessorID, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, read)
|
|
|
|
require.Equal(t, cloned, read)
|
|
|
|
}
|
|
|
|
|
Add fields to the /acl/auth-methods endpoint. (#9741)
* A GET of the /acl/auth-method/:name endpoint returns the fields
MaxTokenTTL and TokenLocality, while a LIST (/acl/auth-methods) does
not.
The list command returns a filtered subset of the full set. This is
somewhat deliberate, so that secrets aren't shown, but the TTL and
Locality fields aren't (IMO) security critical, and it is useful for
the front end to be able to show them.
For consistency these changes mirror the 'omit empty' and string
representation choices made for the GET call.
This includes changes to the gRPC and API code in the client.
The new output looks similar to this
curl 'http://localhost:8500/v1/acl/auth-methods' | jq '.'
{
"MaxTokenTTL": "8m20s",
"Name": "minikube-ttl-local2",
"Type": "kubernetes",
"Description": "minikube auth method",
"TokenLocality": "local",
"CreateIndex": 530,
"ModifyIndex": 530,
"Namespace": "default"
}
]
Signed-off-by: Mark Anderson <manderson@hashicorp.com>
* Add changelog
Signed-off-by: Mark Anderson <manderson@hashicorp.com>
2021-02-17 16:16:57 +00:00
|
|
|
//
|
|
|
|
func TestAPI_AuthMethod_List(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
c, s := makeACLClient(t)
|
|
|
|
defer s.Stop()
|
|
|
|
|
|
|
|
acl := c.ACL()
|
|
|
|
s.WaitForSerfCheck(t)
|
|
|
|
|
|
|
|
method1 := ACLAuthMethod{
|
|
|
|
Name: "test_1",
|
|
|
|
Type: "kubernetes",
|
|
|
|
Description: "test 1",
|
|
|
|
MaxTokenTTL: 260 * time.Second,
|
|
|
|
TokenLocality: "global",
|
|
|
|
Config: AuthMethodCreateKubernetesConfigHelper(),
|
|
|
|
}
|
|
|
|
|
|
|
|
created1, wm, err := acl.AuthMethodCreate(&method1, nil)
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, created1)
|
|
|
|
require.NotEqual(t, "", created1.Name)
|
|
|
|
require.NotEqual(t, 0, wm.RequestTime)
|
|
|
|
|
|
|
|
method2 := ACLAuthMethod{
|
|
|
|
Name: "test_2",
|
|
|
|
Type: "kubernetes",
|
|
|
|
Description: "test 2",
|
|
|
|
MaxTokenTTL: 0,
|
|
|
|
TokenLocality: "local",
|
|
|
|
Config: AuthMethodCreateKubernetesConfigHelper(),
|
|
|
|
}
|
|
|
|
|
|
|
|
_, _, err = acl.AuthMethodCreate(&method2, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
entries, _, err := acl.AuthMethodList(nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, entries)
|
|
|
|
require.Equal(t, 2, len(entries))
|
|
|
|
|
|
|
|
{
|
|
|
|
entry := entries[0]
|
|
|
|
require.Equal(t, "test_1", entry.Name)
|
|
|
|
require.Equal(t, 260*time.Second, entry.MaxTokenTTL)
|
|
|
|
require.Equal(t, "global", entry.TokenLocality)
|
|
|
|
}
|
|
|
|
{
|
|
|
|
entry := entries[1]
|
|
|
|
require.Equal(t, "test_2", entry.Name)
|
|
|
|
require.Equal(t, time.Duration(0), entry.MaxTokenTTL)
|
|
|
|
require.Equal(t, "local", entry.TokenLocality)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func AuthMethodCreateKubernetesConfigHelper() (result map[string]interface{}) {
|
|
|
|
var pemData = `
|
|
|
|
-----BEGIN CERTIFICATE-----
|
|
|
|
MIIE1DCCArwCCQC2kx7TchbxAzANBgkqhkiG9w0BAQsFADAsMQswCQYDVQQGEwJV
|
|
|
|
UzELMAkGA1UECAwCV0ExEDAOBgNVBAcMB1NlYXR0bGUwHhcNMjEwMTI3MDIzNDA1
|
|
|
|
WhcNMjIwMTI3MDIzNDA1WjAsMQswCQYDVQQGEwJVUzELMAkGA1UECAwCV0ExEDAO
|
|
|
|
BgNVBAcMB1NlYXR0bGUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCt
|
|
|
|
j3zRFLg2A2DcZFwoc1HvIsGzqcfvxjee/OQjKyIuXbdpbJGIahB2piNYtd49zU/5
|
|
|
|
ofRAuqIQOco3V9LfL52I7NchNBvPQOrXjbpcM3qF2qQvunVlnnaPCIf8S5hsFMaq
|
|
|
|
w2/+jnLjaUdXGJ9bold5E/bms87uRahvhUpY7MhkSDNsAen+YThpwucc9JFRmrz3
|
|
|
|
EXGtTzcpyEn9b0s6ut9mum2UVqghAQyLeW8cNx1zeg6Bi5USjOKF6CQgF7o4kZ9X
|
|
|
|
D0Nk5vB9eePs/q5N9LHkDFKVCmzAYgzcQeGZFEzNcgK7N5y+aB2xXKpH3tydpwRd
|
|
|
|
uS+g05Jvk8M8P34wteUb8tq3jZuY7UYzlINMSrPuZdFhcGjmxPjC5hl1SZy4vF1s
|
|
|
|
GAD9RsleTZ8yeC6Cfo4mba214C9CqYkC2NBw2HO53pzO/tYI844QPhjmVBJ7bb35
|
|
|
|
S052HD7m+AzbfY6w9CDH4D4mzIM4u1yRB6OlXdXTH58BhgxHdEnugLYr13QlVWRW
|
|
|
|
4nZgMFKiTY7cBscpPcVRsne/VR9VwSatp3adj+G8+WUtwQLJC2OcCFYvmHfdSOs0
|
|
|
|
B15LH/tGeJcfKViKC9ifPq5abVZByr66jTQMAdBWet03OBnmLqJs9TI4wci0MkK/
|
|
|
|
HlHYdy734rReD81LY9fCRCRFV4ZtMx2rfj7cqgKLlwIDAQABMA0GCSqGSIb3DQEB
|
|
|
|
CwUAA4ICAQB6ji6wA9ROFx8ZhLPlEnDiielSUN8LR2K8cmAjxxffJo3GxRH/zZYl
|
|
|
|
CM+DzU5VVzW6RGWuTNzcFNsxlaRx20sj5RyXLH90wFYLO2Rrs1XKWmqpfdN0Iiue
|
|
|
|
W7rYdNPV7YPjIVQVoijEt8kwx24jE9mU5ILXe4+WKPWavG+dHA1r8lQdg7wmE/8R
|
|
|
|
E/nSVtusuX0JRVdL96iy2HB37DYj+rJEE0C7fKAk51o0C4F6fOzUsWCaP/23pZNI
|
|
|
|
rA6hCq2CJeT4ObVukCIrnylrckZs8ElcZ7PvJ9bCNvma+dAxbL0uEkv0q0feLeVh
|
|
|
|
OTttNIVTUjYjr3KE6rtE1Rr35R/6HCK+zZDOkKf+TVEQsFuI4DRVEuntzjo9bgZf
|
|
|
|
fAL6G+UXpzW440BJzmzADnSthawMZFdqVrrBzpzb+B2d9VLDEoyCCFzaJyj/Gyff
|
|
|
|
kqxRFTHZJRKC/3iIRXOX64bIr1YmXHFHCBkcq7eyh1oeaTrGZ43HimaveWwcsPv/
|
|
|
|
SxTJANJHqf4BiFtVjN7LZXi3HUIRAsceEbd0TfW5be9SQ0tbDyyGYt/bXtBLGTIh
|
|
|
|
9kerr9eWDHlpHMTyP01+Ua3EacbfgrmvD9sa3s6gC4SnwlvLdubmyLwoorCs77eF
|
|
|
|
15bSOU7NsVZfwLw+M+DyNWPxI1BR/XOP+YoyTgIEChIC9eYnmlWU2Q==
|
|
|
|
-----END CERTIFICATE-----`
|
|
|
|
|
|
|
|
result = map[string]interface{}{
|
|
|
|
"Host": "https://192.0.2.42:8443",
|
|
|
|
"CACert": pemData,
|
|
|
|
"ServiceAccountJWT": `eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImp0aSI6ImQxYTZiYzE5LWZiODItNDI5ZC05NmUxLTg1YTFjYjEyNGQ3MCIsImlhdCI6MTYxMTcxNTQ5NiwiZXhwIjoxNjExNzE5MDk2fQ.rrVS5h1Yw20eI41RsTl2YAqzKKikKNg3qMkDmspTPQs`,
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-10-25 15:09:46 +00:00
|
|
|
func TestAPI_RulesTranslate_FromToken(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
c, s := makeACLClient(t)
|
|
|
|
defer s.Stop()
|
|
|
|
|
|
|
|
acl := c.ACL()
|
|
|
|
|
|
|
|
ae := ACLEntry{
|
|
|
|
Name: "API test",
|
|
|
|
Type: ACLClientType,
|
|
|
|
Rules: `key "" { policy = "deny" }`,
|
|
|
|
}
|
|
|
|
|
|
|
|
id, _, err := acl.Create(&ae, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
var accessor string
|
|
|
|
acl.c.config.Token = id
|
|
|
|
|
|
|
|
// This relies on the token upgrade loop running in the background
|
|
|
|
// to assign an accessor
|
2019-07-16 20:47:45 +00:00
|
|
|
retry.Run(t, func(r *retry.R) {
|
2018-10-25 15:09:46 +00:00
|
|
|
token, _, err := acl.TokenReadSelf(nil)
|
2019-07-16 20:47:45 +00:00
|
|
|
require.NoError(r, err)
|
|
|
|
require.NotEqual(r, "", token.AccessorID)
|
2018-10-25 15:09:46 +00:00
|
|
|
accessor = token.AccessorID
|
|
|
|
})
|
|
|
|
acl.c.config.Token = "root"
|
|
|
|
|
|
|
|
rules, err := acl.RulesTranslateToken(accessor)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, "key_prefix \"\" {\n policy = \"deny\"\n}", rules)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAPI_RulesTranslate_Raw(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
c, s := makeACLClient(t)
|
|
|
|
defer s.Stop()
|
|
|
|
|
|
|
|
acl := c.ACL()
|
|
|
|
|
|
|
|
input := `#start of policy
|
|
|
|
agent "" {
|
|
|
|
policy = "read"
|
|
|
|
}
|
|
|
|
|
|
|
|
node "" {
|
|
|
|
policy = "read"
|
|
|
|
}
|
|
|
|
|
|
|
|
service "" {
|
|
|
|
policy = "read"
|
|
|
|
}
|
|
|
|
|
|
|
|
key "" {
|
|
|
|
policy = "read"
|
|
|
|
}
|
|
|
|
|
|
|
|
session "" {
|
|
|
|
policy = "read"
|
|
|
|
}
|
|
|
|
|
|
|
|
event "" {
|
|
|
|
policy = "read"
|
|
|
|
}
|
|
|
|
|
|
|
|
query "" {
|
|
|
|
policy = "read"
|
|
|
|
}`
|
|
|
|
|
|
|
|
expected := `#start of policy
|
|
|
|
agent_prefix "" {
|
|
|
|
policy = "read"
|
|
|
|
}
|
|
|
|
|
|
|
|
node_prefix "" {
|
|
|
|
policy = "read"
|
|
|
|
}
|
|
|
|
|
|
|
|
service_prefix "" {
|
|
|
|
policy = "read"
|
|
|
|
}
|
|
|
|
|
|
|
|
key_prefix "" {
|
|
|
|
policy = "read"
|
|
|
|
}
|
|
|
|
|
|
|
|
session_prefix "" {
|
|
|
|
policy = "read"
|
|
|
|
}
|
|
|
|
|
|
|
|
event_prefix "" {
|
|
|
|
policy = "read"
|
|
|
|
}
|
|
|
|
|
|
|
|
query_prefix "" {
|
|
|
|
policy = "read"
|
|
|
|
}`
|
|
|
|
|
|
|
|
rules, err := acl.RulesTranslate(strings.NewReader(input))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, expected, rules)
|
|
|
|
}
|