|
|
|
|
@ -24,7 +24,7 @@ import ( |
|
|
|
|
var _ ssosettings.Service = (*SSOSettingsService)(nil) |
|
|
|
|
|
|
|
|
|
type SSOSettingsService struct { |
|
|
|
|
log log.Logger |
|
|
|
|
logger log.Logger |
|
|
|
|
cfg *setting.Cfg |
|
|
|
|
store ssosettings.Store |
|
|
|
|
ac ac.AccessControl |
|
|
|
|
@ -45,7 +45,7 @@ func ProvideService(cfg *setting.Cfg, sqlStore db.DB, ac ac.AccessControl, |
|
|
|
|
store := database.ProvideStore(sqlStore) |
|
|
|
|
|
|
|
|
|
svc := &SSOSettingsService{ |
|
|
|
|
log: log.New("ssosettings.service"), |
|
|
|
|
logger: log.New("ssosettings.service"), |
|
|
|
|
cfg: cfg, |
|
|
|
|
store: store, |
|
|
|
|
ac: ac, |
|
|
|
|
@ -65,24 +65,17 @@ func ProvideService(cfg *setting.Cfg, sqlStore db.DB, ac ac.AccessControl, |
|
|
|
|
var _ ssosettings.Service = (*SSOSettingsService)(nil) |
|
|
|
|
|
|
|
|
|
func (s *SSOSettingsService) GetForProvider(ctx context.Context, provider string) (*models.SSOSettings, error) { |
|
|
|
|
storeSettings, err := s.store.Get(ctx, provider) |
|
|
|
|
|
|
|
|
|
if errors.Is(err, ssosettings.ErrNotFound) { |
|
|
|
|
settings, err := s.loadSettingsUsingFallbackStrategy(ctx, provider) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return settings, nil |
|
|
|
|
dbSettings, err := s.store.Get(ctx, provider) |
|
|
|
|
if err != nil && !errors.Is(err, ssosettings.ErrNotFound) { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
systemSettings, err := s.loadSettingsUsingFallbackStrategy(ctx, provider) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
storeSettings.Source = models.DB |
|
|
|
|
|
|
|
|
|
return storeSettings, nil |
|
|
|
|
return s.mergeSSOSettings(dbSettings, systemSettings), nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (s *SSOSettingsService) GetForProviderWithRedactedSecrets(ctx context.Context, provider string) (*models.SSOSettings, error) { |
|
|
|
|
@ -93,7 +86,7 @@ func (s *SSOSettingsService) GetForProviderWithRedactedSecrets(ctx context.Conte |
|
|
|
|
|
|
|
|
|
for k, v := range storeSettings.Settings { |
|
|
|
|
if isSecret(k) && v != "" { |
|
|
|
|
storeSettings.Settings[k] = "*********" |
|
|
|
|
storeSettings.Settings[k] = setting.RedactedPassword |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -109,17 +102,13 @@ func (s *SSOSettingsService) List(ctx context.Context) ([]*models.SSOSettings, e |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for _, provider := range ssosettings.AllOAuthProviders { |
|
|
|
|
settings := getSettingsByProvider(provider, storedSettings) |
|
|
|
|
if len(settings) == 0 { |
|
|
|
|
// If there is no data in the DB then we need to load the settings using the fallback strategy
|
|
|
|
|
fallbackSettings, err := s.loadSettingsUsingFallbackStrategy(ctx, provider) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
settings = append(settings, fallbackSettings) |
|
|
|
|
dbSettings := getSettingByProvider(provider, storedSettings) |
|
|
|
|
fallbackSettings, err := s.loadSettingsUsingFallbackStrategy(ctx, provider) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
result = append(result, settings...) |
|
|
|
|
|
|
|
|
|
result = append(result, s.mergeSSOSettings(dbSettings, fallbackSettings)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return result, nil |
|
|
|
|
@ -140,15 +129,6 @@ func (s *SSOSettingsService) Upsert(ctx context.Context, settings models.SSOSett |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
systemSettings, err := s.loadSettingsUsingFallbackStrategy(ctx, settings.Provider) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// add the SSO settings from system that are not available in the user input
|
|
|
|
|
// in order to have a complete set of SSO settings for every provider in the database
|
|
|
|
|
settings.Settings = mergeSettings(settings.Settings, systemSettings.Settings) |
|
|
|
|
|
|
|
|
|
settings.Settings, err = s.encryptSecrets(ctx, settings.Settings) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
@ -162,7 +142,7 @@ func (s *SSOSettingsService) Upsert(ctx context.Context, settings models.SSOSett |
|
|
|
|
go func() { |
|
|
|
|
err = social.Reload(context.Background(), settings) |
|
|
|
|
if err != nil { |
|
|
|
|
s.log.Error("failed to reload the provider", "provider", settings.Provider, "error", err) |
|
|
|
|
s.logger.Error("failed to reload the provider", "provider", settings.Provider, "error", err) |
|
|
|
|
} |
|
|
|
|
}() |
|
|
|
|
|
|
|
|
|
@ -210,14 +190,13 @@ func (s *SSOSettingsService) loadSettingsUsingFallbackStrategy(ctx context.Conte |
|
|
|
|
}, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func getSettingsByProvider(provider string, settings []*models.SSOSettings) []*models.SSOSettings { |
|
|
|
|
result := make([]*models.SSOSettings, 0) |
|
|
|
|
func getSettingByProvider(provider string, settings []*models.SSOSettings) *models.SSOSettings { |
|
|
|
|
for _, item := range settings { |
|
|
|
|
if item.Provider == provider { |
|
|
|
|
result = append(result, item) |
|
|
|
|
return item |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return result |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (s *SSOSettingsService) getFallbackStrategyFor(provider string) (ssosettings.FallbackStrategy, bool) { |
|
|
|
|
@ -273,42 +252,47 @@ func (s *SSOSettingsService) Run(ctx context.Context) error { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (s *SSOSettingsService) doReload(ctx context.Context) { |
|
|
|
|
s.log.Debug("reloading SSO Settings for all providers") |
|
|
|
|
s.logger.Debug("reloading SSO Settings for all providers") |
|
|
|
|
|
|
|
|
|
settingsList, err := s.List(ctx) |
|
|
|
|
if err != nil { |
|
|
|
|
s.log.Error("failed to fetch SSO Settings for all providers", "err", err) |
|
|
|
|
s.logger.Error("failed to fetch SSO Settings for all providers", "err", err) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for provider, connector := range s.reloadables { |
|
|
|
|
settings := getSettingsByProvider(provider, settingsList) |
|
|
|
|
setting := getSettingByProvider(provider, settingsList) |
|
|
|
|
|
|
|
|
|
if len(settings) > 0 { |
|
|
|
|
err = connector.Reload(ctx, *settings[0]) |
|
|
|
|
if err != nil { |
|
|
|
|
s.log.Error("failed to reload SSO Settings", "provider", provider, "err", err) |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
err = connector.Reload(ctx, *setting) |
|
|
|
|
if err != nil { |
|
|
|
|
s.logger.Error("failed to reload SSO Settings", "provider", provider, "err", err) |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func isSecret(fieldName string) bool { |
|
|
|
|
secretFieldPatterns := []string{"secret"} |
|
|
|
|
|
|
|
|
|
for _, v := range secretFieldPatterns { |
|
|
|
|
if strings.Contains(strings.ToLower(fieldName), strings.ToLower(v)) { |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
// mergeSSOSettings merges the settings from the database with the system settings
|
|
|
|
|
// Required because it is possible that the user has configured some of the settings (current Advanced OAuth settings)
|
|
|
|
|
// and the rest of the settings are loaded from the system settings
|
|
|
|
|
func (s *SSOSettingsService) mergeSSOSettings(dbSettings, systemSettings *models.SSOSettings) *models.SSOSettings { |
|
|
|
|
if dbSettings == nil { |
|
|
|
|
s.logger.Debug("No SSO Settings found in the database, using system settings") |
|
|
|
|
return systemSettings |
|
|
|
|
} |
|
|
|
|
return false |
|
|
|
|
|
|
|
|
|
s.logger.Debug("Merging SSO Settings", "dbSettings", dbSettings.Settings, "systemSettings", systemSettings.Settings) |
|
|
|
|
|
|
|
|
|
finalSettings := mergeSettings(dbSettings.Settings, systemSettings.Settings) |
|
|
|
|
|
|
|
|
|
dbSettings.Settings = finalSettings |
|
|
|
|
|
|
|
|
|
return dbSettings |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func mergeSettings(apiSettings, systemSettings map[string]any) map[string]any { |
|
|
|
|
func mergeSettings(storedSettings, systemSettings map[string]any) map[string]any { |
|
|
|
|
settings := make(map[string]any) |
|
|
|
|
|
|
|
|
|
for k, v := range apiSettings { |
|
|
|
|
for k, v := range storedSettings { |
|
|
|
|
settings[k] = v |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -321,6 +305,17 @@ func mergeSettings(apiSettings, systemSettings map[string]any) map[string]any { |
|
|
|
|
return settings |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func isSecret(fieldName string) bool { |
|
|
|
|
secretFieldPatterns := []string{"secret"} |
|
|
|
|
|
|
|
|
|
for _, v := range secretFieldPatterns { |
|
|
|
|
if strings.Contains(strings.ToLower(fieldName), strings.ToLower(v)) { |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func isProviderConfigurable(provider string) bool { |
|
|
|
|
for _, configurable := range ssosettings.ConfigurableOAuthProviders { |
|
|
|
|
if provider == configurable { |
|
|
|
|
|