mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 09:28:54 +00:00
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #40538 This is the initial iteration of CSP functionality, currently gated behind FLEET_SERVER_ENABLE_CSP. If disabled, no CSP is served. Nonces are still injected into pages however a dummy nonce is used and has no effect. With this setting turned on things break and will be addressed by mainly frontend changes in https://github.com/fleetdm/fleet/issues/41577 # Checklist for submitter If some of the following don't apply, delete the relevant line. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements), JS inline code is prevented especially for url redirects - [x] If paths of existing endpoints are modified without backwards compatibility, checked the frontend/CLI for any necessary changes ## Testing - [x] Added/updated automated tests - [x] Where appropriate, [automated tests simulate multiple hosts and test for host isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing) (updates to one hosts's records do not affect another) - [x] QA'd all new/changed functionality manually --------- Co-authored-by: Gabriel Hernandez <ghernandez345@gmail.com>
107 lines
4.3 KiB
Go
107 lines
4.3 KiB
Go
package service
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"log/slog"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/fleetdm/fleet/v4/server/fleet"
|
|
"github.com/fleetdm/fleet/v4/server/mock"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestServeFrontend(t *testing.T) {
|
|
if !hasBuildTag("full") {
|
|
t.Skip("This test requires running with -tags full")
|
|
}
|
|
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
|
|
h := ServeFrontend("", false, logger, false)
|
|
ts := httptest.NewServer(h)
|
|
t.Cleanup(func() {
|
|
ts.Close()
|
|
})
|
|
|
|
// Simulate a misconfigured osquery sending log requests to the root endpoint.
|
|
requestBody := []byte(`
|
|
{"data":[{"snapshot":[{"build_distro":"10.14","build_platform":"darwin","config_hash":"d8d220440ebea888f8704c4a0a5c1ced4ab601b5",
|
|
"config_valid":"1","extensions":"active","instance_id":"522e6020-37de-460b-bb01-b76c77298f75","pid":"57456","platform_mask":"21",
|
|
"start_time":"1707768989","uuid":"408F3B27-434F-4776-8538-DA394A3D545F","version":"5.11.0","watcher":"57455"}],"action":"snapshot",
|
|
"name":"packFOOBARGlobalFOOBARQuery_50","hostIdentifier":"589966AE-074A-503B-B17B-54B05684A120","calendarTime":"Mon Feb 12 20:16:40 2024 UTC",
|
|
"unixTime":1707769000,"epoch":0,"counter":0,"numerics":false,"decorations":{"host_uuid":"589966AE-074A-503B-B17B-54B05684A120",
|
|
"hostname":"foobar.local"}},{"snapshot":[{"build_distro":"10.14","build_platform":"darwin",
|
|
"config_hash":"d8d220440ebea888f8704c4a0a5c1ced4ab601b5","config_valid":"1","extensions":"active",
|
|
"instance_id":"522e6020-37de-460b-bb01-b76c77298f75","pid":"57456","platform_mask":"21","start_time":"1707768989",
|
|
"uuid":"408F3B27-434F-4776-8538-DA394A3D545F","version":"5.11.0","watcher":"57455"}],"action":"snapshot",
|
|
"name":"packFOOBARGlobalFOOBARQuery_28","hostIdentifier": "589966AE-074A-503B-B17B-54B05684A120","calendarTime":"Mon Feb 12 20:16:41 2024 UTC",
|
|
"unixTime":1707769001,"epoch":0,"counter":0,"numerics":false,"decorations":{"host_uuid":"408F3B27-434F-4776-8538-DA394A3D545F",
|
|
"hostname":"foobar.local"}}],"log_type":"result","node_key":"J9pA1CmjydHGi0bqS1XkkR9pOJQJzoPA"}`)
|
|
response, err := http.DefaultClient.Post(ts.URL, "", bytes.NewReader(requestBody))
|
|
require.NoError(t, err)
|
|
require.Equal(t, http.StatusMethodNotAllowed, response.StatusCode)
|
|
}
|
|
|
|
func TestServeEndUserEnrollOTA(t *testing.T) {
|
|
if !hasBuildTag("full") {
|
|
t.Skip("This test requires running with -tags full")
|
|
}
|
|
|
|
ds := new(mock.DataStore)
|
|
ds.HasUsersFunc = func(ctx context.Context) (bool, error) {
|
|
return true, nil
|
|
}
|
|
appCfg := &fleet.AppConfig{
|
|
MDM: fleet.MDM{
|
|
EnabledAndConfigured: false,
|
|
AndroidEnabledAndConfigured: false,
|
|
},
|
|
}
|
|
ds.AppConfigFunc = func(ctx context.Context) (*fleet.AppConfig, error) {
|
|
return appCfg, nil
|
|
}
|
|
ds.VerifyEnrollSecretFunc = func(ctx context.Context, secret string) (*fleet.EnrollSecret, error) {
|
|
return nil, ¬FoundError{}
|
|
}
|
|
ds.TeamIDsWithSetupExperienceIdPEnabledFunc = func(ctx context.Context) ([]uint, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
svc, _ := newTestService(t, ds, nil, nil)
|
|
|
|
for _, enabled := range []bool{true, false} {
|
|
t.Run(fmt.Sprintf("MDM enabled: %t", enabled), func(t *testing.T) {
|
|
appCfg.MDM.EnabledAndConfigured = enabled
|
|
appCfg.MDM.AndroidEnabledAndConfigured = enabled
|
|
|
|
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
|
|
h := ServeEndUserEnrollOTA(svc, "", ds, logger, false)
|
|
ts := httptest.NewServer(h)
|
|
t.Cleanup(func() {
|
|
ts.Close()
|
|
})
|
|
|
|
// assert html is returned
|
|
response, err := http.DefaultClient.Get(ts.URL + "?enroll_secret=foo")
|
|
require.NoError(t, err)
|
|
require.Equal(t, http.StatusOK, response.StatusCode)
|
|
require.Equal(t, response.Header.Get("Content-Type"), "text/html; charset=utf-8")
|
|
assert.True(t, ds.AppConfigFuncInvoked)
|
|
|
|
// assert it contains the content we expect
|
|
defer response.Body.Close()
|
|
bodyBytes, err := io.ReadAll(response.Body)
|
|
require.NoError(t, err)
|
|
bodyString := string(bodyBytes)
|
|
require.Contains(t, bodyString, "api/v1/fleet/enrollment_profiles/ota?enroll_secret=foo")
|
|
require.Contains(t, bodyString, "/api/v1/fleet/android_enterprise/enrollment_token")
|
|
require.Contains(t, bodyString, fmt.Sprintf(`const ANDROID_MDM_ENABLED = "%t" === "true";`, enabled))
|
|
require.Contains(t, bodyString, fmt.Sprintf(`const MAC_MDM_ENABLED = "%t" == "true";`, enabled))
|
|
})
|
|
}
|
|
}
|