mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
MT AuthZ: Resolve renderer permissions in MT authZ service (#99362)
* resolve renderer permissions in MT authZ service * also include DS read perms * fix tests and linting
This commit is contained in:
parent
4fb7b47971
commit
723fa7ddf9
@ -41,9 +41,13 @@ func (c *Render) Authenticate(ctx context.Context, r *authn.Request) (*authn.Ide
|
|||||||
}
|
}
|
||||||
|
|
||||||
if renderUsr.UserID <= 0 {
|
if renderUsr.UserID <= 0 {
|
||||||
|
identityType := claims.TypeAnonymous
|
||||||
|
if org.RoleType(renderUsr.OrgRole) == org.RoleAdmin {
|
||||||
|
identityType = claims.TypeRenderService
|
||||||
|
}
|
||||||
return &authn.Identity{
|
return &authn.Identity{
|
||||||
ID: "0",
|
ID: "0",
|
||||||
Type: claims.TypeRenderService,
|
Type: identityType,
|
||||||
OrgID: renderUsr.OrgID,
|
OrgID: renderUsr.OrgID,
|
||||||
OrgRoles: map[int64]org.RoleType{renderUsr.OrgID: org.RoleType(renderUsr.OrgRole)},
|
OrgRoles: map[int64]org.RoleType{renderUsr.OrgID: org.RoleType(renderUsr.OrgRole)},
|
||||||
ClientParams: authn.ClientParams{SyncPermissions: true},
|
ClientParams: authn.ClientParams{SyncPermissions: true},
|
||||||
|
@ -29,7 +29,29 @@ func TestRender_Authenticate(t *testing.T) {
|
|||||||
|
|
||||||
tests := []TestCase{
|
tests := []TestCase{
|
||||||
{
|
{
|
||||||
desc: "expect valid render key to return render user identity",
|
desc: "expect valid render key to return anonymous user identity for org role Viewer",
|
||||||
|
renderKey: "123",
|
||||||
|
req: &authn.Request{
|
||||||
|
HTTPRequest: &http.Request{
|
||||||
|
Header: map[string][]string{"Cookie": {"renderKey=123"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedIdentity: &authn.Identity{
|
||||||
|
ID: "0",
|
||||||
|
Type: claims.TypeAnonymous,
|
||||||
|
OrgID: 1,
|
||||||
|
OrgRoles: map[int64]org.RoleType{1: org.RoleViewer},
|
||||||
|
AuthenticatedBy: login.RenderModule,
|
||||||
|
ClientParams: authn.ClientParams{SyncPermissions: true},
|
||||||
|
},
|
||||||
|
expectedRenderUsr: &rendering.RenderUser{
|
||||||
|
OrgID: 1,
|
||||||
|
UserID: 0,
|
||||||
|
OrgRole: "Viewer",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "expect valid render key to return render user identity for org role Admin",
|
||||||
renderKey: "123",
|
renderKey: "123",
|
||||||
req: &authn.Request{
|
req: &authn.Request{
|
||||||
HTTPRequest: &http.Request{
|
HTTPRequest: &http.Request{
|
||||||
@ -40,14 +62,14 @@ func TestRender_Authenticate(t *testing.T) {
|
|||||||
ID: "0",
|
ID: "0",
|
||||||
Type: claims.TypeRenderService,
|
Type: claims.TypeRenderService,
|
||||||
OrgID: 1,
|
OrgID: 1,
|
||||||
OrgRoles: map[int64]org.RoleType{1: org.RoleViewer},
|
OrgRoles: map[int64]org.RoleType{1: org.RoleAdmin},
|
||||||
AuthenticatedBy: login.RenderModule,
|
AuthenticatedBy: login.RenderModule,
|
||||||
ClientParams: authn.ClientParams{SyncPermissions: true},
|
ClientParams: authn.ClientParams{SyncPermissions: true},
|
||||||
},
|
},
|
||||||
expectedRenderUsr: &rendering.RenderUser{
|
expectedRenderUsr: &rendering.RenderUser{
|
||||||
OrgID: 1,
|
OrgID: 1,
|
||||||
UserID: 0,
|
UserID: 0,
|
||||||
OrgRole: "Viewer",
|
OrgRole: "Admin",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -98,7 +98,7 @@ func (s *Service) Check(ctx context.Context, req *authzv1.CheckRequest) (*authzv
|
|||||||
}
|
}
|
||||||
ctx = request.WithNamespace(ctx, req.GetNamespace())
|
ctx = request.WithNamespace(ctx, req.GetNamespace())
|
||||||
|
|
||||||
permissions, err := s.getUserPermissions(ctx, checkReq.Namespace, checkReq.IdentityType, checkReq.UserUID, checkReq.Action)
|
permissions, err := s.getIdentityPermissions(ctx, checkReq.Namespace, checkReq.IdentityType, checkReq.UserUID, checkReq.Action)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctxLogger.Error("could not get user permissions", "subject", req.GetSubject(), "error", err)
|
ctxLogger.Error("could not get user permissions", "subject", req.GetSubject(), "error", err)
|
||||||
return deny, err
|
return deny, err
|
||||||
@ -124,7 +124,7 @@ func (s *Service) List(ctx context.Context, req *authzv1.ListRequest) (*authzv1.
|
|||||||
}
|
}
|
||||||
ctx = request.WithNamespace(ctx, req.GetNamespace())
|
ctx = request.WithNamespace(ctx, req.GetNamespace())
|
||||||
|
|
||||||
permissions, err := s.getUserPermissions(ctx, listReq.Namespace, listReq.IdentityType, listReq.UserUID, listReq.Action)
|
permissions, err := s.getIdentityPermissions(ctx, listReq.Namespace, listReq.IdentityType, listReq.UserUID, listReq.Action)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctxLogger.Error("could not get user permissions", "subject", req.GetSubject(), "error", err)
|
ctxLogger.Error("could not get user permissions", "subject", req.GetSubject(), "error", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -226,8 +226,8 @@ func (s *Service) validateSubject(ctx context.Context, subject string) (string,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
// Permission check currently only checks user, anonymous user and service account permissions
|
// Permission check currently only checks user, anonymous user, service account and renderer permissions
|
||||||
if !(identityType == claims.TypeUser || identityType == claims.TypeServiceAccount || identityType == claims.TypeAnonymous) {
|
if !(identityType == claims.TypeUser || identityType == claims.TypeServiceAccount || identityType == claims.TypeAnonymous || identityType == claims.TypeRenderService) {
|
||||||
ctxLogger.Error("unsupported identity type", "type", identityType)
|
ctxLogger.Error("unsupported identity type", "type", identityType)
|
||||||
return "", "", status.Error(codes.PermissionDenied, "unsupported identity type")
|
return "", "", status.Error(codes.PermissionDenied, "unsupported identity type")
|
||||||
}
|
}
|
||||||
@ -252,8 +252,8 @@ func (s *Service) validateAction(ctx context.Context, group, resource, verb stri
|
|||||||
return action, nil
|
return action, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) getUserPermissions(ctx context.Context, ns claims.NamespaceInfo, idType claims.IdentityType, userID, action string) (map[string]bool, error) {
|
func (s *Service) getIdentityPermissions(ctx context.Context, ns claims.NamespaceInfo, idType claims.IdentityType, userID, action string) (map[string]bool, error) {
|
||||||
ctx, span := s.tracer.Start(ctx, "authz_direct_db.service.getUserPermissions")
|
ctx, span := s.tracer.Start(ctx, "authz_direct_db.service.getIdentityPermissions")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
// When checking folder creation permissions, also check edit and admin action sets for folder, as the scoped folder create actions aren't stored in the DB separately
|
// When checking folder creation permissions, also check edit and admin action sets for folder, as the scoped folder create actions aren't stored in the DB separately
|
||||||
@ -263,9 +263,21 @@ func (s *Service) getUserPermissions(ctx context.Context, ns claims.NamespaceInf
|
|||||||
actionSets = append(actionSets, "folders:admin")
|
actionSets = append(actionSets, "folders:admin")
|
||||||
}
|
}
|
||||||
|
|
||||||
if idType == claims.TypeAnonymous {
|
switch idType {
|
||||||
|
case claims.TypeAnonymous:
|
||||||
return s.getAnonymousPermissions(ctx, ns, action, actionSets)
|
return s.getAnonymousPermissions(ctx, ns, action, actionSets)
|
||||||
|
case claims.TypeRenderService:
|
||||||
|
return s.getRendererPermissions(ctx, action)
|
||||||
|
case claims.TypeUser, claims.TypeServiceAccount:
|
||||||
|
return s.getUserPermissions(ctx, ns, userID, action, actionSets)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported identity type: %s", idType)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) getUserPermissions(ctx context.Context, ns claims.NamespaceInfo, userID, action string, actionSets []string) (map[string]bool, error) {
|
||||||
|
ctx, span := s.tracer.Start(ctx, "authz_direct_db.service.getUserPermissions")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
userIdentifiers, err := s.GetUserIdentifiers(ctx, ns, userID)
|
userIdentifiers, err := s.GetUserIdentifiers(ctx, ns, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -342,6 +354,17 @@ func (s *Service) getAnonymousPermissions(ctx context.Context, ns claims.Namespa
|
|||||||
return res.(map[string]bool), nil
|
return res.(map[string]bool), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Renderer is granted permissions to read all dashboards and folders, and no other permissions
|
||||||
|
func (s *Service) getRendererPermissions(ctx context.Context, action string) (map[string]bool, error) {
|
||||||
|
_, span := s.tracer.Start(ctx, "authz_direct_db.service.getRendererPermissions")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
|
if action == "dashboards:read" || action == "folders:read" || action == "datasources:read" {
|
||||||
|
return map[string]bool{"*": true}, nil
|
||||||
|
}
|
||||||
|
return map[string]bool{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) GetUserIdentifiers(ctx context.Context, ns claims.NamespaceInfo, userUID string) (*store.UserIdentifiers, error) {
|
func (s *Service) GetUserIdentifiers(ctx context.Context, ns claims.NamespaceInfo, userUID string) (*store.UserIdentifiers, error) {
|
||||||
uidCacheKey := userIdentifierCacheKey(ns.Value, userUID)
|
uidCacheKey := userIdentifierCacheKey(ns.Value, userUID)
|
||||||
if cached, ok := s.idCache.Get(uidCacheKey); ok {
|
if cached, ok := s.idCache.Get(uidCacheKey); ok {
|
||||||
|
@ -379,7 +379,7 @@ func TestService_getUserPermissions(t *testing.T) {
|
|||||||
teamCache: localcache.New(shortCacheTTL, shortCleanupInterval),
|
teamCache: localcache.New(shortCacheTTL, shortCleanupInterval),
|
||||||
}
|
}
|
||||||
|
|
||||||
perms, err := s.getUserPermissions(ctx, ns, claims.TypeUser, userID.UID, action)
|
perms, err := s.getIdentityPermissions(ctx, ns, claims.TypeUser, userID.UID, action)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, perms, len(tc.expectedPerms))
|
require.Len(t, perms, len(tc.expectedPerms))
|
||||||
for _, perm := range tc.permissions {
|
for _, perm := range tc.permissions {
|
||||||
|
Loading…
Reference in New Issue
Block a user