Skip to content

Commit

Permalink
Auth: Extended JWT client for OBO and Service Authentication (#83814)
Browse files Browse the repository at this point in the history
* reenable ext-jwt-client

* fixup settings struct

* add user and service auth

* lint up

* add user auth to grafana ext

* fixes

* Populate token permissions

Co-authored-by: jguer <joao.guerreiro@grafana.com>

* fix tests

* fix lint

* small prealloc

* small prealloc

* use special namespace for access policies

* fix access policy auth

* fix tests

* fix uncalled settings expander

* add feature toggle

* small feedback fixes

* rename entitlements to permissions

* add authlibn

* allow viewing the signed in user info for non user namespace

* fix invalid namespacedID

* use authlib as verifier for tokens

* Update pkg/services/authn/clients/ext_jwt.go

Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com>

* Update pkg/services/authn/clients/ext_jwt_test.go

Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com>

* fix parameter names

* change asserts to normal package

* add rule for assert

* fix ownerships

* Local diff

* test and lint

* Fix test

* Fix ac test

* Fix pluginproxy test

* Revert testdata changes

* Force revert on test data

---------

Co-authored-by: gamab <gabriel.mabille@grafana.com>
Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com>
  • Loading branch information
3 people committed Apr 2, 2024
1 parent ac6e51c commit 5340a6e
Show file tree
Hide file tree
Showing 28 changed files with 433 additions and 316 deletions.
1 change: 1 addition & 0 deletions .golangci.toml
Expand Up @@ -17,6 +17,7 @@ deny = [
{ pkg = "github.com/pkg/errors", desc = "Deprecated: Go 1.13 supports the functionality provided by pkg/errors in the standard library." },
{ pkg = "github.com/xorcare/pointer", desc = "Use pkg/util.Pointer instead, which is a generic one-liner alternative" },
{ pkg = "github.com/gofrs/uuid", desc = "Use github.com/google/uuid instead, which we already depend on." },
{ pkg = "github.com/bmizerany/assert", desc = "Use github.com/stretchr/testify/assert instead, which we already depend on." },
]

[linters-settings.depguard.rules.coreplugins]
Expand Down
16 changes: 8 additions & 8 deletions go.mod
Expand Up @@ -20,7 +20,7 @@ require (
cuelang.org/go v0.6.0-0.dev // @grafana/grafana-as-code
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // @grafana/partner-datasources
github.com/Azure/go-autorest/autorest v0.11.29 // @grafana/backend-platform
github.com/BurntSushi/toml v1.3.2 // @grafana/grafana-authnz-team
github.com/BurntSushi/toml v1.3.2 // @grafana/identity-access-team
github.com/Masterminds/semver v1.5.0 // @grafana/backend-platform
github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f // @grafana/backend-platform
github.com/aws/aws-sdk-go v1.50.8 // @grafana/aws-datasources
Expand All @@ -29,10 +29,10 @@ require (
github.com/blang/semver/v4 v4.0.0 // @grafana/grafana-release-guild
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // @grafana/backend-platform
github.com/centrifugal/centrifuge v0.30.2 // @grafana/grafana-app-platform-squad
github.com/crewjam/saml v0.4.13 // @grafana/grafana-authnz-team
github.com/crewjam/saml v0.4.13 // @grafana/identity-access-team
github.com/fatih/color v1.15.0 // @grafana/backend-platform
github.com/gchaincl/sqlhooks v1.3.0 // @grafana/backend-platform
github.com/go-ldap/ldap/v3 v3.4.4 // @grafana/grafana-authnz-team
github.com/go-ldap/ldap/v3 v3.4.4 // @grafana/identity-access-team
github.com/go-openapi/strfmt v0.22.0 // @grafana/alerting-squad-backend
github.com/go-redis/redis/v8 v8.11.5 // @grafana/backend-platform
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // @grafana/backend-platform
Expand Down Expand Up @@ -96,7 +96,7 @@ require (
golang.org/x/crypto v0.21.0 // @grafana/backend-platform
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb // @grafana/alerting-squad-backend
golang.org/x/net v0.22.0 // @grafana/oss-big-tent @grafana/partner-datasources
golang.org/x/oauth2 v0.18.0 // @grafana/grafana-authnz-team
golang.org/x/oauth2 v0.18.0 // @grafana/identity-access-team
golang.org/x/sync v0.6.0 // @grafana/alerting-squad-backend
golang.org/x/time v0.5.0 // @grafana/backend-platform
golang.org/x/tools v0.17.0 // @grafana/grafana-as-code
Expand Down Expand Up @@ -241,7 +241,7 @@ require (
github.com/Masterminds/semver/v3 v3.1.1 // @grafana/grafana-release-guild
github.com/alicebob/miniredis/v2 v2.30.1 // @grafana/alerting-squad-backend
github.com/dave/dst v0.27.2 // @grafana/grafana-as-code
github.com/go-jose/go-jose/v3 v3.0.3 // @grafana/grafana-authnz-team
github.com/go-jose/go-jose/v3 v3.0.3 // @grafana/identity-access-team
github.com/grafana/dataplane/examples v0.0.1 // @grafana/observability-metrics
github.com/grafana/dataplane/sdata v0.0.7 // @grafana/observability-metrics
github.com/grafana/tempo v1.5.1-0.20230524121406-1dc1bfe7085b // @grafana/observability-traces-and-profiling
Expand Down Expand Up @@ -326,7 +326,7 @@ require (
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-ieproxy v0.0.3 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 //@grafana/grafana-authnz-team
github.com/mitchellh/mapstructure v1.5.0 //@grafana/identity-access-team
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // @grafana/alerting-squad-backend
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
Expand Down Expand Up @@ -384,7 +384,7 @@ require (
require (
cloud.google.com/go/compute v1.23.3 // indirect
cloud.google.com/go/iam v1.1.5 // indirect
filippo.io/age v1.1.1 // @grafana/grafana-authnz-team
filippo.io/age v1.1.1 // @grafana/identity-access-team
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 // indirect
Expand Down Expand Up @@ -473,7 +473,7 @@ require github.com/jackc/pgx/v5 v5.5.5 // @grafana/oss-big-tent

require github.com/getkin/kin-openapi v0.120.0 // @grafana/grafana-as-code

require github.com/grafana/authlib v0.0.0-20240319083410-9d4a6e3861e5 // @grafana/grafana-app-platform-squad
require github.com/grafana/authlib v0.0.0-20240328140636-a7388d0bac72 // @grafana/identity-access-team

require (
github.com/bahlo/generic-list-go v0.2.0 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Expand Up @@ -2161,8 +2161,8 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grafana/alerting v0.0.0-20240322221449-89ae4e299bf8 h1:ndBSFAHmJRWqln2uNys7lV0+9U8tlW6ZuNz8ETW60Us=
github.com/grafana/alerting v0.0.0-20240322221449-89ae4e299bf8/go.mod h1:0nHKO0w8OTemvZ3eh7+s1EqGGhgbs0kvkTeLU1FrbTw=
github.com/grafana/authlib v0.0.0-20240319083410-9d4a6e3861e5 h1:A13Z8Hy60BfIduM819kpk0njrRKjbAVbVRhE+R+AF/8=
github.com/grafana/authlib v0.0.0-20240319083410-9d4a6e3861e5/go.mod h1:86rRD5P6u2JPWtNWTMOlqlU+YMv2fUvVz/DomA6L7w4=
github.com/grafana/authlib v0.0.0-20240328140636-a7388d0bac72 h1:lGEuhD/KhhN1OiPrvwQejl9Lg8MvaHdj3lHZNref4is=
github.com/grafana/authlib v0.0.0-20240328140636-a7388d0bac72/go.mod h1:86rRD5P6u2JPWtNWTMOlqlU+YMv2fUvVz/DomA6L7w4=
github.com/grafana/codejen v0.0.3 h1:tAWxoTUuhgmEqxJPOLtJoxlPBbMULFwKFOcRsPRPXDw=
github.com/grafana/codejen v0.0.3/go.mod h1:zmwwM/DRyQB7pfuBjTWII3CWtxcXh8LTwAYGfDfpR6s=
github.com/grafana/cue v0.0.0-20230926092038-971951014e3f h1:TmYAMnqg3d5KYEAaT6PtTguL2GjLfvr6wnAX8Azw6tQ=
Expand Down
6 changes: 6 additions & 0 deletions go.work.sum
Expand Up @@ -351,6 +351,7 @@ github.com/go-fonts/stix v0.1.0 h1:UlZlgrvvmT/58o573ot7NFw0vZasZ5I6bcIft/oMdgg=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I=
github.com/go-ini/ini v1.25.4 h1:Mujh4R/dH6YL8bxuISne3xX2+qcQ9p0IxKAP6ExWoUo=
github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4=
github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81 h1:6zl3BbBhdnMkpSj2YY30qV3gDcVBGtFgVsV3+/i+mKQ=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab h1:xveKWz2iaueeTaUgdetzel+U7exyigDYBryyVfV/rZk=
Expand Down Expand Up @@ -405,6 +406,9 @@ github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/grafana/authlib v0.0.0-20240319083410-9d4a6e3861e5/go.mod h1:86rRD5P6u2JPWtNWTMOlqlU+YMv2fUvVz/DomA6L7w4=
github.com/grafana/authlib v0.0.0-20240328140636-a7388d0bac72 h1:lGEuhD/KhhN1OiPrvwQejl9Lg8MvaHdj3lHZNref4is=
github.com/grafana/authlib v0.0.0-20240328140636-a7388d0bac72/go.mod h1:86rRD5P6u2JPWtNWTMOlqlU+YMv2fUvVz/DomA6L7w4=
github.com/grafana/e2e v0.1.1-0.20221018202458-cffd2bb71c7b h1:Ha+kSIoTutf4ytlVw/SaEclDUloYx0+FXDKJWKhNbE4=
github.com/grafana/e2e v0.1.1-0.20221018202458-cffd2bb71c7b/go.mod h1:3UsooRp7yW5/NJQBlXcTsAHOoykEhNUYXkQ3r6ehEEY=
github.com/grafana/gomemcache v0.0.0-20231023152154-6947259a0586 h1:/of8Z8taCPftShATouOrBVy6GaTTjgQd/VfNiZp/VXQ=
Expand Down Expand Up @@ -661,6 +665,7 @@ github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad h1:fiWzISvDn0Csy5H0iwgAuJ
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo=
github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e h1:mOtuXaRAbVZsxAHVdPR3IjfmN8T1h2iczJLynhLybf8=
github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0=
github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
github.com/substrait-io/substrait-go v0.4.2 h1:buDnjsb3qAqTaNbOR7VKmNgXf4lYQxWEcnSGUWBtmN8=
github.com/substrait-io/substrait-go v0.4.2/go.mod h1:qhpnLmrcvAnlZsUyPXZRqldiHapPTXC3t7xFgDi3aQg=
Expand Down Expand Up @@ -771,6 +776,7 @@ go.uber.org/mock v0.2.0/go.mod h1:J0y0rp9L3xiff1+ZBfKxlC1fz2+aO16tw0tsDOixfuM=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
Expand Down
1 change: 1 addition & 0 deletions packages/grafana-data/src/types/featureToggles.gen.ts
Expand Up @@ -173,6 +173,7 @@ export interface FeatureToggles {
expressionParser?: boolean;
groupByVariable?: boolean;
betterPageScrolling?: boolean;
authAPIAccessTokenAuth?: boolean;
scopeFilters?: boolean;
ssoSettingsSAML?: boolean;
usePrometheusFrontendPackage?: boolean;
Expand Down
3 changes: 2 additions & 1 deletion pkg/api/pluginproxy/ds_proxy_test.go
Expand Up @@ -513,7 +513,8 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
t,
&contextmodel.ReqContext{
SignedInUser: &user.SignedInUser{
Login: "test_user",
Login: "test_user",
NamespacedID: "user:1",
},
},
&setting.Cfg{SendUserHeader: true},
Expand Down
3 changes: 2 additions & 1 deletion pkg/api/pluginproxy/pluginproxy_test.go
Expand Up @@ -76,7 +76,8 @@ func TestPluginProxy(t *testing.T) {
secretsService,
&contextmodel.ReqContext{
SignedInUser: &user.SignedInUser{
Login: "test_user",
Login: "test_user",
NamespacedID: "user:1",
},
Context: &web.Context{
Req: httpReq,
Expand Down
19 changes: 16 additions & 3 deletions pkg/api/user.go
Expand Up @@ -31,10 +31,23 @@ import (
// 404: notFoundError
// 500: internalServerError
func (hs *HTTPServer) GetSignedInUser(c *contextmodel.ReqContext) response.Response {
userID, errResponse := getUserID(c)
if errResponse != nil {
return errResponse
namespace, identifier := c.SignedInUser.GetNamespacedID()
if namespace != identity.NamespaceUser {
return response.JSON(http.StatusOK, user.UserProfileDTO{
IsGrafanaAdmin: c.SignedInUser.GetIsGrafanaAdmin(),
OrgID: c.SignedInUser.GetOrgID(),
UID: strings.Join([]string{namespace, identifier}, ":"),
Name: c.SignedInUser.NameOrFallback(),
Email: c.SignedInUser.GetEmail(),
Login: c.SignedInUser.GetLogin(),
})
}

userID, err := identity.IntIdentifier(namespace, identifier)
if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to parse user id", err)
}

return hs.getUserUserProfile(c, userID)
}

Expand Down
2 changes: 2 additions & 0 deletions pkg/services/accesscontrol/accesscontrol.go
Expand Up @@ -24,6 +24,8 @@ type AccessControl interface {

type Service interface {
registry.ProvidesUsageStats
// GetRoleByName returns a role by name
GetRoleByName(ctx context.Context, orgID int64, roleName string) (*RoleDTO, error)
// GetUserPermissions returns user permissions with only action and scope fields set.
GetUserPermissions(ctx context.Context, user identity.Requester, options Options) ([]Permission, error)
// GetUserPermissionsInOrg return user permission in a specific organization
Expand Down
23 changes: 23 additions & 0 deletions pkg/services/accesscontrol/acimpl/service.go
Expand Up @@ -504,3 +504,26 @@ func (s *Service) DeleteExternalServiceRole(ctx context.Context, externalService
func (*Service) SyncUserRoles(ctx context.Context, orgID int64, cmd accesscontrol.SyncUserRolesCommand) error {
return nil
}

func (s *Service) GetRoleByName(ctx context.Context, orgID int64, roleName string) (*accesscontrol.RoleDTO, error) {
err := accesscontrol.ErrRoleNotFound
if _, ok := s.roles[roleName]; ok {
return nil, err
}

var role *accesscontrol.RoleDTO
s.registrations.Range(func(registration accesscontrol.RoleRegistration) bool {
if registration.Role.Name == roleName {
role = &accesscontrol.RoleDTO{
Name: registration.Role.Name,
Permissions: registration.Role.Permissions,
DisplayName: registration.Role.DisplayName,
Description: registration.Role.Description,
}
err = nil
return false
}
return true
})
return role, err
}
13 changes: 9 additions & 4 deletions pkg/services/accesscontrol/acimpl/service_test.go
Expand Up @@ -754,8 +754,9 @@ func TestPermissionCacheKey(t *testing.T) {
{
name: "should return correct key for user",
signedInUser: &user.SignedInUser{
OrgID: 1,
UserID: 1,
OrgID: 1,
UserID: 1,
NamespacedID: "user:1",
},
expected: "rbac-permissions-1-user-1",
},
Expand All @@ -765,6 +766,7 @@ func TestPermissionCacheKey(t *testing.T) {
OrgID: 1,
ApiKeyID: 1,
IsServiceAccount: false,
NamespacedID: "user:1",
},
expected: "rbac-permissions-1-api-key-1",
},
Expand All @@ -774,6 +776,7 @@ func TestPermissionCacheKey(t *testing.T) {
OrgID: 1,
UserID: 1,
IsServiceAccount: true,
NamespacedID: "serviceaccount:1",
},
expected: "rbac-permissions-1-service-account-1",
},
Expand All @@ -783,14 +786,16 @@ func TestPermissionCacheKey(t *testing.T) {
OrgID: 1,
UserID: -1,
IsServiceAccount: true,
NamespacedID: "serviceaccount:-1",
},
expected: "rbac-permissions-1-service-account--1",
},
{
name: "should use org role if no unique id",
signedInUser: &user.SignedInUser{
OrgID: 1,
OrgRole: org.RoleNone,
OrgID: 1,
OrgRole: org.RoleNone,
NamespacedID: "user:1",
},
expected: "rbac-permissions-1-user-None",
},
Expand Down
10 changes: 10 additions & 0 deletions pkg/services/accesscontrol/mock/mock.go
Expand Up @@ -20,6 +20,7 @@ type fullAccessControl interface {

type Calls struct {
Evaluate []interface{}
GetRoleByName []interface{}
GetUserPermissions []interface{}
GetUserPermissionsInOrg []interface{}
ClearUserPermissionCache []interface{}
Expand Down Expand Up @@ -47,6 +48,7 @@ type Mock struct {

// Override functions
EvaluateFunc func(context.Context, identity.Requester, accesscontrol.Evaluator) (bool, error)
GetRoleByNameFunc func(context.Context, int64, string) (*accesscontrol.RoleDTO, error)
GetUserPermissionsFunc func(context.Context, identity.Requester, accesscontrol.Options) ([]accesscontrol.Permission, error)
GetUserPermissionsInOrgFunc func(context.Context, identity.Requester, int64) ([]accesscontrol.Permission, error)
ClearUserPermissionCacheFunc func(identity.Requester)
Expand Down Expand Up @@ -81,6 +83,14 @@ func New() *Mock {
return mock
}

func (m *Mock) GetRoleByName(ctx context.Context, orgID int64, roleName string) (*accesscontrol.RoleDTO, error) {
m.Calls.GetRoleByName = append(m.Calls.GetRoleByName, []interface{}{ctx, orgID, roleName})
if m.GetRoleByNameFunc != nil {
return m.GetRoleByNameFunc(ctx, orgID, roleName)
}
return nil, nil
}

func (m *Mock) GetUsageStats(ctx context.Context) map[string]interface{} {
return make(map[string]interface{})
}
Expand Down
1 change: 1 addition & 0 deletions pkg/services/auth/identity/requester.go
Expand Up @@ -14,6 +14,7 @@ const (
NamespaceServiceAccount = "service-account"
NamespaceAnonymous = "anonymous"
NamespaceRenderService = "render"
NamespaceAccessPolicy = "access-policy"
)

var ErrNotIntIdentifier = errors.New("identifier is not an int64")
Expand Down
9 changes: 9 additions & 0 deletions pkg/services/authn/authn.go
Expand Up @@ -57,6 +57,15 @@ type ClientParams struct {
LookUpParams login.UserLookupParams
// SyncPermissions ensure that permissions are loaded from DB and added to the identity
SyncPermissions bool
// FetchPermissionsParams are the arguments used to fetch permissions from the DB
FetchPermissionsParams FetchPermissionsParams
}

type FetchPermissionsParams struct {
// ActionsLookup will restrict the permissions to only these actions
ActionsLookup []string
// Roles permissions will be directly added to the identity permissions
Roles []string
}

type PostAuthHookFn func(ctx context.Context, identity *Identity, r *Request) error
Expand Down
7 changes: 3 additions & 4 deletions pkg/services/authn/authnimpl/service.go
Expand Up @@ -135,10 +135,9 @@ func ProvideService(
s.RegisterClient(clients.ProvideJWT(jwtService, cfg))
}

// FIXME (gamab): Commenting that out for now as we want to re-use the client for external service auth
// if s.cfg.ExtendedJWTAuthEnabled && features.IsEnabledGlobally(featuremgmt.FlagExternalServiceAuth) {
// s.RegisterClient(clients.ProvideExtendedJWT(userService, cfg, signingKeysService, oauthServer))
// }
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)
Expand Down
49 changes: 44 additions & 5 deletions pkg/services/authn/authnimpl/sync/rbac_sync.go
Expand Up @@ -2,6 +2,7 @@ package sync

import (
"context"
"errors"

"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/accesscontrol"
Expand Down Expand Up @@ -34,19 +35,57 @@ func (s *RBACSync) SyncPermissionsHook(ctx context.Context, ident *authn.Identit
return nil
}

permissions, err := s.ac.GetUserPermissions(ctx, ident, accesscontrol.Options{ReloadCache: false})
// Populate permissions from roles
permissions, err := s.fetchPermissions(ctx, ident)
if err != nil {
s.log.FromContext(ctx).Error("Failed to fetch permissions from db", "error", err, "id", ident.ID)
return errSyncPermissionsForbidden
return err
}

if ident.Permissions == nil {
ident.Permissions = make(map[int64]map[string][]string)
ident.Permissions = make(map[int64]map[string][]string, 1)
}
grouped := accesscontrol.GroupScopesByAction(permissions)

// Restrict access to the list of actions
actionsLookup := ident.ClientParams.FetchPermissionsParams.ActionsLookup
if len(actionsLookup) > 0 {
filtered := make(map[string][]string, len(actionsLookup))
for _, action := range actionsLookup {
if scopes, ok := grouped[action]; ok {
filtered[action] = scopes
}
}
grouped = filtered
}
ident.Permissions[ident.OrgID] = accesscontrol.GroupScopesByAction(permissions)

ident.Permissions[ident.OrgID] = grouped
return nil
}

func (s *RBACSync) fetchPermissions(ctx context.Context, ident *authn.Identity) ([]accesscontrol.Permission, error) {
permissions := make([]accesscontrol.Permission, 0, 8)
roles := ident.ClientParams.FetchPermissionsParams.Roles
if len(roles) > 0 {
for _, role := range roles {
roleDTO, err := s.ac.GetRoleByName(ctx, ident.GetOrgID(), role)
if err != nil && !errors.Is(err, accesscontrol.ErrRoleNotFound) {
s.log.FromContext(ctx).Error("Failed to fetch role from db", "error", err, "role", role)
return nil, errSyncPermissionsForbidden
}
permissions = append(permissions, roleDTO.Permissions...)
}

return permissions, nil
}

permissions, err := s.ac.GetUserPermissions(ctx, ident, accesscontrol.Options{ReloadCache: false})
if err != nil {
s.log.FromContext(ctx).Error("Failed to fetch permissions from db", "error", err, "id", ident.ID)
return nil, errSyncPermissionsForbidden
}
return permissions, nil
}

var fixedCloudRoles = map[org.RoleType]string{
org.RoleViewer: accesscontrol.FixedCloudViewerRole,
org.RoleEditor: accesscontrol.FixedCloudEditorRole,
Expand Down

0 comments on commit 5340a6e

Please sign in to comment.