From 4167d6456e77b4d67353241cdd23e408caddf044 Mon Sep 17 00:00:00 2001 From: Rico Chavez-Lopez Date: Wed, 21 Sep 2022 14:41:33 -0700 Subject: [PATCH] fix: added consul policy list check Added a check in getPolicyByName to see whether the policy exists in the policy list before attempting to get the policy. This prevents erroneous or unclear logging. closes: #4108 Signed-off-by: Rico Chavez-Lopez --- .../command/setupacl/aclpolicies.go | 54 +++++++++++++++++++ .../setupacl/stubregistryserver_test.go | 16 ++++++ 2 files changed, 70 insertions(+) diff --git a/internal/security/bootstrapper/command/setupacl/aclpolicies.go b/internal/security/bootstrapper/command/setupacl/aclpolicies.go index 569a842f62..173b6cea59 100644 --- a/internal/security/bootstrapper/command/setupacl/aclpolicies.go +++ b/internal/security/bootstrapper/command/setupacl/aclpolicies.go @@ -66,6 +66,7 @@ const ( edgeXServicePolicyName = "edgex-service-policy" consulCreatePolicyAPI = "/v1/acl/policy" + consulPolicyListAPI = "/v1/acl/policies" consulReadPolicyByNameAPI = "/v1/acl/policy/name/%s" aclNotFoundMessage = "ACL not found" @@ -105,6 +106,10 @@ const ( edgeXManagementPolicyName = "edgex-management-policy" ) +type PolicyListResponse []struct { + Name string `json:"Name"` +} + // getOrCreateRegistryPolicy retrieves or creates a new policy // it inserts a new policy if the policy name does not exist and returns a policy // it returns the same policy if the policy name already exists @@ -184,6 +189,15 @@ func (c *cmd) getOrCreateRegistryPolicy(tokenID, policyName, policyRules string) // getPolicyByName gets policy by policy name, returns nil if not found func (c *cmd) getPolicyByName(tokenID, policyName string) (*Policy, error) { + policyExists, err := c.checkPolicyExists(tokenID, policyName) + if err != nil { + return nil, err + } + + if !policyExists { + return nil, nil + } + readPolicyByNameURL, err := c.getRegistryApiUrl(fmt.Sprintf(consulReadPolicyByNameAPI, policyName)) if err != nil { return nil, err @@ -230,3 +244,43 @@ func (c *cmd) getPolicyByName(tokenID, policyName string) (*Policy, error) { resp.StatusCode, string(readPolicyResp)) } } + +func (c *cmd) checkPolicyExists(tokenID, policyName string) (bool, error) { + policyListURL, err := c.getRegistryApiUrl(consulPolicyListAPI) + if err != nil { + return false, err + } + + policyListReq, err := http.NewRequest(http.MethodGet, policyListURL, http.NoBody) + if err != nil { + return false, fmt.Errorf("Failed to prepare policyListReq request for http URL %s: %w", policyListURL, err) + } + + policyListReq.Header.Add(share.ConsulTokenHeader, tokenID) + policyListResp, err := c.client.Do(policyListReq) + if err != nil { + return false, fmt.Errorf("Failed to GET policy list request for http URL %s: %w", policyListURL, err) + } + defer policyListResp.Body.Close() + + var policyList PolicyListResponse + + err = json.NewDecoder(policyListResp.Body).Decode(&policyList) + if err != nil { + return false, fmt.Errorf("Failed to decode policy list reponse: %w", err) + } + + switch policyListResp.StatusCode { + case http.StatusOK: + for _, policy := range policyList.policies { + // consul is case-sensitive + if policyName == policy.Name { + return true, nil + } + } + default: + return false, fmt.Errorf("Failed to get consul policy list from [%s] and status code= %d", consulPolicyListAPI, + policyListResp.StatusCode) + } + return false, nil +} diff --git a/internal/security/bootstrapper/command/setupacl/stubregistryserver_test.go b/internal/security/bootstrapper/command/setupacl/stubregistryserver_test.go index 008dde483a..399217c1ab 100644 --- a/internal/security/bootstrapper/command/setupacl/stubregistryserver_test.go +++ b/internal/security/bootstrapper/command/setupacl/stubregistryserver_test.go @@ -332,6 +332,22 @@ func (registry *registryTestServer) getRegistryServerConf(t *testing.T) *config. w.WriteHeader(http.StatusInternalServerError) _, _ = w.Write([]byte("Invalid Policy: A Policy with Name " + edgeXServicePolicyName + " already exists")) } + case consulPolicyListAPI: + require.Equal(t, http.MethodGet, r.Method) + w.WriteHeader(http.StatusOK) + jsonResponse := []map[string]interface{}{ + { + "Name": "global-management", + }, + { + "Name": "node-read", + }, + { + "Name": "test-policy-name", + }, + } + err := json.NewEncoder(w).Encode(jsonResponse) + require.NoError(t, err) default: t.Fatalf("Unexpected call to URL %s", r.URL.EscapedPath()) }