diff --git a/pkg/coredata/membership_profile.go b/pkg/coredata/membership_profile.go index 978d7792a..3f35e74cf 100644 --- a/pkg/coredata/membership_profile.go +++ b/pkg/coredata/membership_profile.go @@ -1396,6 +1396,42 @@ WHERE return nil } +func (p *MembershipProfile) ClearExternalID( + ctx context.Context, + conn pg.Conn, + scope Scoper, + externalID string, + organizationID gid.GID, +) error { + q := ` +UPDATE iam_membership_profiles +SET + external_id = NULL, + updated_at = @updated_at +WHERE + %s + AND external_id = @external_id + AND organization_id = @organization_id + AND id != @exclude_id +` + q = fmt.Sprintf(q, scope.SQLFragment()) + + args := pgx.NamedArgs{ + "external_id": externalID, + "organization_id": organizationID, + "exclude_id": p.ID, + "updated_at": time.Now(), + } + maps.Copy(args, scope.SQLArguments()) + + _, err := conn.Exec(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot clear external id: %w", err) + } + + return nil +} + func (p *MembershipProfile) Delete( ctx context.Context, conn pg.Conn, diff --git a/pkg/iam/scim/service.go b/pkg/iam/scim/service.go index e6c3b42ee..32dd15657 100644 --- a/pkg/iam/scim/service.go +++ b/pkg/iam/scim/service.go @@ -244,6 +244,18 @@ func (s *Service) CreateUser( return scimerrors.ScimErrorUniqueness } + if externalIdPtr != nil { + if err := profile.ClearExternalID( + ctx, + tx, + scope, + *externalIdPtr, + config.OrganizationID, + ); err != nil { + return fmt.Errorf("cannot clear conflicting external id: %w", err) + } + } + profile.Source = coredata.ProfileSourceSCIM profile.State = profileState profile.FullName = attrs.FullName