From f5cf1566532369008b510bb34ed60f0eea456298 Mon Sep 17 00:00:00 2001 From: Roberto Dip Date: Fri, 15 Mar 2024 17:10:48 -0300 Subject: [PATCH] improve mdmtest package to handle any kind of command (#17673) it delegates any extra unmarshaling to the caller. We might consider building our own types in the future instead of relying on micromdm, but these are used only for tests right now. --- pkg/mdm/mdmtest/apple.go | 12 +++---- server/service/integration_mdm_test.go | 47 +++++++++++++++++--------- 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/pkg/mdm/mdmtest/apple.go b/pkg/mdm/mdmtest/apple.go index c9c0e5427..b21321898 100644 --- a/pkg/mdm/mdmtest/apple.go +++ b/pkg/mdm/mdmtest/apple.go @@ -31,7 +31,6 @@ import ( httptransport "github.com/go-kit/kit/transport/http" "github.com/google/uuid" "github.com/groob/plist" - micromdm "github.com/micromdm/micromdm/mdm/mdm" "go.mozilla.org/pkcs7" ) @@ -421,7 +420,7 @@ func (c *TestAppleMDMClient) Checkout() error { // receive commands. The server can signal back with either a command to run // or an empty (nil, nil) response body to end the communication // (i.e. no commands to run). -func (c *TestAppleMDMClient) Idle() (*micromdm.CommandPayload, error) { +func (c *TestAppleMDMClient) Idle() (*mdm.Command, error) { payload := map[string]any{ "Status": "Idle", "Topic": "com.apple.mgmt.External." + c.UUID, @@ -437,7 +436,7 @@ func (c *TestAppleMDMClient) Idle() (*micromdm.CommandPayload, error) { // The server can signal back with either a command to run // or an empty (nil, nil) response body to end the communication // (i.e. no commands to run). -func (c *TestAppleMDMClient) Acknowledge(cmdUUID string) (*micromdm.CommandPayload, error) { +func (c *TestAppleMDMClient) Acknowledge(cmdUUID string) (*mdm.Command, error) { payload := map[string]any{ "Status": "Acknowledged", "Topic": "com.apple.mgmt.External." + c.UUID, @@ -490,7 +489,7 @@ func (c *TestAppleMDMClient) GetBootstrapToken() ([]byte, error) { // The server can signal back with either a command to run // or an empty (nil, nil) response body to end the communication // (i.e. no commands to run). -func (c *TestAppleMDMClient) Err(cmdUUID string, errChain []mdm.ErrorChain) (*micromdm.CommandPayload, error) { +func (c *TestAppleMDMClient) Err(cmdUUID string, errChain []mdm.ErrorChain) (*mdm.Command, error) { payload := map[string]any{ "Status": "Error", "Topic": "com.apple.mgmt.External." + c.UUID, @@ -502,7 +501,7 @@ func (c *TestAppleMDMClient) Err(cmdUUID string, errChain []mdm.ErrorChain) (*mi return c.sendAndDecodeCommandResponse(payload) } -func (c *TestAppleMDMClient) sendAndDecodeCommandResponse(payload map[string]any) (*micromdm.CommandPayload, error) { +func (c *TestAppleMDMClient) sendAndDecodeCommandResponse(payload map[string]any) (*mdm.Command, error) { res, err := c.request("", payload) if err != nil { return nil, fmt.Errorf("request error: %w", err) @@ -527,11 +526,12 @@ func (c *TestAppleMDMClient) sendAndDecodeCommandResponse(payload map[string]any if err != nil { return nil, fmt.Errorf("decode command: %w", err) } - var p micromdm.CommandPayload + var p mdm.Command err = plist.Unmarshal(cmd.Raw, &p) if err != nil { return nil, fmt.Errorf("unmarshal command payload: %w", err) } + p.Raw = cmd.Raw return &p, nil } diff --git a/server/service/integration_mdm_test.go b/server/service/integration_mdm_test.go index 4aca6ea83..782ee6dc1 100644 --- a/server/service/integration_mdm_test.go +++ b/server/service/integration_mdm_test.go @@ -1248,7 +1248,7 @@ func (s *integrationMDMTestSuite) TestWindowsProfileRetries() { } func checkNextPayloads(t *testing.T, mdmDevice *mdmtest.TestAppleMDMClient, forceDeviceErr bool) ([][]byte, []string) { - var cmd *micromdm.CommandPayload + var cmd *mdm.Command var err error installs := [][]byte{} removes := []string{} @@ -1273,11 +1273,13 @@ func checkNextPayloads(t *testing.T, mdmDevice *mdmtest.TestAppleMDMClient, forc break } + var fullCmd micromdm.CommandPayload + require.NoError(t, plist.Unmarshal(cmd.Raw, &fullCmd)) switch cmd.Command.RequestType { case "InstallProfile": - installs = append(installs, cmd.Command.InstallProfile.Payload) + installs = append(installs, fullCmd.Command.InstallProfile.Payload) case "RemoveProfile": - removes = append(removes, cmd.Command.RemoveProfile.Identifier) + removes = append(removes, fullCmd.Command.RemoveProfile.Identifier) } } @@ -2008,13 +2010,12 @@ func (s *integrationMDMTestSuite) TestDEPProfileAssignment() { // run the worker to assign configuration profiles s.awaitTriggerProfileSchedule(t) - var fleetdCmd, installProfileCmd *micromdm.CommandPayload + var fleetdCmd, installProfileCmd *mdm.Command cmd, err := mdmDevice.Idle() require.NoError(t, err) for cmd != nil { if cmd.Command.RequestType == "InstallEnterpriseApplication" && - cmd.Command.InstallEnterpriseApplication.ManifestURL != nil && - strings.Contains(*cmd.Command.InstallEnterpriseApplication.ManifestURL, apple_mdm.FleetdPublicManifestURL) { + strings.Contains(string(cmd.Raw), apple_mdm.FleetdPublicManifestURL) { fleetdCmd = cmd } else if cmd.Command.RequestType == "InstallProfile" { installProfileCmd = cmd @@ -5874,9 +5875,13 @@ func (s *integrationMDMTestSuite) TestBootstrapPackageStatus() { cmd, err := d.device.Idle() require.NoError(t, err) for cmd != nil { + var fullCmd micromdm.CommandPayload + require.NoError(t, plist.Unmarshal(cmd.Raw, &fullCmd)) + // if the command is to install the bootstrap package - if manifest := cmd.Command.InstallEnterpriseApplication.Manifest; manifest != nil { + if manifest := fullCmd.Command.InstallEnterpriseApplication.Manifest; manifest != nil { require.Equal(t, "InstallEnterpriseApplication", cmd.Command.RequestType) + require.NotNil(t, manifest) require.Equal(t, "software-package", (*manifest).ManifestItems[0].Assets[0].Kind) wantURL, err := bp.URL(s.server.URL) require.NoError(t, err) @@ -7406,7 +7411,7 @@ func (s *integrationMDMTestSuite) TestSSO() { s.runWorker() // ask for commands and verify that we get AccountConfiguration - var accCmd *micromdm.CommandPayload + var accCmd *mdm.Command cmd, err := mdmDevice.Idle() require.NoError(t, err) for cmd != nil { @@ -7418,9 +7423,12 @@ func (s *integrationMDMTestSuite) TestSSO() { } require.NotNil(t, accCmd) require.NotNil(t, accCmd.Command) - require.True(t, accCmd.Command.AccountConfiguration.LockPrimaryAccountInfo) - require.Equal(t, "SSO User 1", accCmd.Command.AccountConfiguration.PrimaryAccountFullName) - require.Equal(t, "sso_user", accCmd.Command.AccountConfiguration.PrimaryAccountUserName) + + var fullAccCmd *micromdm.CommandPayload + require.NoError(t, plist.Unmarshal(accCmd.Raw, &fullAccCmd)) + require.True(t, fullAccCmd.Command.AccountConfiguration.LockPrimaryAccountInfo) + require.Equal(t, "SSO User 1", fullAccCmd.Command.AccountConfiguration.PrimaryAccountFullName) + require.Equal(t, "sso_user", fullAccCmd.Command.AccountConfiguration.PrimaryAccountUserName) // report host details for the device var hostResp getHostResponse @@ -11568,10 +11576,12 @@ func (s *integrationMDMTestSuite) TestManualEnrollmentCommands() { cmd, err := mdmDevice.Idle() require.NoError(t, err) for cmd != nil { - if manifest := cmd.Command.InstallEnterpriseApplication.ManifestURL; manifest != nil { + var fullCmd micromdm.CommandPayload + require.NoError(t, plist.Unmarshal(cmd.Raw, &fullCmd)) + if manifest := fullCmd.Command.InstallEnterpriseApplication.ManifestURL; manifest != nil { foundInstallFleetdCommand = true require.Equal(t, "InstallEnterpriseApplication", cmd.Command.RequestType) - require.Contains(t, *cmd.Command.InstallEnterpriseApplication.ManifestURL, apple_mdm.FleetdPublicManifestURL) + require.Contains(t, *fullCmd.Command.InstallEnterpriseApplication.ManifestURL, apple_mdm.FleetdPublicManifestURL) } cmd, err = mdmDevice.Acknowledge(cmd.CommandUUID) require.NoError(t, err) @@ -12245,7 +12255,10 @@ func (s *integrationMDMTestSuite) TestDontIgnoreAnyProfileErrors() { for cmd != nil { if cmd.Command.RequestType == "RemoveProfile" { var errChain []mdm.ErrorChain - if cmd.Command.RemoveProfile.Identifier == "I1" { + var fullCmd micromdm.CommandPayload + require.NoError(t, plist.Unmarshal(cmd.Raw, &fullCmd)) + + if fullCmd.Command.RemoveProfile.Identifier == "I1" { errChain = append(errChain, mdm.ErrorChain{ErrorCode: 89, ErrorDomain: "MDMClientError", USEnglishDescription: "Profile with identifier 'I1' not found."}) } else { errChain = append(errChain, mdm.ErrorChain{ErrorCode: 96, ErrorDomain: "MDMClientError", USEnglishDescription: "Cannot replace profile 'I2' because it was not installed by the MDM server."}) @@ -12375,7 +12388,7 @@ func (s *integrationMDMTestSuite) TestSCEPCertExpiration() { require.NoError(t, err) checkRenewCertCommand := func(device *mdmtest.TestAppleMDMClient, enrollRef string) { - var renewCmd *micromdm.CommandPayload + var renewCmd *mdm.Command cmd, err := device.Idle() require.NoError(t, err) for cmd != nil { @@ -12386,7 +12399,9 @@ func (s *integrationMDMTestSuite) TestSCEPCertExpiration() { require.NoError(t, err) } require.NotNil(t, renewCmd) - s.verifyEnrollmentProfile(renewCmd.Command.InstallProfile.Payload, enrollRef) + var fullCmd micromdm.CommandPayload + require.NoError(t, plist.Unmarshal(renewCmd.Raw, &fullCmd)) + s.verifyEnrollmentProfile(fullCmd.Command.InstallProfile.Payload, enrollRef) } checkRenewCertCommand(manualEnrolledDevice, "")