Wire up UI and server for correct ABM credentials download (#9660)

Final alignment of UI and server for ABM credential downloads

- [x] Added/updated test inventory
- [x] Manual QA for all new/changed functionality

---------

Co-authored-by: Jacob Shandling <jacob@fleetdm.com>
Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
This commit is contained in:
Jacob Shandling 2023-02-03 11:02:50 -08:00 committed by GitHub
parent ec947bc5f0
commit 9630f64e40
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 36 additions and 26 deletions

View file

@ -20,21 +20,21 @@ import { readableDate } from "utilities/helpers";
import RequestCSRModal from "./components/RequestCSRModal";
import EditTeamModal from "./components/EditTeamModal";
// MDM TODO: key validation?
// import { isValidKeys } from "../../..";
interface IABMKeys {
decodedPublic: string;
decodedPrivate: string;
}
const baseClass = "mdm-integrations";
const Mdm = (): JSX.Element => {
const { isPremiumTier } = useContext(AppContext);
const { isPremiumTier, config } = useContext(AppContext);
const { renderFlash } = useContext(NotificationContext);
const [showRequestCSRModal, setShowRequestCSRModal] = useState(false);
const [showEditTeamModal, setShowEditTeamModal] = useState(false);
const [defaultTeamName, setDefaultTeamName] = useState("No team");
const [showCSRFlag, setShowCSRFlag] = useState(true);
const {
data: appleAPNInfo,
isLoading: isLoadingMdmApple,
@ -43,7 +43,7 @@ const Mdm = (): JSX.Element => {
["appleAPNInfo"],
() => mdmAppleAPI.getAppleAPNInfo(),
{
enabled: isPremiumTier,
enabled: isPremiumTier && config?.mdm.enabled_and_configured,
staleTime: 5000,
}
);
@ -56,7 +56,7 @@ const Mdm = (): JSX.Element => {
["mdmAppleBmAPI"],
() => mdmAppleBmAPI.getAppleBMInfo(),
{
enabled: isPremiumTier,
enabled: isPremiumTier && config?.mdm.enabled_and_configured,
staleTime: 5000,
onSuccess: (appleBmData) => {
setDefaultTeamName(appleBmData.default_team ?? "No team");
@ -64,12 +64,11 @@ const Mdm = (): JSX.Element => {
}
);
// MDM TODO: Test manually after backend is merged
const {
data: keys,
error: fetchKeysError,
isFetching: isFetchingKeys,
} = useQuery<string, Error>(["keys"], () => mdmAppleBmAPI.loadKeys(), {
} = useQuery<IABMKeys, Error>(["keys"], () => mdmAppleBmAPI.loadKeys(), {
enabled: isPremiumTier,
refetchOnWindowFocus: false,
});
@ -95,14 +94,26 @@ const Mdm = (): JSX.Element => {
}
if (keys) {
// MDM TODO: Validate keys like we validate certificates?
// if (keys && isValidKeys(keys)) {
const filename = "fleet.pem";
const file = new global.window.File([keys], filename, {
type: "application/x-pem-file",
});
const publicFilename = "fleet-apple-mdm-bm-public-key.crt";
const publicFile = new global.window.File(
[keys.decodedPublic],
publicFilename,
{
type: "application/x-pem-file",
}
);
FileSaver.saveAs(file);
const privateFilename = "fleet-apple-mdm-bm-private.key";
const privateFile = new global.window.File(
[keys.decodedPublic],
privateFilename,
{
type: "application/x-pem-file",
}
);
FileSaver.saveAs(publicFile);
FileSaver.saveAs(privateFile);
} else {
renderFlash(
"error",

View file

@ -3,8 +3,6 @@ import sendRequest from "services";
import endpoints from "utilities/endpoints";
export default {
// TODO: set up full MDM testing environment, including all keys/credentials/tokens, to be able to
// get proper data from this API as opposed to the mock backend above
getAppleBMInfo: () => {
const { MDM_APPLE_BM } = endpoints;
const path = MDM_APPLE_BM;
@ -14,19 +12,20 @@ export default {
const { MDM_APPLE_BM_KEYS } = endpoints;
const path = MDM_APPLE_BM_KEYS;
// MDM TODO: Originally written for certificate_chain for certificate, refactor for keys when backend is merged
return sendRequest("GET", path).then(({ certificate_chain }) => {
let decodedKeys;
return sendRequest("POST", path).then(({ private_key, public_key }) => {
let decodedPublic;
let decodedPrivate;
try {
decodedKeys = global.window.atob(certificate_chain);
decodedPublic = global.window.atob(public_key);
decodedPrivate = global.window.atob(private_key);
} catch (err) {
return Promise.reject(`Unable to decode keys: ${err}`);
}
if (!decodedKeys) {
if (!decodedPrivate || !decodedPublic) {
return Promise.reject("Missing or undefined keys.");
}
return Promise.resolve(decodedKeys);
return Promise.resolve({ decodedPublic, decodedPrivate });
});
},
};

View file

@ -37,7 +37,7 @@ export default {
// TODO: Clean up MDM endpoints to be consistent and up to date
MDM_APPLE: `/${API_VERSION}/fleet/mdm/apple`,
MDM_APPLE_BM: `/${API_VERSION}/fleet/mdm/apple_bm`,
MDM_APPLE_BM_KEYS: `/${API_VERSION}/fleet/mdm/apple_bm/keys`,
MDM_APPLE_BM_KEYS: `/${API_VERSION}/fleet/mdm/apple/dep/key_pair`,
MDM_SUMMARY: `/${API_VERSION}/fleet/hosts/summary/mdm`,
MDM_REQUEST_CSR: `/${API_VERSION}/fleet/mdm/apple/request_csr`,
// Should below 2 endpoints be consistent?

View file

@ -437,11 +437,11 @@ func attachFleetAPIRoutes(r *mux.Router, svc fleet.Service, config config.FleetC
ue.GET("/api/_version_/fleet/mdm/apple/installers", listMDMAppleInstallersEndpoint, listMDMAppleInstallersRequest{})
ue.GET("/api/_version_/fleet/mdm/apple/devices", listMDMAppleDevicesEndpoint, listMDMAppleDevicesRequest{})
ue.GET("/api/_version_/fleet/mdm/apple/dep/devices", listMDMAppleDEPDevicesEndpoint, listMDMAppleDEPDevicesRequest{})
ue.POST("/api/_version_/fleet/mdm/apple/dep/key_pair", newMDMAppleDEPKeyPairEndpoint, nil)
// host-specific mdm commands
ue.PATCH("/api/_version_/fleet/mdm/hosts/{id:[0-9]+}/unenroll", mdmAppleCommandRemoveEnrollmentProfileEndpoint, mdmAppleCommandRemoveEnrollmentProfileRequest{})
}
ue.POST("/api/_version_/fleet/mdm/apple/dep/key_pair", newMDMAppleDEPKeyPairEndpoint, nil)
ue.GET("/api/_version_/fleet/mdm/apple", getAppleMDMEndpoint, nil)
ue.GET("/api/_version_/fleet/mdm/apple_bm", getAppleBMEndpoint, nil)
// this endpoint must always be accessible (even if MDM is not configured) as