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: Extended JWT client for OBO and Service Authentication #83814
Changes from 35 commits
b711c2b
a1a3939
6c0390e
9fe9ca3
a29b546
cd17a97
6d76d7f
952c3b4
005bf9f
fb3966f
c8b1f0d
14702cd
5a9eae1
135749f
dfe274e
4158a07
8f83de8
f9779c5
58a2a74
18d71ff
a0f19d1
82c8f3b
4a0c064
710fa9e
e0fdf55
33aa8a5
9b397f7
43447d1
e19dfd0
295afc6
231db44
b7c9dec
35f7352
d97605b
6b747d6
af7740b
4361ff4
295d046
3fba2a8
47e8cea
720691f
de73e0c
480b4a6
cd6b274
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a reason to not clone the entire There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since these are not persisted in the DB we don't have all the fields, I've added the ones we actually have |
||
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 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ package sync | |
|
||
import ( | ||
"context" | ||
"errors" | ||
|
||
"github.com/grafana/grafana/pkg/infra/log" | ||
"github.com/grafana/grafana/pkg/services/accesscontrol" | ||
|
@@ -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 | ||
Jguer marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Curious how you landed on 8 for the initial capacity - typically in these kind of dynamic slices I don't see a capacity set. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. normally set an octet multiple for these, we're normally sure to get around this value |
||
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, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose we don't want to allow basic roles? Side note, this check could actually be skipped as we won't find basic roles in the registration list.