diff --git a/pkg/infra/usagestats/service/accesscontrol.go b/pkg/infra/usagestats/service/accesscontrol.go deleted file mode 100644 index 380380ff802..00000000000 --- a/pkg/infra/usagestats/service/accesscontrol.go +++ /dev/null @@ -1,30 +0,0 @@ -package service - -import ( - "github.com/grafana/grafana/pkg/services/accesscontrol" -) - -const ( - ActionRead = "server.usagestats.report:read" -) - -var ( - usagestatsReaderRole = accesscontrol.RoleDTO{ - Name: "fixed:usagestats:reader", - DisplayName: "Usage stats report reader", - Description: "View usage statistics report", - Group: "Statistics", - Permissions: []accesscontrol.Permission{ - {Action: ActionRead}, - }, - } -) - -func declareFixedRoles(ac accesscontrol.Service) error { - usagestatsReader := accesscontrol.RoleRegistration{ - Role: usagestatsReaderRole, - Grants: []string{string(accesscontrol.RoleGrafanaAdmin)}, - } - - return ac.DeclareFixedRoles(usagestatsReader) -} diff --git a/pkg/infra/usagestats/service/api.go b/pkg/infra/usagestats/service/api.go index 1217b639613..7a124e9a1c7 100644 --- a/pkg/infra/usagestats/service/api.go +++ b/pkg/infra/usagestats/service/api.go @@ -15,7 +15,7 @@ func (uss *UsageStats) registerAPIEndpoints() { authorize := accesscontrol.Middleware(uss.accesscontrol) uss.RouteRegister.Group(rootUrl, func(subrouter routing.RouteRegister) { - subrouter.Get("/usage-report-preview", authorize(accesscontrol.EvalPermission(ActionRead)), routing.Wrap(uss.getUsageReportPreview)) + subrouter.Get("/usage-report-preview", authorize(accesscontrol.EvalPermission(accesscontrol.ActionUsageStatsRead)), routing.Wrap(uss.getUsageReportPreview)) }) } diff --git a/pkg/infra/usagestats/service/api_test.go b/pkg/infra/usagestats/service/api_test.go index f2b749f5dff..2a424f995a0 100644 --- a/pkg/infra/usagestats/service/api_test.go +++ b/pkg/infra/usagestats/service/api_test.go @@ -10,6 +10,7 @@ import ( "github.com/grafana/grafana/pkg/infra/db/dbtest" "github.com/grafana/grafana/pkg/infra/log" + "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/contexthandler/ctxkey" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" "github.com/grafana/grafana/pkg/services/stats" @@ -28,13 +29,13 @@ func TestApi_getUsageStats(t *testing.T) { { desc: "expect usage stats", enabled: true, - permissions: map[string][]string{ActionRead: {}}, + permissions: map[string][]string{accesscontrol.ActionUsageStatsRead: {}}, expectedStatus: 200, }, { desc: "expect usage stat preview still there after disabling", enabled: false, - permissions: map[string][]string{ActionRead: {}}, + permissions: map[string][]string{accesscontrol.ActionUsageStatsRead: {}}, expectedStatus: 200, }, { diff --git a/pkg/infra/usagestats/service/service.go b/pkg/infra/usagestats/service/service.go index 06ed6509ab6..ccd9357fb56 100644 --- a/pkg/infra/usagestats/service/service.go +++ b/pkg/infra/usagestats/service/service.go @@ -35,7 +35,6 @@ func ProvideService(cfg *setting.Cfg, routeRegister routing.RouteRegister, tracer tracing.Tracer, accesscontrol ac.AccessControl, - accesscontrolService ac.Service, bundleRegistry supportbundles.Service, ) (*UsageStats, error) { s := &UsageStats{ @@ -47,10 +46,6 @@ func ProvideService(cfg *setting.Cfg, accesscontrol: accesscontrol, } - if err := declareFixedRoles(accesscontrolService); err != nil { - return nil, err - } - s.registerAPIEndpoints() bundleRegistry.RegisterSupportItemCollector(s.supportBundleCollector()) diff --git a/pkg/infra/usagestats/service/usage_stats_test.go b/pkg/infra/usagestats/service/usage_stats_test.go index cd0d9a83704..03023e99268 100644 --- a/pkg/infra/usagestats/service/usage_stats_test.go +++ b/pkg/infra/usagestats/service/usage_stats_test.go @@ -23,7 +23,6 @@ import ( "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/infra/usagestats" "github.com/grafana/grafana/pkg/services/accesscontrol/acimpl" - "github.com/grafana/grafana/pkg/services/accesscontrol/actest" "github.com/grafana/grafana/pkg/services/supportbundles/supportbundlestest" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/tests/testsuite" @@ -248,7 +247,6 @@ func createService(t *testing.T, sqlStore db.DB, withDB bool) *UsageStats { routing.NewRouteRegister(), tracing.InitializeTracerForTest(), acimpl.ProvideAccessControl(cfg), - actest.FakeService{}, supportbundlestest.NewFakeBundleService(), ) diff --git a/pkg/registry/backgroundsvcs/background_services.go b/pkg/registry/backgroundsvcs/background_services.go index 43dd35bcd25..4c5cc6b9164 100644 --- a/pkg/registry/backgroundsvcs/background_services.go +++ b/pkg/registry/backgroundsvcs/background_services.go @@ -12,6 +12,7 @@ import ( "github.com/grafana/grafana/pkg/services/anonymous/anonimpl" grafanaapiserver "github.com/grafana/grafana/pkg/services/apiserver" "github.com/grafana/grafana/pkg/services/auth" + "github.com/grafana/grafana/pkg/services/authn/authnimpl" "github.com/grafana/grafana/pkg/services/cleanup" "github.com/grafana/grafana/pkg/services/cloudmigration" "github.com/grafana/grafana/pkg/services/dashboardsnapshots" @@ -68,7 +69,7 @@ func ProvideBackgroundServiceRegistry( _ *plugindashboardsservice.DashboardUpdater, _ *sanitizer.Provider, _ *grpcserver.HealthService, _ entity.EntityStoreServer, _ *grpcserver.ReflectionService, _ *ldapapi.Service, _ *apiregistry.Service, _ auth.IDService, _ *teamapi.TeamAPI, _ ssosettings.Service, - _ cloudmigration.Service, + _ cloudmigration.Service, _ authnimpl.Registration, ) *BackgroundServiceRegistry { return NewBackgroundServiceRegistry( httpServer, diff --git a/pkg/server/wire.go b/pkg/server/wire.go index 64d94f62d68..437c930235e 100644 --- a/pkg/server/wire.go +++ b/pkg/server/wire.go @@ -356,6 +356,7 @@ var wireBasicSet = wire.NewSet( authnimpl.ProvideService, authnimpl.ProvideIdentitySynchronizer, authnimpl.ProvideAuthnService, + authnimpl.ProvideRegistration, supportbundlesimpl.ProvideService, extsvcaccounts.ProvideExtSvcAccountsService, wire.Bind(new(serviceaccounts.ExtSvcAccountsService), new(*extsvcaccounts.ExtSvcAccountsService)), diff --git a/pkg/services/accesscontrol/models.go b/pkg/services/accesscontrol/models.go index d0f5aeb54d9..79e35c65db3 100644 --- a/pkg/services/accesscontrol/models.go +++ b/pkg/services/accesscontrol/models.go @@ -481,6 +481,9 @@ const ( ActionLibraryPanelsRead = "library.panels:read" ActionLibraryPanelsWrite = "library.panels:write" ActionLibraryPanelsDelete = "library.panels:delete" + + // Usage stats actions + ActionUsageStatsRead = "server.usagestats.report:read" ) var ( diff --git a/pkg/services/accesscontrol/roles.go b/pkg/services/accesscontrol/roles.go index 48e493ea3ef..72334fee499 100644 --- a/pkg/services/accesscontrol/roles.go +++ b/pkg/services/accesscontrol/roles.go @@ -280,6 +280,16 @@ var ( }, }, } + + usagestatsReaderRole = RoleDTO{ + Name: "fixed:usagestats:reader", + DisplayName: "Usage stats report reader", + Description: "View usage statistics report", + Group: "Statistics", + Permissions: []Permission{ + {Action: ActionUsageStatsRead}, + }, + } ) // Declare OSS roles to the accesscontrol service @@ -320,15 +330,22 @@ func DeclareFixedRoles(service Service, cfg *setting.Cfg) error { Role: generalAuthConfigWriterRole, Grants: []string{RoleGrafanaAdmin}, } - // TODO: Move to own service when implemented authenticationConfigWriter := RoleRegistration{ Role: authenticationConfigWriterRole, Grants: []string{RoleGrafanaAdmin}, } - return service.DeclareFixedRoles(ldapReader, ldapWriter, orgUsersReader, orgUsersWriter, - settingsReader, statsReader, usersReader, usersWriter, authenticationConfigWriter, generalAuthConfigWriter) + usageStatsReader := RoleRegistration{ + Role: usagestatsReaderRole, + Grants: []string{RoleGrafanaAdmin}, + } + + return service.DeclareFixedRoles( + ldapReader, ldapWriter, orgUsersReader, orgUsersWriter, + settingsReader, statsReader, usersReader, usersWriter, + authenticationConfigWriter, generalAuthConfigWriter, usageStatsReader, + ) } func ConcatPermissions(permissions ...[]Permission) []Permission { diff --git a/pkg/services/authn/authnimpl/registration.go b/pkg/services/authn/authnimpl/registration.go new file mode 100644 index 00000000000..9ed6bf80e18 --- /dev/null +++ b/pkg/services/authn/authnimpl/registration.go @@ -0,0 +1,116 @@ +package authnimpl + +import ( + "github.com/grafana/grafana/pkg/infra/log" + "github.com/grafana/grafana/pkg/infra/remotecache" + "github.com/grafana/grafana/pkg/login/social" + "github.com/grafana/grafana/pkg/services/accesscontrol" + "github.com/grafana/grafana/pkg/services/apikey" + "github.com/grafana/grafana/pkg/services/auth" + "github.com/grafana/grafana/pkg/services/authn" + "github.com/grafana/grafana/pkg/services/authn/authnimpl/sync" + "github.com/grafana/grafana/pkg/services/authn/clients" + "github.com/grafana/grafana/pkg/services/featuremgmt" + "github.com/grafana/grafana/pkg/services/ldap/service" + "github.com/grafana/grafana/pkg/services/login" + "github.com/grafana/grafana/pkg/services/loginattempt" + "github.com/grafana/grafana/pkg/services/oauthtoken" + "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/services/quota" + "github.com/grafana/grafana/pkg/services/rendering" + "github.com/grafana/grafana/pkg/services/signingkeys" + "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/setting" +) + +type Registration struct{} + +func ProvideRegistration( + cfg *setting.Cfg, authnSvc authn.Service, + orgService org.Service, sessionService auth.UserTokenService, + accessControlService accesscontrol.Service, + apikeyService apikey.Service, userService user.Service, + jwtService auth.JWTVerifierService, userProtectionService login.UserProtectionService, + loginAttempts loginattempt.Service, quotaService quota.Service, + authInfoService login.AuthInfoService, renderService rendering.Service, + features *featuremgmt.FeatureManager, oauthTokenService oauthtoken.OAuthTokenService, + socialService social.Service, cache *remotecache.RemoteCache, signingKeysService signingkeys.Service, + ldapService service.LDAP, settingsProviderService setting.Provider, +) Registration { + logger := log.New("authn.registration") + + authnSvc.RegisterClient(clients.ProvideRender(renderService)) + authnSvc.RegisterClient(clients.ProvideAPIKey(apikeyService)) + + if cfg.LoginCookieName != "" { + authnSvc.RegisterClient(clients.ProvideSession(cfg, sessionService)) + } + + var proxyClients []authn.ProxyClient + var passwordClients []authn.PasswordClient + if cfg.LDAPAuthEnabled { + ldap := clients.ProvideLDAP(cfg, ldapService, userService, authInfoService) + proxyClients = append(proxyClients, ldap) + passwordClients = append(passwordClients, ldap) + } + + if !cfg.DisableLogin { + grafana := clients.ProvideGrafana(cfg, userService) + proxyClients = append(proxyClients, grafana) + passwordClients = append(passwordClients, grafana) + } + + // if we have password clients configure check if basic auth or form auth is enabled + if len(passwordClients) > 0 { + passwordClient := clients.ProvidePassword(loginAttempts, passwordClients...) + if cfg.BasicAuthEnabled { + authnSvc.RegisterClient(clients.ProvideBasic(passwordClient)) + } + + if !cfg.DisableLoginForm { + authnSvc.RegisterClient(clients.ProvideForm(passwordClient)) + } + } + + if cfg.AuthProxy.Enabled && len(proxyClients) > 0 { + proxy, err := clients.ProvideProxy(cfg, cache, proxyClients...) + if err != nil { + logger.Error("Failed to configure auth proxy", "err", err) + } else { + authnSvc.RegisterClient(proxy) + } + } + + if cfg.JWTAuth.Enabled { + authnSvc.RegisterClient(clients.ProvideJWT(jwtService, cfg)) + } + + if cfg.ExtJWTAuth.Enabled && features.IsEnabledGlobally(featuremgmt.FlagAuthAPIAccessTokenAuth) { + authnSvc.RegisterClient(clients.ProvideExtendedJWT(userService, cfg, signingKeysService)) + } + + for name := range socialService.GetOAuthProviders() { + clientName := authn.ClientWithPrefix(name) + authnSvc.RegisterClient(clients.ProvideOAuth(clientName, cfg, oauthTokenService, socialService, settingsProviderService, features)) + } + + // FIXME (jguer): move to User package + userSync := sync.ProvideUserSync(userService, userProtectionService, authInfoService, quotaService) + orgSync := sync.ProvideOrgSync(userService, orgService, accessControlService, cfg) + authnSvc.RegisterPostAuthHook(userSync.SyncUserHook, 10) + authnSvc.RegisterPostAuthHook(userSync.EnableUserHook, 20) + authnSvc.RegisterPostAuthHook(orgSync.SyncOrgRolesHook, 30) + authnSvc.RegisterPostAuthHook(userSync.SyncLastSeenHook, 130) + authnSvc.RegisterPostAuthHook(sync.ProvideOAuthTokenSync(oauthTokenService, sessionService, socialService).SyncOauthTokenHook, 60) + authnSvc.RegisterPostAuthHook(userSync.FetchSyncedUserHook, 100) + + rbacSync := sync.ProvideRBACSync(accessControlService) + if features.IsEnabledGlobally(featuremgmt.FlagCloudRBACRoles) { + authnSvc.RegisterPostAuthHook(rbacSync.SyncCloudRoles, 110) + } + + authnSvc.RegisterPostAuthHook(rbacSync.SyncPermissionsHook, 120) + authnSvc.RegisterPostAuthHook(orgSync.SetDefaultOrgHook, 130) + + return Registration{} +} diff --git a/pkg/services/authn/authnimpl/service.go b/pkg/services/authn/authnimpl/service.go index 339d443a728..3fcf1856ac1 100644 --- a/pkg/services/authn/authnimpl/service.go +++ b/pkg/services/authn/authnimpl/service.go @@ -13,26 +13,13 @@ import ( "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/network" - "github.com/grafana/grafana/pkg/infra/remotecache" "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/infra/usagestats" - "github.com/grafana/grafana/pkg/login/social" - "github.com/grafana/grafana/pkg/services/accesscontrol" - "github.com/grafana/grafana/pkg/services/apikey" "github.com/grafana/grafana/pkg/services/auth" "github.com/grafana/grafana/pkg/services/auth/identity" "github.com/grafana/grafana/pkg/services/authn" - "github.com/grafana/grafana/pkg/services/authn/authnimpl/sync" "github.com/grafana/grafana/pkg/services/authn/clients" - "github.com/grafana/grafana/pkg/services/featuremgmt" - "github.com/grafana/grafana/pkg/services/ldap/service" "github.com/grafana/grafana/pkg/services/login" - "github.com/grafana/grafana/pkg/services/loginattempt" - "github.com/grafana/grafana/pkg/services/oauthtoken" - "github.com/grafana/grafana/pkg/services/org" - "github.com/grafana/grafana/pkg/services/quota" - "github.com/grafana/grafana/pkg/services/rendering" - "github.com/grafana/grafana/pkg/services/signingkeys" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util/errutil" @@ -60,19 +47,8 @@ func ProvideIdentitySynchronizer(s *Service) authn.IdentitySynchronizer { func ProvideService( cfg *setting.Cfg, tracer tracing.Tracer, - orgService org.Service, sessionService auth.UserTokenService, - accessControlService accesscontrol.Service, - apikeyService apikey.Service, userService user.Service, - jwtService auth.JWTVerifierService, - usageStats usagestats.Service, - userProtectionService login.UserProtectionService, - loginAttempts loginattempt.Service, quotaService quota.Service, - authInfoService login.AuthInfoService, renderService rendering.Service, - features *featuremgmt.FeatureManager, oauthTokenService oauthtoken.OAuthTokenService, - socialService social.Service, cache *remotecache.RemoteCache, - ldapService service.LDAP, registerer prometheus.Registerer, - signingKeysService signingkeys.Service, - settingsProviderService setting.Provider, + sessionService auth.UserTokenService, usageStats usagestats.Service, + authInfoService login.AuthInfoService, registerer prometheus.Registerer, ) *Service { s := &Service{ log: log.New("authn.service"), @@ -88,81 +64,6 @@ func ProvideService( } usageStats.RegisterMetricsFunc(s.getUsageStats) - - s.RegisterClient(clients.ProvideRender(renderService)) - s.RegisterClient(clients.ProvideAPIKey(apikeyService)) - - if cfg.LoginCookieName != "" { - s.RegisterClient(clients.ProvideSession(cfg, sessionService)) - } - - var proxyClients []authn.ProxyClient - var passwordClients []authn.PasswordClient - if s.cfg.LDAPAuthEnabled { - ldap := clients.ProvideLDAP(cfg, ldapService, userService, authInfoService) - proxyClients = append(proxyClients, ldap) - passwordClients = append(passwordClients, ldap) - } - - if !s.cfg.DisableLogin { - grafana := clients.ProvideGrafana(cfg, userService) - proxyClients = append(proxyClients, grafana) - passwordClients = append(passwordClients, grafana) - } - - // if we have password clients configure check if basic auth or form auth is enabled - if len(passwordClients) > 0 { - passwordClient := clients.ProvidePassword(loginAttempts, passwordClients...) - if s.cfg.BasicAuthEnabled { - s.RegisterClient(clients.ProvideBasic(passwordClient)) - } - - if !s.cfg.DisableLoginForm { - s.RegisterClient(clients.ProvideForm(passwordClient)) - } - } - - if s.cfg.AuthProxy.Enabled && len(proxyClients) > 0 { - proxy, err := clients.ProvideProxy(cfg, cache, proxyClients...) - if err != nil { - s.log.Error("Failed to configure auth proxy", "err", err) - } else { - s.RegisterClient(proxy) - } - } - - if s.cfg.JWTAuth.Enabled { - s.RegisterClient(clients.ProvideJWT(jwtService, cfg)) - } - - if s.cfg.ExtJWTAuth.Enabled && features.IsEnabledGlobally(featuremgmt.FlagAuthAPIAccessTokenAuth) { - s.RegisterClient(clients.ProvideExtendedJWT(userService, cfg, signingKeysService)) - } - - for name := range socialService.GetOAuthProviders() { - clientName := authn.ClientWithPrefix(name) - s.RegisterClient(clients.ProvideOAuth(clientName, cfg, oauthTokenService, socialService, settingsProviderService, features)) - } - - // FIXME (jguer): move to User package - userSyncService := sync.ProvideUserSync(userService, userProtectionService, authInfoService, quotaService) - orgUserSyncService := sync.ProvideOrgSync(userService, orgService, accessControlService, cfg) - s.RegisterPostAuthHook(userSyncService.SyncUserHook, 10) - s.RegisterPostAuthHook(userSyncService.EnableUserHook, 20) - s.RegisterPostAuthHook(orgUserSyncService.SyncOrgRolesHook, 30) - s.RegisterPostAuthHook(userSyncService.SyncLastSeenHook, 130) - s.RegisterPostAuthHook(sync.ProvideOAuthTokenSync(oauthTokenService, sessionService, socialService).SyncOauthTokenHook, 60) - s.RegisterPostAuthHook(userSyncService.FetchSyncedUserHook, 100) - - rbacSync := sync.ProvideRBACSync(accessControlService) - if features.IsEnabledGlobally(featuremgmt.FlagCloudRBACRoles) { - s.RegisterPostAuthHook(rbacSync.SyncCloudRoles, 110) - } - - s.RegisterPostAuthHook(rbacSync.SyncPermissionsHook, 120) - - s.RegisterPostAuthHook(orgUserSyncService.SetDefaultOrgHook, 130) - return s }