Auth: Extended JWT client for OBO and Service Authentication (#83814)

* 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>
This commit is contained in:
Jo
2024-04-02 17:45:15 +02:00
committed by GitHub
co-authored by Gabriel MABILLE gamab
parent ac6e51c94a
commit 5340a6e548
28 changed files with 443 additions and 326 deletions
@@ -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
@@ -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
}
@@ -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",
},
@@ -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",
},
@@ -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",
},
@@ -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",
},
+10
View File
@@ -20,6 +20,7 @@ type fullAccessControl interface {
type Calls struct {
Evaluate []interface{}
GetRoleByName []interface{}
GetUserPermissions []interface{}
GetUserPermissionsInOrg []interface{}
ClearUserPermissionCache []interface{}
@@ -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)
@@ -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{})
}