feat: return better errors when private key not configured (#19471)

> Related issue: #19464

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

<!-- Note that API documentation changes are now addressed by the
product design team. -->

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://fleetdm.com/docs/contributing/committing-changes#changes-files)
for more information.
- [x] Added/updated tests
- [x] Manual QA for all new/changed functionality
This commit is contained in:
Jahziel Villasana-Espinoza 2024-06-04 11:06:30 -04:00 committed by GitHub
commit aac7c0435f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 67 additions and 5 deletions

View file

@ -0,0 +1 @@
- Adds clearer error messages when attempting to set up Apple MDM without a server private key configured.

View file

@ -32,7 +32,10 @@ const ApplePushCertSetup = ({
onSetupSuccess();
} catch (e) {
const msg = getErrorReason(e);
if (msg.toLowerCase().includes("invalid certificate")) {
if (
msg.toLowerCase().includes("invalid certificate") ||
msg.toLowerCase().includes("required private key")
) {
renderFlash("error", msg);
} else {
renderFlash("error", "Couldnt connect. Please try again.");
@ -46,7 +49,10 @@ const ApplePushCertSetup = ({
const onDownloadError = useCallback(
(e: unknown) => {
const msg = getErrorReason(e);
if (msg.toLowerCase().includes("email address")) {
if (
msg.toLowerCase().includes("email address") ||
msg.toLowerCase().includes("required private key")
) {
renderFlash("error", msg);
} else {
renderFlash("error", "Somethings gone wrong. Please try again.");

View file

@ -1,6 +1,14 @@
import React, { FormEvent, useCallback, useMemo, useState } from "react";
import React, {
FormEvent,
useCallback,
useMemo,
useState,
useContext,
} from "react";
import mdmAppleBusinessManagerApi from "services/entities/mdm_apple_bm";
import { NotificationContext } from "context/notification";
import { getErrorReason } from "interfaces/errors";
import Icon from "components/Icon";
import Button from "components/buttons/Button";
@ -23,6 +31,7 @@ const useDownloadABMKey = ({
onError,
}: Omit<IDownloadABMKeyProps, "baseClass">) => {
const [downloadState, setDownloadState] = useState<RequestState>(undefined);
const { renderFlash } = useContext(NotificationContext);
const handleDownload = useCallback(
async (evt: FormEvent) => {
@ -34,6 +43,8 @@ const useDownloadABMKey = ({
setDownloadState("success");
onSuccess && onSuccess();
} catch (e) {
const msg = getErrorReason(e);
renderFlash("error", msg);
setDownloadState("error");
onError && onError(e);
}

View file

@ -3592,6 +3592,16 @@ func (svc *Service) GenerateABMKeyPair(ctx context.Context) (*fleet.MDMAppleDEPK
if err := svc.authz.Authorize(ctx, &fleet.AppleBM{}, fleet.ActionWrite); err != nil {
return nil, err
}
privateKey := svc.config.Server.PrivateKey
if testSetEmptyPrivateKey {
privateKey = ""
}
if len(privateKey) == 0 {
return nil, ctxerr.New(ctx, "Couldn't download public key. Missing required private key. Learn how to configure the private key here: https://fleetdm.com/learn-more-about/fleet-server-private-key")
}
var publicKeyPEM, privateKeyPEM []byte
assets, err := svc.ds.GetAllMDMConfigAssetsByName(ctx, []fleet.MDMAssetName{
fleet.MDMAssetABMCert,

View file

@ -936,6 +936,15 @@ func (s *integrationMDMTestSuite) TestGetMDMCSR() {
t := s.T()
ctx := context.Background()
// Validate errors if no private key is set
testSetEmptyPrivateKey = true
t.Cleanup(func() { testSetEmptyPrivateKey = false })
s.uploadAPNSCert([]byte("-----BEGIN CERTIFICATE-----\nZm9vCg==\n-----END CERTIFICATE-----"), http.StatusInternalServerError, "Couldn't upload APNs certificate. Missing required private key. Learn how to configure the private key here: https://fleetdm.com/learn-more-about/fleet-server-private-key")
r := s.Do("GET", "/api/latest/fleet/mdm/apple/request_csr", getMDMAppleCSRRequest{}, http.StatusInternalServerError)
require.Contains(t, extractServerErrorText(r.Body), "Couldn't download signed CSR. Missing required private key. Learn how to configure the private key here: https://fleetdm.com/learn-more-about/fleet-server-private-key")
testSetEmptyPrivateKey = false
// ensure we leave everything in a clean state for other tests
t.Cleanup(s.appleCoreCertsSetup)
@ -8674,6 +8683,14 @@ func (s *integrationMDMTestSuite) TestABMAssetManagement() {
// ensure enable ABM again for other tests
t.Cleanup(s.enableABM)
// Validate error when server private key not set
testSetEmptyPrivateKey = true
t.Cleanup(func() { testSetEmptyPrivateKey = false })
r := s.Do("GET", "/api/latest/fleet/mdm/apple/abm_public_key", generateABMKeyPairResponse{}, http.StatusInternalServerError)
require.Contains(t, extractServerErrorText(r.Body), "Couldn't download public key. Missing required private key. Learn how to configure the private key here: https://fleetdm.com/learn-more-about/fleet-server-private-key")
testSetEmptyPrivateKey = false
// grab the current public key
var abmResp generateABMKeyPairResponse
s.DoJSON("GET", "/api/latest/fleet/mdm/apple/abm_public_key", nil, http.StatusOK, &abmResp)

View file

@ -2120,6 +2120,9 @@ func (svc *Service) ResendHostMDMProfile(ctx context.Context, hostID uint, profi
// GET /mdm/apple/request_csr
////////////////////////////////////////////////////////////////////////////////
// Used for overriding the env var value in testing
var testSetEmptyPrivateKey bool
type getMDMAppleCSRRequest struct{}
type getMDMAppleCSRResponse struct {
@ -2143,8 +2146,13 @@ func (svc *Service) GetMDMAppleCSR(ctx context.Context) ([]byte, error) {
return nil, err
}
if len(svc.config.Server.PrivateKey) == 0 {
return nil, ctxerr.New(ctx, "no private key configured")
privateKey := svc.config.Server.PrivateKey
if testSetEmptyPrivateKey {
privateKey = ""
}
if len(privateKey) == 0 {
return nil, ctxerr.New(ctx, "Couldn't download signed CSR. Missing required private key. Learn how to configure the private key here: https://fleetdm.com/learn-more-about/fleet-server-private-key")
}
vc, ok := viewer.FromContext(ctx)
@ -2298,6 +2306,15 @@ func (svc *Service) UploadMDMAppleAPNSCert(ctx context.Context, cert io.ReadSeek
return err
}
privateKey := svc.config.Server.PrivateKey
if testSetEmptyPrivateKey {
privateKey = ""
}
if len(privateKey) == 0 {
return ctxerr.New(ctx, "Couldn't upload APNs certificate. Missing required private key. Learn how to configure the private key here: https://fleetdm.com/learn-more-about/fleet-server-private-key")
}
if cert == nil {
return ctxerr.Wrap(ctx, fleet.NewInvalidArgumentError("certificate", "Invalid certificate. Please provide a valid certificate from Apple Push Certificate Portal."))
}