Added view_pin param. (#19788)

#19545

`/api/latest/fleet/hosts/:id/lock` returns `unlock_pin` for Apple hosts
when query parameter `view_pin=true` is set

The lock host activity now has a `view_pin` parameter. Frontend change
is needed to reflect this in the UI.

# Checklist for submitter

<!-- Note that API documentation changes are now addressed by the
product design team. -->

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://fleetdm.com/docs/contributing/committing-changes#changes-files)
for more information.
- [x] Added/updated tests
- [x] Manual QA for all new/changed functionality
This commit is contained in:
Victor Lyuboslavsky
2024-06-17 11:30:53 -05:00
committed by GitHub
parent 11a1c58094
commit 05547a5130
9 changed files with 23 additions and 18 deletions
+1 -1
View File
@@ -1,2 +1,2 @@
* /api/latest/fleet/hosts/:id/lock returns `unlock_pin` for Apple hosts
* /api/latest/fleet/hosts/:id/lock returns `unlock_pin` for Apple hosts when query parameter `view_pin=true` is set
* UI no longer uses unlock pending state for Apple hosts
+4 -3
View File
@@ -38,7 +38,7 @@ func (svc *Service) OSVersion(ctx context.Context, osID uint, teamID *uint, incl
return svc.Service.OSVersion(ctx, osID, teamID, true)
}
func (svc *Service) LockHost(ctx context.Context, hostID uint) (unlockPIN string, err error) {
func (svc *Service) LockHost(ctx context.Context, hostID uint, viewPIN bool) (unlockPIN string, err error) {
// First ensure the user has access to list hosts, then check the specific
// host once team_id is loaded.
if err := svc.authz.Authorize(ctx, &fleet.Host{}, fleet.ActionList); err != nil {
@@ -152,7 +152,7 @@ func (svc *Service) LockHost(ctx context.Context, hostID uint) (unlockPIN string
}
// all good, go ahead with queuing the lock request.
return svc.enqueueLockHostRequest(ctx, host, lockWipe)
return svc.enqueueLockHostRequest(ctx, host, lockWipe, viewPIN)
}
func (svc *Service) UnlockHost(ctx context.Context, hostID uint) (string, error) {
@@ -345,7 +345,7 @@ func (svc *Service) WipeHost(ctx context.Context, hostID uint) error {
return svc.enqueueWipeHostRequest(ctx, host, lockWipe)
}
func (svc *Service) enqueueLockHostRequest(ctx context.Context, host *fleet.Host, lockStatus *fleet.HostLockWipeStatus) (
func (svc *Service) enqueueLockHostRequest(ctx context.Context, host *fleet.Host, lockStatus *fleet.HostLockWipeStatus, viewPIN bool) (
unlockPIN string, err error,
) {
vc, ok := viewer.FromContext(ctx)
@@ -365,6 +365,7 @@ func (svc *Service) enqueueLockHostRequest(ctx context.Context, host *fleet.Host
fleet.ActivityTypeLockedHost{
HostID: host.ID,
HostDisplayName: host.DisplayName(),
ViewPIN: viewPIN,
},
); err != nil {
return "", ctxerr.Wrap(ctx, err, "create activity for darwin lock host request")
+1
View File
@@ -1267,6 +1267,7 @@ func (a ActivityTypeEditedWindowsProfile) Documentation() (activity, details, de
type ActivityTypeLockedHost struct {
HostID uint `json:"host_id"`
HostDisplayName string `json:"host_display_name"`
ViewPIN bool `json:"view_pin"`
}
func (a ActivityTypeLockedHost) ActivityName() string {
+1 -1
View File
@@ -1042,7 +1042,7 @@ type Service interface {
BatchSetScripts(ctx context.Context, maybeTmID *uint, maybeTmName *string, payloads []ScriptPayload, dryRun bool) error
// Script-based methods (at least for some platforms, MDM-based for others)
LockHost(ctx context.Context, hostID uint) (unlockPIN string, err error)
LockHost(ctx context.Context, hostID uint, viewPIN bool) (unlockPIN string, err error)
UnlockHost(ctx context.Context, hostID uint) (unlockPIN string, err error)
WipeHost(ctx context.Context, hostID uint) error
+2
View File
@@ -598,6 +598,8 @@ func attachFleetAPIRoutes(r *mux.Router, svc fleet.Service, config config.FleetC
mdmAppleMW.PATCH("/api/_version_/fleet/mdm/hosts/{id:[0-9]+}/unenroll", mdmAppleCommandRemoveEnrollmentProfileEndpoint, mdmAppleCommandRemoveEnrollmentProfileRequest{})
mdmAppleMW.DELETE("/api/_version_/fleet/hosts/{id:[0-9]+}/mdm", mdmAppleCommandRemoveEnrollmentProfileEndpoint, mdmAppleCommandRemoveEnrollmentProfileRequest{})
// Deprecated: POST /mdm/hosts/:id/lock is now deprecated, replaced by
// POST /hosts/:id/lock.
mdmAppleMW.POST("/api/_version_/fleet/mdm/hosts/{id:[0-9]+}/lock", deviceLockEndpoint, deviceLockRequest{})
mdmAppleMW.POST("/api/_version_/fleet/mdm/hosts/{id:[0-9]+}/wipe", deviceWipeEndpoint, deviceWipeRequest{})
+2 -2
View File
@@ -1651,9 +1651,9 @@ func TestLockUnlockWipeHostAuth(t *testing.T) {
}
ctx := viewer.NewContext(ctx, viewer.Viewer{User: tt.user})
_, err := svc.LockHost(ctx, globalHostID)
_, err := svc.LockHost(ctx, globalHostID, false)
checkAuthErr(t, tt.shouldFailGlobalWrite, err)
_, err = svc.LockHost(ctx, teamHostID)
_, err = svc.LockHost(ctx, teamHostID, false)
checkAuthErr(t, tt.shouldFailTeamWrite, err)
// Pretend we locked the host
@@ -5,7 +5,6 @@ import (
"encoding/json"
"encoding/xml"
"fmt"
"github.com/stretchr/testify/assert"
"net/http"
"os"
"path/filepath"
@@ -74,15 +73,12 @@ func (s *integrationMDMTestSuite) TestTurnOnLifecycleEventsApple() {
{
"locked host turns on MDM",
func(t *testing.T, host *fleet.Host, device *mdmtest.TestAppleMDMClient) {
var resp lockHostResponse
s.DoJSON(
s.Do(
"POST",
fmt.Sprintf("/api/latest/fleet/hosts/%d/lock", host.ID),
nil,
http.StatusOK,
&resp,
http.StatusNoContent,
)
assert.Len(t, resp.UnlockPIN, 6)
cmd, err := device.Idle()
require.NoError(t, err)
+5 -1
View File
@@ -8024,7 +8024,7 @@ func (s *integrationMDMTestSuite) TestLockUnlockWipeMacOS() {
// lock the host
var lockResp lockHostResponse
s.DoJSON("POST", fmt.Sprintf("/api/latest/fleet/hosts/%d/lock", host.ID), nil, http.StatusOK, &lockResp)
s.DoJSON("POST", fmt.Sprintf("/api/latest/fleet/hosts/%d/lock", host.ID), nil, http.StatusOK, &lockResp, "view_pin", "true")
assert.Len(t, lockResp.UnlockPIN, 6)
// refresh the host's status, it is now pending lock
@@ -8155,6 +8155,10 @@ func (s *integrationMDMTestSuite) TestLockUnlockWipeMacOS() {
require.Equal(t, "unlocked", *getHostResp.Host.MDM.DeviceStatus)
require.NotNil(t, getHostResp.Host.MDM.PendingAction)
require.Equal(t, "", *getHostResp.Host.MDM.PendingAction)
// lock the host without viewing the PIN
s.Do("POST", fmt.Sprintf("/api/latest/fleet/hosts/%d/lock", host.ID), nil, http.StatusNoContent)
}
func (s *integrationMDMTestSuite) TestZCustomConfigurationWebURL() {
+5 -4
View File
@@ -911,7 +911,8 @@ func (svc *Service) authorizeScriptByID(ctx context.Context, scriptID uint, auth
////////////////////////////////////////////////////////////////////////////////
type lockHostRequest struct {
HostID uint `url:"id"`
HostID uint `url:"id"`
ViewPin bool `query:"view_pin,optional"`
}
type lockHostResponse struct {
@@ -930,17 +931,17 @@ func (r lockHostResponse) error() error { return r.Err }
func lockHostEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (errorer, error) {
req := request.(*lockHostRequest)
unlockPIN, err := svc.LockHost(ctx, req.HostID)
unlockPIN, err := svc.LockHost(ctx, req.HostID, req.ViewPin)
if err != nil {
return lockHostResponse{Err: err}, nil
}
if unlockPIN != "" {
if req.ViewPin && unlockPIN != "" {
return lockHostResponse{UnlockPIN: unlockPIN, StatusCode: http.StatusOK}, nil
}
return lockHostResponse{}, nil
}
func (svc *Service) LockHost(ctx context.Context, hostID uint) (string, error) {
func (svc *Service) LockHost(ctx context.Context, _ uint, _ bool) (string, error) {
// skipauth: No authorization check needed due to implementation returning
// only license error.
svc.authz.SkipAuthorization(ctx)