diff --git a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md index ef2ca7ab494..a3e2776142e 100644 --- a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md +++ b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md @@ -50,7 +50,6 @@ Most [generally available](https://grafana.com/docs/release-life-cycle/#general- | `dashboardSceneForViewers` | Enables dashboard rendering using Scenes for viewer roles | Yes | | `dashboardSceneSolo` | Enables rendering dashboards using scenes for solo panels | Yes | | `dashboardScene` | Enables dashboard rendering using scenes for all roles | Yes | -| `ssoSettingsApi` | Enables the SSO settings API and the OAuth configuration UIs in Grafana | Yes | | `logsInfiniteScrolling` | Enables infinite scrolling for the Logs panel in Explore and Dashboards | Yes | | `logRowsPopoverMenu` | Enable filtering menu displayed when text of a log line is selected | Yes | | `alertingQueryOptimization` | Optimizes eligible queries in order to reduce load on datasources | | diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index 167962c0745..46aa38792a9 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -393,11 +393,6 @@ export interface FeatureToggles { */ pdfTables?: boolean; /** - * Enables the SSO settings API and the OAuth configuration UIs in Grafana - * @default true - */ - ssoSettingsApi?: boolean; - /** * Allow pan and zoom in canvas panel */ canvasPanelPanZoom?: boolean; diff --git a/pkg/api/api.go b/pkg/api/api.go index d9ba624d32b..12de28eaa90 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -254,18 +254,15 @@ func (hs *HTTPServer) registerRoutes() { adminAuthPageEvaluator := func() ac.Evaluator { authnSettingsEval := ssoutils.EvalAuthenticationSettings(hs.Cfg) - if hs.Features.IsEnabledGlobally(featuremgmt.FlagSsoSettingsApi) { - return ac.EvalAny(authnSettingsEval, ssoutils.OauthSettingsEvaluator(hs.Cfg)) - } - return authnSettingsEval + + return ac.EvalAny(authnSettingsEval, ssoutils.OauthSettingsEvaluator(hs.Cfg)) } r.Get("/admin/authentication", authorize(adminAuthPageEvaluator()), hs.Index) r.Get("/admin/authentication/ldap", authorize(ac.EvalPermission(ac.ActionLDAPStatusRead)), hs.Index) - if hs.Features.IsEnabledGlobally(featuremgmt.FlagSsoSettingsApi) { - providerParam := ac.Parameter(":provider") - r.Get("/admin/authentication/:provider", authorize(ac.EvalPermission(ac.ActionSettingsRead, ac.ScopeSettingsOAuth(providerParam))), hs.Index) - } + + providerParam := ac.Parameter(":provider") + r.Get("/admin/authentication/:provider", authorize(ac.EvalPermission(ac.ActionSettingsRead, ac.ScopeSettingsOAuth(providerParam))), hs.Index) // authed api r.Group("/api", func(apiRoute routing.RouteRegister) { diff --git a/pkg/api/frontendsettings_test.go b/pkg/api/frontendsettings_test.go index 8c2daa46414..b84a1ae679a 100644 --- a/pkg/api/frontendsettings_test.go +++ b/pkg/api/frontendsettings_test.go @@ -99,7 +99,7 @@ func setupTestEnvironment(t *testing.T, cfg *setting.Cfg, features featuremgmt.F pluginsCDNService: pluginsCDN, pluginAssets: pluginsAssets, namespacer: request.GetNamespaceMapper(cfg), - SocialService: socialimpl.ProvideService(cfg, features, &usagestats.UsageStatsMock{}, supportbundlestest.NewFakeBundleService(), remotecache.NewFakeCacheStorage(), nil, &ssosettingstests.MockService{}), + SocialService: socialimpl.ProvideService(cfg, features, &usagestats.UsageStatsMock{}, supportbundlestest.NewFakeBundleService(), remotecache.NewFakeCacheStorage(), nil, ssosettingstests.NewFakeService()), managedPluginsService: managedplugins.NewNoop(), tracer: tracing.InitializeTracerForTest(), DataSourcesService: &datafakes.FakeDataSourceService{}, diff --git a/pkg/login/social/connectors/azuread_oauth.go b/pkg/login/social/connectors/azuread_oauth.go index d09265407f3..f06373df124 100644 --- a/pkg/login/social/connectors/azuread_oauth.go +++ b/pkg/login/social/connectors/azuread_oauth.go @@ -106,9 +106,7 @@ func NewAzureADProvider(info *social.OAuthInfo, cfg *setting.Cfg, orgRoleMapper appendUniqueScope(provider.Config, social.OfflineAccessScope) } - if features.IsEnabledGlobally(featuremgmt.FlagSsoSettingsApi) { - ssoSettings.RegisterReloadable(social.AzureADProviderName, provider) - } + ssoSettings.RegisterReloadable(social.AzureADProviderName, provider) return provider } diff --git a/pkg/login/social/connectors/azuread_oauth_test.go b/pkg/login/social/connectors/azuread_oauth_test.go index c882a550071..88e2f6039c3 100644 --- a/pkg/login/social/connectors/azuread_oauth_test.go +++ b/pkg/login/social/connectors/azuread_oauth_test.go @@ -841,7 +841,7 @@ func TestSocialAzureAD_UserInfo(t *testing.T) { tt.fields.cfg, ProvideOrgRoleMapper(tt.fields.cfg, &orgtest.FakeOrgService{ExpectedOrgs: []*org.OrgDTO{{ID: 4, Name: "Org4"}, {ID: 5, Name: "Org5"}}}), - &ssosettingstests.MockService{}, + ssosettingstests.NewFakeService(), featuremgmt.WithFeatures(), cache) @@ -1019,7 +1019,7 @@ func TestSocialAzureAD_SkipOrgRole(t *testing.T) { tt.fields.cfg, ProvideOrgRoleMapper(tt.fields.cfg, &orgtest.FakeOrgService{ExpectedOrgs: []*org.OrgDTO{{ID: 4, Name: "Org4"}, {ID: 5, Name: "Org5"}}}), - &ssosettingstests.MockService{}, + ssosettingstests.NewFakeService(), featuremgmt.WithFeatures(), cache) @@ -1119,7 +1119,7 @@ func TestSocialAzureAD_InitializeExtraFields(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - s := NewAzureADProvider(tc.settings, &setting.Cfg{}, nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures(), nil) + s := NewAzureADProvider(tc.settings, &setting.Cfg{}, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures(), nil) require.Equal(t, tc.want.forceUseGraphAPI, s.forceUseGraphAPI) require.Equal(t, tc.want.allowedOrganizations, s.allowedOrganizations) @@ -1280,7 +1280,7 @@ func TestSocialAzureAD_Validate(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - s := NewAzureADProvider(&social.OAuthInfo{}, &setting.Cfg{}, nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures(), nil) + s := NewAzureADProvider(&social.OAuthInfo{}, &setting.Cfg{}, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures(), nil) if tc.requester == nil { tc.requester = &user.SignedInUser{IsGrafanaAdmin: false} @@ -1360,7 +1360,7 @@ func TestSocialAzureAD_Reload(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - s := NewAzureADProvider(tc.info, &setting.Cfg{}, nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures(), nil) + s := NewAzureADProvider(tc.info, &setting.Cfg{}, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures(), nil) err := s.Reload(context.Background(), tc.settings) if tc.expectError { @@ -1417,7 +1417,7 @@ func TestSocialAzureAD_Reload_ExtraFields(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - s := NewAzureADProvider(tc.info, setting.NewCfg(), nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures(), remotecache.FakeCacheStorage{}) + s := NewAzureADProvider(tc.info, setting.NewCfg(), nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures(), remotecache.FakeCacheStorage{}) err := s.Reload(context.Background(), tc.settings) require.NoError(t, err) diff --git a/pkg/login/social/connectors/generic_oauth.go b/pkg/login/social/connectors/generic_oauth.go index 0209b4bb0da..7d1d5842a47 100644 --- a/pkg/login/social/connectors/generic_oauth.go +++ b/pkg/login/social/connectors/generic_oauth.go @@ -79,9 +79,7 @@ func NewGenericOAuthProvider(info *social.OAuthInfo, cfg *setting.Cfg, orgRoleMa allowedOrganizations: allowedOrganizations, } - if features.IsEnabledGlobally(featuremgmt.FlagSsoSettingsApi) { - ssoSettings.RegisterReloadable(social.GenericOAuthProviderName, provider) - } + ssoSettings.RegisterReloadable(social.GenericOAuthProviderName, provider) return provider } diff --git a/pkg/login/social/connectors/generic_oauth_test.go b/pkg/login/social/connectors/generic_oauth_test.go index f61b06b0a98..881ed9fd541 100644 --- a/pkg/login/social/connectors/generic_oauth_test.go +++ b/pkg/login/social/connectors/generic_oauth_test.go @@ -458,7 +458,7 @@ func TestUserInfoSearchesForEmailAndOrgRoles(t *testing.T) { EmailAttributePath: "email", }, cfg, orgRoleMapper, - &ssosettingstests.MockService{}, + ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) provider.info.RoleAttributePath = tc.RoleAttributePath @@ -507,7 +507,7 @@ func TestUserInfoSearchesForEmailAndOrgRoles(t *testing.T) { EmailAttributePath: "email", }, cfg, orgRoleMapper, - &ssosettingstests.MockService{}, + ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) body, err := json.Marshal(map[string]any{"info": map[string]any{"roles": []string{"engineering", "SRE"}}}) @@ -600,7 +600,7 @@ func TestUserInfoSearchesForLogin(t *testing.T) { }, }, setting.NewCfg(), ProvideOrgRoleMapper(setting.NewCfg(), orgtest.NewOrgServiceFake()), - &ssosettingstests.MockService{}, + ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) for _, tc := range testCases { @@ -700,7 +700,7 @@ func TestUserInfoSearchesForName(t *testing.T) { }, setting.NewCfg(), ProvideOrgRoleMapper(setting.NewCfg(), orgtest.NewOrgServiceFake()), - &ssosettingstests.MockService{}, + ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) for _, tc := range testCases { @@ -782,7 +782,7 @@ func TestUserInfoSearchesForGroup(t *testing.T) { ApiUrl: ts.URL, }, setting.NewCfg(), ProvideOrgRoleMapper(setting.NewCfg(), orgtest.NewOrgServiceFake()), - &ssosettingstests.MockService{}, + ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) token := &oauth2.Token{ @@ -802,7 +802,7 @@ func TestUserInfoSearchesForGroup(t *testing.T) { func TestPayloadCompression(t *testing.T) { provider := NewGenericOAuthProvider(&social.OAuthInfo{ EmailAttributePath: "email", - }, &setting.Cfg{}, nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures()) + }, &setting.Cfg{}, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) tests := []struct { Name string @@ -957,7 +957,7 @@ func TestSocialGenericOAuth_InitializeExtraFields(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - s := NewGenericOAuthProvider(tc.settings, &setting.Cfg{}, nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures()) + s := NewGenericOAuthProvider(tc.settings, &setting.Cfg{}, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) require.Equal(t, tc.want.nameAttributePath, s.nameAttributePath) require.Equal(t, tc.want.loginAttributePath, s.loginAttributePath) @@ -1176,7 +1176,7 @@ func TestSocialGenericOAuth_Validate(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - s := NewGenericOAuthProvider(&social.OAuthInfo{}, &setting.Cfg{}, nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures()) + s := NewGenericOAuthProvider(&social.OAuthInfo{}, &setting.Cfg{}, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) if tc.requester == nil { tc.requester = &user.SignedInUser{IsGrafanaAdmin: false} @@ -1256,7 +1256,7 @@ func TestSocialGenericOAuth_Reload(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - s := NewGenericOAuthProvider(tc.info, &setting.Cfg{}, nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures()) + s := NewGenericOAuthProvider(tc.info, &setting.Cfg{}, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) err := s.Reload(context.Background(), tc.settings) if tc.expectError { @@ -1354,7 +1354,7 @@ func TestGenericOAuth_Reload_ExtraFields(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - s := NewGenericOAuthProvider(tc.info, setting.NewCfg(), nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures()) + s := NewGenericOAuthProvider(tc.info, setting.NewCfg(), nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) err := s.Reload(context.Background(), tc.settings) require.NoError(t, err) diff --git a/pkg/login/social/connectors/github_oauth.go b/pkg/login/social/connectors/github_oauth.go index f5f0b43b3f3..619e7fa63c5 100644 --- a/pkg/login/social/connectors/github_oauth.go +++ b/pkg/login/social/connectors/github_oauth.go @@ -85,9 +85,7 @@ func NewGitHubProvider(info *social.OAuthInfo, cfg *setting.Cfg, orgRoleMapper * provider.log.Warn("Failed to parse team ids. Team ids must be a list of numbers.", "teamIds", teamIdsSplitted) } - if features.IsEnabledGlobally(featuremgmt.FlagSsoSettingsApi) { - ssoSettings.RegisterReloadable(social.GitHubProviderName, provider) - } + ssoSettings.RegisterReloadable(social.GitHubProviderName, provider) return provider } diff --git a/pkg/login/social/connectors/github_oauth_test.go b/pkg/login/social/connectors/github_oauth_test.go index 90b648f5f84..b6cfeeb5aa3 100644 --- a/pkg/login/social/connectors/github_oauth_test.go +++ b/pkg/login/social/connectors/github_oauth_test.go @@ -390,7 +390,7 @@ func TestSocialGitHub_UserInfo(t *testing.T) { }, cfg, ProvideOrgRoleMapper(cfg, &orgtest.FakeOrgService{ExpectedOrgs: []*org.OrgDTO{{ID: 4, Name: "Org4"}, {ID: 5, Name: "Org5"}}}), - &ssosettingstests.MockService{}, + ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) token := &oauth2.Token{ @@ -471,7 +471,7 @@ func TestSocialGitHub_InitializeExtraFields(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - s := NewGitHubProvider(tc.settings, &setting.Cfg{}, nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures()) + s := NewGitHubProvider(tc.settings, &setting.Cfg{}, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) require.Equal(t, tc.want.teamIds, s.teamIds) require.Equal(t, tc.want.allowedOrganizations, s.allowedOrganizations) @@ -598,7 +598,7 @@ func TestSocialGitHub_Validate(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - s := NewGitHubProvider(&social.OAuthInfo{}, &setting.Cfg{}, nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures()) + s := NewGitHubProvider(&social.OAuthInfo{}, &setting.Cfg{}, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) if tc.requester == nil { tc.requester = &user.SignedInUser{IsGrafanaAdmin: false} @@ -679,7 +679,7 @@ func TestSocialGitHub_Reload(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - s := NewGitHubProvider(tc.info, &setting.Cfg{}, nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures()) + s := NewGitHubProvider(tc.info, &setting.Cfg{}, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) err := s.Reload(context.Background(), tc.settings) if tc.expectError { @@ -738,7 +738,7 @@ func TestGitHub_Reload_ExtraFields(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - s := NewGitHubProvider(tc.info, setting.NewCfg(), nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures()) + s := NewGitHubProvider(tc.info, setting.NewCfg(), nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) err := s.Reload(context.Background(), tc.settings) require.NoError(t, err) diff --git a/pkg/login/social/connectors/gitlab_oauth.go b/pkg/login/social/connectors/gitlab_oauth.go index 7497c24d619..8545040aa0f 100644 --- a/pkg/login/social/connectors/gitlab_oauth.go +++ b/pkg/login/social/connectors/gitlab_oauth.go @@ -57,9 +57,7 @@ func NewGitLabProvider(info *social.OAuthInfo, cfg *setting.Cfg, orgRoleMapper * SocialBase: newSocialBase(social.GitlabProviderName, orgRoleMapper, info, features, cfg), } - if features.IsEnabledGlobally(featuremgmt.FlagSsoSettingsApi) { - ssoSettings.RegisterReloadable(social.GitlabProviderName, provider) - } + ssoSettings.RegisterReloadable(social.GitlabProviderName, provider) return provider } diff --git a/pkg/login/social/connectors/gitlab_oauth_test.go b/pkg/login/social/connectors/gitlab_oauth_test.go index 3963864974d..09a621f645f 100644 --- a/pkg/login/social/connectors/gitlab_oauth_test.go +++ b/pkg/login/social/connectors/gitlab_oauth_test.go @@ -209,7 +209,7 @@ func TestSocialGitlab_UserInfo(t *testing.T) { SkipOrgRoleSync: tt.Cfg.SkipOrgRoleSync, OrgMapping: tt.Cfg.OrgMapping, // OrgAttributePath: "", - }, cfg, orgMapper, &ssosettingstests.MockService{}, featuremgmt.WithFeatures()) + }, cfg, orgMapper, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") @@ -398,7 +398,7 @@ func TestSocialGitlab_extractFromToken(t *testing.T) { }, &setting.Cfg{ AutoAssignOrgRole: "", - }, nil, &ssosettingstests.MockService{}, + }, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) // Test case: successful extraction @@ -489,7 +489,7 @@ func TestSocialGitlab_GetGroupsNextPage(t *testing.T) { defer mockServer.Close() // Create a SocialGitlab instance with the mock server URL - s := NewGitLabProvider(&social.OAuthInfo{ApiUrl: mockServer.URL}, &setting.Cfg{}, nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures()) + s := NewGitLabProvider(&social.OAuthInfo{ApiUrl: mockServer.URL}, &setting.Cfg{}, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) // Call getGroups and verify that it returns all groups expectedGroups := []string{"admins", "editors", "viewers", "serveradmins"} @@ -611,7 +611,7 @@ func TestSocialGitlab_Validate(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - s := NewGitLabProvider(&social.OAuthInfo{}, &setting.Cfg{}, nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures()) + s := NewGitLabProvider(&social.OAuthInfo{}, &setting.Cfg{}, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) if tc.requester == nil { tc.requester = &user.SignedInUser{IsGrafanaAdmin: false} @@ -692,7 +692,7 @@ func TestSocialGitlab_Reload(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - s := NewGitLabProvider(tc.info, &setting.Cfg{}, nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures()) + s := NewGitLabProvider(tc.info, &setting.Cfg{}, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) err := s.Reload(context.Background(), tc.settings) if tc.expectError { diff --git a/pkg/login/social/connectors/google_oauth.go b/pkg/login/social/connectors/google_oauth.go index de72b011eaf..2191a2c01e8 100644 --- a/pkg/login/social/connectors/google_oauth.go +++ b/pkg/login/social/connectors/google_oauth.go @@ -58,9 +58,7 @@ func NewGoogleProvider(info *social.OAuthInfo, cfg *setting.Cfg, orgRoleMapper * provider.log.Warn("Using legacy Google API URL, please update your configuration") } - if features.IsEnabledGlobally(featuremgmt.FlagSsoSettingsApi) { - ssoSettings.RegisterReloadable(social.GoogleProviderName, provider) - } + ssoSettings.RegisterReloadable(social.GoogleProviderName, provider) return provider } diff --git a/pkg/login/social/connectors/google_oauth_test.go b/pkg/login/social/connectors/google_oauth_test.go index 4865c259674..0446a749adc 100644 --- a/pkg/login/social/connectors/google_oauth_test.go +++ b/pkg/login/social/connectors/google_oauth_test.go @@ -204,7 +204,7 @@ func TestSocialGoogle_retrieveGroups(t *testing.T) { AutoAssignOrgRole: "", }, nil, - &ssosettingstests.MockService{}, + ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) got, err := s.retrieveGroups(context.Background(), tt.args.client, tt.args.userData) @@ -693,7 +693,7 @@ func TestSocialGoogle_UserInfo(t *testing.T) { }, cfg, ProvideOrgRoleMapper(cfg, &orgtest.FakeOrgService{ExpectedOrgs: []*org.OrgDTO{{ID: 4, Name: "Org4"}, {ID: 5, Name: "Org5"}}}), - &ssosettingstests.MockService{}, + ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) gotData, err := s.UserInfo(context.Background(), tt.args.client, tt.args.token) @@ -834,7 +834,7 @@ func TestSocialGoogle_Validate(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - s := NewGoogleProvider(&social.OAuthInfo{}, &setting.Cfg{}, nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures()) + s := NewGoogleProvider(&social.OAuthInfo{}, &setting.Cfg{}, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) if tc.requester == nil { tc.requester = &user.SignedInUser{IsGrafanaAdmin: false} @@ -915,7 +915,7 @@ func TestSocialGoogle_Reload(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - s := NewGoogleProvider(tc.info, &setting.Cfg{}, nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures()) + s := NewGoogleProvider(tc.info, &setting.Cfg{}, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) err := s.Reload(context.Background(), tc.settings) if tc.expectError { @@ -968,7 +968,7 @@ func TestIsHDAllowed(t *testing.T) { t.Run(tc.name, func(t *testing.T) { info := &social.OAuthInfo{} info.AllowedDomains = tc.allowedDomains - s := NewGoogleProvider(info, &setting.Cfg{}, nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures()) + s := NewGoogleProvider(info, &setting.Cfg{}, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) s.validateHD = tc.validateHD err := s.isHDAllowed(tc.email) diff --git a/pkg/login/social/connectors/grafana_com_oauth.go b/pkg/login/social/connectors/grafana_com_oauth.go index a4efd5cd116..aea507ffdf7 100644 --- a/pkg/login/social/connectors/grafana_com_oauth.go +++ b/pkg/login/social/connectors/grafana_com_oauth.go @@ -57,9 +57,7 @@ func NewGrafanaComProvider(info *social.OAuthInfo, cfg *setting.Cfg, orgRoleMapp allowedOrganizations: allowedOrganizations, } - if features.IsEnabledGlobally(featuremgmt.FlagSsoSettingsApi) { - ssoSettings.RegisterReloadable(social.GrafanaComProviderName, provider) - } + ssoSettings.RegisterReloadable(social.GrafanaComProviderName, provider) return provider } diff --git a/pkg/login/social/connectors/grafana_com_oauth_test.go b/pkg/login/social/connectors/grafana_com_oauth_test.go index a9ee26bbbd2..32def336540 100644 --- a/pkg/login/social/connectors/grafana_com_oauth_test.go +++ b/pkg/login/social/connectors/grafana_com_oauth_test.go @@ -41,7 +41,7 @@ func TestSocialGrafanaCom_UserInfo(t *testing.T) { provider := NewGrafanaComProvider(social.NewOAuthInfo(), cfg, ProvideOrgRoleMapper(cfg, &orgtest.FakeOrgService{}), - &ssosettingstests.MockService{}, + ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) type conf struct { @@ -140,7 +140,7 @@ func TestSocialGrafanaCom_InitializeExtraFields(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - s := NewGrafanaComProvider(tc.settings, &setting.Cfg{}, nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures()) + s := NewGrafanaComProvider(tc.settings, &setting.Cfg{}, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) require.Equal(t, tc.want.allowedOrganizations, s.allowedOrganizations) }) @@ -209,7 +209,7 @@ func TestSocialGrafanaCom_Validate(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - s := NewGrafanaComProvider(&social.OAuthInfo{}, &setting.Cfg{}, nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures()) + s := NewGrafanaComProvider(&social.OAuthInfo{}, &setting.Cfg{}, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) if tc.requester == nil { tc.requester = &user.SignedInUser{IsGrafanaAdmin: false} @@ -309,7 +309,7 @@ func TestSocialGrafanaCom_Reload(t *testing.T) { cfg := &setting.Cfg{ GrafanaComURL: GrafanaComURL, } - s := NewGrafanaComProvider(tc.info, cfg, nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures()) + s := NewGrafanaComProvider(tc.info, cfg, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) err := s.Reload(context.Background(), tc.settings) if tc.expectError { @@ -370,7 +370,7 @@ func TestSocialGrafanaCom_Reload_ExtraFields(t *testing.T) { cfg := &setting.Cfg{ GrafanaComURL: GrafanaComURL, } - s := NewGrafanaComProvider(tc.info, cfg, nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures()) + s := NewGrafanaComProvider(tc.info, cfg, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) err := s.Reload(context.Background(), tc.settings) require.NoError(t, err) diff --git a/pkg/login/social/connectors/okta_oauth.go b/pkg/login/social/connectors/okta_oauth.go index ffa3a32a350..597051f7eae 100644 --- a/pkg/login/social/connectors/okta_oauth.go +++ b/pkg/login/social/connectors/okta_oauth.go @@ -54,9 +54,7 @@ func NewOktaProvider(info *social.OAuthInfo, cfg *setting.Cfg, orgRoleMapper *Or appendUniqueScope(provider.Config, social.OfflineAccessScope) } - if features.IsEnabledGlobally(featuremgmt.FlagSsoSettingsApi) { - ssoSettings.RegisterReloadable(social.OktaProviderName, provider) - } + ssoSettings.RegisterReloadable(social.OktaProviderName, provider) return provider } diff --git a/pkg/login/social/connectors/okta_oauth_test.go b/pkg/login/social/connectors/okta_oauth_test.go index 69c94bdf3bc..73fadd37454 100644 --- a/pkg/login/social/connectors/okta_oauth_test.go +++ b/pkg/login/social/connectors/okta_oauth_test.go @@ -200,7 +200,7 @@ func TestSocialOkta_UserInfo(t *testing.T) { cfg, ProvideOrgRoleMapper(cfg, &orgtest.FakeOrgService{ExpectedOrgs: []*org.OrgDTO{{ID: 4, Name: "Org4"}, {ID: 5, Name: "Org5"}}}), - &ssosettingstests.MockService{}, + ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) // create a oauth2 token with a id_token @@ -372,7 +372,7 @@ func TestSocialOkta_Validate(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - s := NewOktaProvider(&social.OAuthInfo{}, &setting.Cfg{}, nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures()) + s := NewOktaProvider(&social.OAuthInfo{}, &setting.Cfg{}, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) if tc.requester == nil { tc.requester = &user.SignedInUser{IsGrafanaAdmin: false} @@ -452,7 +452,7 @@ func TestSocialOkta_Reload(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - s := NewOktaProvider(tc.info, &setting.Cfg{}, nil, &ssosettingstests.MockService{}, featuremgmt.WithFeatures()) + s := NewOktaProvider(tc.info, &setting.Cfg{}, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) err := s.Reload(context.Background(), tc.settings) if tc.expectError { diff --git a/pkg/login/social/socialimpl/service.go b/pkg/login/social/socialimpl/service.go index 65a9a5573cc..ace96529443 100644 --- a/pkg/login/social/socialimpl/service.go +++ b/pkg/login/social/socialimpl/service.go @@ -25,11 +25,6 @@ import ( "github.com/grafana/grafana/pkg/setting" ) -var ( - allOauthes = []string{social.GitHubProviderName, social.GitlabProviderName, social.GoogleProviderName, social.GenericOAuthProviderName, social.GrafanaNetProviderName, - social.GrafanaComProviderName, social.AzureADProviderName, social.OktaProviderName} -) - type SocialService struct { cfg *setting.Cfg @@ -53,56 +48,30 @@ func ProvideService(cfg *setting.Cfg, usageStats.RegisterMetricsFunc(ss.getUsageStats) - if features.IsEnabledGlobally(featuremgmt.FlagSsoSettingsApi) { - allSettings, err := ssoSettings.List(context.Background()) + allSettings, err := ssoSettings.List(context.Background()) + if err != nil { + ss.log.Error("Failed to get SSO settings", "error", err) + } + + for _, ssoSetting := range allSettings { + // ignore non-oauth2 providers + if !slices.Contains(ssosettings.AllOAuthProviders, ssoSetting.Provider) { + continue + } + + info, err := connectors.CreateOAuthInfoFromKeyValuesWithLogging(ss.log, ssoSetting.Provider, ssoSetting.Settings) if err != nil { - ss.log.Error("Failed to get SSO settings", "error", err) + ss.log.Error("Failed to create OAuthInfo for provider", "error", err, "provider", ssoSetting.Provider) + continue } - for _, ssoSetting := range allSettings { - // ignore non-oauth2 providers - if !slices.Contains(ssosettings.AllOAuthProviders, ssoSetting.Provider) { - continue - } - - info, err := connectors.CreateOAuthInfoFromKeyValuesWithLogging(ss.log, ssoSetting.Provider, ssoSetting.Settings) - if err != nil { - ss.log.Error("Failed to create OAuthInfo for provider", "error", err, "provider", ssoSetting.Provider) - continue - } - - conn, err := createOAuthConnector(ssoSetting.Provider, info, cfg, orgRoleMapper, ssoSettings, features, cache) - if err != nil { - ss.log.Error("Failed to create OAuth provider", "error", err, "provider", ssoSetting.Provider) - continue - } - - ss.socialMap[ssoSetting.Provider] = conn + conn, err := createOAuthConnector(ssoSetting.Provider, info, cfg, orgRoleMapper, ssoSettings, features, cache) + if err != nil { + ss.log.Error("Failed to create OAuth provider", "error", err, "provider", ssoSetting.Provider) + continue } - } else { - for _, name := range allOauthes { - sec := cfg.Raw.Section("auth." + name) - settingsKVs := convertIniSectionToMap(sec) - - info, err := connectors.CreateOAuthInfoFromKeyValuesWithLogging(ss.log, name, settingsKVs) - if err != nil { - ss.log.Error("Failed to create OAuthInfo for provider", "error", err, "provider", name) - continue - } - - if !info.Enabled { - continue - } - - if name == social.GrafanaNetProviderName { - name = social.GrafanaComProviderName - } - - conn, _ := createOAuthConnector(name, info, cfg, orgRoleMapper, ssoSettings, features, cache) - - ss.socialMap[name] = conn - } + ss.socialMap[ssoSetting.Provider] = conn } ss.registerSupportBundleCollectors(bundleRegistry) diff --git a/pkg/login/social/socialimpl/service_test.go b/pkg/login/social/socialimpl/service_test.go index e188fbb53d9..870c13cf8e3 100644 --- a/pkg/login/social/socialimpl/service_test.go +++ b/pkg/login/social/socialimpl/service_test.go @@ -4,6 +4,7 @@ import ( "context" "testing" + "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/require" "gopkg.in/ini.v1" @@ -28,26 +29,14 @@ func TestMain(m *testing.M) { } func TestIntegrationSocialService_ProvideService(t *testing.T) { - type testEnv struct { - features featuremgmt.FeatureToggles - } testCases := []struct { name string - setup func(t *testing.T, env *testEnv) + setup func(t *testing.T) expectedSocialMapLength int expectedGenericOAuthSkipOrgRoleSync bool }{ { - name: "should load only enabled social connectors when ssoSettingsApi is disabled", - setup: nil, - expectedSocialMapLength: 1, - expectedGenericOAuthSkipOrgRoleSync: false, - }, - { - name: "should load all social connectors when ssoSettingsApi is enabled", - setup: func(t *testing.T, env *testEnv) { - env.features = featuremgmt.WithFeatures(featuremgmt.FlagSsoSettingsApi) - }, + name: "should load all social connectors when ssoSettingsApi is enabled", expectedSocialMapLength: 7, expectedGenericOAuthSkipOrgRoleSync: false, }, @@ -88,17 +77,14 @@ func TestIntegrationSocialService_ProvideService(t *testing.T) { t.Run(tc.name, func(t *testing.T) { ctx := context.Background() - env := &testEnv{ - features: featuremgmt.WithFeatures(), - } if tc.setup != nil { - tc.setup(t, env) + tc.setup(t) } usageInsights := &usagestats.UsageStatsMock{} supportBundle := supportbundlestest.NewFakeBundleService() - socialService := ProvideService(cfg, env.features, usageInsights, supportBundle, remotecache.NewFakeStore(t), nil, ssoSettingsSvc) + socialService := ProvideService(cfg, featuremgmt.WithFeatures(), usageInsights, supportBundle, remotecache.NewFakeStore(t), nil, ssoSettingsSvc) require.Equal(t, tc.expectedSocialMapLength, len(socialService.GetOAuthProviders())) genericOAuthInfo := socialService.GetOAuthInfoProvider("generic_oauth") @@ -160,6 +146,9 @@ func TestIntegrationSocialService_ProvideService_GrafanaComGrafanaNet(t *testing TokenUrl: "/api/oauth2/token", Enabled: true, ClientId: "grafanaComClientId", + Extra: map[string]string{ + "allowed_organizations": "", + }, }, }, { @@ -178,6 +167,9 @@ func TestIntegrationSocialService_ProvideService_GrafanaComGrafanaNet(t *testing TokenUrl: "/api/oauth2/token", Enabled: true, ClientId: "grafanaNetClientId", + Extra: map[string]string{ + "allowed_organizations": "", + }, }, }, { @@ -196,6 +188,9 @@ func TestIntegrationSocialService_ProvideService_GrafanaComGrafanaNet(t *testing TokenUrl: "/api/oauth2/token", Enabled: true, ClientId: "grafanaComClientId", + Extra: map[string]string{ + "allowed_organizations": "", + }, }, }, { @@ -208,28 +203,19 @@ func TestIntegrationSocialService_ProvideService_GrafanaComGrafanaNet(t *testing [auth.grafananet] enabled = false client_id = grafanaNetClientId`, - expectedGrafanaComOAuthInfo: nil, + expectedGrafanaComOAuthInfo: &social.OAuthInfo{ + AuthStyle: "inheader", + AuthUrl: "/oauth2/authorize", + TokenUrl: "/api/oauth2/token", + Enabled: false, + ClientId: "grafanaComClientId", + Extra: map[string]string{ + "allowed_organizations": "", + }, + }, }, } - cfg := setting.NewCfg() - secrets := secretsfake.NewMockService(t) - accessControl := acimpl.ProvideAccessControl(featuremgmt.WithFeatures()) - sqlStore := db.InitTestDB(t) - - ssoSettingsSvc := ssosettingsimpl.ProvideService( - cfg, - sqlStore, - accessControl, - routing.NewRouteRegister(), - featuremgmt.WithFeatures(), - secrets, - &usagestats.UsageStatsMock{}, - nil, - nil, - &licensing.OSSLicensingService{}, - ) - for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { iniFile, err := ini.Load([]byte(tc.rawIniContent)) @@ -238,8 +224,45 @@ func TestIntegrationSocialService_ProvideService_GrafanaComGrafanaNet(t *testing cfg := setting.NewCfg() cfg.Raw = iniFile + secrets := secretsfake.NewMockService(t) + accessControl := acimpl.ProvideAccessControl(featuremgmt.WithFeatures()) + sqlStore := db.InitTestDB(t) + + ssoSettingsSvc := ssosettingsimpl.ProvideService( + cfg, + sqlStore, + accessControl, + routing.NewRouteRegister(), + featuremgmt.WithFeatures(), + secrets, + &usagestats.UsageStatsMock{}, + nil, + nil, + &licensing.OSSLicensingService{}, + ) + socialService := ProvideService(cfg, featuremgmt.WithFeatures(), &usagestats.UsageStatsMock{}, supportbundlestest.NewFakeBundleService(), remotecache.NewFakeStore(t), nil, ssoSettingsSvc) - require.EqualValues(t, tc.expectedGrafanaComOAuthInfo, socialService.GetOAuthInfoProvider("grafana_com")) + + // Create a custom comparison that treats nil slices as equal to empty slices for the tests + opts := cmp.Options{ + cmp.Transformer("normalizeSlice", func(s []string) []string { + if s == nil { + return []string{} + } + return s + }), + cmp.Transformer("normalizeMap", func(m map[string]string) map[string]string { + if m == nil { + return map[string]string{} + } + return m + }), + } + + actual := socialService.GetOAuthInfoProvider("grafana_com") + if diff := cmp.Diff(tc.expectedGrafanaComOAuthInfo, actual, opts); diff != "" { + t.Errorf("OAuthInfo mismatch (-want +got):\n%s", diff) + } }) } } diff --git a/pkg/services/authn/authnimpl/registration.go b/pkg/services/authn/authnimpl/registration.go index e8fa578ad39..7eadac99083 100644 --- a/pkg/services/authn/authnimpl/registration.go +++ b/pkg/services/authn/authnimpl/registration.go @@ -58,8 +58,7 @@ func ProvideRegistration( var passwordClients []authn.PasswordClient // always register LDAP if LDAP is enabled in SSO settings - ssoSettingsLDAP := features.IsEnabledGlobally(featuremgmt.FlagSsoSettingsApi) && features.IsEnabledGlobally(featuremgmt.FlagSsoSettingsLDAP) - if cfg.LDAPAuthEnabled || ssoSettingsLDAP { + if cfg.LDAPAuthEnabled || features.IsEnabledGlobally(featuremgmt.FlagSsoSettingsLDAP) { ldap := clients.ProvideLDAP(cfg, ldapService, userService, authInfoService) proxyClients = append(proxyClients, ldap) passwordClients = append(passwordClients, ldap) diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index fe6fe7d4fab..cfa967694a8 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -651,15 +651,6 @@ var ( FrontendOnly: false, Owner: grafanaOperatorExperienceSquad, }, - { - Name: "ssoSettingsApi", - Description: "Enables the SSO settings API and the OAuth configuration UIs in Grafana", - Stage: FeatureStageGeneralAvailability, - Expression: "true", - AllowSelfServe: true, - FrontendOnly: false, - Owner: identityAccessTeam, - }, { Name: "canvasPanelPanZoom", Description: "Allow pan and zoom in canvas panel", diff --git a/pkg/services/featuremgmt/toggles_gen.csv b/pkg/services/featuremgmt/toggles_gen.csv index 5b44906dfc1..6739f18dd88 100644 --- a/pkg/services/featuremgmt/toggles_gen.csv +++ b/pkg/services/featuremgmt/toggles_gen.csv @@ -86,7 +86,6 @@ dashboardScene,GA,@grafana/dashboards-squad,false,false,true dashboardNewLayouts,experimental,@grafana/dashboards-squad,false,false,true panelFilterVariable,experimental,@grafana/dashboards-squad,false,false,true pdfTables,preview,@grafana/grafana-operator-experience-squad,false,false,false -ssoSettingsApi,GA,@grafana/identity-access-team,false,false,false canvasPanelPanZoom,preview,@grafana/dataviz-squad,false,false,true logsInfiniteScrolling,GA,@grafana/observability-logs,false,false,true logRowsPopoverMenu,GA,@grafana/observability-logs,false,false,true diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index bc513ac82d5..67685845005 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -355,10 +355,6 @@ const ( // Enables generating table data as PDF in reporting FlagPdfTables = "pdfTables" - // FlagSsoSettingsApi - // Enables the SSO settings API and the OAuth configuration UIs in Grafana - FlagSsoSettingsApi = "ssoSettingsApi" - // FlagCanvasPanelPanZoom // Allow pan and zoom in canvas panel FlagCanvasPanelPanZoom = "canvasPanelPanZoom" diff --git a/pkg/services/featuremgmt/toggles_gen.json b/pkg/services/featuremgmt/toggles_gen.json index c1cb552b6bb..9b00950e11f 100644 --- a/pkg/services/featuremgmt/toggles_gen.json +++ b/pkg/services/featuremgmt/toggles_gen.json @@ -2839,7 +2839,8 @@ "metadata": { "name": "ssoSettingsApi", "resourceVersion": "1750434297879", - "creationTimestamp": "2023-11-08T09:50:01Z" + "creationTimestamp": "2023-11-08T09:50:01Z", + "deletionTimestamp": "2025-07-02T14:16:57Z" }, "spec": { "description": "Enables the SSO settings API and the OAuth configuration UIs in Grafana", diff --git a/pkg/services/ldap/service/ldap.go b/pkg/services/ldap/service/ldap.go index 0a72f93721b..0a7144f99c1 100644 --- a/pkg/services/ldap/service/ldap.go +++ b/pkg/services/ldap/service/ldap.go @@ -56,7 +56,7 @@ func ProvideService(cfg *setting.Cfg, features featuremgmt.FeatureToggles, ssoSe ssoSettings: ssoSettings, } - if s.features.IsEnabledGlobally(featuremgmt.FlagSsoSettingsApi) && s.features.IsEnabledGlobally(featuremgmt.FlagSsoSettingsLDAP) { + if s.features.IsEnabledGlobally(featuremgmt.FlagSsoSettingsLDAP) { s.ssoSettings.RegisterReloadable(social.LDAPProviderName, s) ldapSettings, err := s.ssoSettings.GetForProvider(context.Background(), social.LDAPProviderName) diff --git a/pkg/services/ldap/service/ldap_test.go b/pkg/services/ldap/service/ldap_test.go index d58efaf49aa..72accd20613 100644 --- a/pkg/services/ldap/service/ldap_test.go +++ b/pkg/services/ldap/service/ldap_test.go @@ -6,7 +6,6 @@ import ( "sync" "testing" - "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/ldap" "github.com/grafana/grafana/pkg/services/ssosettings/models" "github.com/stretchr/testify/require" @@ -309,7 +308,6 @@ func TestReload(t *testing.T) { for _, tt := range testCases { t.Run(tt.description, func(t *testing.T) { ldapImpl := &LDAPImpl{ - features: featuremgmt.WithManager(featuremgmt.FlagSsoSettingsApi), loadingMutex: &sync.Mutex{}, } @@ -544,7 +542,6 @@ func TestValidate(t *testing.T) { for _, tt := range testCases { t.Run(tt.description, func(t *testing.T) { ldapImpl := &LDAPImpl{ - features: featuremgmt.WithManager(featuremgmt.FlagSsoSettingsApi), loadingMutex: &sync.Mutex{}, } diff --git a/pkg/services/navtree/navtreeimpl/admin.go b/pkg/services/navtree/navtreeimpl/admin.go index 7bc0bd5e102..7337a832d71 100644 --- a/pkg/services/navtree/navtreeimpl/admin.go +++ b/pkg/services/navtree/navtreeimpl/admin.go @@ -183,7 +183,7 @@ func (s *ServiceImpl) getAdminNode(c *contextmodel.ReqContext) (*navtree.NavLink configNodes = append(configNodes, usersNode) if authConfigUIAvailable && hasAccess(ssoutils.EvalAuthenticationSettings(s.cfg)) || - (hasAccess(ssoutils.OauthSettingsEvaluator(s.cfg)) && s.features.IsEnabled(ctx, featuremgmt.FlagSsoSettingsApi)) { + hasAccess(ssoutils.OauthSettingsEvaluator(s.cfg)) { configNodes = append(configNodes, &navtree.NavLink{ Text: "Authentication", Id: "authentication", diff --git a/pkg/services/ssosettings/ssosettingsimpl/service.go b/pkg/services/ssosettings/ssosettingsimpl/service.go index 6f27368b095..458c0a21b6a 100644 --- a/pkg/services/ssosettings/ssosettingsimpl/service.go +++ b/pkg/services/ssosettings/ssosettingsimpl/service.go @@ -93,10 +93,8 @@ func ProvideService(cfg *setting.Cfg, sqlStore db.DB, ac ac.AccessControl, usageStats.RegisterMetricsFunc(svc.getUsageStats) - if features.IsEnabledGlobally(featuremgmt.FlagSsoSettingsApi) { - ssoSettingsApi := api.ProvideApi(svc, routeRegister, ac) - ssoSettingsApi.RegisterAPIEndpoints() - } + ssoSettingsApi := api.ProvideApi(svc, routeRegister, ac) + ssoSettingsApi.RegisterAPIEndpoints() return svc } diff --git a/pkg/services/ssosettings/ssosettingstests/service_fake.go b/pkg/services/ssosettings/ssosettingstests/service_fake.go new file mode 100644 index 00000000000..f629d25a296 --- /dev/null +++ b/pkg/services/ssosettings/ssosettingstests/service_fake.go @@ -0,0 +1,119 @@ +package ssosettingstests + +import ( + context "context" + + "github.com/grafana/grafana/pkg/apimachinery/identity" + "github.com/grafana/grafana/pkg/services/ssosettings" + models "github.com/grafana/grafana/pkg/services/ssosettings/models" +) + +var _ ssosettings.Service = (*FakeService)(nil) + +type FakeService struct { + ExpectedSSOSetting *models.SSOSettings + ExpectedSSOSettings []*models.SSOSettings + ExpectedError error + ExpectedReloadablesRegistry map[string]ssosettings.Reloadable + + ActualSSOSettings models.SSOSettings + ActualPatchData map[string]any + ActualProvider string + ActualRequester identity.Requester + + ListFn func(ctx context.Context) ([]*models.SSOSettings, error) + ListWithRedactedSecretsFn func(ctx context.Context) ([]*models.SSOSettings, error) + GetForProviderFn func(ctx context.Context, provider string) (*models.SSOSettings, error) + GetForProviderWithRedactedSecretsFn func(ctx context.Context, provider string) (*models.SSOSettings, error) + UpsertFn func(ctx context.Context, settings *models.SSOSettings, requester identity.Requester) error + DeleteFn func(ctx context.Context, provider string) error + PatchFn func(ctx context.Context, provider string, data map[string]any) error + RegisterReloadableFn func(provider string, reloadable ssosettings.Reloadable) + ReloadFn func(ctx context.Context, provider string) +} + +func NewFakeService() *FakeService { + return &FakeService{ + ExpectedReloadablesRegistry: make(map[string]ssosettings.Reloadable), + } +} + +func (f *FakeService) List(ctx context.Context) ([]*models.SSOSettings, error) { + if f.ListFn != nil { + return f.ListFn(ctx) + } + return f.ExpectedSSOSettings, f.ExpectedError +} + +func (f *FakeService) ListWithRedactedSecrets(ctx context.Context) ([]*models.SSOSettings, error) { + if f.ListWithRedactedSecretsFn != nil { + return f.ListWithRedactedSecretsFn(ctx) + } + return f.ExpectedSSOSettings, f.ExpectedError +} + +func (f *FakeService) GetForProvider(ctx context.Context, provider string) (*models.SSOSettings, error) { + if f.GetForProviderFn != nil { + return f.GetForProviderFn(ctx, provider) + } + f.ActualProvider = provider + return f.ExpectedSSOSetting, f.ExpectedError +} + +func (f *FakeService) GetForProviderWithRedactedSecrets(ctx context.Context, provider string) (*models.SSOSettings, error) { + if f.GetForProviderWithRedactedSecretsFn != nil { + return f.GetForProviderWithRedactedSecretsFn(ctx, provider) + } + f.ActualProvider = provider + return f.ExpectedSSOSetting, f.ExpectedError +} + +func (f *FakeService) Upsert(ctx context.Context, settings *models.SSOSettings, requester identity.Requester) error { + if f.UpsertFn != nil { + return f.UpsertFn(ctx, settings, requester) + } + + f.ActualSSOSettings = *settings + f.ActualRequester = requester + + return f.ExpectedError +} + +func (f *FakeService) Delete(ctx context.Context, provider string) error { + if f.DeleteFn != nil { + return f.DeleteFn(ctx, provider) + } + + f.ActualProvider = provider + + return f.ExpectedError +} + +func (f *FakeService) Patch(ctx context.Context, provider string, data map[string]any) error { + if f.PatchFn != nil { + return f.PatchFn(ctx, provider, data) + } + + f.ActualProvider = provider + f.ActualPatchData = data + + return f.ExpectedError +} + +func (f *FakeService) RegisterReloadable(provider string, reloadable ssosettings.Reloadable) { + if f.RegisterReloadableFn != nil { + f.RegisterReloadableFn(provider, reloadable) + return + } + + f.ExpectedReloadablesRegistry[provider] = reloadable +} + +func (f *FakeService) Reload(ctx context.Context, provider string) { + if f.ReloadFn != nil { + f.ReloadFn(ctx, provider) + return + } + + f.ActualProvider = provider +} diff --git a/public/app/features/auth-config/index.ts b/public/app/features/auth-config/index.ts index cca2b7208af..c927b22e701 100644 --- a/public/app/features/auth-config/index.ts +++ b/public/app/features/auth-config/index.ts @@ -53,7 +53,7 @@ export async function getAuthProviderStatus(providerId: string): Promise> export function loadProviders(provider = ''): ThunkResult> { return async (dispatch) => { - if (!config.featureToggles.ssoSettingsApi) { - return []; - } const result = await getBackendSrv().get(`/api/v1/sso-settings${provider ? `/${provider}` : ''}`); dispatch(providersLoaded(provider ? [result] : result)); return result; diff --git a/public/app/routes/routes.tsx b/public/app/routes/routes.tsx index 252b8703bd4..e1baf824794 100644 --- a/public/app/routes/routes.tsx +++ b/public/app/routes/routes.tsx @@ -301,7 +301,7 @@ export function getAppRoutes(): RouteDescriptor[] { path: '/admin/authentication', roles: () => contextSrv.evaluatePermission([AccessControlAction.SettingsWrite]), component: - config.licenseInfo.enabledFeatures?.saml || config.ldapEnabled || config.featureToggles.ssoSettingsApi + config.licenseInfo.enabledFeatures?.saml || config.ldapEnabled ? SafeDynamicImport( () => import(/* webpackChunkName: "AdminAuthentication" */ '../features/auth-config/AuthProvidersListPage') @@ -319,11 +319,9 @@ export function getAppRoutes(): RouteDescriptor[] { { path: '/admin/authentication/:provider', roles: () => contextSrv.evaluatePermission([AccessControlAction.SettingsWrite]), - component: config.featureToggles.ssoSettingsApi - ? SafeDynamicImport( - () => import(/* webpackChunkName: "AdminAuthentication" */ '../features/auth-config/ProviderConfigPage') - ) - : () => , + component: SafeDynamicImport( + () => import(/* webpackChunkName: "AdminAuthentication" */ '../features/auth-config/ProviderConfigPage') + ), }, { path: '/admin/settings',