From bb8054bbcdc5fbebae03df4d5de7b5570fc0dec5 Mon Sep 17 00:00:00 2001 From: Jahziel Villasana-Espinoza Date: Wed, 22 Jan 2025 09:55:49 -0500 Subject: [PATCH] fix: correctly get VPP token ID when doing a renewal (#25657) > For #25567 # Checklist for submitter If some of the following don't apply, delete the relevant line. - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Committing-Changes.md#changes-files) for more information. - [x] Added/updated automated tests - [x] A detailed QA plan exists on the associated ticket (if it isn't there, work with the product group's QA engineer to add it) - [x] Manual QA for all new/changed functionality --------- Co-authored-by: Ian Littman --- changes/25567-renew-vpp | 1 + server/service/integration_mdm_test.go | 16 +++++++++++++++- server/service/vpp.go | 8 ++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 changes/25567-renew-vpp diff --git a/changes/25567-renew-vpp b/changes/25567-renew-vpp new file mode 100644 index 000000000000..57aaf6435492 --- /dev/null +++ b/changes/25567-renew-vpp @@ -0,0 +1 @@ +* Fixed a bug in Fleet's handling of VPP token renewal requests diff --git a/server/service/integration_mdm_test.go b/server/service/integration_mdm_test.go index eb009c3f816d..f5291da435a0 100644 --- a/server/service/integration_mdm_test.go +++ b/server/service/integration_mdm_test.go @@ -1405,6 +1405,10 @@ func (s *integrationMDMTestSuite) TestGetMDMCSR() { } func (s *integrationMDMTestSuite) uploadDataViaForm(endpoint, fieldName, fileName string, data []byte, expectedStatus int, wantErr string, response any) { + s.uploadDataViaFormWithVerb(endpoint, "POST", fieldName, fileName, data, expectedStatus, wantErr, response) +} + +func (s *integrationMDMTestSuite) uploadDataViaFormWithVerb(endpoint, verb, fieldName, fileName string, data []byte, expectedStatus int, wantErr string, response any) { t := s.T() var b bytes.Buffer @@ -1424,7 +1428,7 @@ func (s *integrationMDMTestSuite) uploadDataViaForm(endpoint, fieldName, fileNam "Authorization": fmt.Sprintf("Bearer %s", s.token), } - res := s.DoRawWithHeaders("POST", endpoint, b.Bytes(), expectedStatus, headers) + res := s.DoRawWithHeaders(verb, endpoint, b.Bytes(), expectedStatus, headers) if wantErr != "" { errMsg := extractServerErrorText(res.Body) assert.Contains(t, errMsg, wantErr) @@ -10907,6 +10911,8 @@ func (s *integrationMDMTestSuite) TestVPPApps() { // Invalid token t.Setenv("FLEET_DEV_VPP_URL", s.appleVPPConfigSrv.URL+"?invalidToken") s.uploadDataViaForm("/api/latest/fleet/vpp_tokens", "token", "token.vpptoken", []byte("foobar"), http.StatusUnprocessableEntity, "Invalid token. Please provide a valid content token from Apple Business Manager.", nil) + // Attempt to renew an invalid (nonexistent) token, should fail + s.uploadDataViaFormWithVerb("/api/latest/fleet/vpp_tokens/999/renew", "PATCH", "token", "token.vpptoken", []byte(base64.StdEncoding.EncodeToString([]byte("foobar"))), http.StatusUnprocessableEntity, "Invalid token. Please provide a valid content token from Apple Business Manager.", nil) // Simulate a server error from the Apple API t.Setenv("FLEET_DEV_VPP_URL", s.appleVPPConfigSrv.URL+"?serverError") @@ -10925,6 +10931,14 @@ func (s *integrationMDMTestSuite) TestVPPApps() { s.lastActivityMatches(fleet.ActivityEnabledVPP{}.ActivityName(), "", 0) + // Renew valid token + expTime = expTime.Add(24 * time.Hour).UTC().Round(time.Second) + expDate = expTime.Format(fleet.VPPTimeFormat) + tokenJSON = fmt.Sprintf(`{"expDate":"%s","token":"%s","orgName":"%s"}`, expDate, token, orgName) + s.uploadDataViaFormWithVerb(fmt.Sprintf("/api/latest/fleet/vpp_tokens/%d/renew", validToken.Token.ID), "PATCH", "token", "token.vpptoken", []byte(base64.StdEncoding.EncodeToString([]byte(tokenJSON))), http.StatusAccepted, "", &validToken) + // Valid token bytes, but non-existent token ID. Should get not found + s.uploadDataViaFormWithVerb("/api/latest/fleet/vpp_tokens/999/renew", "PATCH", "token", "token.vpptoken", []byte(base64.StdEncoding.EncodeToString([]byte(tokenJSON))), http.StatusNotFound, "VPPToken was not found in the datastore", nil) + // Get the token var resp getVPPTokensResponse s.DoJSON("GET", "/api/latest/fleet/vpp_tokens", &getVPPTokensRequest{}, http.StatusOK, &resp) diff --git a/server/service/vpp.go b/server/service/vpp.go index c2e25eddc060..92e92d9794fe 100644 --- a/server/service/vpp.go +++ b/server/service/vpp.go @@ -7,6 +7,7 @@ import ( "net/http" "github.com/docker/go-units" + "github.com/fleetdm/fleet/v4/server/contexts/ctxerr" "github.com/fleetdm/fleet/v4/server/fleet" ) @@ -173,6 +174,13 @@ func (patchVPPTokenRenewRequest) DecodeRequest(ctx context.Context, r *http.Requ decoded.File = r.MultipartForm.File["token"][0] + id, err := uintFromRequest(r, "id") + if err != nil { + return nil, ctxerr.Wrap(ctx, err, "failed to parse vpp token id") + } + + decoded.ID = uint(id) //nolint:gosec // dismiss G115 + return &decoded, nil }