From 60712144f2d46ec3a4d23e894e4cc9d23ed74bff Mon Sep 17 00:00:00 2001 From: Jacob Shandling <61553566+jacobshandling@users.noreply.github.com> Date: Mon, 30 Jan 2023 11:44:33 -0800 Subject: [PATCH] UI: Add automatic EnrollMdm modal (#9455) # Addresses #9365 # Implements MDM enrollment modal that handles both automatic and manual enrollment instructions: - Automatic: Screenshot 2023-01-20 at 4 33 50 PM - Manual: Screenshot 2023-01-20 at 4 35 04 PM - Also includes (by mistake, but might as well include them now) some small bash scripts for use in MDM development # 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/` - [x] Updated testing inventory - [x] Manual QA for all new/changed functionality --------- Co-authored-by: Jacob Shandling --- .../9365-add-automatic-MDM-enrollment-modal | 1 + .../AutoEnrollMdmModal/AutoEnrollMdmModal.tsx | 48 +++++++++++++++++++ .../AutoEnrollMdmModal/_styles.scss | 0 .../AutoEnrollMdmModal/index.ts | 1 + .../details/DeviceUserPage/DeviceUserPage.tsx | 32 ++++++++----- .../ManualEnrollMdmModal.tsx | 32 +++++-------- .../ManualEnrollMdmModal/_styles.scss | 15 ------ .../hosts/details/DeviceUserPage/_styles.scss | 17 +++++++ tools/dbutils/delete-host | 5 ++ tools/dbutils/get-host-tokens | 3 ++ tools/dbutils/insert-host-and-token | 7 +++ tools/mdm/apple/toggle-mdm-dev.sh | 43 +++++++++++++++++ 12 files changed, 158 insertions(+), 46 deletions(-) create mode 100644 changes/9365-add-automatic-MDM-enrollment-modal create mode 100644 frontend/pages/hosts/details/DeviceUserPage/AutoEnrollMdmModal/AutoEnrollMdmModal.tsx create mode 100644 frontend/pages/hosts/details/DeviceUserPage/AutoEnrollMdmModal/_styles.scss create mode 100644 frontend/pages/hosts/details/DeviceUserPage/AutoEnrollMdmModal/index.ts create mode 100755 tools/dbutils/delete-host create mode 100755 tools/dbutils/get-host-tokens create mode 100755 tools/dbutils/insert-host-and-token create mode 100755 tools/mdm/apple/toggle-mdm-dev.sh diff --git a/changes/9365-add-automatic-MDM-enrollment-modal b/changes/9365-add-automatic-MDM-enrollment-modal new file mode 100644 index 0000000000..ba413107c5 --- /dev/null +++ b/changes/9365-add-automatic-MDM-enrollment-modal @@ -0,0 +1 @@ +* Add modal for automatic enrollment of a macOS host to MDM diff --git a/frontend/pages/hosts/details/DeviceUserPage/AutoEnrollMdmModal/AutoEnrollMdmModal.tsx b/frontend/pages/hosts/details/DeviceUserPage/AutoEnrollMdmModal/AutoEnrollMdmModal.tsx new file mode 100644 index 0000000000..d21f5ffc13 --- /dev/null +++ b/frontend/pages/hosts/details/DeviceUserPage/AutoEnrollMdmModal/AutoEnrollMdmModal.tsx @@ -0,0 +1,48 @@ +import React from "react"; + +import Button from "components/buttons/Button"; +import Modal from "components/Modal"; + +interface IAutoEnrollMdmModalProps { + onCancel: () => void; +} + +const baseClass = "auto-enroll-mdm-modal enroll-mdm-modal"; + +const AutoEnrollMdmModal = ({ + onCancel, +}: IAutoEnrollMdmModalProps): JSX.Element => { + return ( + +
+

+ To turn on MDM, Apple Inc. requires that you install a profile. +

+
    +
  1. + From the Apple menu in the top left corner of your screen, select{" "} + System Settings or System Preferences. +
  2. +
  3. + In the search bar, type “Profiles.” Select Profiles, find and + select Enrollment Profile, and select Install. +
  4. +
  5. + Enter your password, and select Enroll. +
  6. +
  7. + Close this window and select Refetch on your My device page + to tell your organization that MDM is on. +
  8. +
+
+ +
+
+
+ ); +}; + +export default AutoEnrollMdmModal; diff --git a/frontend/pages/hosts/details/DeviceUserPage/AutoEnrollMdmModal/_styles.scss b/frontend/pages/hosts/details/DeviceUserPage/AutoEnrollMdmModal/_styles.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/pages/hosts/details/DeviceUserPage/AutoEnrollMdmModal/index.ts b/frontend/pages/hosts/details/DeviceUserPage/AutoEnrollMdmModal/index.ts new file mode 100644 index 0000000000..2f1855ae8c --- /dev/null +++ b/frontend/pages/hosts/details/DeviceUserPage/AutoEnrollMdmModal/index.ts @@ -0,0 +1 @@ +export { default } from "./AutoEnrollMdmModal"; diff --git a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx index 5468553948..31bc52de36 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx +++ b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx @@ -34,11 +34,12 @@ import AboutCard from "../cards/About"; import SoftwareCard from "../cards/Software"; import PoliciesCard from "../cards/Policies"; import InfoModal from "./InfoModal"; -import ManualEnrollMdmModal from "./ManualEnrollMdmModal"; import InfoIcon from "../../../../../assets/images/icon-info-purple-14x14@2x.png"; import FleetIcon from "../../../../../assets/images/fleet-avatar-24x24@2x.png"; import PolicyDetailsModal from "../cards/Policies/HostPoliciesTable/PolicyDetailsModal"; +import AutoEnrollMdmModal from "./AutoEnrollMdmModal"; +import ManualEnrollMdmModal from "./ManualEnrollMdmModal"; const baseClass = "device-user"; @@ -59,7 +60,7 @@ const DeviceUserPage = ({ const [isPremiumTier, setIsPremiumTier] = useState(false); const [showInfoModal, setShowInfoModal] = useState(false); - const [showMdmModal, setShowMdmModal] = useState(false); + const [showEnrollMdmModal, setShowEnrollMdmModal] = useState(false); const [refetchStartTime, setRefetchStartTime] = useState(null); const [showRefetchSpinner, setShowRefetchSpinner] = useState(false); const [hostSoftware, setHostSoftware] = useState([]); @@ -215,9 +216,9 @@ const DeviceUserPage = ({ setShowInfoModal(!showInfoModal); }, [showInfoModal, setShowInfoModal]); - const toggleTurnOnMdmModal = useCallback(() => { - setShowMdmModal(!showMdmModal); - }, [showMdmModal, setShowMdmModal]); + const toggleEnrollMdmModal = useCallback(() => { + setShowEnrollMdmModal(!showEnrollMdmModal); + }, [showEnrollMdmModal, setShowEnrollMdmModal]); const togglePolicyDetailsModal = useCallback( (policy: IHostPolicy) => { @@ -264,10 +265,22 @@ const DeviceUserPage = ({ const statusClassName = classnames("status", `status--${host?.status}`); const turnOnMdmButton = ( - ); + + const renderEnrollMdmModal = () => { + return host?.mdm_enrollment_status === "Pending" ? ( + + ) : ( + + ); + }; + const renderDeviceUserPage = () => { const failingPoliciesCount = host?.issues?.failing_policies_count || 0; return ( @@ -339,12 +352,7 @@ const DeviceUserPage = ({ {showInfoModal && } - {showMdmModal && ( - - )} + {showEnrollMdmModal && renderEnrollMdmModal()} )} {!!host && showPolicyDetailsModal && ( diff --git a/frontend/pages/hosts/details/DeviceUserPage/ManualEnrollMdmModal/ManualEnrollMdmModal.tsx b/frontend/pages/hosts/details/DeviceUserPage/ManualEnrollMdmModal/ManualEnrollMdmModal.tsx index 107487de40..aa34a1f594 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/ManualEnrollMdmModal/ManualEnrollMdmModal.tsx +++ b/frontend/pages/hosts/details/DeviceUserPage/ManualEnrollMdmModal/ManualEnrollMdmModal.tsx @@ -11,17 +11,17 @@ import Spinner from "components/Spinner"; import mdmAPI from "services/entities/mdm"; -export interface IInfoModalProps { +interface IManualEnrollMdmModalProps { onCancel: () => void; - token: string; + token?: string; } -const baseClass = "manual-enroll-mdm-modal"; +const baseClass = "manual-enroll-mdm-modal enroll-mdm-modal"; const ManualEnrollMdmModal = ({ onCancel, - token, -}: IInfoModalProps): JSX.Element => { + token = "", +}: IManualEnrollMdmModalProps): JSX.Element => { const { renderFlash } = useContext(NotificationContext); const [isDownloadingProfile, setIsDownloadingProfile] = useState(false); @@ -60,15 +60,15 @@ const ManualEnrollMdmModal = ({ return false; }; - const renderModalContent = () => { - if (isFetchingMdmProfile) { - return ; - } - if (fetchMdmProfileError) { - return ; - } + if (isFetchingMdmProfile) { + return ; + } + if (fetchMdmProfileError) { + return ; + } - return ( + return ( +

To turn on MDM, Apple Inc. requires that you download and install a @@ -119,12 +119,6 @@ const ManualEnrollMdmModal = ({

- ); - }; - - return ( - - {renderModalContent()} ); }; diff --git a/frontend/pages/hosts/details/DeviceUserPage/ManualEnrollMdmModal/_styles.scss b/frontend/pages/hosts/details/DeviceUserPage/ManualEnrollMdmModal/_styles.scss index d32b74249c..e7aacf4253 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/ManualEnrollMdmModal/_styles.scss +++ b/frontend/pages/hosts/details/DeviceUserPage/ManualEnrollMdmModal/_styles.scss @@ -1,19 +1,4 @@ .manual-enroll-mdm-modal { - width: 800px; - - &__description { - margin: $pad-large 0; - } - - ol { - padding-left: 0; - } - - li { - margin-bottom: $pad-large; - list-style: number inside; - } - &__download-button { margin-top: 12px; } diff --git a/frontend/pages/hosts/details/DeviceUserPage/_styles.scss b/frontend/pages/hosts/details/DeviceUserPage/_styles.scss index 172673b311..8fb4416672 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/_styles.scss +++ b/frontend/pages/hosts/details/DeviceUserPage/_styles.scss @@ -2,6 +2,23 @@ // TODO: talk to rachel about removing this background-color: $ui-off-white; } +.enroll-mdm-modal { + width: 800px; + + &__description { + margin: $pad-large 0; + } + + ol { + padding-left: 0; + } + + li { + margin-bottom: $pad-large; + list-style: number inside; + } +} + .device-user { display: flex; flex-wrap: wrap; diff --git a/tools/dbutils/delete-host b/tools/dbutils/delete-host new file mode 100755 index 0000000000..4ca93060f1 --- /dev/null +++ b/tools/dbutils/delete-host @@ -0,0 +1,5 @@ +#!/bin/bash + +# experimental – doesn't always work right + +docker compose exec mysql mysql -uroot -ptoor -Dfleet -e "DELETE FROM host_device_auth WHERE host_id=$1;" diff --git a/tools/dbutils/get-host-tokens b/tools/dbutils/get-host-tokens new file mode 100755 index 0000000000..1dc07fcfe7 --- /dev/null +++ b/tools/dbutils/get-host-tokens @@ -0,0 +1,3 @@ +#!/bin/bash + +docker compose exec mysql mysql -uroot -ptoor -Dfleet -e "SELECT host_id, token FROM host_device_auth;" diff --git a/tools/dbutils/insert-host-and-token b/tools/dbutils/insert-host-and-token new file mode 100755 index 0000000000..bdf6df6a40 --- /dev/null +++ b/tools/dbutils/insert-host-and-token @@ -0,0 +1,7 @@ +#!/bin/bash + +# experimental – doesn't always work right + +NEW_ID=$1 +NEW_TOKEN=$2 +docker compose exec mysql mysql -uroot -ptoor -Dfleet -e "INSERT INTO host_device_auth VALUES ($NEW_ID, $NEW_TOKEN, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);" diff --git a/tools/mdm/apple/toggle-mdm-dev.sh b/tools/mdm/apple/toggle-mdm-dev.sh new file mode 100755 index 0000000000..b2444adc4f --- /dev/null +++ b/tools/mdm/apple/toggle-mdm-dev.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +# To toggle MDM, run `source toggle-mdm-dev` +# Requires the env at $FLEET_ENV_PATH to contain logic something like: + +# if [[ $USE_MDM == "1" ]]; then + +# # for UI dev: +# export FLEET_DEV_MDM_ENABLED=1 + +# # for MDM server +# export FLEET_MDM_APPLE_ENABLE=1 +# export FLEET_MDM_APPLE_SCEP_CHALLENGE=scepchallenge +# MDM_PATH={PATH_TO_YOUR_MDM_RELATED_KEYS_AND_CERTS} +# export FLEET_MDM_APPLE_SCEP_CERT=$MDM_PATH"fleet-mdm-apple-scep.crt" +# export FLEET_MDM_APPLE_SCEP_KEY=$MDM_PATH"fleet-mdm-apple-scep.key" +# export FLEET_MDM_APPLE_BM_SERVER_TOKEN=$MDM_PATH"downloadtoken.p7m" +# export FLEET_MDM_APPLE_BM_CERT=$MDM_PATH"fleet-apple-mdm-bm-public-key.crt" +# export FLEET_MDM_APPLE_BM_KEY=$MDM_PATH"fleet-apple-mdm-bm-private.key" +# #below files are from the shared Fleet 1Password +# export FLEET_MDM_APPLE_APNS_CERT=$MDM_PATH"mdmcert.download.push.pem" +# export FLEET_MDM_APPLE_APNS_KEY=$MDM_PATH"mdmcert.download.push.key" +# else +# unset FLEET_DEV_MDM_ENABLED +# unset FLEET_MDM_APPLE_ENABLE +# unset FLEET_MDM_APPLE_SCEP_CHALLENGE +# unset FLEET_MDM_APPLE_SCEP_CERT +# unset FLEET_MDM_APPLE_SCEP_KEY +# unset FLEET_MDM_APPLE_BM_SERVER_TOKEN +# unset FLEET_MDM_APPLE_BM_CERT +# unset FLEET_MDM_APPLE_BM_KEY +# #below files are from the shared Fleet 1Password +# unset FLEET_MDM_APPLE_APNS_CERT +# unset FLEET_MDM_APPLE_APNS_KEY +# fi + +if [[ $USE_MDM == "1" ]]; then +export USE_MDM=0 +else +export USE_MDM=1 +fi + +source $FLEET_ENV_PATH