pkg/services/scimutil/README.md
This package provides utility functions for checking SCIM dynamic app platform settings using the client.K8sHandler. It allows both the authimpl and saml packages to check SCIM settings with dynamic configuration support and static fallback.
The main utility struct that provides methods for checking SCIM settings.
type SCIMUtil struct {
k8sClient client.K8sHandler
logger log.Logger
}
Creates a new SCIMUtil instance.
func NewSCIMUtil(k8sClient client.K8sHandler) *SCIMUtil
Checks if SCIM user sync is enabled using dynamic configuration with static fallback.
func (s *SCIMUtil) IsUserSyncEnabled(ctx context.Context, orgID int64, staticEnabled bool) bool
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
Note: This field defaults to false when not present in the dynamic configuration.
import (
"context"
"github.com/grafana/grafana/pkg/services/apiserver/client"
"github.com/grafana/grafana/pkg/services/scimutil"
)
// Create a new SCIM utility instance
scimUtil := scimutil.NewSCIMUtil(k8sClient)
// Check if user sync is enabled (with dynamic config support)
userSyncEnabled := scimUtil.IsUserSyncEnabled(ctx, orgID, staticConfig.IsUserProvisioningEnabled)
// Check if non-provisioned users are allowed (with dynamic config support)
nonProvisionedAllowed := scimUtil.AreNonProvisionedUsersAllowed(ctx, orgID, staticConfig.AllowNonProvisionedUsers)
The authimpl package uses this utility in the UserSync struct to check SCIM settings during user provisioning validation:
// In user_sync.go
type UserSync struct {
// ... other fields ...
scimUtil *scim_util.SCIMUtil
staticConfig *StaticSCIMConfig
}
func (s *UserSync) skipProvisioningValidation(ctx context.Context, currentIdentity *authn.Identity) bool {
// 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)
}
// ... rest of validation logic ...
}
The SAML package can use this utility to check SCIM settings during authentication:
// In saml package
type SCIMHelper struct {
scimUtil *scim_util.SCIMUtil
}
func (h *SCIMHelper) CheckUserSyncEnabled(ctx context.Context, orgID int64, staticEnabled bool) bool {
if h.scimUtil == nil {
return staticEnabled
}
return h.scimUtil.IsUserSyncEnabled(ctx, orgID, staticEnabled)
}
The utility supports dynamic SCIM configuration through the Kubernetes API. It will:
config.inidefaultscim.grafana.com/v0alpha1SCIMConfigauth.scim section in config.ini (global)apiVersion: scim.grafana.com/v0alpha1
kind: SCIMConfig
metadata:
name: default
namespace: <org-namespace>
spec:
enableUserSync: true # Controls user provisioning
enableGroupSync: false # Controls group/team provisioning
allowNonProvisionedUsers: false # Controls whether non-provisioned users are allowed (optional)
The utility gracefully handles errors and falls back to static configuration when:
All errors are logged for debugging purposes with appropriate log levels:
Debug: Normal operation messagesWarn: Fallback scenarios and non-critical errorsError: Invalid configuration or unexpected errorsThis package is designed to work with the open-source Grafana build and does not depend on enterprise-only SCIM API types. It uses a simplified SCIMConfigSpec struct that contains only the essential configuration fields:
type SCIMConfigSpec struct {
EnableUserSync bool `json:"enableUserSync"`
EnableGroupSync bool `json:"enableGroupSync"`
AllowNonProvisionedUsers *bool `json:"allowNonProvisionedUsers,omitempty"`
}
The AllowNonProvisionedUsers field is optional and defaults to false when not present in the configuration.
The utility directly works with Kubernetes unstructured objects and extracts the configuration values without requiring the full SCIM API types.
The package includes comprehensive tests covering:
allowNonProvisionedUsersRun tests with:
go test ./pkg/services/scimutil