diff --git a/server/datastore/mysql/hosts.go b/server/datastore/mysql/hosts.go index 3686262b76e..365e3571854 100644 --- a/server/datastore/mysql/hosts.go +++ b/server/datastore/mysql/hosts.go @@ -4253,7 +4253,7 @@ func (ds *Datastore) DeleteHostIDP(ctx context.Context, id uint) error { // remove an scim associations, if present. Note that this will not delete the associated row in // scim_users, if it exists - if err := deleteHostSCIMUserMapping(ctx, tx, id); err != nil { + if _, err := deleteHostSCIMUserMapping(ctx, tx, id); err != nil { return ctxerr.Wrap(ctx, err, "delete existing host SCIM user mapping") } @@ -4816,7 +4816,7 @@ WHERE %s` // host_id (INSERT ... ON DUPLICATE KEY UPDATE) and handles its own profile resend, // so calling it once per host is safe. for _, hid := range hostIDs { - if err := associateHostWithScimUser(ctx, tx, hid, user.ID); err != nil { + if _, err := associateHostWithScimUser(ctx, tx, hid, user.ID); err != nil { return ctxerr.Wrapf(ctx, err, "maybeAssociateScimUserWithHostMDMIdPAccount: associate host %d with scim user", hid) } } @@ -4890,7 +4890,7 @@ func maybeAssociateHostMDMIdPWithScimUser(ctx context.Context, tx sqlx.ExtContex return nil } - err = associateHostWithScimUser(ctx, tx, hostID, scimUser.ID) + _, err = associateHostWithScimUser(ctx, tx, hostID, scimUser.ID) if err != nil { return ctxerr.Wrap(ctx, err, "associate host with scim user") } @@ -4900,11 +4900,12 @@ func maybeAssociateHostMDMIdPWithScimUser(ctx context.Context, tx sqlx.ExtContex func (ds *Datastore) associateHostWithScimUser(ctx context.Context, hostID uint, scimUserID uint) error { return ds.withRetryTxx(ctx, func(tx sqlx.ExtContext) error { - return associateHostWithScimUser(ctx, tx, hostID, scimUserID) + _, err := associateHostWithScimUser(ctx, tx, hostID, scimUserID) + return err }) } -func associateHostWithScimUser(ctx context.Context, tx sqlx.ExtContext, hostID uint, scimUserID uint) error { +func associateHostWithScimUser(ctx context.Context, tx sqlx.ExtContext, hostID uint, scimUserID uint) ([]fleet.ActivityTypeResentCertificate, error) { // On conflict with host_scim_user.PRIMARY (host_id), reassign the host to the current SCIM user. result, err := tx.ExecContext( ctx, @@ -4913,14 +4914,14 @@ func associateHostWithScimUser(ctx context.Context, tx sqlx.ExtContext, hostID u hostID, scimUserID, ) if err != nil { - return ctxerr.Wrap(ctx, err, "insert into host_scim_user") + return nil, ctxerr.Wrap(ctx, err, "insert into host_scim_user") } rows, err := result.RowsAffected() if err != nil { - return ctxerr.Wrap(ctx, err, "host_scim_user rows affected") + return nil, ctxerr.Wrap(ctx, err, "host_scim_user rows affected") } if rows == 0 { - return nil + return nil, nil } // resend profiles that depend on the user now associated with that host // @@ -4930,37 +4931,71 @@ func associateHostWithScimUser(ctx context.Context, tx sqlx.ExtContext, hostID u } // deleteHostSCIMUserMapping is a helper function to delete SCIM user mapping for a host -func deleteHostSCIMUserMapping(ctx context.Context, exec sqlx.ExtContext, hostID uint) error { - _, err := exec.ExecContext(ctx, `DELETE FROM host_scim_user WHERE host_id = ?`, hostID) +func deleteHostSCIMUserMapping(ctx context.Context, exec sqlx.ExtContext, hostID uint) ([]fleet.ActivityTypeResentCertificate, error) { + result, err := exec.ExecContext(ctx, `DELETE FROM host_scim_user WHERE host_id = ?`, hostID) + if err != nil { + return nil, ctxerr.Wrap(ctx, err, "delete host SCIM user mapping") + } + rows, err := result.RowsAffected() if err != nil { - return ctxerr.Wrap(ctx, err, "delete host SCIM user mapping") + return nil, ctxerr.Wrap(ctx, err, "delete host SCIM user mapping rows affected") + } + if rows == 0 { + return nil, nil } - return triggerResendProfilesUsingVariables(ctx, exec, []uint{hostID}, - []fleet.FleetVarName{ - fleet.FleetVarHostEndUserIDPUsername, - fleet.FleetVarHostEndUserIDPUsernameLocalPart, - fleet.FleetVarHostEndUserIDPGroups, - fleet.FleetVarHostEndUserIDPDepartment, - fleet.FleetVarHostEndUserIDPFullname, - }) + vars := []fleet.FleetVarName{ + fleet.FleetVarHostEndUserIDPUsername, + fleet.FleetVarHostEndUserIDPUsernameLocalPart, + fleet.FleetVarHostEndUserIDPGroups, + fleet.FleetVarHostEndUserIDPDepartment, + fleet.FleetVarHostEndUserIDPFullname, + } + resentCerts, err := selectCertTemplatesToResend(ctx, exec, []uint{hostID}, fleetVarNamesToDBVars(vars)) + if err != nil { + return nil, err + } + if err := triggerResendProfilesUsingVariables(ctx, exec, []uint{hostID}, vars); err != nil { + return nil, err + } + return resentCerts, nil } -func (ds *Datastore) SetOrUpdateHostSCIMUserMapping(ctx context.Context, hostID uint, scimUserID uint) error { - return ds.withRetryTxx(ctx, func(tx sqlx.ExtContext) error { +func (ds *Datastore) SetOrUpdateHostSCIMUserMapping(ctx context.Context, hostID uint, scimUserID uint) ([]fleet.ActivityTypeResentCertificate, error) { + var allResentCerts []fleet.ActivityTypeResentCertificate + err := ds.withRetryTxx(ctx, func(tx sqlx.ExtContext) error { + allResentCerts = nil // Remove any existing SCIM user mapping for this host - if err := deleteHostSCIMUserMapping(ctx, tx, hostID); err != nil { + delCerts, err := deleteHostSCIMUserMapping(ctx, tx, hostID) + if err != nil { return err } + allResentCerts = append(allResentCerts, delCerts...) - return associateHostWithScimUser(ctx, tx, hostID, scimUserID) + assocCerts, err := associateHostWithScimUser(ctx, tx, hostID, scimUserID) + if err != nil { + return err + } + allResentCerts = append(allResentCerts, assocCerts...) + return nil }) + if err != nil { + return nil, err + } + return allResentCerts, nil } -func (ds *Datastore) DeleteHostSCIMUserMapping(ctx context.Context, hostID uint) error { - return ds.withTx(ctx, func(tx sqlx.ExtContext) error { - return deleteHostSCIMUserMapping(ctx, tx, hostID) +func (ds *Datastore) DeleteHostSCIMUserMapping(ctx context.Context, hostID uint) ([]fleet.ActivityTypeResentCertificate, error) { + var resentCerts []fleet.ActivityTypeResentCertificate + err := ds.withTx(ctx, func(tx sqlx.ExtContext) error { + var txErr error + resentCerts, txErr = deleteHostSCIMUserMapping(ctx, tx, hostID) + return txErr }) + if err != nil { + return nil, err + } + return resentCerts, nil } func (ds *Datastore) GetHostEmails(ctx context.Context, hostUUID string, source string) ([]string, error) { diff --git a/server/datastore/mysql/hosts_test.go b/server/datastore/mysql/hosts_test.go index 3e5bbab0c98..39495dfbfab 100644 --- a/server/datastore/mysql/hosts_test.go +++ b/server/datastore/mysql/hosts_test.go @@ -9615,7 +9615,8 @@ func testHostsDeleteHosts(t *testing.T, ds *Datastore) { // Create a SCIM user and link it to host scimUserID, err := ds.CreateScimUser(ctx, &fleet.ScimUser{UserName: "user"}) require.NoError(t, err) - require.NoError(t, associateHostWithScimUser(ctx, ds.writer(ctx), host.ID, scimUserID)) + _, err = associateHostWithScimUser(ctx, ds.writer(ctx), host.ID, scimUserID) + require.NoError(t, err) script, err := ds.NewScript(ctx, &fleet.Script{ Name: "script.sh", diff --git a/server/datastore/mysql/scim.go b/server/datastore/mysql/scim.go index 0d7c001463b..461d00b0a06 100644 --- a/server/datastore/mysql/scim.go +++ b/server/datastore/mysql/scim.go @@ -1266,25 +1266,32 @@ func triggerResendProfilesForIDPGroupChangeByUsers(ctx context.Context, tx sqlx. []fleet.FleetVarName{fleet.FleetVarHostEndUserIDPGroups}) } -func triggerResendProfilesForIDPUserAddedToHost(ctx context.Context, tx sqlx.ExtContext, hostID, updatedScimUserID uint) error { +func triggerResendProfilesForIDPUserAddedToHost(ctx context.Context, tx sqlx.ExtContext, hostID, updatedScimUserID uint) ([]fleet.ActivityTypeResentCertificate, error) { // check that this user is indeed the scim IdP user for this host (and not an // extra, unused one) user, err := getScimUserLiteByHostID(ctx, tx, hostID) if err != nil { - return err + return nil, err } if updatedScimUserID != user.ID { // host is not impacted, updated user is not its IdP user - return nil + return nil, nil } - return triggerResendProfilesUsingVariables(ctx, tx, []uint{hostID}, - []fleet.FleetVarName{ - fleet.FleetVarHostEndUserIDPUsername, - fleet.FleetVarHostEndUserIDPUsernameLocalPart, - fleet.FleetVarHostEndUserIDPDepartment, - fleet.FleetVarHostEndUserIDPGroups, - fleet.FleetVarHostEndUserIDPFullname, - }) + vars := []fleet.FleetVarName{ + fleet.FleetVarHostEndUserIDPUsername, + fleet.FleetVarHostEndUserIDPUsernameLocalPart, + fleet.FleetVarHostEndUserIDPDepartment, + fleet.FleetVarHostEndUserIDPGroups, + fleet.FleetVarHostEndUserIDPFullname, + } + resentCerts, err := selectCertTemplatesToResend(ctx, tx, []uint{hostID}, fleetVarNamesToDBVars(vars)) + if err != nil { + return nil, err + } + if err := triggerResendProfilesUsingVariables(ctx, tx, []uint{hostID}, vars); err != nil { + return nil, err + } + return resentCerts, nil } func selectCertTemplatesToResend(ctx context.Context, tx sqlx.ExtContext, hostIDs []uint, vars []any) ([]fleet.ActivityTypeResentCertificate, error) { @@ -1355,6 +1362,7 @@ func selectCertTemplatesToResend(ctx context.Context, tx sqlx.ExtContext, hostID HostDisplayName: fleet.HostDisplayName(r.ComputerName, r.Hostname, r.HardwareModel, r.HardwareSerial), CertificateTemplateID: r.CertificateTemplateID, CertificateName: r.CertificateName, + Automated: true, }) } return activities, nil diff --git a/server/datastore/mysql/scim_test.go b/server/datastore/mysql/scim_test.go index 5df95ea35c7..37658a63037 100644 --- a/server/datastore/mysql/scim_test.go +++ b/server/datastore/mysql/scim_test.go @@ -2681,7 +2681,7 @@ func testSetOrUpdateHostSCIMUserMapping(t *testing.T, ds *Datastore) { hostID2 := uint(2) // Create new host-SCIM user mapping - err = ds.SetOrUpdateHostSCIMUserMapping(ctx, hostID1, user1.ID) + _, err = ds.SetOrUpdateHostSCIMUserMapping(ctx, hostID1, user1.ID) require.NoError(t, err) // Verify the mapping was created @@ -2693,7 +2693,7 @@ func testSetOrUpdateHostSCIMUserMapping(t *testing.T, ds *Datastore) { assert.Equal(t, user1.ID, scimUserID) // Test 2: Update existing host-SCIM user mapping - err = ds.SetOrUpdateHostSCIMUserMapping(ctx, hostID1, user2.ID) + _, err = ds.SetOrUpdateHostSCIMUserMapping(ctx, hostID1, user2.ID) require.NoError(t, err) // Verify the mapping was updated (should now point to user2) @@ -2712,7 +2712,7 @@ func testSetOrUpdateHostSCIMUserMapping(t *testing.T, ds *Datastore) { assert.Equal(t, 1, count) // Test 3: Create mapping for a different host - err = ds.SetOrUpdateHostSCIMUserMapping(ctx, hostID2, user1.ID) + _, err = ds.SetOrUpdateHostSCIMUserMapping(ctx, hostID2, user1.ID) require.NoError(t, err) // Verify both hosts have mappings @@ -2730,7 +2730,7 @@ func testSetOrUpdateHostSCIMUserMapping(t *testing.T, ds *Datastore) { assert.Equal(t, 2, count) // Update mapping back to original user for hostID1 - err = ds.SetOrUpdateHostSCIMUserMapping(ctx, hostID1, user1.ID) + _, err = ds.SetOrUpdateHostSCIMUserMapping(ctx, hostID1, user1.ID) require.NoError(t, err) // Verify hostID1 now maps to user1 @@ -2742,7 +2742,7 @@ func testSetOrUpdateHostSCIMUserMapping(t *testing.T, ds *Datastore) { // Error case - non-existent SCIM user nonExistentUserID := uint(999999) - err = ds.SetOrUpdateHostSCIMUserMapping(ctx, hostID1, nonExistentUserID) + _, err = ds.SetOrUpdateHostSCIMUserMapping(ctx, hostID1, nonExistentUserID) require.Error(t, err) assert.Contains(t, err.Error(), "foreign key constraint") diff --git a/server/fleet/activities.go b/server/fleet/activities.go index d4a3013afea..63a77b9f26d 100644 --- a/server/fleet/activities.go +++ b/server/fleet/activities.go @@ -1906,6 +1906,7 @@ type ActivityTypeResentCertificate struct { HostDisplayName string `json:"host_display_name"` CertificateTemplateID uint `json:"certificate_template_id"` CertificateName string `json:"certificate_name"` + Automated bool `json:"-"` } func (a ActivityTypeResentCertificate) ActivityName() string { @@ -1916,6 +1917,10 @@ func (a ActivityTypeResentCertificate) HostIDs() []uint { return []uint{a.HostID} } +func (a ActivityTypeResentCertificate) WasFromAutomation() bool { + return a.Automated +} + type ActivityTypeEditedHostIdpData struct { HostID uint `json:"host_id"` HostDisplayName string `json:"host_display_name"` diff --git a/server/fleet/datastore.go b/server/fleet/datastore.go index 4e846d1f8cf..3858853b57a 100644 --- a/server/fleet/datastore.go +++ b/server/fleet/datastore.go @@ -388,9 +388,11 @@ type Datastore interface { DeleteHostIDP(ctx context.Context, id uint) error // SetOrUpdateHostSCIMUserMapping associates a host with a SCIM user. If a // mapping already exists, it will be updated to the new SCIM user. - SetOrUpdateHostSCIMUserMapping(ctx context.Context, hostID uint, scimUserID uint) error + // Returns any resent certificate activities that need to be created. + SetOrUpdateHostSCIMUserMapping(ctx context.Context, hostID uint, scimUserID uint) ([]ActivityTypeResentCertificate, error) // DeleteHostSCIMUserMapping removes the association between a host and a SCIM user. - DeleteHostSCIMUserMapping(ctx context.Context, hostID uint) error + // Returns any resent certificate activities that need to be created. + DeleteHostSCIMUserMapping(ctx context.Context, hostID uint) ([]ActivityTypeResentCertificate, error) // ListHostBatteries returns the list of batteries for the given host ID. ListHostBatteries(ctx context.Context, id uint) ([]*HostBattery, error) ListUpcomingHostMaintenanceWindows(ctx context.Context, hid uint) ([]*HostMaintenanceWindow, error) diff --git a/server/mock/datastore_mock.go b/server/mock/datastore_mock.go index 536d16c689d..a391ea5c054 100644 --- a/server/mock/datastore_mock.go +++ b/server/mock/datastore_mock.go @@ -296,9 +296,9 @@ type SetOrUpdateIDPHostDeviceMappingFunc func(ctx context.Context, hostID uint, type DeleteHostIDPFunc func(ctx context.Context, id uint) error -type SetOrUpdateHostSCIMUserMappingFunc func(ctx context.Context, hostID uint, scimUserID uint) error +type SetOrUpdateHostSCIMUserMappingFunc func(ctx context.Context, hostID uint, scimUserID uint) ([]fleet.ActivityTypeResentCertificate, error) -type DeleteHostSCIMUserMappingFunc func(ctx context.Context, hostID uint) error +type DeleteHostSCIMUserMappingFunc func(ctx context.Context, hostID uint) ([]fleet.ActivityTypeResentCertificate, error) type ListHostBatteriesFunc func(ctx context.Context, id uint) ([]*fleet.HostBattery, error) @@ -6365,14 +6365,14 @@ func (s *DataStore) DeleteHostIDP(ctx context.Context, id uint) error { return s.DeleteHostIDPFunc(ctx, id) } -func (s *DataStore) SetOrUpdateHostSCIMUserMapping(ctx context.Context, hostID uint, scimUserID uint) error { +func (s *DataStore) SetOrUpdateHostSCIMUserMapping(ctx context.Context, hostID uint, scimUserID uint) ([]fleet.ActivityTypeResentCertificate, error) { s.mu.Lock() s.SetOrUpdateHostSCIMUserMappingFuncInvoked = true s.mu.Unlock() return s.SetOrUpdateHostSCIMUserMappingFunc(ctx, hostID, scimUserID) } -func (s *DataStore) DeleteHostSCIMUserMapping(ctx context.Context, hostID uint) error { +func (s *DataStore) DeleteHostSCIMUserMapping(ctx context.Context, hostID uint) ([]fleet.ActivityTypeResentCertificate, error) { s.mu.Lock() s.DeleteHostSCIMUserMappingFuncInvoked = true s.mu.Unlock() diff --git a/server/service/hosts.go b/server/service/hosts.go index 08bb9adc2bb..7913289ef5a 100644 --- a/server/service/hosts.go +++ b/server/service/hosts.go @@ -2384,15 +2384,29 @@ func (svc *Service) SetHostDeviceMapping(ctx context.Context, hostID uint, email if err == nil && scimUser != nil { // User exists in SCIM, create/update the mapping for additional attributes // This enables fields like idp_full_name, idp_groups, etc. to appear in the API - if err := svc.ds.SetOrUpdateHostSCIMUserMapping(ctx, hostID, scimUser.ID); err != nil { + resentCerts, err := svc.ds.SetOrUpdateHostSCIMUserMapping(ctx, hostID, scimUser.ID) + if err != nil { // Log the error but don't fail the request since the main IDP mapping succeeded svc.logger.DebugContext(ctx, "failed to set SCIM user mapping", "err", err) + } else { + for _, cert := range resentCerts { + if err := svc.NewActivity(ctx, nil, cert); err != nil { + svc.logger.DebugContext(ctx, "failed to create resent_certificate activity", "err", err) + } + } } } else { // User doesn't exist in SCIM, remove any existing SCIM mapping for this host - if err := svc.ds.DeleteHostSCIMUserMapping(ctx, hostID); err != nil && !fleet.IsNotFound(err) { + resentCerts, err := svc.ds.DeleteHostSCIMUserMapping(ctx, hostID) + if err != nil && !fleet.IsNotFound(err) { // Log the error but don't fail the request svc.logger.DebugContext(ctx, "failed to delete SCIM user mapping", "err", err) + } else { + for _, cert := range resentCerts { + if err := svc.NewActivity(ctx, nil, cert); err != nil { + svc.logger.DebugContext(ctx, "failed to create resent_certificate activity", "err", err) + } + } } } diff --git a/server/service/hosts_test.go b/server/service/hosts_test.go index 60eb1ca3b44..7862a34feeb 100644 --- a/server/service/hosts_test.go +++ b/server/service/hosts_test.go @@ -4327,8 +4327,8 @@ func TestSetHostDeviceMapping(t *testing.T) { ds.ScimUserByUserNameOrEmailFunc = func(ctx context.Context, userName, email string) (*fleet.ScimUser, error) { return &fleet.ScimUser{ID: 1, UserName: "user@example.com"}, nil } - ds.SetOrUpdateHostSCIMUserMappingFunc = func(ctx context.Context, hostID uint, scimUserID uint) error { - return nil + ds.SetOrUpdateHostSCIMUserMappingFunc = func(ctx context.Context, hostID uint, scimUserID uint) ([]fleet.ActivityTypeResentCertificate, error) { + return nil, nil } ds.SetOrUpdateIDPHostDeviceMappingFunc = func(ctx context.Context, hostID uint, email string) error { return nil @@ -4368,8 +4368,8 @@ func TestSetHostDeviceMapping(t *testing.T) { ds.SetOrUpdateIDPHostDeviceMappingFunc = func(ctx context.Context, hostID uint, email string) error { return nil } - ds.DeleteHostSCIMUserMappingFunc = func(ctx context.Context, hostID uint) error { - return nil + ds.DeleteHostSCIMUserMappingFunc = func(ctx context.Context, hostID uint) ([]fleet.ActivityTypeResentCertificate, error) { + return nil, nil } ds.ListHostDeviceMappingFunc = func(ctx context.Context, hostID uint) ([]*fleet.HostDeviceMapping, error) { return []*fleet.HostDeviceMapping{{HostID: hostID, Email: "any@username.com", Source: fleet.DeviceMappingMDMIdpAccounts}}, nil @@ -4436,8 +4436,8 @@ func TestSetHostDeviceMapping(t *testing.T) { ds.ScimUserByUserNameOrEmailFunc = func(ctx context.Context, userName, email string) (*fleet.ScimUser, error) { return &fleet.ScimUser{ID: 1, UserName: "new@example.com"}, nil } - ds.SetOrUpdateHostSCIMUserMappingFunc = func(ctx context.Context, hostID uint, scimUserID uint) error { - return nil + ds.SetOrUpdateHostSCIMUserMappingFunc = func(ctx context.Context, hostID uint, scimUserID uint) ([]fleet.ActivityTypeResentCertificate, error) { + return nil, nil } ds.AppConfigFunc = func(ctx context.Context) (*fleet.AppConfig, error) { return &fleet.AppConfig{}, nil @@ -4472,8 +4472,8 @@ func TestSetHostDeviceMapping(t *testing.T) { ds.ScimUserByUserNameOrEmailFunc = func(ctx context.Context, userName, email string) (*fleet.ScimUser, error) { return &fleet.ScimUser{ID: 1, UserName: "user@example.com"}, nil } - ds.SetOrUpdateHostSCIMUserMappingFunc = func(ctx context.Context, hostID uint, scimUserID uint) error { - return nil + ds.SetOrUpdateHostSCIMUserMappingFunc = func(ctx context.Context, hostID uint, scimUserID uint) ([]fleet.ActivityTypeResentCertificate, error) { + return nil, nil } ds.AppConfigFunc = func(ctx context.Context) (*fleet.AppConfig, error) { return &fleet.AppConfig{}, nil diff --git a/server/service/orbit.go b/server/service/orbit.go index 791e33f52e7..5412968fafd 100644 --- a/server/service/orbit.go +++ b/server/service/orbit.go @@ -344,12 +344,12 @@ func (svc *Service) EnrollOrbit(ctx context.Context, hostInfo fleet.OrbitHostInf svc.logger.ErrorContext(ctx, "failed to find SCIM user for EUA token enrollment", "err", err, "host_id", host.ID) } else if err == nil && scimUser != nil { - if err := svc.ds.SetOrUpdateHostSCIMUserMapping(ctx, host.ID, scimUser.ID); err != nil { + if _, err := svc.ds.SetOrUpdateHostSCIMUserMapping(ctx, host.ID, scimUser.ID); err != nil { svc.logger.ErrorContext(ctx, "failed to set SCIM user mapping for EUA token enrollment", "err", err, "host_id", host.ID) } } else { - if err := svc.ds.DeleteHostSCIMUserMapping(ctx, host.ID); err != nil && !fleet.IsNotFound(err) { + if _, err := svc.ds.DeleteHostSCIMUserMapping(ctx, host.ID); err != nil && !fleet.IsNotFound(err) { svc.logger.ErrorContext(ctx, "failed to delete SCIM user mapping for EUA token enrollment", "err", err, "host_id", host.ID) } diff --git a/server/service/osquery_utils/queries.go b/server/service/osquery_utils/queries.go index ecefa1f081a..8b18a124bd5 100644 --- a/server/service/osquery_utils/queries.go +++ b/server/service/osquery_utils/queries.go @@ -3182,13 +3182,13 @@ func LinkWindowsHostMDMEnrollment(ctx context.Context, logger *slog.Logger, ds f } if err == nil && scimUser != nil { // User exists in SCIM, create/update the mapping for additional attributes (idp_full_name, idp_groups, etc.). - if err := ds.SetOrUpdateHostSCIMUserMapping(ctx, hostID, scimUser.ID); err != nil { + if _, err := ds.SetOrUpdateHostSCIMUserMapping(ctx, hostID, scimUser.ID); err != nil { // Log the error but don't fail the linkage since the main IDP mapping succeeded. logger.DebugContext(ctx, "failed to set SCIM user mapping", "err", err) } } else { // User doesn't exist in SCIM, remove any existing SCIM mapping for this host. - if err := ds.DeleteHostSCIMUserMapping(ctx, hostID); err != nil && !fleet.IsNotFound(err) { + if _, err := ds.DeleteHostSCIMUserMapping(ctx, hostID); err != nil && !fleet.IsNotFound(err) { logger.DebugContext(ctx, "failed to delete SCIM user mapping", "err", err) } } diff --git a/server/service/osquery_utils/queries_test.go b/server/service/osquery_utils/queries_test.go index f1ea68e2665..ce927b8782d 100644 --- a/server/service/osquery_utils/queries_test.go +++ b/server/service/osquery_utils/queries_test.go @@ -2753,15 +2753,15 @@ func TestDirectIngestMDMDeviceIDWindows(t *testing.T) { return nil, common_mysql.NotFound("SCIMUser") } - ds.SetOrUpdateHostSCIMUserMappingFunc = func(ctx context.Context, hostID uint, scimUserID uint) error { + ds.SetOrUpdateHostSCIMUserMappingFunc = func(ctx context.Context, hostID uint, scimUserID uint) ([]fleet.ActivityTypeResentCertificate, error) { require.Equal(t, host.ID, hostID) require.Equal(t, baseSCIMUser.ID, scimUserID) - return nil + return nil, nil } - ds.DeleteHostSCIMUserMappingFunc = func(ctx context.Context, hostID uint) error { + ds.DeleteHostSCIMUserMappingFunc = func(ctx context.Context, hostID uint) ([]fleet.ActivityTypeResentCertificate, error) { require.Equal(t, host.ID, hostID) - return nil + return nil, nil } testCases := []struct {