diff --git a/agent/acl_endpoint.go b/agent/acl_endpoint.go index d6f230a8f64e..60aa13a1490c 100644 --- a/agent/acl_endpoint.go +++ b/agent/acl_endpoint.go @@ -6,6 +6,7 @@ package agent import ( "fmt" "net/http" + "net/url" "strings" "github.com/hashicorp/consul/acl" @@ -145,6 +146,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 0a6545be1af9..b0e65d224c75 100644 --- a/command/acl/acl_helpers.go +++ b/command/acl/acl_helpers.go @@ -45,9 +45,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) + }) + } +}