mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 09:28:54 +00:00
Added activity feed items for NDES SCEP proxy config. (#22902)
For #21955 (the story has a video demo of core functionality) Follow up for PR #22542 # Checklist for submitter - [x] Added/updated tests - [x] Manual QA for all new/changed functionality
This commit is contained in:
parent
de54588d99
commit
808d6a0007
4 changed files with 118 additions and 6 deletions
|
|
@ -1374,6 +1374,24 @@ This activity contains the following fields:
|
|||
}
|
||||
```
|
||||
|
||||
## added_ndes_scep_proxy
|
||||
|
||||
Generated when NDES SCEP proxy is configured in Fleet.
|
||||
|
||||
This activity does not contain any detail fields.
|
||||
|
||||
## deleted_ndes_scep_proxy
|
||||
|
||||
Generated when NDES SCEP proxy configuration is deleted in Fleet.
|
||||
|
||||
This activity does not contain any detail fields.
|
||||
|
||||
## edited_ndes_scep_proxy
|
||||
|
||||
Generated when NDES SCEP proxy configuration is edited in Fleet.
|
||||
|
||||
This activity does not contain any detail fields.
|
||||
|
||||
|
||||
<meta name="title" value="Audit logs">
|
||||
<meta name="pageOrderInSection" value="1400">
|
||||
|
|
|
|||
|
|
@ -108,6 +108,10 @@ var ActivityDetailsList = []ActivityDetails{
|
|||
ActivityAddedAppStoreApp{},
|
||||
ActivityDeletedAppStoreApp{},
|
||||
ActivityInstalledAppStoreApp{},
|
||||
|
||||
ActivityAddedNDESSCEPProxy{},
|
||||
ActivityDeletedNDESSCEPProxy{},
|
||||
ActivityEditedNDESSCEPProxy{},
|
||||
}
|
||||
|
||||
type ActivityDetails interface {
|
||||
|
|
@ -1851,3 +1855,33 @@ func (a ActivityInstalledAppStoreApp) Documentation() (string, string, string) {
|
|||
"command_uuid": "98765432-1234-1234-1234-1234567890ab"
|
||||
}`
|
||||
}
|
||||
|
||||
type ActivityAddedNDESSCEPProxy struct{}
|
||||
|
||||
func (a ActivityAddedNDESSCEPProxy) ActivityName() string {
|
||||
return "added_ndes_scep_proxy"
|
||||
}
|
||||
|
||||
func (a ActivityAddedNDESSCEPProxy) Documentation() (activity string, details string, detailsExample string) {
|
||||
return "Generated when NDES SCEP proxy is configured in Fleet.", `This activity does not contain any detail fields.`, ``
|
||||
}
|
||||
|
||||
type ActivityDeletedNDESSCEPProxy struct{}
|
||||
|
||||
func (a ActivityDeletedNDESSCEPProxy) ActivityName() string {
|
||||
return "deleted_ndes_scep_proxy"
|
||||
}
|
||||
|
||||
func (a ActivityDeletedNDESSCEPProxy) Documentation() (activity string, details string, detailsExample string) {
|
||||
return "Generated when NDES SCEP proxy configuration is deleted in Fleet.", `This activity does not contain any detail fields.`, ``
|
||||
}
|
||||
|
||||
type ActivityEditedNDESSCEPProxy struct{}
|
||||
|
||||
func (a ActivityEditedNDESSCEPProxy) ActivityName() string {
|
||||
return "edited_ndes_scep_proxy"
|
||||
}
|
||||
|
||||
func (a ActivityEditedNDESSCEPProxy) Documentation() (activity string, details string, detailsExample string) {
|
||||
return "Generated when NDES SCEP proxy configuration is edited in Fleet.", `This activity does not contain any detail fields.`, ``
|
||||
}
|
||||
|
|
|
|||
|
|
@ -335,6 +335,14 @@ func (svc *Service) ModifyAppConfig(ctx context.Context, p []byte, applyOpts fle
|
|||
return nil, ctxerr.Wrap(ctx, err)
|
||||
}
|
||||
|
||||
type ndesStatusType string
|
||||
const (
|
||||
ndesStatusAdded ndesStatusType = "added"
|
||||
ndesStatusEdited ndesStatusType = "edited"
|
||||
ndesStatusDeleted ndesStatusType = "deleted"
|
||||
)
|
||||
var ndesStatus ndesStatusType
|
||||
|
||||
// Validate NDES SCEP URLs if they changed. Validation is done in both dry run and normal mode.
|
||||
if newAppConfig.Integrations.NDESSCEPProxy.Set && newAppConfig.Integrations.NDESSCEPProxy.Valid && !license.IsPremium() {
|
||||
invalid.Append("integrations.ndes_scep_proxy", ErrMissingLicense.Error())
|
||||
|
|
@ -347,12 +355,7 @@ func (svc *Service) ModifyAppConfig(ctx context.Context, p []byte, applyOpts fle
|
|||
case !newAppConfig.Integrations.NDESSCEPProxy.Valid:
|
||||
// User is explicitly clearing this setting
|
||||
appConfig.Integrations.NDESSCEPProxy.Valid = false
|
||||
// Delete stored password
|
||||
if !applyOpts.DryRun {
|
||||
if err := svc.ds.HardDeleteMDMConfigAsset(ctx, fleet.MDMAssetNDESPassword); err != nil {
|
||||
return nil, ctxerr.Wrap(ctx, err, "delete NDES SCEP password")
|
||||
}
|
||||
}
|
||||
ndesStatus = ndesStatusDeleted
|
||||
default:
|
||||
// User is updating the setting
|
||||
appConfig.Integrations.NDESSCEPProxy.Value.URL = fleet.Preprocess(newAppConfig.Integrations.NDESSCEPProxy.Value.URL)
|
||||
|
|
@ -367,15 +370,18 @@ func (svc *Service) ModifyAppConfig(ctx context.Context, p []byte, applyOpts fle
|
|||
validateAdminURL, validateSCEPURL := false, false
|
||||
newSCEPProxy := appConfig.Integrations.NDESSCEPProxy.Value
|
||||
if !oldAppConfig.Integrations.NDESSCEPProxy.Valid {
|
||||
ndesStatus = ndesStatusAdded
|
||||
validateAdminURL, validateSCEPURL = true, true
|
||||
} else {
|
||||
oldSCEPProxy := oldAppConfig.Integrations.NDESSCEPProxy.Value
|
||||
if newSCEPProxy.URL != oldSCEPProxy.URL {
|
||||
ndesStatus = ndesStatusEdited
|
||||
validateSCEPURL = true
|
||||
}
|
||||
if newSCEPProxy.AdminURL != oldSCEPProxy.AdminURL ||
|
||||
newSCEPProxy.Username != oldSCEPProxy.Username ||
|
||||
(newSCEPProxy.Password != "" && newSCEPProxy.Password != fleet.MaskedPassword) {
|
||||
ndesStatus = ndesStatusEdited
|
||||
validateAdminURL = true
|
||||
}
|
||||
}
|
||||
|
|
@ -587,6 +593,27 @@ func (svc *Service) ModifyAppConfig(ctx context.Context, p []byte, applyOpts fle
|
|||
return nil, err
|
||||
}
|
||||
|
||||
switch ndesStatus {
|
||||
case ndesStatusAdded:
|
||||
if err = svc.NewActivity(ctx, authz.UserFromContext(ctx), fleet.ActivityAddedNDESSCEPProxy{}); err != nil {
|
||||
return nil, ctxerr.Wrap(ctx, err, "create activity for added NDES SCEP proxy")
|
||||
}
|
||||
case ndesStatusEdited:
|
||||
if err = svc.NewActivity(ctx, authz.UserFromContext(ctx), fleet.ActivityEditedNDESSCEPProxy{}); err != nil {
|
||||
return nil, ctxerr.Wrap(ctx, err, "create activity for edited NDES SCEP proxy")
|
||||
}
|
||||
case ndesStatusDeleted:
|
||||
// Delete stored password
|
||||
if err := svc.ds.HardDeleteMDMConfigAsset(ctx, fleet.MDMAssetNDESPassword); err != nil {
|
||||
return nil, ctxerr.Wrap(ctx, err, "delete NDES SCEP password")
|
||||
}
|
||||
if err = svc.NewActivity(ctx, authz.UserFromContext(ctx), fleet.ActivityDeletedNDESSCEPProxy{}); err != nil {
|
||||
return nil, ctxerr.Wrap(ctx, err, "create activity for deleted NDES SCEP proxy")
|
||||
}
|
||||
default:
|
||||
// No change, no activity.
|
||||
}
|
||||
|
||||
if oldAppConfig.MDM.MacOSSetup.MacOSSetupAssistant.Value != appConfig.MDM.MacOSSetup.MacOSSetupAssistant.Value &&
|
||||
appConfig.MDM.MacOSSetup.MacOSSetupAssistant.Value == "" {
|
||||
// clear macos setup assistant for no team - note that we cannot call
|
||||
|
|
|
|||
|
|
@ -1474,6 +1474,11 @@ func TestModifyAppConfigForNDESSCEPProxy(t *testing.T) {
|
|||
fleetConfig := config.TestConfig()
|
||||
svc, ctx = newTestServiceWithConfig(t, ds, fleetConfig, nil, nil, &TestServerOpts{License: &fleet.LicenseInfo{Tier: fleet.TierPremium}})
|
||||
ctx = viewer.NewContext(ctx, viewer.Viewer{User: admin})
|
||||
ds.NewActivityFunc = func(ctx context.Context, user *fleet.User, activity fleet.ActivityDetails, details []byte,
|
||||
createdAt time.Time) error {
|
||||
assert.IsType(t, fleet.ActivityAddedNDESSCEPProxy{}, activity)
|
||||
return nil
|
||||
}
|
||||
ac, err := svc.ModifyAppConfig(ctx, []byte(jsonPayload), fleet.ApplySpecOptions{})
|
||||
require.NoError(t, err)
|
||||
checkSCEPProxy := func() {
|
||||
|
|
@ -1486,6 +1491,10 @@ func TestModifyAppConfigForNDESSCEPProxy(t *testing.T) {
|
|||
checkSCEPProxy()
|
||||
assert.True(t, validateNDESSCEPURLCalled)
|
||||
assert.True(t, validateNDESSCEPAdminURLCalled)
|
||||
assert.True(t, ds.SaveAppConfigFuncInvoked)
|
||||
ds.SaveAppConfigFuncInvoked = false
|
||||
assert.True(t, ds.NewActivityFuncInvoked)
|
||||
ds.NewActivityFuncInvoked = false
|
||||
|
||||
// Validation not done if there is no change
|
||||
appConfig = ac
|
||||
|
|
@ -1497,6 +1506,8 @@ func TestModifyAppConfigForNDESSCEPProxy(t *testing.T) {
|
|||
checkSCEPProxy()
|
||||
assert.False(t, validateNDESSCEPURLCalled)
|
||||
assert.False(t, validateNDESSCEPAdminURLCalled)
|
||||
assert.False(t, ds.NewActivityFuncInvoked)
|
||||
ds.NewActivityFuncInvoked = false
|
||||
|
||||
// Validation not done if there is no change, part 2
|
||||
validateNDESSCEPURLCalled = false
|
||||
|
|
@ -1506,10 +1517,17 @@ func TestModifyAppConfigForNDESSCEPProxy(t *testing.T) {
|
|||
checkSCEPProxy()
|
||||
assert.False(t, validateNDESSCEPURLCalled)
|
||||
assert.False(t, validateNDESSCEPAdminURLCalled)
|
||||
assert.False(t, ds.NewActivityFuncInvoked)
|
||||
ds.NewActivityFuncInvoked = false
|
||||
|
||||
// Validation done for SCEP URL. Password is blank, which is not considered a change.
|
||||
scepURL = "https://new.com/mscep/mscep.dll"
|
||||
jsonPayload = fmt.Sprintf(jsonPayloadBase, scepURL, adminURL, username, "")
|
||||
ds.NewActivityFunc = func(ctx context.Context, user *fleet.User, activity fleet.ActivityDetails, details []byte,
|
||||
createdAt time.Time) error {
|
||||
assert.IsType(t, fleet.ActivityEditedNDESSCEPProxy{}, activity)
|
||||
return nil
|
||||
}
|
||||
ac, err = svc.ModifyAppConfig(ctx, []byte(jsonPayload), fleet.ApplySpecOptions{})
|
||||
require.NoError(t, err)
|
||||
checkSCEPProxy()
|
||||
|
|
@ -1518,6 +1536,8 @@ func TestModifyAppConfigForNDESSCEPProxy(t *testing.T) {
|
|||
appConfig = ac
|
||||
validateNDESSCEPURLCalled = false
|
||||
validateNDESSCEPAdminURLCalled = false
|
||||
assert.True(t, ds.NewActivityFuncInvoked)
|
||||
ds.NewActivityFuncInvoked = false
|
||||
|
||||
// Validation done for SCEP admin URL
|
||||
adminURL = "https://new.com/mscep_admin/"
|
||||
|
|
@ -1527,6 +1547,8 @@ func TestModifyAppConfigForNDESSCEPProxy(t *testing.T) {
|
|||
checkSCEPProxy()
|
||||
assert.False(t, validateNDESSCEPURLCalled)
|
||||
assert.True(t, validateNDESSCEPAdminURLCalled)
|
||||
assert.True(t, ds.NewActivityFuncInvoked)
|
||||
ds.NewActivityFuncInvoked = false
|
||||
|
||||
// Validation fails
|
||||
validateNDESSCEPURLCalled = false
|
||||
|
|
@ -1545,6 +1567,8 @@ func TestModifyAppConfigForNDESSCEPProxy(t *testing.T) {
|
|||
assert.ErrorContains(t, err, "**invalid**")
|
||||
assert.True(t, validateNDESSCEPURLCalled)
|
||||
assert.True(t, validateNDESSCEPAdminURLCalled)
|
||||
assert.False(t, ds.NewActivityFuncInvoked)
|
||||
ds.NewActivityFuncInvoked = false
|
||||
|
||||
// Reset validation
|
||||
validateNDESSCEPURLCalled = false
|
||||
|
|
@ -1577,8 +1601,15 @@ func TestModifyAppConfigForNDESSCEPProxy(t *testing.T) {
|
|||
assert.False(t, validateNDESSCEPURLCalled)
|
||||
assert.False(t, validateNDESSCEPAdminURLCalled)
|
||||
assert.False(t, ds.HardDeleteMDMConfigAssetFuncInvoked, "DB write should not happen in dry run")
|
||||
assert.False(t, ds.NewActivityFuncInvoked)
|
||||
ds.NewActivityFuncInvoked = false
|
||||
|
||||
// Second, real run.
|
||||
ds.NewActivityFunc = func(ctx context.Context, user *fleet.User, activity fleet.ActivityDetails, details []byte,
|
||||
createdAt time.Time) error {
|
||||
assert.IsType(t, fleet.ActivityDeletedNDESSCEPProxy{}, activity)
|
||||
return nil
|
||||
}
|
||||
ds.HardDeleteMDMConfigAssetFunc = func(ctx context.Context, assetName fleet.MDMAssetName) error {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1590,6 +1621,8 @@ func TestModifyAppConfigForNDESSCEPProxy(t *testing.T) {
|
|||
assert.False(t, validateNDESSCEPURLCalled)
|
||||
assert.False(t, validateNDESSCEPAdminURLCalled)
|
||||
assert.True(t, ds.HardDeleteMDMConfigAssetFuncInvoked)
|
||||
assert.True(t, ds.NewActivityFuncInvoked)
|
||||
ds.NewActivityFuncInvoked = false
|
||||
|
||||
// Cannot configure NDES without private key
|
||||
fleetConfig.Server.PrivateKey = ""
|
||||
|
|
|
|||
Loading…
Reference in a new issue