From 01b3a6e2d2016a32c2de74f0f63b293c88a7c144 Mon Sep 17 00:00:00 2001 From: Victor Lyuboslavsky Date: Tue, 20 May 2025 21:50:48 +0200 Subject: [PATCH] Remove webview when IdP not enabled. (#29283) For #26996 and #28452 Demo video: https://www.youtube.com/shorts/WGS3JmKiZTs The device/machine info is extracted from the PKCS7 signed body of the POST request. I did manual QA on iPhone since I don't have an ADE macOS device with me. # Checklist for submitter - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) - [x] Added/updated automated tests - [x] Manual QA for all new/changed functionality --- changes/26996-and-28452-skip-webview-popup | 1 + pkg/mdm/mdmtest/apple.go | 78 +++++++++++++++++----- server/datastore/mysql/hosts.go | 1 + server/datastore/mysql/hosts_test.go | 6 ++ server/mdm/apple/apple_mdm.go | 22 +++--- server/mdm/apple/apple_mdm_test.go | 3 +- server/mdm/apple/deviceinfo.go | 4 ++ server/service/apple_mdm.go | 22 ++++++ server/service/handler.go | 1 + server/service/integration_mdm_dep_test.go | 62 +++++++++-------- server/service/integration_mdm_test.go | 21 ++++-- 11 files changed, 162 insertions(+), 59 deletions(-) create mode 100644 changes/26996-and-28452-skip-webview-popup diff --git a/changes/26996-and-28452-skip-webview-popup b/changes/26996-and-28452-skip-webview-popup new file mode 100644 index 0000000000..6d57f4b1e5 --- /dev/null +++ b/changes/26996-and-28452-skip-webview-popup @@ -0,0 +1 @@ +During Apple MDM enrollment, skip webview popup when end user authentication is disabled diff --git a/pkg/mdm/mdmtest/apple.go b/pkg/mdm/mdmtest/apple.go index 18ed892376..ff3d54eb48 100644 --- a/pkg/mdm/mdmtest/apple.go +++ b/pkg/mdm/mdmtest/apple.go @@ -67,6 +67,9 @@ type TestAppleMDMClient struct { // fetchEnrollmentProfileFromDEP indicates whether this simulated device will fetch // the enrollment profile from Fleet as if it were a device running the DEP flow. fetchEnrollmentProfileFromDEP bool + // fetchEnrollmentProfileFromDEPUsingPost functions the same as fetchEnrollmentProfileFromDEP + // except that it uses a POST request instead of a GET request. + fetchEnrollmentProfileFromDEPUsingPost bool // fetchEnrollmentProfileFromOTA indicates whether this simulated device will fetch // the enrollment profile from Fleet as if it were a device running the OTA flow. @@ -96,6 +99,13 @@ func TestMDMAppleClientDebug() TestMDMAppleClientOption { } } +func WithEnrollmentProfileFromDEPUsingPost() TestMDMAppleClientOption { + return func(c *TestAppleMDMClient) { + c.fetchEnrollmentProfileFromDEPUsingPost = true + c.fetchEnrollmentProfileFromDEP = false + } +} + // AppleEnrollInfo contains the necessary information to enroll to an MDM server. type AppleEnrollInfo struct { // SCEPChallenge is the SCEP challenge to present to the SCEP server when enrolling. @@ -195,6 +205,10 @@ func (c *TestAppleMDMClient) Enroll() error { if err := c.fetchEnrollmentProfileFromDesktopURL(); err != nil { return fmt.Errorf("get enrollment profile from desktop URL: %w", err) } + case c.fetchEnrollmentProfileFromDEPUsingPost: + if err := c.fetchEnrollmentProfileFromDEPURLUsingPost(); err != nil { + return fmt.Errorf("get enrollment profile using POST from DEP URL: %w", err) + } case c.fetchEnrollmentProfileFromDEP: if err := c.fetchEnrollmentProfileFromDEPURL(); err != nil { return fmt.Errorf("get enrollment profile from DEP URL: %w", err) @@ -235,7 +249,20 @@ func (c *TestAppleMDMClient) fetchEnrollmentProfileFromDEPURL() error { return fmt.Errorf("test client: encoding device info: %w", err) } return c.fetchEnrollmentProfile( - apple_mdm.EnrollPath + "?token=" + c.depURLToken + "&deviceinfo=" + di, + apple_mdm.EnrollPath+"?token="+c.depURLToken+"&deviceinfo="+di, nil, + ) +} + +func (c *TestAppleMDMClient) fetchEnrollmentProfileFromDEPURLUsingPost() error { + buf, err := MachineInfoAsPKCS7(fleet.MDMAppleMachineInfo{ + Serial: c.SerialNumber, + UDID: c.UUID, + }) + if err != nil { + return fmt.Errorf("test client: encoding device info: %w", err) + } + return c.fetchEnrollmentProfile( + apple_mdm.EnrollPath+"?token="+c.depURLToken, buf, ) } @@ -400,10 +427,19 @@ func (c *TestAppleMDMClient) fetchOTAProfile(url string) error { return nil } -func (c *TestAppleMDMClient) fetchEnrollmentProfile(path string) error { - request, err := http.NewRequest("GET", c.fleetServerURL+path, nil) - if err != nil { - return fmt.Errorf("create request: %w", err) +func (c *TestAppleMDMClient) fetchEnrollmentProfile(path string, body []byte) (err error) { + var request *http.Request + if len(body) > 0 { + request, err = http.NewRequest("POST", c.fleetServerURL+path, bytes.NewReader(body)) + if err != nil { + return fmt.Errorf("create request: %w", err) + } + request.Header.Set("Content-Type", "application/pkcs7-signature") + } else { + request, err = http.NewRequest("GET", c.fleetServerURL+path, nil) + if err != nil { + return fmt.Errorf("create request: %w", err) + } } // #nosec (this client is used for testing only) cc := fleethttp.NewClient(fleethttp.WithTLSClientConfig(&tls.Config{ @@ -417,7 +453,7 @@ func (c *TestAppleMDMClient) fetchEnrollmentProfile(path string) error { if response.StatusCode != http.StatusOK { return fmt.Errorf("request error: %d, %s", response.StatusCode, response.Status) } - body, err := io.ReadAll(response.Body) + rspBody, err := io.ReadAll(response.Body) if err != nil { return fmt.Errorf("read body: %w", err) } @@ -425,9 +461,9 @@ func (c *TestAppleMDMClient) fetchEnrollmentProfile(path string) error { return fmt.Errorf("close body: %w", err) } - rawProfile := body + rawProfile := rspBody if !bytes.HasPrefix(rawProfile, []byte("