mirror of
https://github.com/grafana/grafana.git
synced 2025-08-01 09:21:47 +08:00
141 lines
4.7 KiB
Go
141 lines
4.7 KiB
Go
package scimutil
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
|
|
"github.com/grafana/grafana/pkg/infra/log"
|
|
"github.com/grafana/grafana/pkg/services/apiserver/client"
|
|
)
|
|
|
|
// SCIMUtil provides utility functions for checking SCIM dynamic app platform settings
|
|
type SCIMUtil struct {
|
|
k8sClient client.K8sHandler
|
|
logger log.Logger
|
|
}
|
|
|
|
// NewSCIMUtil creates a new SCIMUtil instance
|
|
func NewSCIMUtil(k8sClient client.K8sHandler) *SCIMUtil {
|
|
return &SCIMUtil{
|
|
k8sClient: k8sClient,
|
|
logger: log.New("scim.util"),
|
|
}
|
|
}
|
|
|
|
// IsUserSyncEnabled 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 {
|
|
if s.k8sClient == nil {
|
|
s.logger.Debug("K8s client not configured, using static SCIM config for user sync")
|
|
return staticEnabled
|
|
}
|
|
|
|
dynamicEnabled, dynamicConfigFetched := s.fetchDynamicSCIMSetting(ctx, orgID, "user")
|
|
|
|
if dynamicConfigFetched {
|
|
s.logger.Debug("Using dynamic SCIM config for user sync", "orgID", orgID, "enabled", dynamicEnabled)
|
|
return dynamicEnabled
|
|
}
|
|
|
|
// Fallback to static config if dynamic config wasn't fetched successfully
|
|
s.logger.Debug("Using static SCIM config for user sync", "orgID", orgID, "enabled", staticEnabled)
|
|
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 {
|
|
if s.k8sClient == nil {
|
|
s.logger.Debug("K8s client not configured, using static SCIM config for non-provisioned users")
|
|
return staticAllowed
|
|
}
|
|
|
|
dynamicAllowed, dynamicConfigFetched := s.fetchDynamicSCIMSetting(ctx, orgID, "allowNonProvisionedUsers")
|
|
|
|
if dynamicConfigFetched {
|
|
s.logger.Debug("Using dynamic SCIM config for user sync", "orgID", orgID, "enabled", dynamicAllowed)
|
|
return dynamicAllowed
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// fetchDynamicSCIMSetting attempts to retrieve a specific dynamic SCIM configuration setting
|
|
func (s *SCIMUtil) fetchDynamicSCIMSetting(ctx context.Context, orgID int64, settingType string) (settingEnabled bool, dynamicConfigFetched bool) {
|
|
if s.k8sClient == nil {
|
|
s.logger.Warn("K8s client not configured, dynamic SCIM config lookup skipped", "orgID", orgID, "settingType", settingType)
|
|
return false, false
|
|
}
|
|
|
|
scimConfig, err := s.getOrgSCIMConfig(ctx, orgID)
|
|
if err != nil {
|
|
s.logger.Warn("Failed to fetch dynamic SCIMConfig resource, will attempt fallback to static config", "orgID", orgID, "error", err)
|
|
return false, false
|
|
}
|
|
|
|
var enabled bool
|
|
switch settingType {
|
|
case "user":
|
|
enabled = scimConfig.EnableUserSync
|
|
case "group":
|
|
enabled = scimConfig.EnableGroupSync
|
|
case "allowNonProvisionedUsers":
|
|
enabled = scimConfig.AllowNonProvisionedUsers
|
|
default:
|
|
s.logger.Error("Invalid setting type provided to fetchDynamicSCIMSetting", "settingType", settingType)
|
|
return false, false
|
|
}
|
|
|
|
return enabled, true
|
|
}
|
|
|
|
// getOrgSCIMConfig fetches and converts the SCIMConfig for an org
|
|
func (s *SCIMUtil) getOrgSCIMConfig(ctx context.Context, orgID int64) (*SCIMConfigSpec, error) {
|
|
if s.k8sClient == nil {
|
|
return nil, errors.New("k8s client not configured")
|
|
}
|
|
|
|
unstructuredObj, err := s.k8sClient.Get(ctx, "default", orgID, metav1.GetOptions{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return s.unstructuredToSCIMConfig(unstructuredObj)
|
|
}
|
|
|
|
// SCIMConfigSpec represents the spec part of a SCIMConfig resource
|
|
type SCIMConfigSpec struct {
|
|
EnableUserSync bool `json:"enableUserSync"`
|
|
EnableGroupSync bool `json:"enableGroupSync"`
|
|
AllowNonProvisionedUsers bool `json:"allowNonProvisionedUsers"`
|
|
}
|
|
|
|
// unstructuredToSCIMConfig converts an unstructured object to a SCIMConfigSpec
|
|
func (s *SCIMUtil) unstructuredToSCIMConfig(obj *unstructured.Unstructured) (*SCIMConfigSpec, error) {
|
|
if obj == nil {
|
|
return nil, errors.New("nil unstructured object")
|
|
}
|
|
|
|
// Convert spec
|
|
spec, found, err := unstructured.NestedMap(obj.Object, "spec")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !found {
|
|
return nil, errors.New("spec not found in SCIMConfig")
|
|
}
|
|
|
|
enableUserSync, _, _ := unstructured.NestedBool(spec, "enableUserSync")
|
|
enableGroupSync, _, _ := unstructured.NestedBool(spec, "enableGroupSync")
|
|
allowNonProvisionedUsers, _, _ := unstructured.NestedBool(spec, "allowNonProvisionedUsers")
|
|
|
|
return &SCIMConfigSpec{
|
|
EnableUserSync: enableUserSync,
|
|
EnableGroupSync: enableGroupSync,
|
|
AllowNonProvisionedUsers: allowNonProvisionedUsers,
|
|
}, nil
|
|
}
|