mirror of
https://github.com/grafana/grafana.git
synced 2024-11-26 19:00:54 -06:00
bf49c20050
* RBAC: Add an endpoint to see all user permissions Co-authored-by: Joey Orlando <joey.orlando@grafana.com> * Fix mock * Add feature flag * Fix merging * Return normal permissions instead of simplified ones * Fix test * Fix tests * Fix tests * Create benchtests * Split function to get basic roles * Comments * Reorg * Add two more tests to the bench * bench comment * Re-ran the test * Rename GetUsersPermissions to SearchUsersPermissions and prepare search options * Remove from model unused struct * Start adding option to get permissions by Action+Scope * Wrong import * Action and Scope * slightly tweak users permissions actionPrefix query param validation logic * Fix xor check * Lint * Account for suggeston Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Add search * Remove comment on global scope * use union all and update test to make it run on all dbs * Fix MySQL needs a space * Account for suggestion. Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> Co-authored-by: Joey Orlando <joey.orlando@grafana.com> Co-authored-by: Joey Orlando <joseph.t.orlando@gmail.com> Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com>
315 lines
7.9 KiB
Go
315 lines
7.9 KiB
Go
package accesscontrol
|
||
|
||
import (
|
||
"fmt"
|
||
"strings"
|
||
"sync"
|
||
|
||
"github.com/grafana/grafana/pkg/services/org"
|
||
)
|
||
|
||
// Roles definition
|
||
var (
|
||
ldapReaderRole = RoleDTO{
|
||
Name: "fixed:ldap:reader",
|
||
DisplayName: "LDAP reader",
|
||
Description: "Read LDAP configuration and status.",
|
||
Group: "LDAP",
|
||
Permissions: []Permission{
|
||
{
|
||
Action: ActionLDAPUsersRead,
|
||
},
|
||
{
|
||
Action: ActionLDAPStatusRead,
|
||
},
|
||
},
|
||
}
|
||
|
||
ldapWriterRole = RoleDTO{
|
||
Name: "fixed:ldap:writer",
|
||
DisplayName: "LDAP writer",
|
||
Description: "Read and update LDAP configuration and read LDAP status.",
|
||
Group: "LDAP",
|
||
Permissions: ConcatPermissions(ldapReaderRole.Permissions, []Permission{
|
||
{
|
||
Action: ActionLDAPUsersSync,
|
||
},
|
||
{
|
||
Action: ActionLDAPConfigReload,
|
||
},
|
||
}),
|
||
}
|
||
|
||
orgUsersWriterRole = RoleDTO{
|
||
Name: "fixed:org.users:writer",
|
||
DisplayName: "Organization user writer",
|
||
Description: "Within a single organization, add a user, invite a user, read information about a user and their role, remove a user from that organization, or change the role of a user.",
|
||
Group: "User administration (organizational)",
|
||
Permissions: ConcatPermissions(orgUsersReaderRole.Permissions, []Permission{
|
||
{
|
||
Action: ActionOrgUsersAdd,
|
||
Scope: ScopeUsersAll,
|
||
},
|
||
{
|
||
Action: ActionOrgUsersWrite,
|
||
Scope: ScopeUsersAll,
|
||
},
|
||
{
|
||
Action: ActionOrgUsersRemove,
|
||
Scope: ScopeUsersAll,
|
||
},
|
||
}),
|
||
}
|
||
|
||
orgUsersReaderRole = RoleDTO{
|
||
Name: "fixed:org.users:reader",
|
||
DisplayName: "Organization user reader",
|
||
Description: "Read users within a single organization.",
|
||
Group: "User administration (organizational)",
|
||
Permissions: []Permission{
|
||
{
|
||
Action: ActionOrgUsersRead,
|
||
Scope: ScopeUsersAll,
|
||
},
|
||
{
|
||
Action: ActionUsersPermissionsRead,
|
||
Scope: ScopeUsersAll,
|
||
},
|
||
},
|
||
}
|
||
|
||
SettingsReaderRole = RoleDTO{
|
||
Name: "fixed:settings:reader",
|
||
DisplayName: "Setting reader",
|
||
Description: "Read Grafana instance settings.",
|
||
Group: "Settings",
|
||
Permissions: []Permission{
|
||
{
|
||
Action: ActionSettingsRead,
|
||
Scope: ScopeSettingsAll,
|
||
},
|
||
},
|
||
}
|
||
|
||
statsReaderRole = RoleDTO{
|
||
Name: "fixed:stats:reader",
|
||
DisplayName: "Statistics reader",
|
||
Description: "Read Grafana instance statistics.",
|
||
Group: "Statistics",
|
||
Permissions: []Permission{
|
||
{
|
||
Action: ActionServerStatsRead,
|
||
},
|
||
},
|
||
}
|
||
|
||
usersReaderRole = RoleDTO{
|
||
Name: "fixed:users:reader",
|
||
DisplayName: "User reader",
|
||
Description: "Read all users and their information, such as team memberships, authentication tokens, and quotas.",
|
||
Group: "User administration (global)",
|
||
Permissions: []Permission{
|
||
{
|
||
Action: ActionUsersRead,
|
||
Scope: ScopeGlobalUsersAll,
|
||
},
|
||
{
|
||
Action: ActionUsersAuthTokenList,
|
||
Scope: ScopeGlobalUsersAll,
|
||
},
|
||
{
|
||
Action: ActionUsersQuotasList,
|
||
Scope: ScopeGlobalUsersAll,
|
||
},
|
||
},
|
||
}
|
||
|
||
usersWriterRole = RoleDTO{
|
||
Name: "fixed:users:writer",
|
||
DisplayName: "User writer",
|
||
Description: "Read and update all attributes and settings for all users in Grafana: update user information, read user information, create or enable or disable a user, make a user a Grafana administrator, sign out a user, update a user’s authentication token, or update quotas for all users.",
|
||
Group: "User administration (global)",
|
||
Permissions: ConcatPermissions(usersReaderRole.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,
|
||
},
|
||
}),
|
||
}
|
||
)
|
||
|
||
// Declare OSS roles to the accesscontrol service
|
||
func DeclareFixedRoles(service Service) error {
|
||
ldapReader := RoleRegistration{
|
||
Role: ldapReaderRole,
|
||
Grants: []string{RoleGrafanaAdmin},
|
||
}
|
||
ldapWriter := RoleRegistration{
|
||
Role: ldapWriterRole,
|
||
Grants: []string{RoleGrafanaAdmin},
|
||
}
|
||
orgUsersReader := RoleRegistration{
|
||
Role: orgUsersReaderRole,
|
||
Grants: []string{RoleGrafanaAdmin, string(org.RoleAdmin)},
|
||
}
|
||
orgUsersWriter := RoleRegistration{
|
||
Role: orgUsersWriterRole,
|
||
Grants: []string{RoleGrafanaAdmin, string(org.RoleAdmin)},
|
||
}
|
||
settingsReader := RoleRegistration{
|
||
Role: SettingsReaderRole,
|
||
Grants: []string{RoleGrafanaAdmin},
|
||
}
|
||
statsReader := RoleRegistration{
|
||
Role: statsReaderRole,
|
||
Grants: []string{RoleGrafanaAdmin},
|
||
}
|
||
usersReader := RoleRegistration{
|
||
Role: usersReaderRole,
|
||
Grants: []string{RoleGrafanaAdmin},
|
||
}
|
||
usersWriter := RoleRegistration{
|
||
Role: usersWriterRole,
|
||
Grants: []string{RoleGrafanaAdmin},
|
||
}
|
||
|
||
return service.DeclareFixedRoles(ldapReader, ldapWriter, orgUsersReader, orgUsersWriter,
|
||
settingsReader, statsReader, usersReader, usersWriter)
|
||
}
|
||
|
||
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 !org.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
|
||
}
|
||
}
|
||
}
|
||
|
||
func BuildBasicRoleDefinitions() map[string]*RoleDTO {
|
||
return map[string]*RoleDTO{
|
||
string(org.RoleAdmin): {
|
||
Name: BasicRolePrefix + "admin",
|
||
UID: BasicRoleUIDPrefix + "admin",
|
||
OrgID: GlobalOrgID,
|
||
Version: 1,
|
||
DisplayName: string(org.RoleAdmin),
|
||
Description: "Admin role",
|
||
Group: "Basic",
|
||
Permissions: []Permission{},
|
||
Hidden: true,
|
||
},
|
||
string(org.RoleEditor): {
|
||
Name: BasicRolePrefix + "editor",
|
||
UID: BasicRoleUIDPrefix + "editor",
|
||
OrgID: GlobalOrgID,
|
||
Version: 1,
|
||
DisplayName: string(org.RoleEditor),
|
||
Description: "Editor role",
|
||
Group: "Basic",
|
||
Permissions: []Permission{},
|
||
Hidden: true,
|
||
},
|
||
string(org.RoleViewer): {
|
||
Name: BasicRolePrefix + "viewer",
|
||
UID: BasicRoleUIDPrefix + "viewer",
|
||
OrgID: GlobalOrgID,
|
||
Version: 1,
|
||
DisplayName: string(org.RoleViewer),
|
||
Description: "Viewer role",
|
||
Group: "Basic",
|
||
Permissions: []Permission{},
|
||
Hidden: true,
|
||
},
|
||
RoleGrafanaAdmin: {
|
||
Name: BasicRolePrefix + "grafana_admin",
|
||
UID: BasicRoleUIDPrefix + "grafana_admin",
|
||
OrgID: GlobalOrgID,
|
||
Version: 1,
|
||
DisplayName: RoleGrafanaAdmin,
|
||
Description: "Grafana Admin role",
|
||
Group: "Basic",
|
||
Permissions: []Permission{},
|
||
Hidden: true,
|
||
},
|
||
}
|
||
}
|