diff --git a/conf/defaults.ini b/conf/defaults.ini index a852dee4e75..b514f480436 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -497,6 +497,7 @@ allowed_groups = #################################### Okta OAuth ####################### [auth.okta] name = Okta +icon = okta enabled = false allow_sign_up = true client_id = some_id @@ -513,6 +514,7 @@ role_attribute_strict = false #################################### Generic OAuth ####################### [auth.generic_oauth] name = OAuth +icon = signin enabled = false allow_sign_up = true client_id = some_id diff --git a/docs/sources/auth/generic-oauth.md b/docs/sources/auth/generic-oauth.md index 444e92f68c1..053758777fb 100755 --- a/docs/sources/auth/generic-oauth.md +++ b/docs/sources/auth/generic-oauth.md @@ -27,6 +27,8 @@ Example config: ```bash [auth.generic_oauth] +name = OAuth +icon = signin enabled = true client_id = YOUR_APP_CLIENT_ID client_secret = YOUR_APP_CLIENT_SECRET diff --git a/docs/sources/auth/okta.md b/docs/sources/auth/okta.md index 14046e5a68a..4b6c63bb973 100644 --- a/docs/sources/auth/okta.md +++ b/docs/sources/auth/okta.md @@ -38,6 +38,7 @@ Before you can sign a user in, you need to create an Okta application from the O ```ini [auth.okta] name = Okta +icon = okta enabled = true allow_sign_up = true client_id = some_id diff --git a/packages/grafana-data/src/types/config.ts b/packages/grafana-data/src/types/config.ts index b1d519c8b12..c62468699be 100644 --- a/packages/grafana-data/src/types/config.ts +++ b/packages/grafana-data/src/types/config.ts @@ -65,6 +65,26 @@ export type PreloadPlugin = { version: string; }; +/** Supported OAuth services + * + * @public + */ +export type OAuth = + | 'github' + | 'gitlab' + | 'google' + | 'generic_oauth' + // | 'grafananet' Deprecated. Key always changed to "grafana_com" + | 'grafana_com' + | 'azuread' + | 'okta'; + +/** Map of enabled OAuth services and their respective names + * + * @public + */ +export type OAuthSettings = Partial>; + /** * Describes all the different Grafana configuration values available for an instance. * diff --git a/pkg/api/login.go b/pkg/api/login.go index f66a2e2740d..b5547bf2c9b 100644 --- a/pkg/api/login.go +++ b/pkg/api/login.go @@ -93,7 +93,10 @@ func (hs *HTTPServer) LoginView(c *models.ReqContext) { enabledOAuths := make(map[string]interface{}) providers := hs.SocialService.GetOAuthInfoProviders() for key, oauth := range providers { - enabledOAuths[key] = map[string]string{"name": oauth.Name} + enabledOAuths[key] = map[string]string{ + "name": oauth.Name, + "icon": oauth.Icon, + } } viewData.Settings["oauth"] = enabledOAuths diff --git a/pkg/login/social/social.go b/pkg/login/social/social.go index 339f4d6b2bb..aad424e3900 100644 --- a/pkg/login/social/social.go +++ b/pkg/login/social/social.go @@ -45,6 +45,7 @@ type OAuthInfo struct { TeamsUrl string AllowSignup bool Name string + Icon string TlsClientCert string TlsClientKey string TlsClientCa string @@ -81,6 +82,7 @@ func ProvideService(cfg *setting.Cfg) *SocialService { HostedDomain: sec.Key("hosted_domain").String(), AllowSignup: sec.Key("allow_sign_up").MustBool(), Name: sec.Key("name").MustString(name), + Icon: sec.Key("icon").String(), TlsClientCert: sec.Key("tls_client_cert").String(), TlsClientKey: sec.Key("tls_client_key").String(), TlsClientCa: sec.Key("tls_client_ca").String(), diff --git a/public/app/core/components/Login/LoginPage.test.tsx b/public/app/core/components/Login/LoginPage.test.tsx index 256dcf4c6b9..3d5161182df 100644 --- a/public/app/core/components/Login/LoginPage.test.tsx +++ b/public/app/core/components/Login/LoginPage.test.tsx @@ -3,8 +3,11 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { LoginPage } from './LoginPage'; +import * as runtimeMock from '@grafana/runtime'; + const postMock = jest.fn(); jest.mock('@grafana/runtime', () => ({ + __esModule: true, getBackendSrv: () => ({ post: postMock, }), @@ -26,6 +29,10 @@ jest.mock('@grafana/runtime', () => ({ })); describe('Login Page', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); + it('renders correctly', () => { render(); @@ -77,4 +84,16 @@ describe('Login Page', () => { await waitFor(() => expect(postMock).toHaveBeenCalledWith('/login', { password: 'test', user: 'admin' })); expect(window.location.assign).toHaveBeenCalledWith('/'); }); + it('renders social logins correctly', () => { + (runtimeMock as any).config.oauth = { + okta: { + name: 'Okta Test', + icon: 'signin', + }, + }; + + render(); + + expect(screen.getByRole('link', { name: 'Sign in with Okta Test' })).toBeInTheDocument(); + }); }); diff --git a/public/app/core/components/Login/LoginServiceButtons.tsx b/public/app/core/components/Login/LoginServiceButtons.tsx index ffb4c5c046c..ab8a648aad7 100644 --- a/public/app/core/components/Login/LoginServiceButtons.tsx +++ b/public/app/core/components/Login/LoginServiceButtons.tsx @@ -29,46 +29,46 @@ const loginServices: () => LoginServices = () => { }, google: { bgColor: '#e84d3c', - enabled: oauthEnabled && config.oauth.google, + enabled: oauthEnabled && Boolean(config.oauth.google), name: 'Google', icon: 'google', }, azuread: { bgColor: '#2f2f2f', - enabled: oauthEnabled && config.oauth.azuread, + enabled: oauthEnabled && Boolean(config.oauth.azuread), name: 'Microsoft', icon: 'microsoft', }, github: { bgColor: '#464646', - enabled: oauthEnabled && config.oauth.github, + enabled: oauthEnabled && Boolean(config.oauth.github), name: 'GitHub', icon: 'github', }, gitlab: { bgColor: '#fc6d26', - enabled: oauthEnabled && config.oauth.gitlab, + enabled: oauthEnabled && Boolean(config.oauth.gitlab), name: 'GitLab', icon: 'gitlab', }, grafanacom: { bgColor: '#262628', - enabled: oauthEnabled && config.oauth.grafana_com, + enabled: oauthEnabled && Boolean(config.oauth.grafana_com), name: 'Grafana.com', - hrefName: 'grafana_com', icon: 'grafana', + hrefName: 'grafana_com', }, okta: { bgColor: '#2f2f2f', - enabled: oauthEnabled && config.oauth.okta, - name: 'Okta', - icon: 'okta', + enabled: oauthEnabled && Boolean(config.oauth.okta), + name: config.oauth?.okta?.name || 'Okta', + icon: (config.oauth?.okta?.icon as IconName) || 'okta', }, oauth: { bgColor: '#262628', - enabled: oauthEnabled && config.oauth.generic_oauth, - name: oauthEnabled && config.oauth.generic_oauth ? config.oauth.generic_oauth.name : 'OAuth', - icon: 'signin', + enabled: oauthEnabled && Boolean(config.oauth.generic_oauth), + name: config.oauth?.generic_oauth?.name || 'OAuth', + icon: (config.oauth?.generic_oauth?.icon as IconName) || 'signin', hrefName: 'generic_oauth', }, };