mirror of
https://github.com/grafana/grafana.git
synced 2024-11-27 11:20:27 -06:00
3c659f1ea0
* Add accesscontrol migrations * Add ResourceStore interface and related structs * Add team/user/builtin-role * Add accesscontrol database with functions to handle managed roles and permissions * Add ResourceManager * Add GetUserPermissions * Update pkg/services/accesscontrol/accesscontrol.go Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com>
301 lines
7.4 KiB
Go
301 lines
7.4 KiB
Go
package accesscontrol
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// RoleRegistration stores a role and its assignments to built-in roles
|
|
// (Viewer, Editor, Admin, Grafana Admin)
|
|
type RoleRegistration struct {
|
|
Role RoleDTO
|
|
Grants []string
|
|
}
|
|
|
|
// Role is the model for Role in RBAC.
|
|
type Role struct {
|
|
ID int64 `json:"-" xorm:"pk autoincr 'id'"`
|
|
OrgID int64 `json:"-" xorm:"org_id"`
|
|
Version int64 `json:"version"`
|
|
UID string `xorm:"uid" json:"uid"`
|
|
Name string `json:"name"`
|
|
DisplayName string `json:"displayName"`
|
|
Description string `json:"description"`
|
|
|
|
Updated time.Time `json:"updated"`
|
|
Created time.Time `json:"created"`
|
|
}
|
|
|
|
func (r Role) Global() bool {
|
|
return r.OrgID == GlobalOrgID
|
|
}
|
|
|
|
func (r Role) IsFixed() bool {
|
|
return strings.HasPrefix(r.Name, FixedRolePrefix)
|
|
}
|
|
|
|
func (r Role) GetDisplayName() string {
|
|
if r.IsFixed() && r.DisplayName == "" {
|
|
r.DisplayName = fallbackDisplayName(r.Name)
|
|
}
|
|
return r.DisplayName
|
|
}
|
|
|
|
func (r Role) MarshalJSON() ([]byte, error) {
|
|
type Alias Role
|
|
|
|
r.DisplayName = r.GetDisplayName()
|
|
return json.Marshal(&struct {
|
|
Alias
|
|
Global bool `json:"global" xorm:"-"`
|
|
}{
|
|
Alias: (Alias)(r),
|
|
Global: r.Global(),
|
|
})
|
|
}
|
|
|
|
type RoleDTO struct {
|
|
Version int64 `json:"version"`
|
|
UID string `xorm:"uid" json:"uid"`
|
|
Name string `json:"name"`
|
|
DisplayName string `json:"displayName"`
|
|
Description string `json:"description"`
|
|
Permissions []Permission `json:"permissions,omitempty"`
|
|
|
|
ID int64 `json:"-" xorm:"pk autoincr 'id'"`
|
|
OrgID int64 `json:"-" xorm:"org_id"`
|
|
|
|
Updated time.Time `json:"updated"`
|
|
Created time.Time `json:"created"`
|
|
}
|
|
|
|
func (r RoleDTO) Role() Role {
|
|
return Role{
|
|
ID: r.ID,
|
|
OrgID: r.OrgID,
|
|
UID: r.UID,
|
|
Name: r.Name,
|
|
DisplayName: r.DisplayName,
|
|
Description: r.Description,
|
|
Updated: r.Updated,
|
|
Created: r.Created,
|
|
}
|
|
}
|
|
|
|
func (r RoleDTO) Global() bool {
|
|
return r.OrgID == GlobalOrgID
|
|
}
|
|
|
|
func (r RoleDTO) IsFixed() bool {
|
|
return strings.HasPrefix(r.Name, FixedRolePrefix)
|
|
}
|
|
|
|
func (r RoleDTO) GetDisplayName() string {
|
|
if r.IsFixed() && r.DisplayName == "" {
|
|
r.DisplayName = fallbackDisplayName(r.Name)
|
|
}
|
|
if r.DisplayName == "" {
|
|
return r.Name
|
|
}
|
|
return r.DisplayName
|
|
}
|
|
|
|
func (r RoleDTO) MarshalJSON() ([]byte, error) {
|
|
type Alias RoleDTO
|
|
|
|
r.DisplayName = r.GetDisplayName()
|
|
return json.Marshal(&struct {
|
|
Alias
|
|
Global bool `json:"global" xorm:"-"`
|
|
}{
|
|
Alias: (Alias)(r),
|
|
Global: r.Global(),
|
|
})
|
|
}
|
|
|
|
// fallbackDisplayName provides a fallback name for role
|
|
// that can be displayed in the ui for better readability
|
|
// example: currently this would give:
|
|
// fixed:datasources:name -> datasources name
|
|
// datasources:admin -> datasources admin
|
|
func fallbackDisplayName(rName string) string {
|
|
// removing prefix for fixed roles
|
|
rNameWithoutPrefix := strings.Replace(rName, FixedRolePrefix, "", 1)
|
|
return strings.TrimSpace(strings.Replace(rNameWithoutPrefix, ":", " ", -1))
|
|
}
|
|
|
|
type TeamRole struct {
|
|
ID int64 `json:"id" xorm:"pk autoincr 'id'"`
|
|
OrgID int64 `json:"orgId" xorm:"org_id"`
|
|
RoleID int64 `json:"roleId" xorm:"role_id"`
|
|
TeamID int64 `json:"teamId" xorm:"team_id"`
|
|
|
|
Created time.Time
|
|
}
|
|
|
|
type UserRole struct {
|
|
ID int64 `json:"id" xorm:"pk autoincr 'id'"`
|
|
OrgID int64 `json:"orgId" xorm:"org_id"`
|
|
RoleID int64 `json:"roleId" xorm:"role_id"`
|
|
UserID int64 `json:"userId" xorm:"user_id"`
|
|
|
|
Created time.Time
|
|
}
|
|
|
|
type BuiltinRole struct {
|
|
ID int64 `json:"id" xorm:"pk autoincr 'id'"`
|
|
RoleID int64 `json:"roleId" xorm:"role_id"`
|
|
OrgID int64 `json:"orgId" xorm:"org_id"`
|
|
Role string
|
|
|
|
Updated time.Time
|
|
Created time.Time
|
|
}
|
|
|
|
// Permission is the model for access control permissions.
|
|
type Permission struct {
|
|
ID int64 `json:"-" xorm:"pk autoincr 'id'"`
|
|
RoleID int64 `json:"-" xorm:"role_id"`
|
|
Action string `json:"action"`
|
|
Scope string `json:"scope"`
|
|
|
|
Updated time.Time `json:"updated"`
|
|
Created time.Time `json:"created"`
|
|
}
|
|
|
|
func (p Permission) OSSPermission() Permission {
|
|
return Permission{
|
|
Action: p.Action,
|
|
Scope: p.Scope,
|
|
}
|
|
}
|
|
|
|
type GetUserPermissionsQuery struct {
|
|
OrgID int64 `json:"-"`
|
|
UserID int64 `json:"userId"`
|
|
Roles []string
|
|
}
|
|
|
|
// ScopeParams holds the parameters used to fill in scope templates
|
|
type ScopeParams struct {
|
|
OrgID int64
|
|
URLParams map[string]string
|
|
}
|
|
|
|
type ResourcePermission struct {
|
|
ID int64 `xorm:"id"`
|
|
ResourceID string `xorm:"resource_id"`
|
|
RoleName string
|
|
Action string
|
|
Scope string
|
|
UserId int64
|
|
UserLogin string
|
|
UserEmail string
|
|
TeamId int64
|
|
TeamEmail string
|
|
Team string
|
|
BuiltInRole string
|
|
Created time.Time
|
|
Updated time.Time
|
|
}
|
|
|
|
func (p *ResourcePermission) Managed() bool {
|
|
return strings.HasPrefix(p.RoleName, "managed:")
|
|
}
|
|
|
|
type SetResourcePermissionsCommand struct {
|
|
Actions []string
|
|
Resource string
|
|
ResourceID string
|
|
}
|
|
|
|
type RemoveResourcePermissionCommand struct {
|
|
Resource string
|
|
Actions []string
|
|
ResourceID string
|
|
PermissionID int64
|
|
}
|
|
|
|
type GetResourcesPermissionsQuery struct {
|
|
Actions []string
|
|
Resource string
|
|
ResourceIDs []string
|
|
}
|
|
|
|
const (
|
|
GlobalOrgID = 0
|
|
// Permission actions
|
|
|
|
// Users actions
|
|
ActionUsersRead = "users:read"
|
|
ActionUsersWrite = "users:write"
|
|
ActionUsersTeamRead = "users.teams:read"
|
|
// We can ignore gosec G101 since this does not contain any credentials.
|
|
// nolint:gosec
|
|
ActionUsersAuthTokenList = "users.authtoken:list"
|
|
// We can ignore gosec G101 since this does not contain any credentials.
|
|
// nolint:gosec
|
|
ActionUsersAuthTokenUpdate = "users.authtoken:update"
|
|
// We can ignore gosec G101 since this does not contain any credentials.
|
|
// nolint:gosec
|
|
ActionUsersPasswordUpdate = "users.password:update"
|
|
ActionUsersDelete = "users:delete"
|
|
ActionUsersCreate = "users:create"
|
|
ActionUsersEnable = "users:enable"
|
|
ActionUsersDisable = "users:disable"
|
|
ActionUsersPermissionsUpdate = "users.permissions:update"
|
|
ActionUsersLogout = "users:logout"
|
|
ActionUsersQuotasList = "users.quotas:list"
|
|
ActionUsersQuotasUpdate = "users.quotas:update"
|
|
|
|
// Org actions
|
|
ActionOrgUsersRead = "org.users:read"
|
|
ActionOrgUsersAdd = "org.users:add"
|
|
ActionOrgUsersRemove = "org.users:remove"
|
|
ActionOrgUsersRoleUpdate = "org.users.role:update"
|
|
|
|
// LDAP actions
|
|
ActionLDAPUsersRead = "ldap.user:read"
|
|
ActionLDAPUsersSync = "ldap.user:sync"
|
|
ActionLDAPStatusRead = "ldap.status:read"
|
|
ActionLDAPConfigReload = "ldap.config:reload"
|
|
|
|
// Server actions
|
|
ActionServerStatsRead = "server.stats:read"
|
|
|
|
// Settings actions
|
|
ActionSettingsRead = "settings:read"
|
|
|
|
// Datasources actions
|
|
ActionDatasourcesExplore = "datasources:explore"
|
|
|
|
// Plugin actions
|
|
ActionPluginsManage = "plugins:manage"
|
|
|
|
// Global Scopes
|
|
ScopeGlobalUsersAll = "global:users:*"
|
|
|
|
// Users scope
|
|
ScopeUsersAll = "users:*"
|
|
|
|
// Settings scope
|
|
ScopeSettingsAll = "settings:*"
|
|
|
|
// Licensing related actions
|
|
ActionLicensingRead = "licensing:read"
|
|
ActionLicensingUpdate = "licensing:update"
|
|
ActionLicensingDelete = "licensing:delete"
|
|
ActionLicensingReportsRead = "licensing.reports:read"
|
|
)
|
|
|
|
const RoleGrafanaAdmin = "Grafana Admin"
|
|
|
|
const FixedRolePrefix = "fixed:"
|
|
|
|
// LicensingPageReaderAccess defines permissions that grant access to the licensing and stats page
|
|
var LicensingPageReaderAccess = EvalAny(
|
|
EvalPermission(ActionLicensingRead),
|
|
EvalPermission(ActionServerStatsRead),
|
|
)
|