diff --git a/agent/acl_endpoint.go b/agent/acl_endpoint.go index 7ad0392f0409..0d1a005e7ff1 100644 --- a/agent/acl_endpoint.go +++ b/agent/acl_endpoint.go @@ -3,6 +3,7 @@ package agent import ( "fmt" "net/http" + "net/url" "strings" "github.com/hashicorp/consul/acl" @@ -142,6 +143,12 @@ func (s *HTTPHandlers) ACLPolicyCRUD(resp http.ResponseWriter, req *http.Request } func (s *HTTPHandlers) ACLPolicyRead(resp http.ResponseWriter, req *http.Request, policyID, policyName string) (interface{}, error) { + // policy name needs to be unescaped in case there were `/` characters + policyName, err := url.QueryUnescape(policyName) + if err != nil { + return nil, err + } + args := structs.ACLPolicyGetRequest{ Datacenter: s.agent.config.Datacenter, PolicyID: policyID, diff --git a/command/acl/acl_helpers.go b/command/acl/acl_helpers.go index c571934edc58..ac1f1c0e99a7 100644 --- a/command/acl/acl_helpers.go +++ b/command/acl/acl_helpers.go @@ -42,9 +42,17 @@ func GetTokenAccessorIDFromPartial(client *api.Client, partialAccessorID string) } func GetPolicyIDFromPartial(client *api.Client, partialID string) (string, error) { - if partialID == "global-management" { - return structs.ACLPolicyGlobalManagementID, nil + // try the builtin policies (by name) first + for _, policy := range structs.ACLBuiltinPolicies { + if partialID == policy.Name { + return policy.ID, nil + } + } + + if policy, ok := structs.ACLBuiltinPolicies[partialID]; ok { + return policy.ID, nil } + // The full UUID string was given if len(partialID) == 36 { return partialID, nil diff --git a/command/acl/acl_test.go b/command/acl/acl_test.go new file mode 100644 index 000000000000..2095795ff00b --- /dev/null +++ b/command/acl/acl_test.go @@ -0,0 +1,83 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package acl + +import ( + "fmt" + "io" + "testing" + + "github.com/hashicorp/consul/agent" + "github.com/hashicorp/consul/agent/structs" + "github.com/hashicorp/consul/testrpc" + "github.com/stretchr/testify/require" +) + +func Test_GetPolicyIDByName_Builtins(t *testing.T) { + t.Parallel() + + a := agent.StartTestAgent(t, + agent.TestAgent{ + LogOutput: io.Discard, + HCL: ` + primary_datacenter = "dc1" + acl { + enabled = true + tokens { + initial_management = "root" + } + } + `, + }, + ) + + defer a.Shutdown() + testrpc.WaitForTestAgent(t, a.RPC, "dc1", testrpc.WithToken("root")) + + client := a.Client() + client.AddHeader("X-Consul-Token", "root") + + for _, policy := range structs.ACLBuiltinPolicies { + name := fmt.Sprintf("%s policy", policy.Name) + t.Run(name, func(t *testing.T) { + id, err := GetPolicyIDByName(client, policy.Name) + require.NoError(t, err) + require.Equal(t, policy.ID, id) + }) + } +} + +func Test_GetPolicyIDFromPartial_Builtins(t *testing.T) { + t.Parallel() + + a := agent.StartTestAgent(t, + agent.TestAgent{ + LogOutput: io.Discard, + HCL: ` + primary_datacenter = "dc1" + acl { + enabled = true + tokens { + initial_management = "root" + } + } + `, + }, + ) + + defer a.Shutdown() + testrpc.WaitForTestAgent(t, a.RPC, "dc1", testrpc.WithToken("root")) + + client := a.Client() + client.AddHeader("X-Consul-Token", "root") + + for _, policy := range structs.ACLBuiltinPolicies { + name := fmt.Sprintf("%s policy", policy.Name) + t.Run(name, func(t *testing.T) { + id, err := GetPolicyIDFromPartial(client, policy.Name) + require.NoError(t, err) + require.Equal(t, policy.ID, id) + }) + } +}