Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/27646-ios-clear-passcode
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Added ability for admins to remotely clear the passcode on ADE-enrolled iOS/iPadOS devices via the host details page.
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@
"enrollment_status": null,
"name": "",
"pending_action": "",
"server_url": null
"server_url": null,
"unlock_token_available": false
},
"memory": 0,
"orbit_version": null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ spec:
name: ""
pending_action: ""
server_url: null
unlock_token_available: false
memory: 0
orbit_version: null
os_version: ""
Expand Down
6 changes: 4 additions & 2 deletions cmd/fleetctl/fleetctl/testdata/expectedListHostsJson.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@
"encryption_key_available": false,
"enrollment_status": null,
"name": "",
"server_url": null
"server_url": null,
"unlock_token_available": false
},
"memory": 0,
"orbit_version": null,
Expand Down Expand Up @@ -123,7 +124,8 @@
"encryption_key_available": false,
"enrollment_status": null,
"name": "",
"server_url": null
"server_url": null,
"unlock_token_available": false
},
"memory": 0,
"orbit_version": null,
Expand Down
6 changes: 4 additions & 2 deletions cmd/fleetctl/fleetctl/testdata/expectedListHostsMDM.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
"encryption_key_available": false,
"enrollment_status": null,
"name": "",
"server_url": null
"server_url": null,
"unlock_token_available": false
},
"memory": 0,
"orbit_version": null,
Expand Down Expand Up @@ -124,7 +125,8 @@
"encryption_key_available": false,
"enrollment_status": null,
"name": "",
"server_url": null
"server_url": null,
"unlock_token_available": false
},
"memory": 0,
"orbit_version": null,
Expand Down
2 changes: 2 additions & 0 deletions cmd/fleetctl/fleetctl/testdata/expectedListHostsYaml.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ spec:
enrollment_status: null
name: ""
server_url: null
unlock_token_available: false
memory: 0
orbit_version: null
os_version: ""
Expand Down Expand Up @@ -115,6 +116,7 @@ spec:
enrollment_status: null
name: ""
server_url: null
unlock_token_available: false
memory: 0
orbit_version: null
os_version: ""
Expand Down
23 changes: 23 additions & 0 deletions docs/REST API/rest-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2882,6 +2882,7 @@ None.
- [Lock host](#lock-host)
- [Unlock host](#unlock-host)
- [Wipe host](#wipe-host)
- [Clear passcode](#clear-passcode)
- [Get host's past activity](#get-hosts-past-activity)
- [Get host's upcoming activity](#get-hosts-upcoming-activity)
- [Cancel host's upcoming activity](#cancel-hosts-upcoming-activity)
Expand Down Expand Up @@ -5187,6 +5188,28 @@ To wipe a macOS, iOS, iPadOS, or Windows host, the host must have MDM turned on.

> To verify the host was successfully wiped, you can use the [Get host](https://fleetdm.com/docs/rest-api/rest-api#get-host) endpoint to retrieve the host's `mdm.device_status`.

### Clear passcode

Sends a command to clear the passcode on the specified iOS or iPadOS host. The device must be enrolled via Automated Device Enrollment (ADE) and have MDM turned on.

The host must have previously sent its unlock token to Fleet (visible via `mdm.unlock_token_available` on the [Get host](https://fleetdm.com/docs/rest-api/rest-api#get-host) response). The unlock token is sent automatically when the device checks in.

`POST /api/v1/fleet/hosts/:id/clear_passcode`

#### Parameters

| Name | Type | In | Description |
|------|---------|------|--------------------------------------------------------|
| id | integer | path | **Required**. ID of the iOS or iPadOS host. |

#### Example

`POST /api/v1/fleet/hosts/123/clear_passcode`

##### Default response

`Status: 200`

### Get host's past activity

`GET /api/v1/fleet/hosts/:id/activities`
Expand Down
79 changes: 79 additions & 0 deletions ee/server/service/hosts.go
Original file line number Diff line number Diff line change
Expand Up @@ -566,3 +566,82 @@ var (
</Item>
</Exec>`
)

func (svc *Service) ClearHostPasscode(ctx context.Context, hostID uint) 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 {
return err
}
host, err := svc.ds.Host(ctx, hostID)
if err != nil {
return ctxerr.Wrap(ctx, err, "get host")
}

// Authorize again with team loaded now that we have the host's team_id.
if err := svc.authz.Authorize(ctx, fleet.MDMCommandAuthz{TeamID: host.TeamID}, fleet.ActionWrite); err != nil {
return err
}

// Only supported for iOS and iPadOS.
switch host.FleetPlatform() {
case "ios", "ipados":
// continue
default:
return ctxerr.Wrap(ctx, fleet.NewInvalidArgumentError("host_id", "Clear passcode is only supported for iOS and iPadOS hosts."))
}

// Personal (BYOD) enrollment is not supported.
if host.MDM.EnrollmentStatus != nil && *host.MDM.EnrollmentStatus == "On (personal)" {
return &fleet.BadRequestError{
Message: "Can't clear passcode on a personal device.",
}
}

// Manual enrollment is not supported — requires ADE.
if host.MDM.EnrollmentStatus != nil && *host.MDM.EnrollmentStatus == "On (manual)" {
return &fleet.BadRequestError{
Message: "Can't clear passcode on a manually enrolled device. The host must be enrolled via Automated Device Enrollment (ADE).",
}
}

if err := svc.VerifyMDMAppleConfigured(ctx); err != nil {
if errors.Is(err, fleet.ErrMDMNotConfigured) {
err = fleet.NewInvalidArgumentError("host_id", fleet.AppleMDMNotConfiguredMessage).WithStatus(http.StatusBadRequest)
}
return ctxerr.Wrap(ctx, err, "check Apple MDM enabled")
}

connected, err := svc.ds.IsHostConnectedToFleetMDM(ctx, host)
if err != nil {
return ctxerr.Wrap(ctx, err, "checking if host is connected to Fleet MDM")
}
if !connected {
return ctxerr.Wrap(ctx, fleet.NewInvalidArgumentError("host_id", "Can't clear passcode because the host doesn't have MDM turned on."))
}

unlockToken, err := svc.ds.GetMDMAppleDeviceUnlockToken(ctx, host.UUID)
if err != nil {
return ctxerr.Wrap(ctx, err, "get device unlock token")
}
if len(unlockToken) == 0 {
return fleet.NewInvalidArgumentError("host_id", "Passcode cannot be cleared. The device unlock token is not yet available. Try again after the device checks in.")
}

if err := svc.mdmAppleCommander.ClearPasscode(ctx, host, uuid.NewString(), unlockToken); err != nil {
return ctxerr.Wrap(ctx, err, "enqueue clear passcode command")
}

vc, ok := viewer.FromContext(ctx)
if !ok {
return fleet.ErrNoContext
}
if err := svc.NewActivity(ctx, vc.User, fleet.ActivityTypeClearedPasscode{
HostID: host.ID,
HostDisplayName: host.DisplayName(),
}); err != nil {
return ctxerr.Wrap(ctx, err, "create activity for clear passcode")
}

return nil
}
Loading
Loading