1
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

261 lines
7.2 KiB

package resourcepermissions
import (
"context"
"fmt"
"sort"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
)
func New(options Options, router routing.RouteRegister, ac accesscontrol.AccessControl, store accesscontrol.ResourcePermissionsStore) (*Service, error) {
var permissions []string
validActions := make(map[string]struct{})
for permission, actions := range options.PermissionsToActions {
permissions = append(permissions, permission)
for _, a := range actions {
validActions[a] = struct{}{}
}
}
// Sort all permissions based on action length. Will be used when mapping between actions to permissions
sort.Slice(permissions, func(i, j int) bool {
return len(options.PermissionsToActions[permissions[i]]) > len(options.PermissionsToActions[permissions[j]])
})
actions := make([]string, 0, len(validActions))
for action := range validActions {
actions = append(actions, action)
}
s := &Service{
ac: ac,
store: store,
options: options,
permissions: permissions,
actions: actions,
validActions: validActions,
}
s.api = newApi(ac, router, s)
if err := s.declareFixedRoles(); err != nil {
return nil, err
}
s.api.registerEndpoints()
return s, nil
}
// Service is used to create access control sub system including api / and service for managed resource permission
type Service struct {
ac accesscontrol.AccessControl
store accesscontrol.ResourcePermissionsStore
api *api
options Options
permissions []string
actions []string
validActions map[string]struct{}
}
func (s *Service) GetPermissions(ctx context.Context, orgID int64, resourceID string) ([]accesscontrol.ResourcePermission, error) {
return s.store.GetResourcesPermissions(ctx, orgID, accesscontrol.GetResourcesPermissionsQuery{
Actions: s.actions,
Resource: s.options.Resource,
ResourceIDs: []string{resourceID},
OnlyManaged: s.options.OnlyManaged,
})
}
func (s *Service) SetUserPermission(ctx context.Context, orgID, userID int64, resourceID string, actions []string) (*accesscontrol.ResourcePermission, error) {
if !s.options.Assignments.Users {
return nil, ErrInvalidAssignment
}
if !s.validateActions(actions) {
return nil, ErrInvalidActions
}
if err := s.validateResource(ctx, orgID, resourceID); err != nil {
return nil, err
}
if err := s.validateUser(ctx, orgID, userID); err != nil {
return nil, err
}
permission, err := s.store.SetUserResourcePermission(ctx, orgID, userID, accesscontrol.SetResourcePermissionCommand{
Actions: actions,
ResourceID: resourceID,
Resource: s.options.Resource,
})
if err != nil {
return nil, err
}
if s.options.OnSetUser != nil {
if err := s.options.OnSetUser(ctx, orgID, userID, resourceID, s.MapActions(*permission)); err != nil {
return nil, err
}
}
return permission, nil
}
func (s *Service) SetTeamPermission(ctx context.Context, orgID, teamID int64, resourceID string, actions []string) (*accesscontrol.ResourcePermission, error) {
if !s.options.Assignments.Teams {
return nil, ErrInvalidAssignment
}
if !s.validateActions(actions) {
return nil, ErrInvalidActions
}
if err := s.validateTeam(ctx, orgID, teamID); err != nil {
return nil, err
}
if err := s.validateResource(ctx, orgID, resourceID); err != nil {
return nil, err
}
permission, err := s.store.SetTeamResourcePermission(ctx, orgID, teamID, accesscontrol.SetResourcePermissionCommand{
Actions: actions,
ResourceID: resourceID,
Resource: s.options.Resource,
})
if err != nil {
return nil, err
}
if s.options.OnSetTeam != nil {
if err := s.options.OnSetTeam(ctx, orgID, teamID, resourceID, s.MapActions(*permission)); err != nil {
return nil, err
}
}
return permission, nil
}
func (s *Service) SetBuiltInRolePermission(ctx context.Context, orgID int64, builtInRole string, resourceID string, actions []string) (*accesscontrol.ResourcePermission, error) {
if !s.options.Assignments.BuiltInRoles {
return nil, ErrInvalidAssignment
}
if !s.validateActions(actions) {
return nil, ErrInvalidActions
}
if err := s.validateBuiltinRole(ctx, builtInRole); err != nil {
return nil, err
}
if err := s.validateResource(ctx, orgID, resourceID); err != nil {
return nil, err
}
permission, err := s.store.SetBuiltInResourcePermission(ctx, orgID, builtInRole, accesscontrol.SetResourcePermissionCommand{
Actions: actions,
ResourceID: resourceID,
Resource: s.options.Resource,
})
if err != nil {
return nil, err
}
if s.options.OnSetBuiltInRole != nil {
if err := s.options.OnSetBuiltInRole(ctx, orgID, builtInRole, resourceID, s.MapActions(*permission)); err != nil {
return nil, err
}
}
return permission, nil
}
func (s *Service) MapActions(permission accesscontrol.ResourcePermission) string {
for _, p := range s.permissions {
if permission.Contains(s.options.PermissionsToActions[p]) {
return p
}
}
return ""
}
func (s *Service) MapPermission(permission string) []string {
for k, v := range s.options.PermissionsToActions {
if permission == k {
return v
}
}
return []string{}
}
func (s *Service) validateResource(ctx context.Context, orgID int64, resourceID string) error {
if s.options.ResourceValidator != nil {
return s.options.ResourceValidator(ctx, orgID, resourceID)
}
return nil
}
func (s *Service) validateActions(actions []string) bool {
for _, a := range actions {
if _, ok := s.validActions[a]; !ok {
return false
}
}
return true
}
func (s *Service) validateUser(ctx context.Context, orgID, userID int64) error {
if err := sqlstore.GetSignedInUser(ctx, &models.GetSignedInUserQuery{OrgId: orgID, UserId: userID}); err != nil {
return err
}
return nil
}
func (s *Service) validateTeam(ctx context.Context, orgID, teamID int64) error {
if err := sqlstore.GetTeamById(ctx, &models.GetTeamByIdQuery{OrgId: orgID, Id: teamID}); err != nil {
return err
}
return nil
}
func (s *Service) validateBuiltinRole(ctx context.Context, builtinRole string) error {
if err := accesscontrol.ValidateBuiltInRoles([]string{builtinRole}); err != nil {
return err
}
return nil
}
func (s *Service) declareFixedRoles() error {
scopeAll := accesscontrol.Scope(s.options.Resource, "*")
readerRole := accesscontrol.RoleRegistration{
Role: accesscontrol.RoleDTO{
Version: 5,
Name: fmt.Sprintf("fixed:%s.permissions:reader", s.options.Resource),
DisplayName: s.options.ReaderRoleName,
Group: s.options.RoleGroup,
Permissions: []accesscontrol.Permission{
{Action: fmt.Sprintf("%s.permissions:read", s.options.Resource), Scope: scopeAll},
},
},
Grants: []string{string(models.ROLE_ADMIN)},
}
writerRole := accesscontrol.RoleRegistration{
Role: accesscontrol.RoleDTO{
Version: 5,
Name: fmt.Sprintf("fixed:%s.permissions:writer", s.options.Resource),
DisplayName: s.options.WriterRoleName,
Group: s.options.RoleGroup,
Permissions: accesscontrol.ConcatPermissions(readerRole.Role.Permissions, []accesscontrol.Permission{
{Action: fmt.Sprintf("%s.permissions:write", s.options.Resource), Scope: scopeAll},
}),
},
Grants: []string{string(models.ROLE_ADMIN)},
}
return s.ac.DeclareFixedRoles(readerRole, writerRole)
}