mirror of
https://github.com/fleetdm/fleet
synced 2026-05-23 00:49:03 +00:00
For #26519 This PR allows Fleet server to use Android with either fleetdm.com proxy or locally. It also removes the Android feature flag from the backend. The frontend changes and proxy API documentation will be in separate PRs. Updated contributor docs: https://github.com/fleetdm/fleet/pull/29880/files Integration tests are missing and tracked as a separate issue: https://github.com/fleetdm/fleet/issues/27080 # Checklist for submitter - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. - [x] Added/updated automated tests - [x] Manual QA for all new/changed functionality
176 lines
4.5 KiB
Go
176 lines
4.5 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/fleetdm/fleet/v4/server/authz"
|
|
"github.com/fleetdm/fleet/v4/server/contexts/viewer"
|
|
"github.com/fleetdm/fleet/v4/server/fleet"
|
|
android_mock "github.com/fleetdm/fleet/v4/server/mdm/android/mock"
|
|
ds_mock "github.com/fleetdm/fleet/v4/server/mock"
|
|
"github.com/fleetdm/fleet/v4/server/ptr"
|
|
kitlog "github.com/go-kit/log"
|
|
"github.com/jmoiron/sqlx"
|
|
"github.com/stretchr/testify/mock"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestEnterprisesAuth(t *testing.T) {
|
|
androidAPIClient := android_mock.Client{}
|
|
androidAPIClient.InitCommonMocks()
|
|
logger := kitlog.NewLogfmtLogger(os.Stdout)
|
|
fleetDS := InitCommonDSMocks()
|
|
fleetSvc := mockService{}
|
|
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, &fleetSvc)
|
|
require.NoError(t, err)
|
|
|
|
testCases := []struct {
|
|
name string
|
|
user *fleet.User
|
|
shouldFailWrite bool
|
|
shouldFailRead bool
|
|
}{
|
|
{
|
|
"global admin",
|
|
&fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)},
|
|
false,
|
|
false,
|
|
},
|
|
{
|
|
"global maintainer",
|
|
&fleet.User{GlobalRole: ptr.String(fleet.RoleMaintainer)},
|
|
true,
|
|
true,
|
|
},
|
|
{
|
|
"global gitops",
|
|
&fleet.User{GlobalRole: ptr.String(fleet.RoleGitOps)},
|
|
true,
|
|
true,
|
|
},
|
|
{
|
|
"global observer",
|
|
&fleet.User{GlobalRole: ptr.String(fleet.RoleObserver)},
|
|
true,
|
|
true,
|
|
},
|
|
{
|
|
"global observer+",
|
|
&fleet.User{GlobalRole: ptr.String(fleet.RoleObserverPlus)},
|
|
true,
|
|
true,
|
|
},
|
|
{
|
|
"team admin",
|
|
&fleet.User{Teams: []fleet.UserTeam{{Team: fleet.Team{ID: 1}, Role: fleet.RoleAdmin}}},
|
|
true,
|
|
true,
|
|
},
|
|
{
|
|
"team maintainer",
|
|
&fleet.User{Teams: []fleet.UserTeam{{Team: fleet.Team{ID: 1}, Role: fleet.RoleMaintainer}}},
|
|
true,
|
|
true,
|
|
},
|
|
{
|
|
"team observer",
|
|
&fleet.User{Teams: []fleet.UserTeam{{Team: fleet.Team{ID: 1}, Role: fleet.RoleObserver}}},
|
|
true,
|
|
true,
|
|
},
|
|
{
|
|
"team observer+",
|
|
&fleet.User{Teams: []fleet.UserTeam{{Team: fleet.Team{ID: 1}, Role: fleet.RoleObserverPlus}}},
|
|
true,
|
|
true,
|
|
},
|
|
}
|
|
for _, tt := range testCases {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
ctx := viewer.NewContext(context.Background(), viewer.Viewer{User: tt.user})
|
|
|
|
_, err := svc.GetEnterprise(ctx)
|
|
checkAuthErr(t, tt.shouldFailRead, err)
|
|
|
|
err = svc.DeleteEnterprise(ctx)
|
|
checkAuthErr(t, tt.shouldFailWrite, err)
|
|
|
|
_, err = svc.EnterpriseSignup(ctx)
|
|
checkAuthErr(t, tt.shouldFailWrite, err)
|
|
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
defer cancel()
|
|
_, err = svc.EnterpriseSignupSSE(ctx)
|
|
checkAuthErr(t, tt.shouldFailRead, err)
|
|
|
|
})
|
|
}
|
|
|
|
t.Run("unauthorized", func(t *testing.T) {
|
|
err := svc.EnterpriseSignupCallback(context.Background(), "signup_token", "token")
|
|
checkAuthErr(t, false, err)
|
|
err = svc.EnterpriseSignupCallback(context.Background(), "bad_token", "token")
|
|
checkAuthErr(t, true, err)
|
|
})
|
|
}
|
|
|
|
func checkAuthErr(t *testing.T, shouldFail bool, err error) {
|
|
t.Helper()
|
|
if shouldFail {
|
|
require.Error(t, err)
|
|
var forbiddenError *authz.Forbidden
|
|
require.ErrorAs(t, err, &forbiddenError)
|
|
} else {
|
|
require.NoError(t, err)
|
|
}
|
|
}
|
|
|
|
func InitCommonDSMocks() fleet.AndroidDatastore {
|
|
ds := AndroidMockDS{}
|
|
ds.Datastore.InitCommonMocks()
|
|
|
|
ds.Store.AppConfigFunc = func(_ context.Context) (*fleet.AppConfig, error) {
|
|
return &fleet.AppConfig{}, nil
|
|
}
|
|
ds.Store.SetAndroidEnabledAndConfiguredFunc = func(_ context.Context, configured bool) error {
|
|
return nil
|
|
}
|
|
ds.Store.UserOrDeletedUserByIDFunc = func(ctx context.Context, id uint) (*fleet.User, error) {
|
|
return &fleet.User{ID: id}, nil
|
|
}
|
|
ds.Store.GetAllMDMConfigAssetsByNameFunc = func(ctx context.Context, assetNames []fleet.MDMAssetName,
|
|
queryerContext sqlx.QueryerContext) (map[fleet.MDMAssetName]fleet.MDMConfigAsset, error) {
|
|
result := make(map[fleet.MDMAssetName]fleet.MDMConfigAsset, len(assetNames))
|
|
for _, name := range assetNames {
|
|
result[name] = fleet.MDMConfigAsset{Value: []byte("value")}
|
|
}
|
|
return result, nil
|
|
}
|
|
ds.Store.InsertOrReplaceMDMConfigAssetFunc = func(ctx context.Context, asset fleet.MDMConfigAsset) error {
|
|
return nil
|
|
}
|
|
ds.Store.DeleteMDMConfigAssetsByNameFunc = func(ctx context.Context, assetNames []fleet.MDMAssetName) error {
|
|
return nil
|
|
}
|
|
ds.Store.BulkSetAndroidHostsUnenrolledFunc = func(ctx context.Context) error {
|
|
return nil
|
|
}
|
|
return &ds
|
|
}
|
|
|
|
type AndroidMockDS struct {
|
|
android_mock.Datastore
|
|
ds_mock.Store
|
|
}
|
|
|
|
type mockService struct {
|
|
mock.Mock
|
|
fleet.Service
|
|
}
|
|
|
|
// NewActivity mocks the fleet.Service method.
|
|
func (m *mockService) NewActivity(_ context.Context, _ *fleet.User, _ fleet.ActivityDetails) error {
|
|
return nil
|
|
}
|