diff --git a/consul/acl_endpoint.go b/consul/acl_endpoint.go index 211a785741..31f2f0a372 100644 --- a/consul/acl_endpoint.go +++ b/consul/acl_endpoint.go @@ -27,7 +27,7 @@ func (a *ACL) Apply(args *structs.ACLRequest, reply *string) error { return fmt.Errorf(aclDisabled) } - // Verify token is permitted to list ACLs + // Verify token is permitted to modify ACLs if acl, err := a.srv.resolveToken(args.Token); err != nil { return err } else if acl == nil || !acl.ACLModify() { @@ -44,6 +44,11 @@ func (a *ACL) Apply(args *structs.ACLRequest, reply *string) error { return fmt.Errorf("Invalid ACL Type") } + // Verify this is not a root ACL + if acl.RootACL(args.ACL.ID) != nil { + return fmt.Errorf("%s: Cannot modify root ACL", permissionDenied) + } + // Validate the rules compile _, err := acl.Parse(args.ACL.Rules) if err != nil { @@ -53,6 +58,8 @@ func (a *ACL) Apply(args *structs.ACLRequest, reply *string) error { case structs.ACLDelete: if args.ACL.ID == "" { return fmt.Errorf("Missing ACL ID") + } else if args.ACL.ID == anonymousToken { + return fmt.Errorf("%s: Cannot delete anonymous token", permissionDenied) } default: diff --git a/consul/acl_endpoint_test.go b/consul/acl_endpoint_test.go index 18e1ddf383..4c2e4410a3 100644 --- a/consul/acl_endpoint_test.go +++ b/consul/acl_endpoint_test.go @@ -174,6 +174,64 @@ func TestACLEndpoint_Apply_Denied(t *testing.T) { } } +func TestACLEndpoint_Apply_DeleteAnon(t *testing.T) { + dir1, s1 := testServerWithConfig(t, func(c *Config) { + c.ACLDatacenter = "dc1" + c.ACLMasterToken = "root" + }) + defer os.RemoveAll(dir1) + defer s1.Shutdown() + client := rpcClient(t, s1) + defer client.Close() + + testutil.WaitForLeader(t, client.Call, "dc1") + + arg := structs.ACLRequest{ + Datacenter: "dc1", + Op: structs.ACLDelete, + ACL: structs.ACL{ + ID: anonymousToken, + Name: "User token", + Type: structs.ACLTypeClient, + }, + WriteRequest: structs.WriteRequest{Token: "root"}, + } + var out string + err := client.Call("ACL.Apply", &arg, &out) + if err == nil || !strings.Contains(err.Error(), "delete anonymous") { + t.Fatalf("err: %v", err) + } +} + +func TestACLEndpoint_Apply_RootChange(t *testing.T) { + dir1, s1 := testServerWithConfig(t, func(c *Config) { + c.ACLDatacenter = "dc1" + c.ACLMasterToken = "root" + }) + defer os.RemoveAll(dir1) + defer s1.Shutdown() + client := rpcClient(t, s1) + defer client.Close() + + testutil.WaitForLeader(t, client.Call, "dc1") + + arg := structs.ACLRequest{ + Datacenter: "dc1", + Op: structs.ACLSet, + ACL: structs.ACL{ + ID: "manage", + Name: "User token", + Type: structs.ACLTypeClient, + }, + WriteRequest: structs.WriteRequest{Token: "root"}, + } + var out string + err := client.Call("ACL.Apply", &arg, &out) + if err == nil || !strings.Contains(err.Error(), "root ACL") { + t.Fatalf("err: %v", err) + } +} + func TestACLEndpoint_Get(t *testing.T) { dir1, s1 := testServerWithConfig(t, func(c *Config) { c.ACLDatacenter = "dc1"