mirror of
https://github.com/fleetdm/fleet
synced 2026-05-06 06:48:54 +00:00
allow turning off mdm for iphone and ipad hosts (#29087)
For [#23784](https://github.com/fleetdm/fleet/issues/23784) This adds the "turn off mdm" option don't he host details page for iPhone and iPad devices. - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. - [ ] Added/updated automated tests - [ ] Manual QA for all new/changed functionality
This commit is contained in:
parent
5815dc4e54
commit
63b2e19630
8 changed files with 53 additions and 37 deletions
1
changes/issue-23784-turn-off-mdm-iphone-ipad
Normal file
1
changes/issue-23784-turn-off-mdm-iphone-ipad
Normal file
|
|
@ -0,0 +1 @@
|
|||
- add ability to turn off mdm for iphone and ipad hosts on the hosts details page
|
||||
|
|
@ -1230,7 +1230,6 @@ describe("Host Actions Dropdown", () => {
|
|||
expect(
|
||||
screen.queryByText("Show disk encryption key")
|
||||
).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("Turn off MDM")).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("Lock")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
|
@ -1270,7 +1269,6 @@ describe("Host Actions Dropdown", () => {
|
|||
expect(
|
||||
screen.queryByText("Show disk encryption key")
|
||||
).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("Turn off MDM")).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("Lock")).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {
|
|||
isAppleDevice,
|
||||
isMobilePlatform,
|
||||
isAndroid,
|
||||
isIPadOrIPhone,
|
||||
} from "interfaces/platform";
|
||||
import { isScriptSupportedPlatform } from "interfaces/script";
|
||||
|
||||
|
|
@ -89,7 +90,7 @@ const canTransferTeam = (config: IHostActionConfigOptions) => {
|
|||
return isPremiumTier && (isGlobalAdmin || isGlobalMaintainer);
|
||||
};
|
||||
|
||||
const canEditMdm = (config: IHostActionConfigOptions) => {
|
||||
const canTurnOffMdm = (config: IHostActionConfigOptions) => {
|
||||
const {
|
||||
hostPlatform,
|
||||
isGlobalAdmin,
|
||||
|
|
@ -102,7 +103,7 @@ const canEditMdm = (config: IHostActionConfigOptions) => {
|
|||
} = config;
|
||||
return (
|
||||
!isAndroid(hostPlatform) && // TODO(android): confirm can't turn off MDM for windows, iOS, iPadOS?
|
||||
hostPlatform === "darwin" &&
|
||||
isAppleDevice(hostPlatform) &&
|
||||
isMacMdmEnabledAndConfigured &&
|
||||
isEnrolledInMdm &&
|
||||
isConnectedToFleetMdm &&
|
||||
|
|
@ -257,7 +258,7 @@ const removeUnavailableOptions = (
|
|||
options = options.filter((option) => option.value !== "diskEncryption");
|
||||
}
|
||||
|
||||
if (!canEditMdm(config)) {
|
||||
if (!canTurnOffMdm(config)) {
|
||||
options = options.filter((option) => option.value !== "mdmOff");
|
||||
}
|
||||
|
||||
|
|
@ -339,7 +340,7 @@ const modifyOptions = (
|
|||
|
||||
let optionsToDisable: IDropdownOption[] = [];
|
||||
if (
|
||||
!isHostOnline ||
|
||||
(!isIPadOrIPhone(hostPlatform) && !isHostOnline) ||
|
||||
isDeviceStatusUpdating(hostMdmDeviceStatus) ||
|
||||
hostMdmDeviceStatus === "locked" ||
|
||||
hostMdmDeviceStatus === "wiped"
|
||||
|
|
@ -386,7 +387,6 @@ const modifyOptions = (
|
|||
* many variations of the options that are shown/not shown or disabled/enabled
|
||||
* which are all controlled by the configurations options argument.
|
||||
*/
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export const generateHostActionOptions = (config: IHostActionConfigOptions) => {
|
||||
// deep clone to always start with a fresh copy of the default options.
|
||||
let options: IDropdownOption[] = cloneDeep([...DEFAULT_OPTIONS]);
|
||||
|
|
|
|||
|
|
@ -1160,7 +1160,12 @@ const HostDetailsPage = ({
|
|||
/>
|
||||
)}
|
||||
{showUnenrollMdmModal && !!host && (
|
||||
<UnenrollMdmModal hostId={host.id} onClose={toggleUnenrollMdmModal} />
|
||||
<UnenrollMdmModal
|
||||
hostId={host.id}
|
||||
hostPlatform={host.platform}
|
||||
hostName={host.display_name}
|
||||
onClose={toggleUnenrollMdmModal}
|
||||
/>
|
||||
)}
|
||||
{showDiskEncryptionModal && host && (
|
||||
<DiskEncryptionKeyModal
|
||||
|
|
|
|||
|
|
@ -6,15 +6,24 @@ import Modal from "components/Modal";
|
|||
import { NotificationContext } from "context/notification";
|
||||
|
||||
import mdmAPI from "services/entities/mdm";
|
||||
import { isIPadOrIPhone } from "interfaces/platform";
|
||||
import CustomLink from "components/CustomLink";
|
||||
|
||||
interface IUnenrollMdmModalProps {
|
||||
hostId: number;
|
||||
hostPlatform: string;
|
||||
hostName: string;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const baseClass = "unenroll-mdm-modal";
|
||||
|
||||
const UnenrollMdmModal = ({ hostId, onClose }: IUnenrollMdmModalProps) => {
|
||||
const UnenrollMdmModal = ({
|
||||
hostId,
|
||||
hostPlatform,
|
||||
hostName,
|
||||
onClose,
|
||||
}: IUnenrollMdmModalProps) => {
|
||||
const [requestState, setRequestState] = useState<
|
||||
undefined | "unenrolling" | "error"
|
||||
>(undefined);
|
||||
|
|
@ -27,28 +36,50 @@ const UnenrollMdmModal = ({ hostId, onClose }: IUnenrollMdmModalProps) => {
|
|||
await mdmAPI.unenrollHostFromMdm(hostId, 5000);
|
||||
renderFlash(
|
||||
"success",
|
||||
"Turning off MDM or will turn off when the host comes online."
|
||||
<>
|
||||
MDM will be turned off for <b>{hostName}</b> next time this host
|
||||
checks in.
|
||||
</>
|
||||
);
|
||||
onClose();
|
||||
} catch (unenrollMdmError: unknown) {
|
||||
renderFlash("error", "Couldn't turn off MDM. Please try again.");
|
||||
console.log(unenrollMdmError);
|
||||
onClose();
|
||||
renderFlash(
|
||||
"error",
|
||||
<>
|
||||
Failed to turn off MDM for <b>{hostName}</b>.
|
||||
</>
|
||||
);
|
||||
}
|
||||
onClose();
|
||||
};
|
||||
|
||||
const renderModalContent = () => {
|
||||
if (requestState === "error") {
|
||||
return <DataError />;
|
||||
}
|
||||
|
||||
const turnOnMDMInstructions = isIPadOrIPhone(hostPlatform) ? (
|
||||
<>
|
||||
invite the end user to{" "}
|
||||
<CustomLink
|
||||
text="enroll a BYOD iPhone or iPad"
|
||||
url="https://fleetdm.com/guides/enroll-byod-ios-ipados-hosts"
|
||||
newTab
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
ask the device user to follow the <b>Turn on MDM</b> instructions on
|
||||
their <b>My device</b> page.
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<p className={`${baseClass}__description`}>
|
||||
Settings configured by Fleet will be removed.
|
||||
<br />
|
||||
<br />
|
||||
To turn on MDM again, ask the device user to follow the{" "}
|
||||
<b>Turn on MDM</b> instructions on their <b>My device</b> page.
|
||||
To turn on MDM again, {turnOnMDMInstructions}
|
||||
</p>
|
||||
<div className="modal-cta-wrap">
|
||||
<Button
|
||||
|
|
@ -72,7 +103,7 @@ const UnenrollMdmModal = ({ hostId, onClose }: IUnenrollMdmModalProps) => {
|
|||
title="Turn off MDM"
|
||||
onExit={onClose}
|
||||
className={baseClass}
|
||||
width="large"
|
||||
width="medium"
|
||||
>
|
||||
{renderModalContent()}
|
||||
</Modal>
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ var (
|
|||
AppleMDMNotConfiguredMessage = "macOS MDM isn't turned on. Visit https://fleetdm.com/docs/using-fleet to learn how to turn on MDM."
|
||||
AppleABMDefaultTeamDeprecatedMessage = "mdm.apple_bm_default_team has been deprecated. Please use the new mdm.apple_business_manager key documented here: https://fleetdm.com/learn-more-about/apple-business-manager-gitops"
|
||||
CantTurnOffMDMForWindowsHostsMessage = "Can't turn off MDM for Windows hosts."
|
||||
CantTurnOffMDMForIOSOrIPadOSMessage = "Can't turn off MDM for iOS or iPadOS hosts. Use wipe instead."
|
||||
)
|
||||
|
||||
// ErrWithStatusCode is an interface for errors that should set a specific HTTP
|
||||
|
|
|
|||
|
|
@ -1995,12 +1995,6 @@ func (svc *Service) EnqueueMDMAppleCommandRemoveEnrollmentProfile(ctx context.Co
|
|||
}
|
||||
|
||||
switch h.Platform {
|
||||
case "ios":
|
||||
fallthrough
|
||||
case "ipados":
|
||||
return &fleet.BadRequestError{
|
||||
Message: fleet.CantTurnOffMDMForIOSOrIPadOSMessage,
|
||||
}
|
||||
case "windows":
|
||||
return &fleet.BadRequestError{
|
||||
Message: fleet.CantTurnOffMDMForWindowsHostsMessage,
|
||||
|
|
|
|||
|
|
@ -14972,20 +14972,8 @@ func (s *integrationMDMTestSuite) TestWindowsMigrationEnabled() {
|
|||
|
||||
func (s *integrationMDMTestSuite) TestHostsCantTurnMDMOff() {
|
||||
t := s.T()
|
||||
iOSHost, _ := s.createAppleMobileHostThenEnrollMDM("ios")
|
||||
require.NoError(t, s.ds.SetOrUpdateMDMData(context.Background(), iOSHost.ID, false, true, "https://foo.com", true, "", ""))
|
||||
|
||||
r := s.Do("DELETE", fmt.Sprintf("/api/latest/fleet/hosts/%d/mdm", iOSHost.ID), nil, http.StatusBadRequest)
|
||||
require.Contains(t, extractServerErrorText(r.Body), fleet.CantTurnOffMDMForIOSOrIPadOSMessage)
|
||||
|
||||
iPadOSHost, _ := s.createAppleMobileHostThenEnrollMDM("ipados")
|
||||
require.NoError(t, s.ds.SetOrUpdateMDMData(context.Background(), iPadOSHost.ID, false, true, "https://foo.com", true, "", ""))
|
||||
|
||||
r = s.Do("DELETE", fmt.Sprintf("/api/latest/fleet/hosts/%d/mdm", iPadOSHost.ID), nil, http.StatusBadRequest)
|
||||
require.Contains(t, extractServerErrorText(r.Body), fleet.CantTurnOffMDMForIOSOrIPadOSMessage)
|
||||
|
||||
winHost, _ := createWindowsHostThenEnrollMDM(s.ds, s.server.URL, t)
|
||||
r = s.Do("DELETE", fmt.Sprintf("/api/latest/fleet/hosts/%d/mdm", winHost.ID), nil, http.StatusBadRequest)
|
||||
r := s.Do("DELETE", fmt.Sprintf("/api/latest/fleet/hosts/%d/mdm", winHost.ID), nil, http.StatusBadRequest)
|
||||
require.Contains(t, extractServerErrorText(r.Body), fleet.CantTurnOffMDMForWindowsHostsMessage)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue