grafana/pkg/services/accesscontrol/roles.go
Arve Knudsen 78596a6756
Migrate to Wire for dependency injection (#32289)
Fixes #30144

Co-authored-by: dsotirakis <sotirakis.dim@gmail.com>
Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
Co-authored-by: Ida Furjesova <ida.furjesova@grafana.com>
Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com>
Co-authored-by: Will Browne <wbrowne@users.noreply.github.com>
Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
Co-authored-by: Andrej Ocenas <mr.ocenas@gmail.com>
Co-authored-by: spinillos <selenepinillos@gmail.com>
Co-authored-by: Karl Persson <kalle.persson@grafana.com>
Co-authored-by: Leonard Gram <leo@xlson.com>
2021-08-25 15:11:22 +02:00

286 lines
6.0 KiB
Go

package accesscontrol
import (
"fmt"
"strings"
"sync"
"github.com/grafana/grafana/pkg/models"
)
type RoleRegistry interface {
// RegisterFixedRoles registers all roles declared to AccessControl
RegisterFixedRoles() error
}
// Roles definition
var (
datasourcesEditorReadRole = RoleDTO{
Version: 1,
Name: datasourcesEditorRead,
Permissions: []Permission{
{
Action: ActionDatasourcesExplore,
},
},
}
ldapAdminReadRole = RoleDTO{
Name: ldapAdminRead,
Version: 1,
Permissions: []Permission{
{
Action: ActionLDAPUsersRead,
},
{
Action: ActionLDAPStatusRead,
},
},
}
ldapAdminEditRole = RoleDTO{
Name: ldapAdminEdit,
Version: 2,
Permissions: ConcatPermissions(ldapAdminReadRole.Permissions, []Permission{
{
Action: ActionLDAPUsersSync,
},
{
Action: ActionLDAPConfigReload,
},
}),
}
serverAdminReadRole = RoleDTO{
Version: 1,
Name: serverAdminRead,
Permissions: []Permission{
{
Action: ActionServerStatsRead,
},
},
}
settingsAdminReadRole = RoleDTO{
Version: 2,
Name: settingsAdminRead,
Permissions: []Permission{
{
Action: ActionSettingsRead,
Scope: ScopeSettingsAll,
},
},
}
usersOrgReadRole = RoleDTO{
Name: usersOrgRead,
Version: 1,
Permissions: []Permission{
{
Action: ActionOrgUsersRead,
Scope: ScopeUsersAll,
},
},
}
usersOrgEditRole = RoleDTO{
Name: usersOrgEdit,
Version: 1,
Permissions: ConcatPermissions(usersOrgReadRole.Permissions, []Permission{
{
Action: ActionOrgUsersAdd,
Scope: ScopeUsersAll,
},
{
Action: ActionOrgUsersRoleUpdate,
Scope: ScopeUsersAll,
},
{
Action: ActionOrgUsersRemove,
Scope: ScopeUsersAll,
},
}),
}
usersAdminReadRole = RoleDTO{
Name: usersAdminRead,
Version: 1,
Permissions: []Permission{
{
Action: ActionUsersRead,
Scope: ScopeGlobalUsersAll,
},
{
Action: ActionUsersTeamRead,
Scope: ScopeGlobalUsersAll,
},
{
Action: ActionUsersAuthTokenList,
Scope: ScopeGlobalUsersAll,
},
{
Action: ActionUsersQuotasList,
Scope: ScopeGlobalUsersAll,
},
},
}
usersAdminEditRole = RoleDTO{
Name: usersAdminEdit,
Version: 1,
Permissions: ConcatPermissions(usersAdminReadRole.Permissions, []Permission{
{
Action: ActionUsersPasswordUpdate,
Scope: ScopeGlobalUsersAll,
},
{
Action: ActionUsersCreate,
},
{
Action: ActionUsersWrite,
Scope: ScopeGlobalUsersAll,
},
{
Action: ActionUsersDelete,
Scope: ScopeGlobalUsersAll,
},
{
Action: ActionUsersEnable,
Scope: ScopeGlobalUsersAll,
},
{
Action: ActionUsersDisable,
Scope: ScopeGlobalUsersAll,
},
{
Action: ActionUsersPermissionsUpdate,
Scope: ScopeGlobalUsersAll,
},
{
Action: ActionUsersLogout,
Scope: ScopeGlobalUsersAll,
},
{
Action: ActionUsersAuthTokenUpdate,
Scope: ScopeGlobalUsersAll,
},
{
Action: ActionUsersQuotasUpdate,
Scope: ScopeGlobalUsersAll,
},
}),
}
)
// Role names definitions
const (
datasourcesEditorRead = "fixed:datasources:editor:read"
serverAdminRead = "fixed:server:admin:read"
settingsAdminRead = "fixed:settings:admin:read"
usersAdminEdit = "fixed:users:admin:edit"
usersAdminRead = "fixed:users:admin:read"
usersOrgEdit = "fixed:users:org:edit"
usersOrgRead = "fixed:users:org:read"
ldapAdminEdit = "fixed:ldap:admin:edit"
ldapAdminRead = "fixed:ldap:admin:read"
)
var (
// FixedRoles provides a map of permission sets/roles which can be
// assigned to a set of users. When adding a new resource protected by
// Grafana access control the default permissions should be added to a
// new fixed role in this set so that users can access the new
// resource. FixedRoleGrants lists which built-in roles are
// assigned which fixed roles in this list.
FixedRoles = map[string]RoleDTO{
datasourcesEditorRead: datasourcesEditorReadRole,
usersAdminEdit: usersAdminEditRole,
usersAdminRead: usersAdminReadRole,
usersOrgEdit: usersOrgEditRole,
usersOrgRead: usersOrgReadRole,
ldapAdminEdit: ldapAdminEditRole,
ldapAdminRead: ldapAdminReadRole,
serverAdminRead: serverAdminReadRole,
settingsAdminRead: settingsAdminReadRole,
}
// FixedRoleGrants specifies which built-in roles are assigned
// to which set of FixedRoles by default. Alphabetically sorted.
FixedRoleGrants = map[string][]string{
RoleGrafanaAdmin: {
ldapAdminEdit,
ldapAdminRead,
serverAdminRead,
settingsAdminRead,
usersAdminEdit,
usersAdminRead,
usersOrgEdit,
usersOrgRead,
},
string(models.ROLE_ADMIN): {
usersOrgEdit,
usersOrgRead,
},
string(models.ROLE_EDITOR): {
datasourcesEditorRead,
},
}
)
func ConcatPermissions(permissions ...[]Permission) []Permission {
if permissions == nil {
return nil
}
perms := make([]Permission, 0)
for _, p := range permissions {
pCopy := make([]Permission, 0, len(p))
copy(pCopy, p)
perms = append(perms, p...)
}
return perms
}
// ValidateFixedRole errors when a fixed role does not match expected pattern
func ValidateFixedRole(role RoleDTO) error {
if !strings.HasPrefix(role.Name, FixedRolePrefix) {
return ErrFixedRolePrefixMissing
}
return nil
}
// ValidateBuiltInRoles errors when a built-in role does not match expected pattern
func ValidateBuiltInRoles(builtInRoles []string) error {
for _, br := range builtInRoles {
if !models.RoleType(br).IsValid() && br != RoleGrafanaAdmin {
return fmt.Errorf("'%s' %w", br, ErrInvalidBuiltinRole)
}
}
return nil
}
type RegistrationList struct {
mx sync.RWMutex
registrations []RoleRegistration
}
func (m *RegistrationList) Append(regs ...RoleRegistration) {
m.mx.Lock()
defer m.mx.Unlock()
m.registrations = append(m.registrations, regs...)
}
func (m *RegistrationList) Range(f func(registration RoleRegistration) bool) {
m.mx.RLock()
defer m.mx.RUnlock()
for _, registration := range m.registrations {
if ok := f(registration); !ok {
return
}
}
}