mirror of
https://github.com/empayre/fleet.git
synced 2024-11-07 01:15:22 +00:00
183 lines
7.2 KiB
Go
183 lines
7.2 KiB
Go
|
package service
|
||
|
|
||
|
import (
|
||
|
"io"
|
||
|
"net/http"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
"testing"
|
||
|
"time"
|
||
|
|
||
|
"github.com/fleetdm/fleet/v4/server/config"
|
||
|
"github.com/fleetdm/fleet/v4/server/fleet"
|
||
|
"github.com/fleetdm/fleet/v4/server/live_query/live_query_mock"
|
||
|
apple_mdm "github.com/fleetdm/fleet/v4/server/mdm/apple"
|
||
|
"github.com/fleetdm/fleet/v4/server/pubsub"
|
||
|
"github.com/groob/plist"
|
||
|
nanodep_client "github.com/micromdm/nanodep/client"
|
||
|
"github.com/stretchr/testify/require"
|
||
|
"github.com/stretchr/testify/suite"
|
||
|
)
|
||
|
|
||
|
func TestIntegrationsMDM(t *testing.T) {
|
||
|
testingSuite := new(integrationMDMTestSuite)
|
||
|
testingSuite.s = &testingSuite.Suite
|
||
|
suite.Run(t, testingSuite)
|
||
|
}
|
||
|
|
||
|
type integrationMDMTestSuite struct {
|
||
|
withServer
|
||
|
suite.Suite
|
||
|
}
|
||
|
|
||
|
func (s *integrationMDMTestSuite) SetupSuite() {
|
||
|
s.withDS.SetupSuite("integrationMDMTestSuite")
|
||
|
|
||
|
rs := pubsub.NewInmemQueryResults()
|
||
|
lq := live_query_mock.New(s.T())
|
||
|
|
||
|
fleetCfg := config.TestConfig()
|
||
|
config.SetTestMDMConfig(s.T(), &fleetCfg, testCert, testKey, testBMToken)
|
||
|
|
||
|
mdmStorage, err := s.ds.NewMDMAppleMDMStorage(testCert, testKey)
|
||
|
require.NoError(s.T(), err)
|
||
|
depStorage, err := s.ds.NewMDMAppleDEPStorage(*testBMToken)
|
||
|
require.NoError(s.T(), err)
|
||
|
|
||
|
config := TestServerOpts{
|
||
|
License: &fleet.LicenseInfo{
|
||
|
Tier: fleet.TierPremium,
|
||
|
},
|
||
|
Rs: rs,
|
||
|
Lq: lq,
|
||
|
FleetConfig: &fleetCfg,
|
||
|
MDMStorage: mdmStorage,
|
||
|
DEPStorage: depStorage,
|
||
|
MDMPusher: dummyMDMPusher{},
|
||
|
}
|
||
|
users, server := RunServerForTestsWithDS(s.T(), s.ds, &config)
|
||
|
s.server = server
|
||
|
s.users = users
|
||
|
s.token = s.getTestAdminToken()
|
||
|
s.cachedAdminToken = s.token
|
||
|
}
|
||
|
|
||
|
func (s *integrationMDMTestSuite) TearDownTest() {
|
||
|
s.withServer.commonTearDownTest(s.T())
|
||
|
}
|
||
|
|
||
|
func (s *integrationMDMTestSuite) TestAppleGetAppleMDM() {
|
||
|
t := s.T()
|
||
|
|
||
|
var mdmResp getAppleMDMResponse
|
||
|
s.DoJSON("GET", "/api/latest/fleet/mdm/apple", nil, http.StatusOK, &mdmResp)
|
||
|
// returned values are dummy, this is a test certificate
|
||
|
require.Equal(t, "Certificate Authority", mdmResp.Issuer)
|
||
|
require.NotZero(t, mdmResp.SerialNumber)
|
||
|
require.Equal(t, "Generic-cert", mdmResp.CommonName)
|
||
|
require.NotZero(t, mdmResp.RenewDate)
|
||
|
|
||
|
// GET /api/latest/fleet/mdm/apple_bm is not tested because it makes a call
|
||
|
// to an Apple API that would a) fail because we use dummy token/certs and b)
|
||
|
// could get us in trouble with many invalid requests.
|
||
|
// TODO: eventually add a way to mock the apple API, maybe with a test http
|
||
|
// server running and a way to use its URL instead of Apple's. (#8948)
|
||
|
}
|
||
|
|
||
|
func (s *integrationMDMTestSuite) TestDeviceMDMManualEnroll() {
|
||
|
t := s.T()
|
||
|
|
||
|
token := "token_test_manual_enroll"
|
||
|
createHostAndDeviceToken(t, s.ds, token)
|
||
|
|
||
|
// invalid token fails
|
||
|
s.DoRaw("GET", "/api/latest/fleet/device/invalid_token/mdm/apple/manual_enrollment_profile", nil, http.StatusUnauthorized)
|
||
|
|
||
|
// valid token downloads the profile
|
||
|
resp := s.DoRaw("GET", "/api/latest/fleet/device/"+token+"/mdm/apple/manual_enrollment_profile", nil, http.StatusOK)
|
||
|
body, err := io.ReadAll(resp.Body)
|
||
|
resp.Body.Close()
|
||
|
require.NoError(t, err)
|
||
|
require.Contains(t, resp.Header, "Content-Disposition")
|
||
|
require.Contains(t, resp.Header, "Content-Type")
|
||
|
require.Contains(t, resp.Header, "X-Content-Type-Options")
|
||
|
require.Contains(t, resp.Header.Get("Content-Disposition"), "attachment;")
|
||
|
require.Contains(t, resp.Header.Get("Content-Type"), "application/x-apple-aspen-config")
|
||
|
require.Contains(t, resp.Header.Get("X-Content-Type-Options"), "nosniff")
|
||
|
headerLen, err := strconv.Atoi(resp.Header.Get("Content-Length"))
|
||
|
require.NoError(t, err)
|
||
|
require.Equal(t, len(body), headerLen)
|
||
|
|
||
|
var profile struct {
|
||
|
PayloadIdentifier string `plist:"PayloadIdentifier"`
|
||
|
}
|
||
|
require.NoError(t, plist.Unmarshal(body, &profile))
|
||
|
require.Equal(t, apple_mdm.FleetPayloadIdentifier, profile.PayloadIdentifier)
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
testBMToken = &nanodep_client.OAuth1Tokens{
|
||
|
ConsumerKey: "test_consumer",
|
||
|
ConsumerSecret: "test_secret",
|
||
|
AccessToken: "test_access_token",
|
||
|
AccessSecret: "test_access_secret",
|
||
|
AccessTokenExpiry: time.Date(2999, 1, 1, 0, 0, 0, 0, time.UTC),
|
||
|
}
|
||
|
|
||
|
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") }
|