implement logic to sign apple profiles (#16490)

#10418
This commit is contained in:
Roberto Dip
2024-04-18 18:01:37 -03:00
committed by GitHub
parent e0bcf05242
commit e39f5bce3b
23 changed files with 4791 additions and 4378 deletions
+12 -1
View File
@@ -1014,6 +1014,7 @@ func newMDMProfileManager(
commander *apple_mdm.MDMAppleCommander,
logger kitlog.Logger,
loggingDebug bool,
cfg config.MDMConfig,
) (*schedule.Schedule, error) {
const (
name = string(fleet.CronMDMAppleProfileManager)
@@ -1022,12 +1023,22 @@ func newMDMProfileManager(
// cron interval as we scale to more hosts.
defaultInterval = 30 * time.Second
)
if !cfg.IsAppleSCEPSet() {
return nil, ctxerr.New(ctx, "SCEP configuration is required")
}
cert, _, _, err := cfg.AppleSCEP()
if err != nil {
return nil, ctxerr.Wrap(ctx, err, "getting Apple SCEP keypair")
}
logger = kitlog.With(logger, "cron", name)
s := schedule.New(
ctx, name, instanceID, defaultInterval, ds, ds,
schedule.WithLogger(logger),
schedule.WithJob("manage_apple_profiles", func(ctx context.Context) error {
return service.ReconcileAppleProfiles(ctx, ds, commander, logger)
return service.ReconcileAppleProfiles(ctx, ds, commander, logger, cert)
}),
schedule.WithJob("manage_apple_declarations", func(ctx context.Context) error {
return service.ReconcileAppleDeclarations(ctx, ds, commander, logger)
+6 -5
View File
@@ -546,7 +546,7 @@ the way that the Fleet server works.
} else {
mdmPushService = nanomdm_pushsvc.New(mdmStorage, mdmStorage, pushProviderFactory, nanoMDMLogger)
}
commander := apple_mdm.NewMDMAppleCommander(mdmStorage, mdmPushService)
commander := apple_mdm.NewMDMAppleCommander(mdmStorage, mdmPushService, config.MDM)
mdmCheckinAndCommandService = service.NewMDMAppleCheckinAndCommandService(ds, commander, logger)
ddmService = service.NewMDMAppleDDMService(ds, logger)
appCfg.MDM.EnabledAndConfigured = true
@@ -640,7 +640,7 @@ the way that the Fleet server works.
mailService,
clock.C,
depStorage,
apple_mdm.NewMDMAppleCommander(mdmStorage, mdmPushService),
apple_mdm.NewMDMAppleCommander(mdmStorage, mdmPushService, config.MDM),
mdmPushCertTopic,
ssoSessionStore,
profileMatcher,
@@ -697,7 +697,7 @@ the way that the Fleet server works.
func() (fleet.CronSchedule, error) {
var commander *apple_mdm.MDMAppleCommander
if appCfg.MDM.EnabledAndConfigured {
commander = apple_mdm.NewMDMAppleCommander(mdmStorage, mdmPushService)
commander = apple_mdm.NewMDMAppleCommander(mdmStorage, mdmPushService, config.MDM)
}
return newCleanupsAndAggregationSchedule(
ctx, instanceID, ds, logger, redisWrapperDS, &config, commander,
@@ -740,7 +740,7 @@ the way that the Fleet server works.
if err := cronSchedules.StartCronSchedule(func() (fleet.CronSchedule, error) {
var commander *apple_mdm.MDMAppleCommander
if appCfg.MDM.EnabledAndConfigured {
commander = apple_mdm.NewMDMAppleCommander(mdmStorage, mdmPushService)
commander = apple_mdm.NewMDMAppleCommander(mdmStorage, mdmPushService, config.MDM)
}
return newWorkerIntegrationsSchedule(ctx, instanceID, ds, logger, depStorage, commander)
}); err != nil {
@@ -761,9 +761,10 @@ the way that the Fleet server works.
ctx,
instanceID,
ds,
apple_mdm.NewMDMAppleCommander(mdmStorage, mdmPushService),
apple_mdm.NewMDMAppleCommander(mdmStorage, mdmPushService, config.MDM),
logger,
config.Logging.Debug,
config.MDM,
)
}); err != nil {
initFatal(err, "failed to register mdm_apple_profile_manager schedule")
+6
View File
@@ -1156,5 +1156,11 @@ func (svc *Service) GetMDMManualEnrollmentProfile(ctx context.Context) ([]byte,
return nil, ctxerr.Wrap(ctx, err)
}
// NOTE: the profile returned by this endpoint is intentionally not
// signed so it can be modified and signed by the IT admin with a
// custom certificate.
//
// Per @marko-lisica, we can add a parameter like `signed=true` if the
// need arises.
return mobileConfig, nil
}
+17 -1
View File
@@ -214,7 +214,23 @@ func (c *TestAppleMDMClient) fetchEnrollmentProfile(path string) error {
if err := response.Body.Close(); err != nil {
return fmt.Errorf("close body: %w", err)
}
enrollInfo, err := ParseEnrollmentProfile(body)
rawProfile := body
if !bytes.HasPrefix(rawProfile, []byte("<?xml")) {
p7, err := pkcs7.Parse(body)
if err != nil {
return fmt.Errorf("enrollment profile is not XML nor PKCS7 parseable: %w", err)
}
err = p7.Verify()
if err != nil {
return err
}
rawProfile = p7.Content
}
enrollInfo, err := ParseEnrollmentProfile(rawProfile)
if err != nil {
return fmt.Errorf("parse enrollment profile: %w", err)
}
+4 -4
View File
@@ -366,9 +366,9 @@ COALESCE(status, '%s') AS status,
COALESCE(operation_type, '') AS operation_type,
COALESCE(detail, '') AS detail
FROM
host_mdm_apple_profiles
host_mdm_apple_profiles
WHERE
host_uuid = ? AND NOT (operation_type = '%s' AND COALESCE(status, '%s') IN('%s', '%s'))
host_uuid = ? AND NOT (operation_type = '%s' AND COALESCE(status, '%s') IN('%s', '%s'))
UNION ALL
SELECT
@@ -383,9 +383,9 @@ COALESCE(status, '%s') AS status,
COALESCE(operation_type, '') AS operation_type,
COALESCE(detail, '') AS detail
FROM
host_mdm_apple_declarations
host_mdm_apple_declarations
WHERE
host_uuid = ? AND declaration_name NOT IN (?) AND NOT (operation_type = '%s' AND COALESCE(status, '%s') IN('%s', '%s'))`,
host_uuid = ? AND declaration_name NOT IN (?) AND NOT (operation_type = '%s' AND COALESCE(status, '%s') IN('%s', '%s'))`,
fleet.MDMDeliveryPending,
fleet.MDMOperationTypeRemove,
fleet.MDMDeliveryPending,
+2 -1
View File
@@ -14,6 +14,7 @@ import (
"github.com/VividCortex/mysqlerr"
"github.com/fleetdm/fleet/v4/pkg/optjson"
"github.com/fleetdm/fleet/v4/server/config"
"github.com/fleetdm/fleet/v4/server/fleet"
fleetmdm "github.com/fleetdm/fleet/v4/server/mdm"
apple_mdm "github.com/fleetdm/fleet/v4/server/mdm/apple"
@@ -2999,7 +3000,7 @@ func createMDMAppleCommanderAndStorage(t *testing.T, ds *Datastore) (*apple_mdm.
mdmStorage, err := ds.NewMDMAppleMDMStorage(testCertPEM, testKeyPEM)
require.NoError(t, err)
return apple_mdm.NewMDMAppleCommander(mdmStorage, pusherFunc(okPusherFunc)), mdmStorage
return apple_mdm.NewMDMAppleCommander(mdmStorage, pusherFunc(okPusherFunc), config.MDMConfig{}), mdmStorage
}
func okPusherFunc(ctx context.Context, ids []string) (map[string]*push.Response, error) {
+5
View File
@@ -32,6 +32,11 @@ func TestMDMAppleConfigProfile(t *testing.T) {
mobileconfig: MobileconfigForTest("ValidName", "ValidIdentifier", uuid.NewString(), ""),
shouldFail: false,
},
{
testName: "TestParseConfigProfileLeadingSpace",
mobileconfig: append([]byte{' '}, []byte(MobileconfigForTest("ValidName", "ValidIdentifier", uuid.NewString(), ""))...),
shouldFail: false,
},
{
testName: "TestParseConfigProfileNoIdentifier",
mobileconfig: MobileconfigForTest("ValidName", "", uuid.NewString(), ""),
+11 -3
View File
@@ -6,6 +6,7 @@ import (
"fmt"
"net/http"
"github.com/fleetdm/fleet/v4/server/config"
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/mdm/apple/appmanifest"
@@ -29,21 +30,28 @@ type commandPayload struct {
// the caller.
type MDMAppleCommander struct {
storage fleet.MDMAppleStore
config config.MDMConfig
pusher nanomdm_push.Pusher
}
// NewMDMAppleCommander creates a new commander instance.
func NewMDMAppleCommander(mdmStorage fleet.MDMAppleStore, mdmPushService nanomdm_push.Pusher) *MDMAppleCommander {
func NewMDMAppleCommander(mdmStorage fleet.MDMAppleStore, mdmPushService nanomdm_push.Pusher, config config.MDMConfig) *MDMAppleCommander {
return &MDMAppleCommander{
storage: mdmStorage,
pusher: mdmPushService,
config: config,
}
}
// InstallProfile sends the homonymous MDM command to the given hosts, it also
// takes care of the base64 encoding of the provided profile bytes.
func (svc *MDMAppleCommander) InstallProfile(ctx context.Context, hostUUIDs []string, profile mobileconfig.Mobileconfig, uuid string) error {
base64Profile := base64.StdEncoding.EncodeToString(profile)
signedProfile, err := mobileconfig.Sign(profile, svc.config)
if err != nil {
return ctxerr.Wrap(ctx, err, "signing profile")
}
base64Profile := base64.StdEncoding.EncodeToString(signedProfile)
raw := fmt.Sprintf(`<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
@@ -59,7 +67,7 @@ func (svc *MDMAppleCommander) InstallProfile(ctx context.Context, hostUUIDs []st
</dict>
</dict>
</plist>`, uuid, base64Profile)
err := svc.EnqueueCommand(ctx, hostUUIDs, raw)
err = svc.EnqueueCommand(ctx, hostUUIDs, raw)
return ctxerr.Wrap(ctx, err, "commander install profile")
}
+13 -3
View File
@@ -3,10 +3,10 @@ package apple_mdm
import (
"context"
"crypto/tls"
"encoding/base64"
"fmt"
"testing"
"github.com/fleetdm/fleet/v4/server/config"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/mdm/nanomdm/log/stdlogfmt"
"github.com/fleetdm/fleet/v4/server/mdm/nanomdm/mdm"
@@ -15,7 +15,10 @@ import (
"github.com/fleetdm/fleet/v4/server/mock"
svcmock "github.com/fleetdm/fleet/v4/server/service/mock"
"github.com/google/uuid"
"github.com/groob/plist"
micromdm "github.com/micromdm/micromdm/mdm/mdm"
"github.com/stretchr/testify/require"
"go.mozilla.org/pkcs7"
)
func TestMDMAppleCommander(t *testing.T) {
@@ -28,7 +31,10 @@ func TestMDMAppleCommander(t *testing.T) {
pushFactory,
stdlogfmt.New(),
)
cmdr := NewMDMAppleCommander(mdmStorage, pusher)
cmdr := NewMDMAppleCommander(mdmStorage, pusher, config.MDMConfig{
AppleSCEPCert: "../../service/testdata/server.pem",
AppleSCEPKey: "../../service/testdata/server.key",
})
// TODO(roberto): there's a data race in the mock when more
// than one host ID is provided because the pusher uses one
@@ -41,7 +47,11 @@ func TestMDMAppleCommander(t *testing.T) {
mdmStorage.EnqueueCommandFunc = func(ctx context.Context, id []string, cmd *mdm.Command) (map[string]error, error) {
require.NotNil(t, cmd)
require.Equal(t, cmd.Command.RequestType, "InstallProfile")
require.Contains(t, string(cmd.Raw), base64.StdEncoding.EncodeToString(mc))
var fullCmd micromdm.CommandPayload
require.NoError(t, plist.Unmarshal(cmd.Raw, &fullCmd))
p7, err := pkcs7.Parse(fullCmd.Command.InstallProfile.Payload)
require.NoError(t, err)
require.Equal(t, string(p7.Content), string(mc))
return nil, nil
}
+29 -3
View File
@@ -6,7 +6,9 @@ import (
"fmt"
"strings"
"github.com/fleetdm/fleet/v4/server/config"
"github.com/fleetdm/fleet/v4/server/mdm"
"github.com/micromdm/micromdm/pkg/crypto/profileutil"
"go.mozilla.org/pkcs7"
"howett.net/plist"
)
@@ -20,6 +22,9 @@ const (
// by fleetd to read configuration values from the system.
FleetdConfigPayloadIdentifier = "com.fleetdm.fleetd.config"
// FleetCARootConfigPayloadIdentifier TODO
FleetCARootConfigPayloadIdentifier = "com.fleetdm.caroot"
// FleetEnrollmentPayloadIdentifier is the value for the PayloadIdentifier used
// by Fleet to enroll a device with the MDM server.
FleetEnrollmentPayloadIdentifier = "com.fleetdm.fleet.mdm.apple.mdm"
@@ -43,8 +48,9 @@ const (
// files around due to import cycles.
func FleetPayloadIdentifiers() map[string]struct{} {
return map[string]struct{}{
FleetFileVaultPayloadIdentifier: {},
FleetdConfigPayloadIdentifier: {},
FleetFileVaultPayloadIdentifier: {},
FleetdConfigPayloadIdentifier: {},
FleetCARootConfigPayloadIdentifier: {},
}
}
@@ -83,7 +89,7 @@ type Parsed struct {
// Adapted from https://github.com/micromdm/micromdm/blob/main/platform/profile/profile.go
func (mc Mobileconfig) ParseConfigProfile() (*Parsed, error) {
mcBytes := mc
if !bytes.HasPrefix(mcBytes, []byte("<?xml")) {
if !bytes.HasPrefix(bytes.TrimSpace(mcBytes), []byte("<?xml")) {
p7, err := pkcs7.Parse(mcBytes)
if err != nil {
return nil, fmt.Errorf("mobileconfig is not XML nor PKCS7 parseable: %w", err)
@@ -247,3 +253,23 @@ var (
ErrEmptyPayloadContent = errors.New("empty PayloadContent")
ErrEncryptedPayloadContent = errors.New("encrypted PayloadContent")
)
// Sign signs an enrollment profile using the SCEP certificate from the
// provided MDM config.
func Sign(profile []byte, cfg config.MDMConfig) ([]byte, error) {
if !cfg.IsAppleSCEPSet() {
return nil, errors.New("SCEP configuration is required")
}
cert, _, _, err := cfg.AppleSCEP()
if err != nil {
return nil, fmt.Errorf("retrieving SCEP certificate from config: %w", err)
}
signed, err := profileutil.Sign(cert.PrivateKey, cert.Leaf, profile)
if err != nil {
return nil, fmt.Errorf("signing profile with the specified key: %w", err)
}
return signed, nil
}
@@ -0,0 +1,110 @@
package mobileconfig
import (
"strings"
"testing"
"github.com/fleetdm/fleet/v4/server/config"
"github.com/stretchr/testify/require"
)
func TestSign(t *testing.T) {
tests := []struct {
name string
config config.MDMConfig
profile []byte
expectError bool
}{
{
name: "SCEP not set",
config: config.MDMConfig{},
profile: []byte("profile data"),
expectError: true,
},
{
name: "Error with invalid certificate",
config: config.MDMConfig{AppleSCEPCertBytes: "foo", AppleSCEPKeyBytes: "bar"},
profile: []byte("profile data"),
expectError: true,
},
{
name: "Successful signing",
config: config.MDMConfig{
AppleSCEPCertBytes: string(testCert),
AppleSCEPKeyBytes: string(testKey),
},
profile: []byte("profile data"),
expectError: false,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
result, err := Sign(tc.profile, tc.config)
if tc.expectError {
require.Error(t, err)
} else {
require.NoError(t, err)
require.NotNil(t, result)
}
})
}
}
var (
testCert = []byte(`-----BEGIN CERTIFICATE-----
MIID6DCCAdACFGX99Sw4aF2qKGLucoIWQRAXHrs1MA0GCSqGSIb3DQEBCwUAMDUx
EzARBgNVBAoMClJlZGlzIFRlc3QxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhv
cml0eTAeFw0yMTEwMTkxNzM0MzlaFw0yMjEwMTkxNzM0MzlaMCwxEzARBgNVBAoM
ClJlZGlzIFRlc3QxFTATBgNVBAMMDEdlbmVyaWMtY2VydDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAKSHcH8EjSvp3Nm4IHAFxG9DZm8+0h1BwU0OX0VH
cJ+Cf+f6h0XYMcMo9LFEpnUJRRMjKrM4mkI75NIIufNBN+GrtqqTPTid8wfOGu/U
fa5EEU1hb2j7AiMlpM6i0+ZysXSNo+Vc/cNZT0PXfyOtJnYm6p9WZM84ID1t2ea0
bLwC12cTKv5oybVGtJHh76TRxAR3FeQ9+SY30vUAxYm6oWyYho8rRdKtUSe11pXj
6OhxxfTZnsSWn4lo0uBpXai63XtieTVpz74htSNC1bunIGv7//m5F60sH5MrF5JS
kPxfCfgqski84ICDSRNlvpT+eMPiygAAJ8zY8wYUXRYFYTUCAwEAATANBgkqhkiG
9w0BAQsFAAOCAgEAAAw+6Uz2bAcXgQ7fQfdOm+T6FLRBcr8PD4ajOvSu/T+HhVVj
E26Qt2IBwFEYve2FvDxrBCF8aQYZcyQqnP8bdKebnWAaqL8BbTwLWW+fDuZLO2b4
QHjAEdEKKdZC5/FRpQrkerf5CCPTHE+5M17OZg41wdVYnCEwJOkP5pUAVsmwtrSw
VeIquy20TZO0qbscDQETf7NIJgW0IXg82wBe53Rv4/wL3Ybq13XVRGYiJrwpaNTf
UNgsDWqgwlQ5L2GOLDgg8S2NoF9mWVgCGSp3a2eHW+EmBRQ1OP6EYQtIhKdGLrSn
dAOMJ2ER1pgHWUFKkWQaZ9i37Dx2j7P5c4/XNeVozcRQcLwKwN+n8k+bwIYcTX0H
MOVFYm+WiFi/gjI860Tx853Sc0nkpOXmBCeHSXigGUscgjBYbmJz4iExXuwgawLX
KLDKs0yyhLDnKEjmx/Vhz03JpsVFJ84kSWkTZkYsXiG306TxuJCX9zAt1z+6Clie
TTGiFY+D8DfkC4H82rlPEtImpZ6rInsMUlAykImpd58e4PMSa+w/wSHXDvwFP7py
1Gvz3XvcbGLmpBXblxTUpToqC7zSQJhHOMBBt6XnhcRwd6G9Vj/mQM3FvJIrxtKk
8O7FwMJloGivS85OEzCIur5A+bObXbM2pcI8y4ueHE4NtElRBwn859AdB2k=
-----END CERTIFICATE-----`)
testKey = []byte(testingKey(`-----BEGIN RSA TESTING KEY-----
MIIEogIBAAKCAQEApIdwfwSNK+nc2bggcAXEb0Nmbz7SHUHBTQ5fRUdwn4J/5/qH
Rdgxwyj0sUSmdQlFEyMqsziaQjvk0gi580E34au2qpM9OJ3zB84a79R9rkQRTWFv
aPsCIyWkzqLT5nKxdI2j5Vz9w1lPQ9d/I60mdibqn1ZkzzggPW3Z5rRsvALXZxMq
/mjJtUa0keHvpNHEBHcV5D35JjfS9QDFibqhbJiGjytF0q1RJ7XWlePo6HHF9Nme
xJafiWjS4GldqLrde2J5NWnPviG1I0LVu6cga/v/+bkXrSwfkysXklKQ/F8J+Cqy
SLzggINJE2W+lP54w+LKAAAnzNjzBhRdFgVhNQIDAQABAoIBAAtUbFHC3XnVq+iu
PkWYkBNdX9NvTwbGvWnyAGuD5OSHFwnBfck4fwzCaD9Ay/mpPsF3nXwj/LNs7m/s
O+ndZty6d2S9qOyaK98wuTgkuNbkRxC+Ee73wgjrkbLNEax/32p4Sn4D7lGid8vj
LhUl2k0ult+MEnsWkVnJk8TITeiQaT2AHhMr3HKdaI86hJJfam3wEBiLBglnnKqA
TInMqHoudnFOn/C8iVCFuHCE0oo1dMalbc4rlZuRBqezVhbSMWPLypMVXQb7eixM
ScJ3m8+DooGDSIe+EW/afhN2VnFbrhQC9/DlxGfwTwsUseWv7pgp53ufyyAzzydn
2plW/4ECgYEA1Va5RzSUDxr75JX003YZiBcYrG268vosiNYWRhE7frvn5EorZBRW
t4R70Y2gcXA10aPHzpbq40t6voWtpkfynU3fyRzbBmwfiWLEgckrYMwtcNz8nhG2
ETAg4LXO9CufbwuDa66h76TpkBzQVNc5TSbBUr/apLDWjKPMz6qW7VUCgYEAxW4K
Yqp3NgJkC5DhuD098jir9AH96hGhUryOi2CasCvmbjWCgWdolD7SRZJfxOXFOtHv
7Dkp9glA1Cg/nSmEHKslaTJfBIWK+5rqVD6k6kZE/+4QQWQtUxXXVgGINnGrnPvo
6MlRJxqGUtYJ0GRTFJP4Py0gwuzf5BMIwe+fpGECgYAOhLRfMCjTTlbOG5ZpvaPH
Kys2sNEEMBpPxaIGaq3N1iPV2WZSjT/JhW6XuDevAJ/pAGhcmtCpXz2fMaG7qzHL
mr0cBqaxLTKIOvx8iKA3Gi4NfDyE1Ve6m7fhEv5eh4l2GSZ8cYn7sRFkCVH0NCFm
KrkFVKEgjBhNwefySf2zcQKBgHDVPgw7nlv4q9LMX6RbI98eMnAG/2XZ45gUeWcA
tAeBX3WXEVoBjoxDBwuJ5z/xjXHbb8JSvT+G9E0MH6cjhgSYb44aoqFD7TV0yP2S
u8/Ej0SxewrURO8aKXJW99Edz9WtRuRbwgyWJTSMbRlzbOPy2UrJ8NJWbHK9yiCE
YXmhAoGAA3QUiCCl11c1C4VsF68Fa2i7qwnty3fvFidZpW3ds0tzZdIvkpRLp5+u
XAJ5+zStdEGdnu0iXALQlY7ektawXguT/zYKg3nfS9RMGW6CxZotn4bqfQwDuttf
b1xn1jGQd/o0xFf9ojpDNy6vNojidQGHh6E3h0GYvxbnQmVNq5U=
-----END RSA TESTING KEY-----`))
)
// prevent static analysis tools from raising issues due to detection of private key
// in code.
func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") }
+49
View File
@@ -60,3 +60,52 @@ var FleetdProfileTemplate = template.Must(template.New("").Option("missingkey=er
</dict>
</plist>
`))
// FleetCARootTemplateOptions are the keys required to execute a
// FleetCARootTemplate.
type FleetCARootTemplateOptions struct {
PayloadName string
PayloadIdentifier string
Certificate string
}
var FleetCARootTemplate = template.Must(template.New("").Option("missingkey=error").Parse(`<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PayloadContent</key>
<array>
<dict>
<key>PayloadCertificateFileName</key>
<string>CertificateRoot</string>
<key>PayloadContent</key>
<data>{{ .Certificate }}</data>
<key>PayloadDescription</key>
<string>{{ .PayloadName }}</string>
<key>PayloadDisplayName</key>
<string>{{ .PayloadName }}</string>
<key>PayloadIdentifier</key>
<string>{{ .PayloadIdentifier }}.certpayload</string>
<key>PayloadType</key>
<string>com.apple.security.root</string>
<key>PayloadUUID</key>
<string>B295992E-861A-4F92-902-17BCF4E33C61</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>AllowAllAppsAccess</key>
<false/>
</dict>
</array>
<key>PayloadDisplayName</key>
<string>{{ .PayloadName }}</string>
<key>PayloadIdentifier</key>
<string>{{ .PayloadIdentifier }}</string>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadUUID</key>
<string>4F5428DE-05B6-4965-87AD-532CAFC35FCF</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
</plist>
`))
+6 -1
View File
@@ -86,6 +86,10 @@ const (
// fleetd to read configuration values from the system.
FleetdConfigProfileName = "Fleetd configuration"
// FleetCAConfigProfileName is the value for the PayloadDisplayName used by
// fleetd to read configuration values from the system.
FleetCAConfigProfileName = "Fleet root certificate authority (CA)"
// FleetdFileVaultProfileName is the value for the PayloadDisplayName used
// by Fleet to configure FileVault and FileVault Escrow.
FleetFileVaultProfileName = "Disk encryption"
@@ -107,6 +111,7 @@ func FleetReservedProfileNames() map[string]struct{} {
FleetFileVaultProfileName: {},
FleetWindowsOSUpdatesProfileName: {},
FleetMacOSUpdatesProfileName: {},
FleetCAConfigProfileName: {},
}
}
@@ -119,7 +124,7 @@ func ListFleetReservedWindowsProfileNames() []string {
// ListFleetReservedMacOSProfileNames returns a list of PayloadDisplayName strings
// that are reserved by Fleet for macOS.
func ListFleetReservedMacOSProfileNames() []string {
return []string{FleetFileVaultProfileName, FleetdConfigProfileName}
return []string{FleetFileVaultProfileName, FleetdConfigProfileName, FleetCAConfigProfileName}
}
// ListFleetReservedMacOSDeclarationNames returns a list of declaration names
+35 -8
View File
@@ -3,6 +3,8 @@ package service
import (
"bytes"
"context"
"crypto/tls"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
@@ -1330,16 +1332,22 @@ func (svc *Service) GetMDMAppleEnrollmentProfileByToken(ctx context.Context, tok
return nil, ctxerr.Wrap(ctx, err, "adding reference to fleet URL")
}
mobileconfig, err := apple_mdm.GenerateEnrollmentProfileMobileconfig(
enrollmentProf, err := apple_mdm.GenerateEnrollmentProfileMobileconfig(
appConfig.OrgInfo.OrgName,
enrollURL,
svc.config.MDM.AppleSCEPChallenge,
svc.mdmPushCertTopic,
)
if err != nil {
return nil, ctxerr.Wrap(ctx, err)
return nil, ctxerr.Wrap(ctx, err, "generating enrollment profile")
}
return mobileconfig, nil
signed, err := mobileconfig.Sign(enrollmentProf, svc.config.MDM)
if err != nil {
return nil, ctxerr.Wrap(ctx, err, "signing profile")
}
return signed, nil
}
type mdmAppleCommandRemoveEnrollmentProfileRequest struct {
@@ -2710,7 +2718,7 @@ func mdmAppleDeliveryStatusFromCommandStatus(cmdStatus string) *fleet.MDMDeliver
}
}
// ensureFleetdConfig ensures there's a fleetd configuration profile in
// ensureFleetProfiles ensures there's a fleetd configuration profile in
// mdm_apple_configuration_profiles for each team and for "no team"
//
// We try our best to use each team's secret but we default to creating a
@@ -2720,12 +2728,26 @@ func mdmAppleDeliveryStatusFromCommandStatus(cmdStatus string) *fleet.MDMDeliver
// This profile will be installed to all hosts in the team (or "no team",) but it
// will only be used by hosts that have a fleetd installation without an enroll
// secret and fleet URL (mainly DEP enrolled hosts).
func ensureFleetdConfig(ctx context.Context, ds fleet.Datastore, logger kitlog.Logger) error {
func ensureFleetProfiles(ctx context.Context, ds fleet.Datastore, logger kitlog.Logger, signingCert *tls.Certificate) error {
appCfg, err := ds.AppConfig(ctx)
if err != nil {
return ctxerr.Wrap(ctx, err, "fetching app config")
}
var rootCAProfContents bytes.Buffer
params := mobileconfig.FleetCARootTemplateOptions{
PayloadIdentifier: mobileconfig.FleetCARootConfigPayloadIdentifier,
PayloadName: mdm_types.FleetCAConfigProfileName,
Certificate: base64.StdEncoding.EncodeToString(signingCert.Certificate[0]),
}
if err := mobileconfig.FleetCARootTemplate.Execute(&rootCAProfContents, params); err != nil {
return ctxerr.Wrap(ctx, err, "executing fleet root CA config template")
}
b := rootCAProfContents.Bytes()
fmt.Println(string(b))
enrollSecrets, err := ds.AggregateEnrollSecretPerTeam(ctx)
if err != nil {
return ctxerr.Wrap(ctx, err, "getting enroll secrets aggregates")
@@ -2767,11 +2789,15 @@ func ensureFleetdConfig(ctx context.Context, ds fleet.Datastore, logger kitlog.L
cp, err := fleet.NewMDMAppleConfigProfile(contents.Bytes(), es.TeamID)
if err != nil {
return ctxerr.Wrap(ctx, err, "building configuration profile")
return ctxerr.Wrap(ctx, err, "building fleetd configuration profile")
}
profiles = append(profiles, cp)
rootCAProf, err := fleet.NewMDMAppleConfigProfile(b, es.TeamID)
if err != nil {
return ctxerr.Wrap(ctx, err, "building root CA configuration profile")
}
profiles = append(profiles, rootCAProf)
}
if err := ds.BulkUpsertMDMAppleConfigProfiles(ctx, profiles); err != nil {
@@ -2813,6 +2839,7 @@ func ReconcileAppleProfiles(
ds fleet.Datastore,
commander *apple_mdm.MDMAppleCommander,
logger kitlog.Logger,
signingCert *tls.Certificate,
) error {
appConfig, err := ds.AppConfig(ctx)
if err != nil {
@@ -2821,7 +2848,7 @@ func ReconcileAppleProfiles(
if !appConfig.MDM.EnabledAndConfigured {
return nil
}
if err := ensureFleetdConfig(ctx, ds, logger); err != nil {
if err := ensureFleetProfiles(ctx, ds, logger, signingCert); err != nil {
logger.Log("err", "unable to ensure a fleetd configuration profiles are in place", "details", err)
}
+77 -25
View File
@@ -19,6 +19,7 @@ import (
"net/http/httptest"
"os"
"strings"
"sync"
"sync/atomic"
"testing"
"time"
@@ -41,7 +42,10 @@ import (
"github.com/fleetdm/fleet/v4/server/test"
kitlog "github.com/go-kit/kit/log"
"github.com/google/uuid"
"github.com/groob/plist"
micromdm "github.com/micromdm/micromdm/mdm/mdm"
"github.com/stretchr/testify/require"
"go.mozilla.org/pkcs7"
)
type nopProfileMatcher struct{}
@@ -57,6 +61,9 @@ func (nopProfileMatcher) RetrieveProfiles(ctx context.Context, extHostID string)
func setupAppleMDMService(t *testing.T, license *fleet.LicenseInfo) (fleet.Service, context.Context, *mock.Store) {
ds := new(mock.Store)
cfg := config.TestConfig()
testCertPEM, testKeyPEM, err := generateCertWithAPNsTopic()
require.NoError(t, err)
config.SetTestMDMConfig(t, &cfg, testCertPEM, testKeyPEM, testBMToken, "../../server/service/testdata")
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch {
case strings.Contains(r.URL.Path, "/server/devices"):
@@ -1165,7 +1172,7 @@ func TestMDMTokenUpdate(t *testing.T) {
pushFactory,
NewNanoMDMLogger(kitlog.NewJSONLogger(os.Stdout)),
)
cmdr := apple_mdm.NewMDMAppleCommander(mdmStorage, pusher)
cmdr := apple_mdm.NewMDMAppleCommander(mdmStorage, pusher, config.MDMConfig{})
svc := MDMAppleCheckinAndCommandService{ds: ds, commander: cmdr, logger: kitlog.NewNopLogger()}
uuid, serial, model, wantTeamID := "ABC-DEF-GHI", "XYZABC", "MacBookPro 16,1", uint(12)
@@ -2088,14 +2095,17 @@ func TestMDMAppleReconcileAppleProfiles(t *testing.T) {
pushFactory,
NewNanoMDMLogger(kitlog.NewNopLogger()),
)
cmdr := apple_mdm.NewMDMAppleCommander(mdmStorage, pusher)
mdmConfig := config.MDMConfig{
AppleSCEPCert: "./testdata/server.pem",
AppleSCEPKey: "./testdata/server.key",
}
cmdr := apple_mdm.NewMDMAppleCommander(mdmStorage, pusher, mdmConfig)
hostUUID, hostUUID2 := "ABC-DEF", "GHI-JKL"
contents1 := []byte("test-content-1")
contents1Base64 := base64.StdEncoding.EncodeToString(contents1)
contents2 := []byte("test-content-2")
contents2Base64 := base64.StdEncoding.EncodeToString(contents2)
contents4 := []byte("test-content-4")
contents4Base64 := base64.StdEncoding.EncodeToString(contents4)
signingCert, _, _, err := mdmConfig.AppleSCEP()
require.NoError(t, err)
p1, p2, p3, p4 := "a"+uuid.NewString(), "a"+uuid.NewString(), "a"+uuid.NewString(), "a"+uuid.NewString()
ds.ListMDMAppleProfilesToInstallFunc = func(ctx context.Context) ([]*fleet.MDMAppleProfilePayload, error) {
@@ -2130,6 +2140,7 @@ func TestMDMAppleReconcileAppleProfiles(t *testing.T) {
}
var enqueueFailForOp fleet.MDMOperationType
var mu sync.Mutex
mdmStorage.EnqueueCommandFunc = func(ctx context.Context, id []string, cmd *mdm.Command) (map[string]error, error) {
require.NotNil(t, cmd)
require.NotEmpty(t, cmd.CommandUUID)
@@ -2143,10 +2154,18 @@ func TestMDMAppleReconcileAppleProfiles(t *testing.T) {
require.Len(t, id, 1)
}
if !strings.Contains(string(cmd.Raw), contents1Base64) && !strings.Contains(string(cmd.Raw), contents2Base64) &&
!strings.Contains(string(cmd.Raw), contents4Base64) {
var fullCmd micromdm.CommandPayload
require.NoError(t, plist.Unmarshal(cmd.Raw, &fullCmd))
// the p7 library doesn't support concurrent calls to Parse
mu.Lock()
p7, err := pkcs7.Parse(fullCmd.Command.InstallProfile.Payload)
mu.Unlock()
require.NoError(t, err)
if !bytes.Equal(p7.Content, contents1) && !bytes.Equal(p7.Content, contents2) &&
!bytes.Equal(p7.Content, contents4) {
require.Failf(t, "profile contents don't match", "expected to contain %s, %s or %s but got %s",
contents1Base64, contents2Base64, contents4Base64, string(cmd.Raw))
contents1, contents2, contents4, p7.Content)
}
case "RemoveProfile":
require.ElementsMatch(t, []string{hostUUID, hostUUID2}, id)
@@ -2299,7 +2318,7 @@ func TestMDMAppleReconcileAppleProfiles(t *testing.T) {
failedCount++
require.Len(t, payload, 0)
}
err := ReconcileAppleProfiles(ctx, ds, cmdr, kitlog.NewNopLogger())
err := ReconcileAppleProfiles(ctx, ds, cmdr, kitlog.NewNopLogger(), signingCert)
require.NoError(t, err)
require.Equal(t, 1, failedCount)
checkAndReset(t, true, &ds.ListMDMAppleProfilesToInstallFuncInvoked)
@@ -2335,7 +2354,7 @@ func TestMDMAppleReconcileAppleProfiles(t *testing.T) {
}
enqueueFailForOp = fleet.MDMOperationTypeRemove
err := ReconcileAppleProfiles(ctx, ds, cmdr, kitlog.NewNopLogger())
err := ReconcileAppleProfiles(ctx, ds, cmdr, kitlog.NewNopLogger(), signingCert)
require.NoError(t, err)
require.Equal(t, 1, failedCount)
checkAndReset(t, true, &ds.ListMDMAppleProfilesToInstallFuncInvoked)
@@ -2388,7 +2407,7 @@ func TestMDMAppleReconcileAppleProfiles(t *testing.T) {
}
enqueueFailForOp = fleet.MDMOperationTypeInstall
err := ReconcileAppleProfiles(ctx, ds, cmdr, kitlog.NewNopLogger())
err := ReconcileAppleProfiles(ctx, ds, cmdr, kitlog.NewNopLogger(), signingCert)
require.NoError(t, err)
require.Equal(t, 1, failedCount)
checkAndReset(t, true, &ds.ListMDMAppleProfilesToInstallFuncInvoked)
@@ -2420,6 +2439,12 @@ func TestEnsureFleetdConfig(t *testing.T) {
testURL := "https://example.com"
testTeamName := "test-team"
logger := kitlog.NewNopLogger()
mdmConfig := config.MDMConfig{
AppleSCEPCert: "./testdata/server.pem",
AppleSCEPKey: "./testdata/server.key",
}
signingCert, _, _, err := mdmConfig.AppleSCEP()
require.NoError(t, err)
t.Run("no enroll secret found", func(t *testing.T) {
ctx := context.Background()
@@ -2435,7 +2460,7 @@ func TestEnsureFleetdConfig(t *testing.T) {
require.Empty(t, ps)
return nil
}
err := ensureFleetdConfig(ctx, ds, logger)
err := ensureFleetProfiles(ctx, ds, logger, signingCert)
require.NoError(t, err)
require.True(t, ds.BulkUpsertMDMAppleConfigProfilesFuncInvoked)
require.True(t, ds.AggregateEnrollSecretPerTeamFuncInvoked)
@@ -2460,7 +2485,7 @@ func TestEnsureFleetdConfig(t *testing.T) {
require.Empty(t, ps)
return nil
}
err := ensureFleetdConfig(ctx, ds, logger)
err := ensureFleetProfiles(ctx, ds, logger, signingCert)
require.NoError(t, err)
require.True(t, ds.BulkUpsertMDMAppleConfigProfilesFuncInvoked)
require.True(t, ds.AggregateEnrollSecretPerTeamFuncInvoked)
@@ -2485,16 +2510,28 @@ func TestEnsureFleetdConfig(t *testing.T) {
return secrets, nil
}
ds.BulkUpsertMDMAppleConfigProfilesFunc = func(ctx context.Context, ps []*fleet.MDMAppleConfigProfile) error {
require.Len(t, ps, len(secrets))
for i, p := range ps {
// fleetd + CA profiles
require.Len(t, ps, len(secrets)*2)
var fleetd, fleetCA []*fleet.MDMAppleConfigProfile
for _, p := range ps {
switch p.Identifier {
case mobileconfig.FleetdConfigPayloadIdentifier:
fleetd = append(fleetd, p)
case mobileconfig.FleetCARootConfigPayloadIdentifier:
fleetCA = append(fleetCA, p)
}
}
require.Len(t, fleetd, 3)
require.Len(t, fleetCA, 3)
for i, p := range fleetd {
require.Contains(t, string(p.Mobileconfig), testURL)
require.Contains(t, string(p.Mobileconfig), secrets[i].Secret)
require.Equal(t, mobileconfig.FleetdConfigPayloadIdentifier, p.Identifier)
}
return nil
}
err := ensureFleetdConfig(ctx, ds, logger)
err := ensureFleetProfiles(ctx, ds, logger, signingCert)
require.NoError(t, err)
require.True(t, ds.AggregateEnrollSecretPerTeamFuncInvoked)
require.True(t, ds.BulkUpsertMDMAppleConfigProfilesFuncInvoked)
@@ -2517,15 +2554,27 @@ func TestEnsureFleetdConfig(t *testing.T) {
return secrets, nil
}
ds.BulkUpsertMDMAppleConfigProfilesFunc = func(ctx context.Context, ps []*fleet.MDMAppleConfigProfile) error {
require.Len(t, ps, len(secrets))
for i, p := range ps {
// fleetd + CA profiles
require.Len(t, ps, len(secrets)*2)
var fleetd, fleetCA []*fleet.MDMAppleConfigProfile
for _, p := range ps {
switch p.Identifier {
case mobileconfig.FleetdConfigPayloadIdentifier:
fleetd = append(fleetd, p)
case mobileconfig.FleetCARootConfigPayloadIdentifier:
fleetCA = append(fleetCA, p)
}
}
require.Len(t, fleetd, 2)
require.Len(t, fleetCA, 2)
for i, p := range fleetd {
require.Contains(t, string(p.Mobileconfig), testURL)
require.Contains(t, string(p.Mobileconfig), secrets[i].Secret)
require.Equal(t, mobileconfig.FleetdConfigPayloadIdentifier, p.Identifier)
}
return nil
}
err := ensureFleetdConfig(ctx, ds, logger)
err := ensureFleetProfiles(ctx, ds, logger, signingCert)
require.NoError(t, err)
require.True(t, ds.AppConfigFuncInvoked)
require.True(t, ds.AggregateEnrollSecretPerTeamFuncInvoked)
@@ -2538,7 +2587,7 @@ func TestEnsureFleetdConfig(t *testing.T) {
ds.AppConfigFunc = func(ctx context.Context) (*fleet.AppConfig, error) {
return nil, testError
}
err := ensureFleetdConfig(ctx, ds, logger)
err := ensureFleetProfiles(ctx, ds, logger, signingCert)
require.ErrorIs(t, err, testError)
})
@@ -2551,7 +2600,7 @@ func TestEnsureFleetdConfig(t *testing.T) {
ds.AggregateEnrollSecretPerTeamFunc = func(ctx context.Context) ([]*fleet.EnrollSecret, error) {
return nil, testError
}
err := ensureFleetdConfig(ctx, ds, logger)
err := ensureFleetProfiles(ctx, ds, logger, signingCert)
require.ErrorIs(t, err, testError)
})
@@ -2571,7 +2620,7 @@ func TestEnsureFleetdConfig(t *testing.T) {
ds.BulkUpsertMDMAppleConfigProfilesFunc = func(ctx context.Context, p []*fleet.MDMAppleConfigProfile) error {
return testError
}
err := ensureFleetdConfig(ctx, ds, logger)
err := ensureFleetProfiles(ctx, ds, logger, signingCert)
require.ErrorIs(t, err, testError)
require.True(t, ds.AppConfigFuncInvoked)
require.True(t, ds.AggregateEnrollSecretPerTeamFuncInvoked)
@@ -2852,7 +2901,10 @@ func setupTest(t *testing.T) (context.Context, kitlog.Logger, *mock.Store, *conf
pushFactory,
stdlogfmt.New(),
)
commander := apple_mdm.NewMDMAppleCommander(mdmStorage, pusher)
commander := apple_mdm.NewMDMAppleCommander(mdmStorage, pusher, config.MDMConfig{
AppleSCEPCert: "./testdata/server.pem",
AppleSCEPKey: "./testdata/server.key",
})
return ctx, logger, ds, &cfg, mdmStorage, commander
}
+10 -3
View File
@@ -16,6 +16,7 @@ import (
"github.com/fleetdm/fleet/v4/server/contexts/logging"
"github.com/fleetdm/fleet/v4/server/fleet"
apple_mdm "github.com/fleetdm/fleet/v4/server/mdm/apple"
"github.com/fleetdm/fleet/v4/server/mdm/apple/mobileconfig"
"github.com/fleetdm/fleet/v4/server/ptr"
)
@@ -500,16 +501,22 @@ func (svc *Service) GetDeviceMDMAppleEnrollmentProfile(ctx context.Context) ([]b
return nil, ctxerr.Wrap(ctx, err)
}
mobileConfig, err := apple_mdm.GenerateEnrollmentProfileMobileconfig(
enrollmentProf, err := apple_mdm.GenerateEnrollmentProfileMobileconfig(
appConfig.OrgInfo.OrgName,
appConfig.ServerSettings.ServerURL,
svc.config.MDM.AppleSCEPChallenge,
svc.mdmPushCertTopic,
)
if err != nil {
return nil, ctxerr.Wrap(ctx, err)
return nil, ctxerr.Wrap(ctx, err, "generating manual enrollment profile")
}
return mobileConfig, nil
signed, err := mobileconfig.Sign(enrollmentProf, svc.config.MDM)
if err != nil {
return nil, ctxerr.Wrap(ctx, err, "signing profile")
}
return signed, nil
}
////////////////////////////////////////////////////////////////////////////////
+7 -4
View File
@@ -272,12 +272,12 @@ func (s *integrationMDMTestSuite) runDEPEnrollReleaseDeviceTest(t *testing.T, de
require.NoError(t, err)
}
// expected commands: install fleetd, install bootstrap, install profiles
// expected commands: install fleetd, install bootstrap, install CA, install profiles
// (custom one and fleetd configuration) (not expected: account
// configuration, since enrollment_reference not set)
require.Len(t, cmds, 4)
require.Len(t, cmds, 5)
var installProfileCount, installEnterpriseCount, otherCount int
var profileCustomSeen, profileFleetdSeen bool
var profileCustomSeen, profileFleetdSeen, profileFleetCASeen bool
for _, cmd := range cmds {
switch cmd.Command.RequestType {
case "InstallProfile":
@@ -286,6 +286,8 @@ func (s *integrationMDMTestSuite) runDEPEnrollReleaseDeviceTest(t *testing.T, de
profileCustomSeen = true
} else if strings.Contains(string(cmd.Command.InstallProfile.Payload), fmt.Sprintf("<string>%s</string>", mobileconfig.FleetdConfigPayloadIdentifier)) {
profileFleetdSeen = true
} else if strings.Contains(string(cmd.Command.InstallProfile.Payload), fmt.Sprintf("<string>%s</string>", mobileconfig.FleetCARootConfigPayloadIdentifier)) {
profileFleetCASeen = true
}
case "InstallEnterpriseApplication":
@@ -294,11 +296,12 @@ func (s *integrationMDMTestSuite) runDEPEnrollReleaseDeviceTest(t *testing.T, de
otherCount++
}
}
require.Equal(t, 2, installProfileCount)
require.Equal(t, 3, installProfileCount)
require.Equal(t, 2, installEnterpriseCount)
require.Equal(t, 0, otherCount)
require.True(t, profileCustomSeen)
require.True(t, profileFleetdSeen)
require.True(t, profileFleetCASeen)
if enableReleaseManually {
// get the worker's pending job from the future, there should not be any
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -141,7 +141,7 @@ func NewService(
mdmStorage: mdmStorage,
mdmPushService: mdmPushService,
mdmPushCertTopic: mdmPushCertTopic,
mdmAppleCommander: apple_mdm.NewMDMAppleCommander(mdmStorage, mdmPushService),
mdmAppleCommander: apple_mdm.NewMDMAppleCommander(mdmStorage, mdmPushService, config.MDM),
cronSchedulesService: cronSchedulesService,
wstepCertManager: wstepCertManager,
}
+2 -2
View File
@@ -182,7 +182,7 @@ func newTestServiceWithConfig(t *testing.T, ds fleet.Datastore, fleetConfig conf
mailer,
c,
depStorage,
apple_mdm.NewMDMAppleCommander(mdmStorage, mdmPusher),
apple_mdm.NewMDMAppleCommander(mdmStorage, mdmPusher, fleetConfig.MDM),
"",
ssoStore,
profMatcher,
@@ -344,7 +344,7 @@ func RunServerForTestsWithDS(t *testing.T, ds fleet.Datastore, opts ...*TestServ
logger,
&MDMAppleCheckinAndCommandService{
ds: ds,
commander: apple_mdm.NewMDMAppleCommander(mdmStorage, mdmPusher),
commander: apple_mdm.NewMDMAppleCommander(mdmStorage, mdmPusher, cfg.MDM),
logger: kitlog.NewNopLogger(),
},
&MDMAppleDDMService{
+11 -10
View File
@@ -8,6 +8,7 @@ import (
"time"
"github.com/fleetdm/fleet/v4/pkg/optjson"
"github.com/fleetdm/fleet/v4/server/config"
"github.com/fleetdm/fleet/v4/server/datastore/mysql"
"github.com/fleetdm/fleet/v4/server/fleet"
apple_mdm "github.com/fleetdm/fleet/v4/server/mdm/apple"
@@ -151,7 +152,7 @@ func TestAppleMDM(t *testing.T) {
mdmWorker := &AppleMDM{
Datastore: ds,
Log: nopLog,
Commander: apple_mdm.NewMDMAppleCommander(mdmStorage, mockPusher{}),
Commander: apple_mdm.NewMDMAppleCommander(mdmStorage, mockPusher{}, config.MDMConfig{}),
}
w := NewWorker(ds, nopLog)
w.Register(mdmWorker)
@@ -184,7 +185,7 @@ func TestAppleMDM(t *testing.T) {
mdmWorker := &AppleMDM{
Datastore: ds,
Log: nopLog,
Commander: apple_mdm.NewMDMAppleCommander(mdmStorage, mockPusher{}),
Commander: apple_mdm.NewMDMAppleCommander(mdmStorage, mockPusher{}, config.MDMConfig{}),
}
w := NewWorker(ds, nopLog)
w.Register(mdmWorker)
@@ -221,7 +222,7 @@ func TestAppleMDM(t *testing.T) {
mdmWorker := &AppleMDM{
Datastore: ds,
Log: nopLog,
Commander: apple_mdm.NewMDMAppleCommander(mdmStorage, mockPusher{}),
Commander: apple_mdm.NewMDMAppleCommander(mdmStorage, mockPusher{}, config.MDMConfig{}),
}
w := NewWorker(ds, nopLog)
w.Register(mdmWorker)
@@ -262,7 +263,7 @@ func TestAppleMDM(t *testing.T) {
mdmWorker := &AppleMDM{
Datastore: ds,
Log: nopLog,
Commander: apple_mdm.NewMDMAppleCommander(mdmStorage, mockPusher{}),
Commander: apple_mdm.NewMDMAppleCommander(mdmStorage, mockPusher{}, config.MDMConfig{}),
}
w := NewWorker(ds, nopLog)
w.Register(mdmWorker)
@@ -313,7 +314,7 @@ func TestAppleMDM(t *testing.T) {
mdmWorker := &AppleMDM{
Datastore: ds,
Log: nopLog,
Commander: apple_mdm.NewMDMAppleCommander(mdmStorage, mockPusher{}),
Commander: apple_mdm.NewMDMAppleCommander(mdmStorage, mockPusher{}, config.MDMConfig{}),
}
w := NewWorker(ds, nopLog)
w.Register(mdmWorker)
@@ -365,7 +366,7 @@ func TestAppleMDM(t *testing.T) {
mdmWorker := &AppleMDM{
Datastore: ds,
Log: nopLog,
Commander: apple_mdm.NewMDMAppleCommander(mdmStorage, mockPusher{}),
Commander: apple_mdm.NewMDMAppleCommander(mdmStorage, mockPusher{}, config.MDMConfig{}),
}
w := NewWorker(ds, nopLog)
w.Register(mdmWorker)
@@ -402,7 +403,7 @@ func TestAppleMDM(t *testing.T) {
mdmWorker := &AppleMDM{
Datastore: ds,
Log: nopLog,
Commander: apple_mdm.NewMDMAppleCommander(mdmStorage, mockPusher{}),
Commander: apple_mdm.NewMDMAppleCommander(mdmStorage, mockPusher{}, config.MDMConfig{}),
}
w := NewWorker(ds, nopLog)
w.Register(mdmWorker)
@@ -444,7 +445,7 @@ func TestAppleMDM(t *testing.T) {
mdmWorker := &AppleMDM{
Datastore: ds,
Log: nopLog,
Commander: apple_mdm.NewMDMAppleCommander(mdmStorage, mockPusher{}),
Commander: apple_mdm.NewMDMAppleCommander(mdmStorage, mockPusher{}, config.MDMConfig{}),
}
w := NewWorker(ds, nopLog)
w.Register(mdmWorker)
@@ -499,7 +500,7 @@ func TestAppleMDM(t *testing.T) {
mdmWorker := &AppleMDM{
Datastore: ds,
Log: nopLog,
Commander: apple_mdm.NewMDMAppleCommander(mdmStorage, mockPusher{}),
Commander: apple_mdm.NewMDMAppleCommander(mdmStorage, mockPusher{}, config.MDMConfig{}),
}
w := NewWorker(ds, nopLog)
w.Register(mdmWorker)
@@ -535,7 +536,7 @@ func TestAppleMDM(t *testing.T) {
mdmWorker := &AppleMDM{
Datastore: ds,
Log: nopLog,
Commander: apple_mdm.NewMDMAppleCommander(mdmStorage, mockPusher{}),
Commander: apple_mdm.NewMDMAppleCommander(mdmStorage, mockPusher{}, config.MDMConfig{}),
}
w := NewWorker(ds, nopLog)
w.Register(mdmWorker)