From 78c32797ed3f57ef5e9dbc5e06f4c5410d30305b Mon Sep 17 00:00:00 2001 From: gbolo Date: Wed, 14 Jun 2023 13:58:48 +0000 Subject: [PATCH 1/4] backport of commit 31d96f5fb22d86b62b5e47a44bc07cdf6eab200b --- agent/acl_endpoint.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/agent/acl_endpoint.go b/agent/acl_endpoint.go index af9f3a15d90..cac3149465d 100644 --- a/agent/acl_endpoint.go +++ b/agent/acl_endpoint.go @@ -438,8 +438,16 @@ func (s *HTTPHandlers) aclTokenSetInternal(req *http.Request, tokenAccessorID st return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: fmt.Sprintf("Token decoding failed: %v", err)} } - if !create && args.ACLToken.AccessorID != tokenAccessorID { - return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "Token Accessor ID in URL and payload do not match"} + if !create { + // NOTE: AccessorID in the request body is optional not creating a new token. + // If not present in the body and only in the URL then it will be filled in by Consul. + if args.ACLToken.AccessorID == "" { + args.ACLToken.AccessorID = tokenAccessorID + } + + if args.ACLToken.AccessorID != tokenAccessorID { + return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "Token Accessor ID in URL and payload do not match"} + } } var out structs.ACLToken From 9e81d6e7f89533e317f1ffa5a2bb7ff3d1450d84 Mon Sep 17 00:00:00 2001 From: gbolo Date: Wed, 14 Jun 2023 16:23:51 +0000 Subject: [PATCH 2/4] backport of commit 78dbcfbeeec535dfc284dfa3c5a13b46893c0a50 --- agent/acl_endpoint.go | 2 +- agent/acl_endpoint_test.go | 42 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/agent/acl_endpoint.go b/agent/acl_endpoint.go index cac3149465d..7ad0392f040 100644 --- a/agent/acl_endpoint.go +++ b/agent/acl_endpoint.go @@ -439,7 +439,7 @@ func (s *HTTPHandlers) aclTokenSetInternal(req *http.Request, tokenAccessorID st } if !create { - // NOTE: AccessorID in the request body is optional not creating a new token. + // NOTE: AccessorID in the request body is optional when not creating a new token. // If not present in the body and only in the URL then it will be filled in by Consul. if args.ACLToken.AccessorID == "" { args.ACLToken.AccessorID = tokenAccessorID diff --git a/agent/acl_endpoint_test.go b/agent/acl_endpoint_test.go index d2822e39e9a..d44efa2645c 100644 --- a/agent/acl_endpoint_test.go +++ b/agent/acl_endpoint_test.go @@ -904,6 +904,48 @@ func TestACL_HTTP(t *testing.T) { tokenMap[token.AccessorID] = token }) + t.Run("Update without AccessorID in request body", func(t *testing.T) { + originalToken := tokenMap[idMap["token-cloned"]] + + // Secret will be filled in + tokenInput := &structs.ACLToken{ + Description: "Better description for this cloned token", + Policies: []structs.ACLTokenPolicyLink{ + { + ID: idMap["policy-read-all-nodes"], + Name: policyMap[idMap["policy-read-all-nodes"]].Name, + }, + }, + NodeIdentities: []*structs.ACLNodeIdentity{ + { + NodeName: "foo", + Datacenter: "bar", + }, + }, + } + + req, _ := http.NewRequest("PUT", "/v1/acl/token/"+originalToken.AccessorID, jsonBody(tokenInput)) + req.Header.Add("X-Consul-Token", "root") + resp := httptest.NewRecorder() + obj, err := a.srv.ACLTokenCRUD(resp, req) + require.NoError(t, err) + token, ok := obj.(*structs.ACLToken) + require.True(t, ok) + + require.Equal(t, originalToken.AccessorID, token.AccessorID) + require.Equal(t, originalToken.SecretID, token.SecretID) + require.Equal(t, tokenInput.Description, token.Description) + require.Equal(t, tokenInput.Policies, token.Policies) + require.Equal(t, tokenInput.NodeIdentities, token.NodeIdentities) + require.True(t, token.CreateIndex > 0) + require.True(t, token.CreateIndex < token.ModifyIndex) + require.NotNil(t, token.Hash) + require.NotEqual(t, token.Hash, []byte{}) + require.NotEqual(t, token.Hash, originalToken.Hash) + + tokenMap[token.AccessorID] = token + }) + t.Run("CRUD Missing Token Accessor ID", func(t *testing.T) { req, _ := http.NewRequest("GET", "/v1/acl/token/", nil) req.Header.Add("X-Consul-Token", "root") From 2c5c88068f39aa9255ef96a2cc79662bce7b3e3c Mon Sep 17 00:00:00 2001 From: gbolo Date: Wed, 14 Jun 2023 16:35:57 +0000 Subject: [PATCH 3/4] backport of commit de3dceed994efefbfd61f0fb136b3cf8265bc3fd --- agent/acl_endpoint_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/acl_endpoint_test.go b/agent/acl_endpoint_test.go index d44efa2645c..55fefbdc066 100644 --- a/agent/acl_endpoint_test.go +++ b/agent/acl_endpoint_test.go @@ -909,7 +909,7 @@ func TestACL_HTTP(t *testing.T) { // Secret will be filled in tokenInput := &structs.ACLToken{ - Description: "Better description for this cloned token", + Description: "Even Better description for this cloned token", Policies: []structs.ACLTokenPolicyLink{ { ID: idMap["policy-read-all-nodes"], From 72e1d5ded65f38839b80978275c57f9ed3e4ddc2 Mon Sep 17 00:00:00 2001 From: gbolo Date: Mon, 19 Jun 2023 13:41:38 +0000 Subject: [PATCH 4/4] backport of commit 2c436e6f59a1f0f7740fa8fa208a992f26898b8b --- .changelog/17739.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/17739.txt diff --git a/.changelog/17739.txt b/.changelog/17739.txt new file mode 100644 index 00000000000..14bbceeaa08 --- /dev/null +++ b/.changelog/17739.txt @@ -0,0 +1,3 @@ +```release-note:bug +http: fixed API endpoint `PUT /acl/token/:AccessorID` (update token), no longer requires `AccessorID` in the request body. Web UI can now update tokens. + ```