SCIM: Disable auto assign organization if the user has been provisioned (#101307)
* Add isProvisioned field to model * Add new isProvisioned column to migration * Disable auto assignment to organization if the user is provisioned * add annotation to user model * add annotation to user models * Remove IsProvisioned field from Identity * Move new field assignenment and add default value * Update annotations for user query results * Remove isProvisioned from identity * Add new column to test * Resolve user from identity at SyncOrgHook
This commit is contained in:
@@ -50,6 +50,16 @@ func (s *OrgSync) SyncOrgRolesHook(ctx context.Context, id *authn.Identity, _ *a
|
||||
return nil
|
||||
}
|
||||
|
||||
// ignore org syncing if the user is provisioned
|
||||
usr, err := s.userService.GetByID(ctx, &user.GetUserByIDQuery{ID: userID})
|
||||
if err != nil {
|
||||
ctxLogger.Error("Failed to get user from provided identity", "error", err)
|
||||
return nil
|
||||
}
|
||||
if usr.IsProvisioned {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctxLogger.Debug("Syncing organization roles", "extOrgRoles", id.OrgRoles)
|
||||
// don't sync org roles if none is specified
|
||||
if len(id.OrgRoles) == 0 {
|
||||
|
||||
@@ -155,6 +155,12 @@ func addUserMigrations(mg *Migrator) {
|
||||
Cols: []string{"uid"}, Type: UniqueIndex,
|
||||
}))
|
||||
|
||||
// Modifies the user table to add a new column is_provisioned to indicate if the user is provisioned
|
||||
// by SCIM or not.
|
||||
mg.AddMigration("Add is_provisioned column to user", NewAddColumnMigration(userV2, &Column{
|
||||
Name: "is_provisioned", Type: DB_Bool, Nullable: false, Default: "0",
|
||||
}))
|
||||
|
||||
// Service accounts login were not unique per org. this migration is part of making it unique per org
|
||||
// to be able to create service accounts that are unique per org
|
||||
mg.AddMigration(usermig.AllowSameLoginCrossOrgs, &usermig.ServiceAccountsSameLoginCrossOrgs{})
|
||||
|
||||
@@ -47,6 +47,8 @@ type User struct {
|
||||
Created time.Time
|
||||
Updated time.Time
|
||||
LastSeenAt time.Time
|
||||
|
||||
IsProvisioned bool `xorm:"is_provisioned"`
|
||||
}
|
||||
|
||||
type CreateUserCommand struct {
|
||||
@@ -64,6 +66,7 @@ type CreateUserCommand struct {
|
||||
SkipOrgSetup bool
|
||||
DefaultOrgRole string
|
||||
IsServiceAccount bool
|
||||
IsProvisioned bool
|
||||
}
|
||||
|
||||
type GetUserByLoginQuery struct {
|
||||
@@ -114,7 +117,8 @@ type SearchUsersQuery struct {
|
||||
SortOpts []model.SortOption
|
||||
Filters []Filter
|
||||
|
||||
IsDisabled *bool
|
||||
IsDisabled *bool
|
||||
IsProvisioned *bool
|
||||
}
|
||||
|
||||
type SearchUserQueryResult struct {
|
||||
@@ -137,6 +141,7 @@ type UserSearchHitDTO struct {
|
||||
LastSeenAtAge string `json:"lastSeenAtAge"`
|
||||
AuthLabels []string `json:"authLabels"`
|
||||
AuthModule AuthModuleConversion `json:"-"`
|
||||
IsProvisioned bool `json:"-" xorm:"is_provisioned"`
|
||||
}
|
||||
|
||||
type GetUserProfileQuery struct {
|
||||
@@ -161,6 +166,7 @@ type UserProfileDTO struct {
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
AvatarURL string `json:"avatarUrl"`
|
||||
AccessControl map[string]bool `json:"accessControl,omitempty"`
|
||||
IsProvisioned bool `json:"-"`
|
||||
}
|
||||
|
||||
// implement Conversion interface to define custom field mapping (xorm feature)
|
||||
|
||||
@@ -134,6 +134,7 @@ func (s *Service) Create(ctx context.Context, cmd *user.CreateUserCommand) (*use
|
||||
Updated: timeNow(),
|
||||
LastSeenAt: timeNow().AddDate(-10, 0, 0),
|
||||
IsServiceAccount: cmd.IsServiceAccount,
|
||||
IsProvisioned: cmd.IsProvisioned,
|
||||
}
|
||||
|
||||
salt, err := util.GetRandomString(10)
|
||||
@@ -164,7 +165,7 @@ func (s *Service) Create(ctx context.Context, cmd *user.CreateUserCommand) (*use
|
||||
}
|
||||
|
||||
// create org user link
|
||||
if !cmd.SkipOrgSetup {
|
||||
if !cmd.SkipOrgSetup && !usr.IsProvisioned {
|
||||
orgUser := org.OrgUser{
|
||||
OrgID: orgID,
|
||||
UserID: usr.ID,
|
||||
|
||||
@@ -57,6 +57,7 @@ func TestUserService(t *testing.T) {
|
||||
require.Equal(t, "login", u.Login)
|
||||
require.Equal(t, "name", u.Name)
|
||||
require.Equal(t, "email", u.Email)
|
||||
require.False(t, u.IsProvisioned)
|
||||
})
|
||||
|
||||
t.Run("delete user store returns error", func(t *testing.T) {
|
||||
|
||||
@@ -69,6 +69,7 @@ func setupDBForGrafana(t *testing.T, ctx context.Context, m cfgMap) {
|
||||
last_seen_at DATETIME NULL,
|
||||
is_disabled INTEGER NOT NULL DEFAULT 0,
|
||||
is_service_account BOOLEAN DEFAULT 0,
|
||||
is_provisioned BOOLEAN DEFAULT 0,
|
||||
uid TEXT NULL
|
||||
);
|
||||
CREATE TABLE org (
|
||||
|
||||
Reference in New Issue
Block a user