mirror of
https://github.com/empayre/fleet.git
synced 2024-11-07 17:28:54 +00:00
266 lines
7.9 KiB
Go
266 lines
7.9 KiB
Go
package apple_mdm
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/fleetdm/fleet/v4/server/datastore/redis"
|
|
"github.com/fleetdm/fleet/v4/server/datastore/redis/redistest"
|
|
"github.com/fleetdm/fleet/v4/server/fleet"
|
|
"github.com/fleetdm/fleet/v4/server/mdm/apple/mobileconfig"
|
|
redigo "github.com/gomodule/redigo/redis"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestPreassignProfile(t *testing.T) {
|
|
runTest := func(t *testing.T, pool fleet.RedisPool) {
|
|
ctx := context.Background()
|
|
matcher := NewProfileMatcher(pool)
|
|
|
|
// preassign a profile
|
|
p1 := fleet.MDMApplePreassignProfilePayload{
|
|
ExternalHostIdentifier: "abcd",
|
|
HostUUID: "1234",
|
|
Profile: generateProfile("p1", "p1", "Configuration", "p1"),
|
|
Group: "g1",
|
|
}
|
|
err := matcher.PreassignProfile(ctx, p1)
|
|
require.NoError(t, err)
|
|
|
|
// should've set a TTL on the key
|
|
conn := redis.ConfigureDoer(pool, pool.Get())
|
|
defer conn.Close()
|
|
|
|
ttl1, err := redigo.Int(conn.Do("TTL", keyForExternalHostIdentifier("abcd")))
|
|
require.NoError(t, err)
|
|
require.NotZero(t, ttl1)
|
|
require.LessOrEqual(t, ttl1, int(preassignKeyExpiration.Seconds()))
|
|
|
|
// sleep a second to see the existing ttl go down
|
|
time.Sleep(time.Second)
|
|
|
|
// preassign another profile on the same host
|
|
p2 := fleet.MDMApplePreassignProfilePayload{
|
|
ExternalHostIdentifier: "abcd",
|
|
HostUUID: "1234",
|
|
Profile: generateProfile("p2", "p2", "Configuration", "p2"),
|
|
Group: "g2",
|
|
}
|
|
err = matcher.PreassignProfile(ctx, p2)
|
|
require.NoError(t, err)
|
|
|
|
// key already existed, so it did not reset the ttl
|
|
ttl2, err := redigo.Int(conn.Do("TTL", keyForExternalHostIdentifier("abcd")))
|
|
require.NoError(t, err)
|
|
require.NotZero(t, ttl2)
|
|
require.Less(t, ttl2, ttl1)
|
|
|
|
// preassign another profile on the same host, without a group
|
|
p3 := fleet.MDMApplePreassignProfilePayload{
|
|
ExternalHostIdentifier: "abcd",
|
|
HostUUID: "1234",
|
|
Profile: generateProfile("p3", "p3", "Configuration", "p3"),
|
|
}
|
|
err = matcher.PreassignProfile(ctx, p3)
|
|
require.NoError(t, err)
|
|
|
|
// key already existed, so it did not reset the ttl
|
|
ttl3, err := redigo.Int(conn.Do("TTL", keyForExternalHostIdentifier("abcd")))
|
|
require.NoError(t, err)
|
|
require.NotZero(t, ttl3)
|
|
require.Less(t, ttl3, ttl1)
|
|
|
|
// preassign the same profile on the same host, no change
|
|
err = matcher.PreassignProfile(ctx, p3)
|
|
require.NoError(t, err)
|
|
|
|
// key already existed, so it did not reset the ttl
|
|
ttl4, err := redigo.Int(conn.Do("TTL", keyForExternalHostIdentifier("abcd")))
|
|
require.NoError(t, err)
|
|
require.NotZero(t, ttl4)
|
|
require.Less(t, ttl4, ttl1)
|
|
|
|
// preassign a profile on a different host
|
|
p4 := fleet.MDMApplePreassignProfilePayload{
|
|
ExternalHostIdentifier: "efgh",
|
|
HostUUID: "5678",
|
|
Profile: generateProfile("p4", "p4", "Configuration", "p4"),
|
|
Group: "g4",
|
|
}
|
|
err = matcher.PreassignProfile(ctx, p4)
|
|
require.NoError(t, err)
|
|
|
|
// original host's key unchanged
|
|
ttl5, err := redigo.Int(conn.Do("TTL", keyForExternalHostIdentifier("abcd")))
|
|
require.NoError(t, err)
|
|
require.NotZero(t, ttl5)
|
|
require.Less(t, ttl5, ttl1)
|
|
|
|
// new host's ttl is set
|
|
ttl1, err = redigo.Int(conn.Do("TTL", keyForExternalHostIdentifier("efgh")))
|
|
require.NoError(t, err)
|
|
require.NotZero(t, ttl1)
|
|
require.LessOrEqual(t, ttl1, int(preassignKeyExpiration.Seconds()))
|
|
|
|
// stored 3 profiles in original host
|
|
profs, err := redigo.StringMap(conn.Do("HGETALL", keyForExternalHostIdentifier("abcd")))
|
|
require.NoError(t, err)
|
|
require.Equal(t, map[string]string{
|
|
"host_uuid": "1234",
|
|
p1.HexMD5Hash(): string(p1.Profile),
|
|
p1.HexMD5Hash() + "_group": "g1",
|
|
p2.HexMD5Hash(): string(p2.Profile),
|
|
p2.HexMD5Hash() + "_group": "g2",
|
|
p3.HexMD5Hash(): string(p3.Profile),
|
|
}, profs)
|
|
|
|
// stored 1 profile in new host
|
|
profs, err = redigo.StringMap(conn.Do("HGETALL", keyForExternalHostIdentifier("efgh")))
|
|
require.NoError(t, err)
|
|
require.Equal(t, map[string]string{
|
|
"host_uuid": "5678",
|
|
p4.HexMD5Hash(): string(p4.Profile),
|
|
p4.HexMD5Hash() + "_group": "g4",
|
|
}, profs)
|
|
}
|
|
|
|
t.Run("standalone", func(t *testing.T) {
|
|
pool := redistest.SetupRedis(t, preassignKeyPrefix, false, false, false)
|
|
runTest(t, pool)
|
|
})
|
|
|
|
t.Run("cluster", func(t *testing.T) {
|
|
pool := redistest.SetupRedis(t, preassignKeyPrefix, true, true, false)
|
|
runTest(t, pool)
|
|
})
|
|
}
|
|
|
|
func TestPreassignProfileValidation(t *testing.T) {
|
|
ctx := context.Background()
|
|
pool := redistest.SetupRedis(t, preassignKeyPrefix, false, false, false)
|
|
matcher := NewProfileMatcher(pool)
|
|
|
|
cases := []struct {
|
|
desc string
|
|
payload fleet.MDMApplePreassignProfilePayload
|
|
err string
|
|
}{
|
|
{
|
|
"empty external host identifier",
|
|
fleet.MDMApplePreassignProfilePayload{
|
|
ExternalHostIdentifier: "",
|
|
HostUUID: "1234",
|
|
Profile: generateProfile("p1", "p1", "Configuration", "p1"),
|
|
},
|
|
"external_host_identifier required",
|
|
},
|
|
{
|
|
"empty host uuid",
|
|
fleet.MDMApplePreassignProfilePayload{
|
|
ExternalHostIdentifier: "abcd",
|
|
HostUUID: "",
|
|
Profile: generateProfile("p1", "p1", "Configuration", "p1"),
|
|
},
|
|
"host_uuid required",
|
|
},
|
|
{
|
|
"empty profile",
|
|
fleet.MDMApplePreassignProfilePayload{
|
|
ExternalHostIdentifier: "abcd",
|
|
HostUUID: "1234",
|
|
Profile: nil,
|
|
},
|
|
"profile required",
|
|
},
|
|
{
|
|
"invalid profile",
|
|
fleet.MDMApplePreassignProfilePayload{
|
|
ExternalHostIdentifier: "abcd",
|
|
HostUUID: "1234",
|
|
Profile: []byte(`abcd`),
|
|
},
|
|
"mobileconfig is not XML nor PKCS7",
|
|
},
|
|
{
|
|
"invalid profile type",
|
|
fleet.MDMApplePreassignProfilePayload{
|
|
ExternalHostIdentifier: "abcd",
|
|
HostUUID: "1234",
|
|
Profile: generateProfile("p1", "p1", "abcd", "p1"),
|
|
},
|
|
"invalid PayloadType: abcd",
|
|
},
|
|
{
|
|
"empty payload identifier",
|
|
fleet.MDMApplePreassignProfilePayload{
|
|
ExternalHostIdentifier: "abcd",
|
|
HostUUID: "1234",
|
|
Profile: generateProfile("p1", "", "Configuration", "p1"),
|
|
},
|
|
"empty PayloadIdentifier in profile",
|
|
},
|
|
{
|
|
"empty payload name",
|
|
fleet.MDMApplePreassignProfilePayload{
|
|
ExternalHostIdentifier: "abcd",
|
|
HostUUID: "1234",
|
|
Profile: generateProfile("", "p1", "Configuration", "p1"),
|
|
},
|
|
"empty PayloadDisplayName in profile",
|
|
},
|
|
{
|
|
"invalid payload identifier",
|
|
fleet.MDMApplePreassignProfilePayload{
|
|
ExternalHostIdentifier: "abcd",
|
|
HostUUID: "1234",
|
|
Profile: generateProfile("p1", mobileconfig.FleetFileVaultPayloadIdentifier, "Configuration", "p1"),
|
|
},
|
|
"payload identifier com.fleetdm.fleet.mdm.filevault is not allowed",
|
|
},
|
|
{
|
|
"valid",
|
|
fleet.MDMApplePreassignProfilePayload{
|
|
ExternalHostIdentifier: "abcd",
|
|
HostUUID: "1234",
|
|
Profile: generateProfile("p1", "p1", "Configuration", "p1"),
|
|
Group: "g1",
|
|
},
|
|
"",
|
|
},
|
|
}
|
|
for _, c := range cases {
|
|
t.Run(c.desc, func(t *testing.T) {
|
|
err := matcher.PreassignProfile(ctx, c.payload)
|
|
if c.err != "" {
|
|
require.ErrorContains(t, err, c.err)
|
|
} else {
|
|
require.NoError(t, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func generateProfile(name, ident, typ, uuid string) []byte {
|
|
return []byte(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">
|
|
<dict>
|
|
<key>PayloadContent</key>
|
|
<array/>
|
|
<key>PayloadDisplayName</key>
|
|
<string>%s</string>
|
|
<key>PayloadIdentifier</key>
|
|
<string>%s</string>
|
|
<key>PayloadType</key>
|
|
<string>%s</string>
|
|
<key>PayloadUUID</key>
|
|
<string>%s</string>
|
|
<key>PayloadVersion</key>
|
|
<integer>1</integer>
|
|
</dict>
|
|
</plist>
|
|
`, name, ident, typ, uuid))
|
|
}
|