mirror of
https://github.com/fleetdm/fleet
synced 2026-05-06 06:48:54 +00:00
Check for device token inactive error in refetcher and turn off MDM (#33027)
fixes: #29650 # 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/guides/committing-changes.md#changes-files) for more information. ## Testing - [x] Added/updated automated tests - [ ] QA'd all new/changed functionality manually (Not possible for me to get it into the same state, I just never get a response from my device, but never the device token is inactive, I think that might be a very long time process?, but verified that if the error comes back it successfully turns off MDM)
This commit is contained in:
parent
4909907edd
commit
0b87656438
3 changed files with 146 additions and 3 deletions
|
|
@ -0,0 +1 @@
|
|||
- Turn off MDM for iOS and iPadOS devices when refetcher returns device token is inactive
|
||||
|
|
@ -1414,7 +1414,11 @@ func IOSiPadOSRefetch(ctx context.Context, ds fleet.Datastore, commander *MDMApp
|
|||
}
|
||||
if len(installedAppsUUIDs) > 0 {
|
||||
err = commander.InstalledApplicationList(ctx, installedAppsUUIDs, fleet.RefetchAppsCommandUUIDPrefix+commandUUID, false)
|
||||
if err != nil {
|
||||
turnedOff, turnedOffError := turnOffMDMIfAPNSFailed(ctx, ds, err, logger)
|
||||
if turnedOffError != nil {
|
||||
return turnedOffError
|
||||
}
|
||||
if err != nil && !turnedOff {
|
||||
return ctxerr.Wrap(ctx, err, "send InstalledApplicationList commands to ios and ipados devices")
|
||||
}
|
||||
}
|
||||
|
|
@ -1431,7 +1435,11 @@ func IOSiPadOSRefetch(ctx context.Context, ds fleet.Datastore, commander *MDMApp
|
|||
}
|
||||
if len(certsListUUIDs) > 0 {
|
||||
err = commander.CertificateList(ctx, certsListUUIDs, fleet.RefetchCertsCommandUUIDPrefix+commandUUID)
|
||||
if err != nil {
|
||||
turnedOff, turnedOffError := turnOffMDMIfAPNSFailed(ctx, ds, err, logger)
|
||||
if turnedOffError != nil {
|
||||
return turnedOffError
|
||||
}
|
||||
if err != nil && !turnedOff {
|
||||
return ctxerr.Wrap(ctx, err, "send CertificateList commands to ios and ipados devices")
|
||||
}
|
||||
}
|
||||
|
|
@ -1448,7 +1456,12 @@ func IOSiPadOSRefetch(ctx context.Context, ds fleet.Datastore, commander *MDMApp
|
|||
}
|
||||
}
|
||||
if len(deviceInfoUUIDs) > 0 {
|
||||
if err := commander.DeviceInformation(ctx, deviceInfoUUIDs, fleet.RefetchDeviceCommandUUIDPrefix+commandUUID); err != nil {
|
||||
err := commander.DeviceInformation(ctx, deviceInfoUUIDs, fleet.RefetchDeviceCommandUUIDPrefix+commandUUID)
|
||||
turnedOff, turnedOffError := turnOffMDMIfAPNSFailed(ctx, ds, err, logger)
|
||||
if turnedOffError != nil {
|
||||
return turnedOffError
|
||||
}
|
||||
if err != nil && !turnedOff {
|
||||
return ctxerr.Wrap(ctx, err, "send DeviceInformation commands to ios and ipados devices")
|
||||
}
|
||||
}
|
||||
|
|
@ -1461,6 +1474,25 @@ func IOSiPadOSRefetch(ctx context.Context, ds fleet.Datastore, commander *MDMApp
|
|||
return nil
|
||||
}
|
||||
|
||||
// turnOffMDMIfAPNSFailed checks if the error is an APNSDeliveryError and turns off MDM for the failed devices.
|
||||
// Returns a boolean value to indicate whether or not MDM was turned off.
|
||||
func turnOffMDMIfAPNSFailed(ctx context.Context, ds fleet.Datastore, err error, logger kitlog.Logger) (bool, error) {
|
||||
var e *APNSDeliveryError
|
||||
if !errors.As(err, &e) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
for uuid, err := range e.errorsByUUID {
|
||||
if strings.Contains(err.Error(), "device token is inactive") {
|
||||
level.Info(logger).Log("msg", "turning off MDM for device with inactive device token", "uuid", uuid)
|
||||
if err := ds.MDMTurnOff(ctx, uuid); err != nil {
|
||||
return false, ctxerr.Wrap(ctx, err, "turn off mdm for failed device")
|
||||
}
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func GenerateOTAEnrollmentProfileMobileconfig(orgName, fleetURL, enrollSecret, idpUUID string) ([]byte, error) {
|
||||
path, err := url.JoinPath(fleetURL, "/api/v1/fleet/ota_enrollment")
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -17799,3 +17799,113 @@ func (s *integrationMDMTestSuite) TestBYODEnrollmentWithIdPEnabled() {
|
|||
require.NotEmpty(t, location)
|
||||
require.True(t, strings.HasPrefix(location, "http://localhost:9080/simplesaml/"))
|
||||
}
|
||||
|
||||
func (s *integrationMDMTestSuite) TestIOSiPadOSRefetch() {
|
||||
ctx := s.T().Context()
|
||||
|
||||
successfulPushUUID := "successful-uuid"
|
||||
failedPushUUID := "failed-uuid"
|
||||
|
||||
// Set up test data
|
||||
|
||||
// Perform the MDM enrollment.
|
||||
mdmEnrollInfo := mdmtest.AppleEnrollInfo{
|
||||
SCEPChallenge: s.scepChallenge,
|
||||
SCEPURL: s.server.URL + apple_mdm.SCEPPath,
|
||||
MDMURL: s.server.URL + apple_mdm.MDMPath,
|
||||
}
|
||||
model := "iPhone14,6"
|
||||
|
||||
successfulHost, err := s.ds.NewHost(ctx, &fleet.Host{
|
||||
HardwareSerial: mdmtest.RandSerialNumber(),
|
||||
UUID: successfulPushUUID,
|
||||
Platform: string(fleet.IOSPlatform),
|
||||
DetailUpdatedAt: time.Now().Add(-2 * time.Hour), // ensure refetch is needed
|
||||
})
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
successfulMdmDevice := mdmtest.NewTestMDMClientAppleDirect(mdmEnrollInfo, model)
|
||||
successfulMdmDevice.SerialNumber = successfulHost.HardwareSerial
|
||||
err = successfulMdmDevice.Enroll()
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
failedHost, err := s.ds.NewHost(ctx, &fleet.Host{
|
||||
HardwareSerial: mdmtest.RandSerialNumber(),
|
||||
UUID: failedPushUUID,
|
||||
Platform: string(fleet.IOSPlatform),
|
||||
DetailUpdatedAt: time.Now().Add(-2 * time.Hour), // ensure refetch is needed
|
||||
})
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
failedMdmDevice := mdmtest.NewTestMDMClientAppleDirect(mdmEnrollInfo, model)
|
||||
failedMdmDevice.SerialNumber = failedHost.HardwareSerial
|
||||
err = failedMdmDevice.Enroll()
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
failedHostTokenInactive, err := s.ds.NewHost(ctx, &fleet.Host{
|
||||
HardwareSerial: mdmtest.RandSerialNumber(),
|
||||
UUID: failedPushUUID,
|
||||
Platform: string(fleet.IOSPlatform),
|
||||
DetailUpdatedAt: time.Now().Add(-2 * time.Hour), // ensure refetch is needed
|
||||
})
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
failedMdmDeviceTokenInactive := mdmtest.NewTestMDMClientAppleDirect(mdmEnrollInfo, model)
|
||||
failedMdmDeviceTokenInactive.SerialNumber = failedHostTokenInactive.HardwareSerial
|
||||
err = failedMdmDeviceTokenInactive.Enroll()
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
originalPushFunc := s.pushProvider.PushFunc
|
||||
s.T().Cleanup(func() {
|
||||
s.pushProvider.PushFunc = originalPushFunc
|
||||
})
|
||||
s.pushProvider.PushFunc = func(_ context.Context, pushes []*mdm.Push) (map[string]*push.Response, error) {
|
||||
require.Len(s.T(), pushes, 1)
|
||||
pushObject := pushes[0]
|
||||
switch pushObject.PushMagic {
|
||||
case "pushmagic" + successfulMdmDevice.SerialNumber:
|
||||
return map[string]*push.Response{
|
||||
pushObject.Token.String(): {
|
||||
Id: successfulPushUUID,
|
||||
Err: nil,
|
||||
},
|
||||
}, nil
|
||||
case "pushmagic" + failedMdmDeviceTokenInactive.SerialNumber:
|
||||
return map[string]*push.Response{
|
||||
pushObject.Token.String(): {
|
||||
Id: failedPushUUID,
|
||||
Err: errors.New("device token is inactive"),
|
||||
},
|
||||
}, nil
|
||||
case "pushmagic" + failedMdmDevice.SerialNumber:
|
||||
return map[string]*push.Response{
|
||||
pushObject.Token.String(): {
|
||||
Id: failedPushUUID,
|
||||
Err: errors.New("random apns error"),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
return nil, errors.New("unknown device")
|
||||
}
|
||||
|
||||
err = apple_mdm.IOSiPadOSRefetch(ctx, s.ds, s.mdmCommander, s.logger)
|
||||
require.NoError(s.T(), err) // Verify it not longer throws an error
|
||||
|
||||
// Verify successful is still enrolled
|
||||
successfulHostMDM, err := s.ds.GetHostMDM(ctx, successfulHost.ID)
|
||||
require.NoError(s.T(), err)
|
||||
require.NotNil(s.T(), successfulHostMDM)
|
||||
require.True(s.T(), successfulHostMDM.Enrolled)
|
||||
|
||||
// Verify random APNS error host is still enrolled
|
||||
failedHostMDM, err := s.ds.GetHostMDM(ctx, failedHost.ID)
|
||||
require.NoError(s.T(), err)
|
||||
require.NotNil(s.T(), failedHostMDM)
|
||||
require.True(s.T(), failedHostMDM.Enrolled)
|
||||
|
||||
// Verify device token inactive host is no longer enrolled
|
||||
failedHostMDMTokenInactive, err := s.ds.GetHostMDM(ctx, failedHostTokenInactive.ID)
|
||||
require.NoError(s.T(), err)
|
||||
require.NotNil(s.T(), failedHostMDMTokenInactive)
|
||||
require.False(s.T(), failedHostMDMTokenInactive.Enrolled)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue