SCIM: Add flag for rejecting non provisioned users from logging in (#108568)

add flag for rejecting non provisioned users from logging in
This commit is contained in:
Mihai Doarna
2025-07-28 11:31:33 +03:00
committed by GitHub
parent 3a285d9b16
commit f9b34baa35
4 changed files with 181 additions and 128 deletions
+22 -14
View File
@@ -84,8 +84,8 @@ var (
// StaticSCIMConfig represents the static SCIM configuration from config.ini
type StaticSCIMConfig struct {
AllowNonProvisionedUsers bool
IsUserProvisioningEnabled bool
RejectNonProvisionedUsers bool
}
func ProvideUserSync(userService user.Service, userProtectionService login.UserProtectionService, authInfoService login.AuthInfoService,
@@ -94,13 +94,13 @@ func ProvideUserSync(userService user.Service, userProtectionService login.UserP
) *UserSync {
scimSection := cfg.Raw.Section("auth.scim")
staticConfig := &StaticSCIMConfig{
AllowNonProvisionedUsers: scimSection.Key("allow_non_provisioned_users").MustBool(false),
IsUserProvisioningEnabled: scimSection.Key("user_sync_enabled").MustBool(false),
RejectNonProvisionedUsers: scimSection.Key("reject_non_provisioned_users").MustBool(false),
}
return &UserSync{
allowNonProvisionedUsers: staticConfig.AllowNonProvisionedUsers,
isUserProvisioningEnabled: staticConfig.IsUserProvisioningEnabled,
rejectNonProvisionedUsers: staticConfig.RejectNonProvisionedUsers,
userService: userService,
authInfoService: authInfoService,
userProtectionService: userProtectionService,
@@ -115,8 +115,8 @@ func ProvideUserSync(userService user.Service, userProtectionService login.UserP
}
type UserSync struct {
allowNonProvisionedUsers bool
isUserProvisioningEnabled bool
rejectNonProvisionedUsers bool
userService user.Service
authInfoService login.AuthInfoService
userProtectionService login.UserProtectionService
@@ -187,9 +187,13 @@ func (s *UserSync) ValidateUserProvisioningHook(ctx context.Context, currentIden
return nil
}
// Reject non-provisioned users
log.Error("Failed to access user, user is not provisioned")
return errUserNotProvisioned.Errorf("user is not provisioned")
// Reject non-provisioned users if configured to do so
if s.shouldRejectNonProvisionedUsers(ctx, currentIdentity) {
log.Error("Failed to authenticate user, user is not provisioned")
return errUserNotProvisioned.Errorf("user is not provisioned")
}
return nil
}
func (s *UserSync) skipProvisioningValidation(ctx context.Context, currentIdentity *authn.Identity) bool {
@@ -197,12 +201,10 @@ func (s *UserSync) skipProvisioningValidation(ctx context.Context, currentIdenti
// Use dynamic SCIM settings if available, otherwise fall back to static config
effectiveUserSyncEnabled := s.isUserProvisioningEnabled
effectiveAllowNonProvisionedUsers := s.allowNonProvisionedUsers
if s.scimUtil != nil {
orgID := currentIdentity.GetOrgID()
effectiveUserSyncEnabled = s.scimUtil.IsUserSyncEnabled(ctx, orgID, s.staticConfig.IsUserProvisioningEnabled)
effectiveAllowNonProvisionedUsers = s.scimUtil.AreNonProvisionedUsersAllowed(ctx, orgID, s.staticConfig.AllowNonProvisionedUsers)
}
if !effectiveUserSyncEnabled {
@@ -210,11 +212,6 @@ func (s *UserSync) skipProvisioningValidation(ctx context.Context, currentIdenti
return true
}
if effectiveAllowNonProvisionedUsers {
log.Debug("Non-provisioned users are allowed, skipping validation")
return true
}
if currentIdentity.AuthenticatedBy == login.GrafanaComAuthModule {
log.Debug("User is authenticated via GrafanaComAuthModule, skipping validation")
return true
@@ -223,6 +220,17 @@ func (s *UserSync) skipProvisioningValidation(ctx context.Context, currentIdenti
return false
}
func (s *UserSync) shouldRejectNonProvisionedUsers(ctx context.Context, currentIdentity *authn.Identity) bool {
effectiveRejectNonProvisionedUsers := s.rejectNonProvisionedUsers
if s.scimUtil != nil {
orgID := currentIdentity.GetOrgID()
effectiveRejectNonProvisionedUsers = s.scimUtil.AreNonProvisionedUsersRejected(ctx, orgID, s.staticConfig.RejectNonProvisionedUsers)
}
return effectiveRejectNonProvisionedUsers
}
// SyncUserHook syncs a user with the database
func (s *UserSync) SyncUserHook(ctx context.Context, id *authn.Identity, _ *authn.Request) error {
ctx, span := s.tracer.Start(ctx, "user.sync.SyncUserHook")
@@ -1092,11 +1092,24 @@ func TestUserSync_ValidateUserProvisioningHook(t *testing.T) {
},
},
{
desc: "it should skip validation if allowedNonProvisionedUsers is enabled",
desc: "it should skip validation if rejectNonProvisionedUsers is disabled",
userSyncServiceSetup: func() *UserSync {
userSyncService := initUserSyncService()
userSyncService.allowNonProvisionedUsers = true
userSyncService.rejectNonProvisionedUsers = false
userSyncService.isUserProvisioningEnabled = true
userSyncService.userService = &usertest.FakeUserService{
ExpectedUser: &user.User{
ID: 1,
IsProvisioned: false,
},
}
userSyncService.authInfoService = &authinfotest.FakeService{
ExpectedUserAuth: &login.UserAuth{
UserId: 1,
AuthModule: login.GenericOAuthModule,
AuthId: "1",
},
}
return userSyncService
},
identity: &authn.Identity{
@@ -1111,7 +1124,7 @@ func TestUserSync_ValidateUserProvisioningHook(t *testing.T) {
desc: "it should skip validation if the user is authenticated via GrafanaComAuthModule",
userSyncServiceSetup: func() *UserSync {
userSyncService := initUserSyncService()
userSyncService.allowNonProvisionedUsers = false
userSyncService.rejectNonProvisionedUsers = true
userSyncService.isUserProvisioningEnabled = true
return userSyncService
},
@@ -1127,7 +1140,7 @@ func TestUserSync_ValidateUserProvisioningHook(t *testing.T) {
desc: "it should fail to validate the identity with the provisioned user, unexpected error",
userSyncServiceSetup: func() *UserSync {
userSyncService := initUserSyncService()
userSyncService.allowNonProvisionedUsers = false
userSyncService.rejectNonProvisionedUsers = true
userSyncService.isUserProvisioningEnabled = true
userSyncService.userService = &usertest.FakeUserService{
ExpectedError: errors.New("random error"),
@@ -1148,7 +1161,7 @@ func TestUserSync_ValidateUserProvisioningHook(t *testing.T) {
desc: "it should fail to validate the identity with the provisioned user, no user found",
userSyncServiceSetup: func() *UserSync {
userSyncService := initUserSyncService()
userSyncService.allowNonProvisionedUsers = false
userSyncService.rejectNonProvisionedUsers = true
userSyncService.isUserProvisioningEnabled = true
userSyncService.userService = &usertest.FakeUserService{}
return userSyncService
@@ -1167,7 +1180,7 @@ func TestUserSync_ValidateUserProvisioningHook(t *testing.T) {
desc: "it should fail to validate the provisioned user.ExternalUID with the identity.ExternalUID - empty ExternalUID",
userSyncServiceSetup: func() *UserSync {
userSyncService := initUserSyncService()
userSyncService.allowNonProvisionedUsers = false
userSyncService.rejectNonProvisionedUsers = true
userSyncService.isUserProvisioningEnabled = true
userSyncService.userService = &usertest.FakeUserService{
ExpectedUser: &user.User{
@@ -1198,7 +1211,7 @@ func TestUserSync_ValidateUserProvisioningHook(t *testing.T) {
desc: "it should fail to validate the provisioned user.ExternalUID with the identity.ExternalUID - different ExternalUID",
userSyncServiceSetup: func() *UserSync {
userSyncService := initUserSyncService()
userSyncService.allowNonProvisionedUsers = false
userSyncService.rejectNonProvisionedUsers = true
userSyncService.isUserProvisioningEnabled = true
userSyncService.userService = &usertest.FakeUserService{
ExpectedUser: &user.User{
@@ -1230,7 +1243,7 @@ func TestUserSync_ValidateUserProvisioningHook(t *testing.T) {
desc: "it should successfully validate the provisioned user.ExternalUID with the identity.ExternalUID",
userSyncServiceSetup: func() *UserSync {
userSyncService := initUserSyncService()
userSyncService.allowNonProvisionedUsers = false
userSyncService.rejectNonProvisionedUsers = true
userSyncService.isUserProvisioningEnabled = true
userSyncService.userService = &usertest.FakeUserService{
ExpectedUser: &user.User{
@@ -1259,10 +1272,10 @@ func TestUserSync_ValidateUserProvisioningHook(t *testing.T) {
expectedErr: nil,
},
{
desc: "it should failed to validate a non provisioned user when retrieved from the database",
desc: "it should fail to validate a non provisioned user when configured to reject non provisioned users",
userSyncServiceSetup: func() *UserSync {
userSyncService := initUserSyncService()
userSyncService.allowNonProvisionedUsers = false
userSyncService.rejectNonProvisionedUsers = true
userSyncService.isUserProvisioningEnabled = true
userSyncService.userService = &usertest.FakeUserService{
ExpectedUser: &user.User{
@@ -1290,6 +1303,38 @@ func TestUserSync_ValidateUserProvisioningHook(t *testing.T) {
},
expectedErr: errUserNotProvisioned.Errorf("user is not provisioned"),
},
{
desc: "it should skip to validate a non provisioned user when configured to allow non provisioned users",
userSyncServiceSetup: func() *UserSync {
userSyncService := initUserSyncService()
userSyncService.rejectNonProvisionedUsers = false
userSyncService.isUserProvisioningEnabled = true
userSyncService.userService = &usertest.FakeUserService{
ExpectedUser: &user.User{
ID: 1,
IsProvisioned: false,
},
}
userSyncService.authInfoService = &authinfotest.FakeService{
ExpectedUserAuth: &login.UserAuth{
UserId: 1,
AuthModule: login.SAMLAuthModule,
AuthId: "1",
ExternalUID: "random-external-uid",
},
}
return userSyncService
},
identity: &authn.Identity{
AuthenticatedBy: login.SAMLAuthModule,
AuthID: "1",
ExternalUID: "different-external-uid",
ClientParams: authn.ClientParams{
SyncUser: true,
},
},
expectedErr: nil,
},
{
desc: "ValidateProvisioning: DB ExternalUID is empty, Incoming ExternalUID is empty - expect mismatch (stricter logic)",
userSyncServiceSetup: func() *UserSync {
@@ -1351,7 +1396,7 @@ func TestUserSync_ValidateUserProvisioningHook(t *testing.T) {
desc: "it should skip ExternalUID validation for a SAML-provisioned user accessed by a non-SAML method with an empty incoming ExternalUID",
userSyncServiceSetup: func() *UserSync {
userSyncService := initUserSyncService()
userSyncService.allowNonProvisionedUsers = false
userSyncService.rejectNonProvisionedUsers = false
userSyncService.isUserProvisioningEnabled = true
userSyncService.userService = &usertest.FakeUserService{
ExpectedUser: &user.User{
@@ -1380,7 +1425,7 @@ func TestUserSync_ValidateUserProvisioningHook(t *testing.T) {
desc: "it should fail validation when a provisioned user is accessed by SAML with an empty incoming ExternalUID",
userSyncServiceSetup: func() *UserSync {
userSyncService := initUserSyncService()
userSyncService.allowNonProvisionedUsers = false
userSyncService.rejectNonProvisionedUsers = true
userSyncService.isUserProvisioningEnabled = true
userSyncService.userService = &usertest.FakeUserService{
ExpectedUser: &user.User{
@@ -1425,10 +1470,10 @@ func TestUserSync_SCIMUtilIntegration(t *testing.T) {
// Mock SCIM utility for testing
type mockSCIMUtil struct {
userSyncEnabled bool
nonProvisionedUsersAllowed bool
shouldUseDynamicConfig bool
shouldReturnError bool
userSyncEnabled bool
nonProvisionedUsersRejected bool
shouldUseDynamicConfig bool
shouldReturnError bool
}
createMockSCIMUtil := func(mockCfg *mockSCIMUtil) *scimutil.SCIMUtil {
@@ -1453,9 +1498,9 @@ func TestUserSync_SCIMUtilIntegration(t *testing.T) {
"namespace": "default",
},
"spec": map[string]interface{}{
"enableUserSync": mockCfg.userSyncEnabled,
"enableGroupSync": false, // Not used for this test
"allowNonProvisionedUsers": mockCfg.nonProvisionedUsersAllowed,
"enableUserSync": mockCfg.userSyncEnabled,
"enableGroupSync": false, // Not used for this test
"rejectNonProvisionedUsers": mockCfg.nonProvisionedUsersRejected,
},
},
}
@@ -1467,13 +1512,13 @@ func TestUserSync_SCIMUtilIntegration(t *testing.T) {
}
tests := []struct {
name string
identity *authn.Identity
staticConfig *StaticSCIMConfig
mockSCIMUtil *mockSCIMUtil
expectedUserSyncEnabled bool
expectedNonProvisionedAllowed bool
expectedError error
name string
identity *authn.Identity
staticConfig *StaticSCIMConfig
mockSCIMUtil *mockSCIMUtil
expectedUserSyncEnabled bool
expectedNonProvisionedRejected bool
expectedError error
}{
{
name: "SCIM util nil - uses static config",
@@ -1483,11 +1528,11 @@ func TestUserSync_SCIMUtilIntegration(t *testing.T) {
},
staticConfig: &StaticSCIMConfig{
IsUserProvisioningEnabled: true,
AllowNonProvisionedUsers: false,
RejectNonProvisionedUsers: false,
},
mockSCIMUtil: nil, // No SCIM util
expectedUserSyncEnabled: true,
expectedNonProvisionedAllowed: false,
mockSCIMUtil: nil, // No SCIM util
expectedUserSyncEnabled: true,
expectedNonProvisionedRejected: false,
},
{
name: "SCIM util with dynamic config - user sync enabled",
@@ -1497,15 +1542,15 @@ func TestUserSync_SCIMUtilIntegration(t *testing.T) {
},
staticConfig: &StaticSCIMConfig{
IsUserProvisioningEnabled: false, // Static disabled
AllowNonProvisionedUsers: false,
RejectNonProvisionedUsers: true,
},
mockSCIMUtil: &mockSCIMUtil{
userSyncEnabled: true, // Dynamic enabled
nonProvisionedUsersAllowed: true,
shouldUseDynamicConfig: true,
userSyncEnabled: true, // Dynamic enabled
nonProvisionedUsersRejected: true,
shouldUseDynamicConfig: true,
},
expectedUserSyncEnabled: true,
expectedNonProvisionedAllowed: true,
expectedUserSyncEnabled: true,
expectedNonProvisionedRejected: true,
},
{
name: "SCIM util with dynamic config - user sync disabled",
@@ -1515,15 +1560,15 @@ func TestUserSync_SCIMUtilIntegration(t *testing.T) {
},
staticConfig: &StaticSCIMConfig{
IsUserProvisioningEnabled: true, // Static enabled
AllowNonProvisionedUsers: true,
RejectNonProvisionedUsers: true,
},
mockSCIMUtil: &mockSCIMUtil{
userSyncEnabled: false, // Dynamic disabled
nonProvisionedUsersAllowed: false,
shouldUseDynamicConfig: true,
userSyncEnabled: false, // Dynamic disabled
nonProvisionedUsersRejected: false,
shouldUseDynamicConfig: true,
},
expectedUserSyncEnabled: false,
expectedNonProvisionedAllowed: false,
expectedUserSyncEnabled: false,
expectedNonProvisionedRejected: false,
},
{
name: "SCIM util with error - falls back to static config",
@@ -1533,13 +1578,13 @@ func TestUserSync_SCIMUtilIntegration(t *testing.T) {
},
staticConfig: &StaticSCIMConfig{
IsUserProvisioningEnabled: true,
AllowNonProvisionedUsers: false,
RejectNonProvisionedUsers: false,
},
mockSCIMUtil: &mockSCIMUtil{
shouldReturnError: true,
},
expectedUserSyncEnabled: true,
expectedNonProvisionedAllowed: false,
expectedUserSyncEnabled: true,
expectedNonProvisionedRejected: false,
},
}
@@ -1559,14 +1604,14 @@ func TestUserSync_SCIMUtilIntegration(t *testing.T) {
}
assert.Equal(t, tt.expectedUserSyncEnabled, userSyncEnabled, "User sync enabled mismatch")
// Test non-provisioned users allowed check
var nonProvisionedAllowed bool
// Test non-provisioned users rejected check
var nonProvisionedReject bool
if userSync.scimUtil != nil {
nonProvisionedAllowed = userSync.scimUtil.AreNonProvisionedUsersAllowed(ctx, orgID, tt.staticConfig.AllowNonProvisionedUsers)
nonProvisionedReject = userSync.scimUtil.AreNonProvisionedUsersRejected(ctx, orgID, tt.staticConfig.RejectNonProvisionedUsers)
} else {
nonProvisionedAllowed = tt.staticConfig.AllowNonProvisionedUsers
nonProvisionedReject = tt.staticConfig.RejectNonProvisionedUsers
}
assert.Equal(t, tt.expectedNonProvisionedAllowed, nonProvisionedAllowed, "Non-provisioned users allowed mismatch")
assert.Equal(t, tt.expectedNonProvisionedRejected, nonProvisionedReject, "Non-provisioned users rejected mismatch")
})
}
}
@@ -1765,7 +1810,7 @@ func TestUserSync_GetUsageStats(t *testing.T) {
func TestUserSync_SCIMLoginUsageStatSet(t *testing.T) {
userSync := initUserSyncService()
userSync.allowNonProvisionedUsers = false
userSync.rejectNonProvisionedUsers = false
userSync.isUserProvisioningEnabled = true
userSync.userService = &usertest.FakeUserService{
ExpectedUser: &user.User{
+17 -17
View File
@@ -44,23 +44,23 @@ func (s *SCIMUtil) IsUserSyncEnabled(ctx context.Context, orgID int64, staticEna
return staticEnabled
}
// AreNonProvisionedUsersAllowed checks if non-provisioned users are allowed using dynamic configuration with static fallback
func (s *SCIMUtil) AreNonProvisionedUsersAllowed(ctx context.Context, orgID int64, staticAllowed bool) bool {
// AreNonProvisionedUsersRejected checks if non-provisioned users are rejected using dynamic configuration with static fallback
func (s *SCIMUtil) AreNonProvisionedUsersRejected(ctx context.Context, orgID int64, staticRejected bool) bool {
if s.k8sClient == nil {
s.logger.Debug("K8s client not configured, using static SCIM config for non-provisioned users")
return staticAllowed
return staticRejected
}
dynamicAllowed, dynamicConfigFetched := s.fetchDynamicSCIMSetting(ctx, orgID, "allowNonProvisionedUsers")
dynamicRejected, dynamicConfigFetched := s.fetchDynamicSCIMSetting(ctx, orgID, "rejectNonProvisionedUsers")
if dynamicConfigFetched {
s.logger.Debug("Using dynamic SCIM config for user sync", "orgID", orgID, "enabled", dynamicAllowed)
return dynamicAllowed
s.logger.Debug("Using dynamic SCIM config for user sync", "orgID", orgID, "enabled", dynamicRejected)
return dynamicRejected
}
// Fallback to static config if dynamic config wasn't fetched successfully
s.logger.Debug("Using static SCIM config for user sync", "orgID", orgID, "enabled", staticAllowed)
return staticAllowed
s.logger.Debug("Using static SCIM config for user sync", "orgID", orgID, "enabled", staticRejected)
return staticRejected
}
// fetchDynamicSCIMSetting attempts to retrieve a specific dynamic SCIM configuration setting
@@ -82,8 +82,8 @@ func (s *SCIMUtil) fetchDynamicSCIMSetting(ctx context.Context, orgID int64, set
enabled = scimConfig.EnableUserSync
case "group":
enabled = scimConfig.EnableGroupSync
case "allowNonProvisionedUsers":
enabled = scimConfig.AllowNonProvisionedUsers
case "rejectNonProvisionedUsers":
enabled = scimConfig.RejectNonProvisionedUsers
default:
s.logger.Error("Invalid setting type provided to fetchDynamicSCIMSetting", "settingType", settingType)
return false, false
@@ -108,9 +108,9 @@ func (s *SCIMUtil) getOrgSCIMConfig(ctx context.Context, orgID int64) (*SCIMConf
// SCIMConfigSpec represents the spec part of a SCIMConfig resource
type SCIMConfigSpec struct {
EnableUserSync bool `json:"enableUserSync"`
EnableGroupSync bool `json:"enableGroupSync"`
AllowNonProvisionedUsers bool `json:"allowNonProvisionedUsers"`
EnableUserSync bool `json:"enableUserSync"`
EnableGroupSync bool `json:"enableGroupSync"`
RejectNonProvisionedUsers bool `json:"rejectNonProvisionedUsers"`
}
// unstructuredToSCIMConfig converts an unstructured object to a SCIMConfigSpec
@@ -130,11 +130,11 @@ func (s *SCIMUtil) unstructuredToSCIMConfig(obj *unstructured.Unstructured) (*SC
enableUserSync, _, _ := unstructured.NestedBool(spec, "enableUserSync")
enableGroupSync, _, _ := unstructured.NestedBool(spec, "enableGroupSync")
allowNonProvisionedUsers, _, _ := unstructured.NestedBool(spec, "allowNonProvisionedUsers")
rejectNonProvisionedUsers, _, _ := unstructured.NestedBool(spec, "rejectNonProvisionedUsers")
return &SCIMConfigSpec{
EnableUserSync: enableUserSync,
EnableGroupSync: enableGroupSync,
AllowNonProvisionedUsers: allowNonProvisionedUsers,
EnableUserSync: enableUserSync,
EnableGroupSync: enableGroupSync,
RejectNonProvisionedUsers: rejectNonProvisionedUsers,
}, nil
}
+46 -46
View File
@@ -213,33 +213,33 @@ func TestSCIMUtil_IsUserSyncEnabled(t *testing.T) {
}
}
func TestSCIMUtil_AreNonProvisionedUsersAllowed(t *testing.T) {
func TestSCIMUtil_AreNonProvisionedUsersRejected(t *testing.T) {
ctx := context.Background()
orgID := int64(1)
tests := []struct {
name string
k8sClient client.K8sHandler
staticAllowed bool
staticRejected bool
expectedResult bool
setupMock func(*MockK8sHandler)
}{
{
name: "k8s client nil - returns static config",
k8sClient: nil,
staticAllowed: true,
staticRejected: true,
expectedResult: true,
},
{
name: "k8s client nil - returns static config false",
k8sClient: nil,
staticAllowed: false,
staticRejected: false,
expectedResult: false,
},
{
name: "k8s client error - falls back to static config",
k8sClient: &MockK8sHandler{},
staticAllowed: true,
name: "k8s client error - falls back to static config",
k8sClient: &MockK8sHandler{},
staticRejected: true,
setupMock: func(mockHandler *MockK8sHandler) {
mockHandler.On("Get", ctx, "default", orgID, metav1.GetOptions{}, mock.Anything).
Return(nil, errors.New("k8s error"))
@@ -247,9 +247,9 @@ func TestSCIMUtil_AreNonProvisionedUsersAllowed(t *testing.T) {
expectedResult: true,
},
{
name: "dynamic config user sync enabled - non-provisioned users allowed",
k8sClient: &MockK8sHandler{},
staticAllowed: false,
name: "dynamic config user sync enabled - non-provisioned users rejected",
k8sClient: &MockK8sHandler{},
staticRejected: false,
setupMock: func(mockHandler *MockK8sHandler) {
obj := createMockSCIMConfigWithNonProvisioned(true, false, true)
mockHandler.On("Get", ctx, "default", orgID, metav1.GetOptions{}, mock.Anything).
@@ -258,9 +258,9 @@ func TestSCIMUtil_AreNonProvisionedUsersAllowed(t *testing.T) {
expectedResult: true,
},
{
name: "dynamic config user sync disabled - non-provisioned users not allowed",
k8sClient: &MockK8sHandler{},
staticAllowed: true,
name: "dynamic config user sync disabled - non-provisioned users allowed",
k8sClient: &MockK8sHandler{},
staticRejected: true,
setupMock: func(mockHandler *MockK8sHandler) {
obj := createMockSCIMConfigWithNonProvisioned(false, true, false)
mockHandler.On("Get", ctx, "default", orgID, metav1.GetOptions{}, mock.Anything).
@@ -269,9 +269,9 @@ func TestSCIMUtil_AreNonProvisionedUsersAllowed(t *testing.T) {
expectedResult: false,
},
{
name: "dynamic config both settings disabled - non-provisioned users not allowed",
k8sClient: &MockK8sHandler{},
staticAllowed: true,
name: "dynamic config both settings disabled - non-provisioned users allowed",
k8sClient: &MockK8sHandler{},
staticRejected: true,
setupMock: func(mockHandler *MockK8sHandler) {
obj := createMockSCIMConfigWithNonProvisioned(false, false, false)
mockHandler.On("Get", ctx, "default", orgID, metav1.GetOptions{}, mock.Anything).
@@ -280,9 +280,9 @@ func TestSCIMUtil_AreNonProvisionedUsersAllowed(t *testing.T) {
expectedResult: false,
},
{
name: "dynamic config both settings enabled - non-provisioned users allowed",
k8sClient: &MockK8sHandler{},
staticAllowed: false,
name: "dynamic config both settings enabled - non-provisioned users rejected",
k8sClient: &MockK8sHandler{},
staticRejected: false,
setupMock: func(mockHandler *MockK8sHandler) {
obj := createMockSCIMConfigWithNonProvisioned(true, true, true)
mockHandler.On("Get", ctx, "default", orgID, metav1.GetOptions{}, mock.Anything).
@@ -299,7 +299,7 @@ func TestSCIMUtil_AreNonProvisionedUsersAllowed(t *testing.T) {
}
util := NewSCIMUtil(tt.k8sClient)
result := util.AreNonProvisionedUsersAllowed(ctx, orgID, tt.staticAllowed)
result := util.AreNonProvisionedUsersRejected(ctx, orgID, tt.staticRejected)
assert.Equal(t, tt.expectedResult, result)
@@ -449,9 +449,9 @@ func TestSCIMUtil_fetchDynamicSCIMSetting(t *testing.T) {
},
},
{
name: "allowNonProvisionedUsers setting enabled",
name: "rejectNonProvisionedUsers setting enabled",
k8sClient: &MockK8sHandler{},
settingType: "allowNonProvisionedUsers",
settingType: "rejectNonProvisionedUsers",
expectedEnabled: true,
expectedDynamicFetched: true,
setupMock: func(mockHandler *MockK8sHandler) {
@@ -461,9 +461,9 @@ func TestSCIMUtil_fetchDynamicSCIMSetting(t *testing.T) {
},
},
{
name: "allowNonProvisionedUsers setting disabled",
name: "rejectNonProvisionedUsers setting disabled",
k8sClient: &MockK8sHandler{},
settingType: "allowNonProvisionedUsers",
settingType: "rejectNonProvisionedUsers",
expectedEnabled: false,
expectedDynamicFetched: true,
setupMock: func(mockHandler *MockK8sHandler) {
@@ -570,36 +570,36 @@ func TestSCIMUtil_unstructuredToSCIMConfig(t *testing.T) {
name: "valid object with both settings enabled",
obj: createMockSCIMConfig(true, true),
expectedSpec: SCIMConfigSpec{
EnableUserSync: true,
EnableGroupSync: true,
AllowNonProvisionedUsers: false,
EnableUserSync: true,
EnableGroupSync: true,
RejectNonProvisionedUsers: false,
},
},
{
name: "valid object with both settings disabled",
obj: createMockSCIMConfig(false, false),
expectedSpec: SCIMConfigSpec{
EnableUserSync: false,
EnableGroupSync: false,
AllowNonProvisionedUsers: false,
EnableUserSync: false,
EnableGroupSync: false,
RejectNonProvisionedUsers: false,
},
},
{
name: "valid object with mixed settings",
obj: createMockSCIMConfig(true, false),
expectedSpec: SCIMConfigSpec{
EnableUserSync: true,
EnableGroupSync: false,
AllowNonProvisionedUsers: false,
EnableUserSync: true,
EnableGroupSync: false,
RejectNonProvisionedUsers: false,
},
},
{
name: "valid object with allowNonProvisionedUsers enabled",
name: "valid object with rejectNonProvisionedUsers enabled",
obj: createMockSCIMConfigWithNonProvisioned(false, false, true),
expectedSpec: SCIMConfigSpec{
EnableUserSync: false,
EnableGroupSync: false,
AllowNonProvisionedUsers: true,
EnableUserSync: false,
EnableGroupSync: false,
RejectNonProvisionedUsers: true,
},
},
{
@@ -641,7 +641,7 @@ func createMockSCIMConfig(userSyncEnabled, groupSyncEnabled bool) *unstructured.
}
// Helper function to create a mock SCIMConfig unstructured object with non-provisioned users setting
func createMockSCIMConfigWithNonProvisioned(userSyncEnabled, groupSyncEnabled, allowNonProvisionedUsers bool) *unstructured.Unstructured {
func createMockSCIMConfigWithNonProvisioned(userSyncEnabled, groupSyncEnabled, rejectNonProvisionedUsers bool) *unstructured.Unstructured {
return &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "scim.grafana.com/v0alpha1",
@@ -651,9 +651,9 @@ func createMockSCIMConfigWithNonProvisioned(userSyncEnabled, groupSyncEnabled, a
"namespace": "default",
},
"spec": map[string]interface{}{
"enableUserSync": userSyncEnabled,
"enableGroupSync": groupSyncEnabled,
"allowNonProvisionedUsers": allowNonProvisionedUsers,
"enableUserSync": userSyncEnabled,
"enableGroupSync": groupSyncEnabled,
"rejectNonProvisionedUsers": rejectNonProvisionedUsers,
},
},
}
@@ -676,9 +676,9 @@ func TestSCIMUtil_Integration(t *testing.T) {
userSyncEnabled := util.IsUserSyncEnabled(ctx, orgID, false)
assert.True(t, userSyncEnabled)
// Test non-provisioned users allowed
nonProvisionedAllowed := util.AreNonProvisionedUsersAllowed(ctx, orgID, false)
assert.True(t, nonProvisionedAllowed)
// Test non-provisioned users rejected
nonProvisionedRejected := util.AreNonProvisionedUsersRejected(ctx, orgID, false)
assert.True(t, nonProvisionedRejected)
mockClient.AssertExpectations(t)
})
@@ -695,8 +695,8 @@ func TestSCIMUtil_Integration(t *testing.T) {
assert.True(t, userSyncEnabled)
// Test non-provisioned users falls back to static config
nonProvisionedAllowed := util.AreNonProvisionedUsersAllowed(ctx, orgID, true)
assert.True(t, nonProvisionedAllowed)
nonProvisionedRejected := util.AreNonProvisionedUsersRejected(ctx, orgID, true)
assert.True(t, nonProvisionedRejected)
mockClient.AssertExpectations(t)
})