Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auth: Decouple client and hook registration #85084

Merged
merged 3 commits into from Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 0 additions & 30 deletions pkg/infra/usagestats/service/accesscontrol.go

This file was deleted.

2 changes: 1 addition & 1 deletion pkg/infra/usagestats/service/api.go
Expand Up @@ -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))
})
}

Expand Down
5 changes: 3 additions & 2 deletions pkg/infra/usagestats/service/api_test.go
Expand Up @@ -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"
Expand All @@ -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,
},
{
Expand Down
5 changes: 0 additions & 5 deletions pkg/infra/usagestats/service/service.go
Expand Up @@ -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{
Expand All @@ -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())

Expand Down
2 changes: 0 additions & 2 deletions pkg/infra/usagestats/service/usage_stats_test.go
Expand Up @@ -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"
Expand Down Expand Up @@ -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(),
)

Expand Down
3 changes: 2 additions & 1 deletion pkg/registry/backgroundsvcs/background_services.go
Expand Up @@ -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"
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions pkg/server/wire.go
Expand Up @@ -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)),
Expand Down
3 changes: 3 additions & 0 deletions pkg/services/accesscontrol/models.go
Expand Up @@ -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 (
Expand Down
23 changes: 20 additions & 3 deletions pkg/services/accesscontrol/roles.go
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
116 changes: 116 additions & 0 deletions 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{}
}