grafana/pkg/services/accesscontrol/models.go

580 lines
17 KiB
Go
Raw Normal View History

package accesscontrol
import (
"encoding/json"
"errors"
"fmt"
"strings"
"time"
"github.com/grafana/grafana/pkg/infra/slugify"
"github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/util/errutil"
)
const (
CacheHit = "hit"
CacheMiss = "miss"
)
var (
ErrInternal = errutil.Internal("accesscontrol.internal")
CacheUsageStatuses = []string{CacheHit, CacheMiss}
)
// 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,omitempty"`
Group string `xorm:"group_name" json:"group"`
Description string `json:"description"`
Hidden bool `json:"hidden"`
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) IsBasic() bool {
return strings.HasPrefix(r.Name, BasicRolePrefix) || strings.HasPrefix(r.UID, BasicRoleUIDPrefix)
}
func (r Role) MarshalJSON() ([]byte, error) {
type Alias Role
return json.Marshal(&struct {
Alias
Global bool `json:"global" xorm:"-"`
}{
Alias: (Alias)(r),
Global: r.Global(),
})
}
// swagger:ignore
type RoleDTO struct {
Version int64 `json:"version"`
UID string `xorm:"uid" json:"uid"`
Name string `json:"name"`
DisplayName string `json:"displayName,omitempty"`
Description string `json:"description"`
Group string `xorm:"group_name" json:"group"`
Permissions []Permission `json:"permissions,omitempty"`
Delegatable *bool `json:"delegatable,omitempty"`
Hidden bool `json:"hidden,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) LogID() string {
var org string
if r.Global() {
org = "Global"
} else {
org = fmt.Sprintf("OrgId:%v", r.OrgID)
}
if r.UID != "" {
return fmt.Sprintf("[%s RoleUID:%v]", org, r.UID)
}
return fmt.Sprintf("[%s Role:%v]", org, r.Name)
}
func (r *RoleDTO) Role() Role {
return Role{
ID: r.ID,
OrgID: r.OrgID,
UID: r.UID,
Version: r.Version,
Name: r.Name,
DisplayName: r.DisplayName,
Group: r.Group,
Description: r.Description,
Hidden: r.Hidden,
Updated: r.Updated,
Created: r.Created,
}
}
func (r *RoleDTO) Global() bool {
return r.OrgID == GlobalOrgID
}
func (r *RoleDTO) IsManaged() bool {
return strings.HasPrefix(r.Name, ManagedRolePrefix)
}
func (r *RoleDTO) IsFixed() bool {
return strings.HasPrefix(r.Name, FixedRolePrefix)
}
RBAC: Allow role registration for plugins (#57387) * Picking role registration from OnCall POC branch * Fix test * Remove include actions from this PR * Removing unused permission * Adding test to DeclarePluginRoles * Add testcase to RegisterFixed role * Additional test case * Adding tests to validate plugins roles * Add test to plugin loader * Nit. * Scuemata validation * Changing the design to decouple accesscontrol from plugin management Co-authored-by: Kalle Persson <kalle.persson@grafana.com> * Fixing tests Co-authored-by: Jguer <joao.guerreiro@grafana.com> * Add missing files Co-authored-by: Jguer <joao.guerreiro@grafana.com> * Remove feature toggle check from loader * Remove feature toggleimport * Feedback Co-Authored-By: marefr <marcus.efraimsson@gmail.com> * Fix test' * Make plugins.RoleRegistry interface typed * Remove comment question * No need for json tags anymore * Nit. log * Adding the schema validation * Remove group to take plugin Name instead * Revert sqlstore -> db * Nit. * Nit. on tests Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Update pkg/services/accesscontrol/plugins.go Co-authored-by: Ieva <ieva.vasiljeva@grafana.com> * Log message Co-Authored-By: marefr <marcus.efraimsson@gmail.com> * Log message Co-Authored-By: marefr <marcus.efraimsson@gmail.com> * Remove unecessary method. Update test name. Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Fix linting * Update cue descriptions * Fix test Co-authored-by: Kalle Persson <kalle.persson@grafana.com> Co-authored-by: Jguer <joao.guerreiro@grafana.com> Co-authored-by: marefr <marcus.efraimsson@gmail.com> Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com>
2022-11-07 04:30:45 -06:00
func (r *RoleDTO) IsPlugin() bool {
return strings.HasPrefix(r.Name, PluginRolePrefix)
}
func (r *RoleDTO) IsBasic() bool {
return strings.HasPrefix(r.Name, BasicRolePrefix) || strings.HasPrefix(r.UID, BasicRoleUIDPrefix)
}
func (r *RoleDTO) IsExternalService() bool {
return strings.HasPrefix(r.Name, ExternalServiceRolePrefix) || strings.HasPrefix(r.UID, ExternalServiceRoleUIDPrefix)
}
// swagger:model RoleDTO
type RoleDTOStatic struct {
RoleDTO
Global bool `json:"global" xorm:"-"`
}
func (r RoleDTO) MarshalJSON() ([]byte, error) {
type Alias RoleDTO
return json.Marshal(&struct {
Alias
Global bool `json:"global" xorm:"-"`
}{
Alias: (Alias)(r),
Global: r.Global(),
})
}
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"`
Kind string `json:"-"`
Attribute string `json:"-"`
Identifier string `json:"-"`
Updated time.Time `json:"updated"`
Created time.Time `json:"created"`
}
func (p Permission) OSSPermission() Permission {
return Permission{
Action: p.Action,
Scope: p.Scope,
}
}
// SplitScope returns kind, attribute and Identifier
func (p Permission) SplitScope() (string, string, string) {
if p.Scope == "" {
return "", "", ""
}
fragments := strings.Split(p.Scope, ":")
switch l := len(fragments); l {
case 1: // Splitting a wildcard scope "*" -> kind: "*"; attribute: "*"; identifier: "*"
return fragments[0], fragments[0], fragments[0]
case 2: // Splitting a wildcard scope with specified kind "dashboards:*" -> kind: "dashboards"; attribute: "*"; identifier: "*"
return fragments[0], fragments[1], fragments[1]
default: // Splitting a scope with all fields specified "dashboards:uid:my_dash" -> kind: "dashboards"; attribute: "uid"; identifier: "my_dash"
return fragments[0], fragments[1], strings.Join(fragments[2:], ":")
}
}
type GetUserPermissionsQuery struct {
OrgID int64
UserID int64
Roles []string
TeamIDs []int64
RolePrefixes []string
}
// ResourcePermission is structure that holds all actions that either a team / user / builtin-role
// can perform against specific resource.
type ResourcePermission struct {
ID int64
RoleName string
Actions []string
Scope string
UserId int64
UserLogin string
UserEmail string
TeamId int64
TeamEmail string
Team string
BuiltInRole string
IsManaged bool
IsInherited bool
IsServiceAccount bool
Created time.Time
Updated time.Time
}
func (p *ResourcePermission) Contains(targetActions []string) bool {
if len(p.Actions) < len(targetActions) {
return false
}
var contain = func(arr []string, s string) bool {
for _, item := range arr {
if item == s {
return true
}
}
return false
}
for _, a := range targetActions {
if !contain(p.Actions, a) {
return false
}
}
return true
}
type SetResourcePermissionCommand struct {
UserID int64 `json:"userId,omitempty"`
TeamID int64 `json:"teamId,omitempty"`
BuiltinRole string `json:"builtInRole,omitempty"`
Permission string `json:"permission"`
}
type SaveExternalServiceRoleCommand struct {
AssignmentOrgID int64
ExternalServiceID string
ServiceAccountID int64
Permissions []Permission
}
func (cmd *SaveExternalServiceRoleCommand) Validate() error {
if cmd.ExternalServiceID == "" {
return errors.New("external service id not specified")
}
// slugify the external service id ID for the role to have correct name and uid
cmd.ExternalServiceID = slugify.Slugify(cmd.ExternalServiceID)
// Check and deduplicate permissions
if cmd.Permissions == nil || len(cmd.Permissions) == 0 {
return errors.New("no permissions provided")
}
dedupMap := map[Permission]bool{}
dedup := make([]Permission, 0, len(cmd.Permissions))
for i := range cmd.Permissions {
if len(cmd.Permissions[i].Action) == 0 {
return fmt.Errorf("external service %v requests a permission with no Action", cmd.ExternalServiceID)
}
if dedupMap[cmd.Permissions[i]] {
continue
}
dedupMap[cmd.Permissions[i]] = true
dedup = append(dedup, cmd.Permissions[i])
}
cmd.Permissions = dedup
if cmd.ServiceAccountID <= 0 {
return fmt.Errorf("invalid service account id %d", cmd.ServiceAccountID)
}
return nil
}
const (
GlobalOrgID = 0
NoOrgID = int64(-1)
GeneralFolderUID = "general"
RoleGrafanaAdmin = "Grafana Admin"
// Permission actions
ActionAPIKeyRead = "apikeys:read"
ActionAPIKeyCreate = "apikeys:create"
ActionAPIKeyDelete = "apikeys:delete"
// Users actions
ActionUsersRead = "users:read"
ActionUsersWrite = "users:write"
AuthN: Embed an OAuth2 server for external service authentication (#68086) * Moving POC files from #64283 to a new branch Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com> * Adding missing permission definition Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com> * Force the service instantiation while client isn't merged Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com> * Merge conf with main Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com> * Leave go-sqlite3 version unchanged Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com> * tidy Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com> * User SearchUserPermissions instead of SearchUsersPermissions * Replace DummyKeyService with signingkeys.Service * Use user:id:<id> as subject * Fix introspection endpoint issue * Add X-Grafana-Org-Id to get_resources.bash script * Regenerate toggles_gen.go * Fix basic.go * Add GetExternalService tests * Add GetPublicKeyScopes tests * Add GetScopesOnUser tests * Add GetScopes tests * Add ParsePublicKeyPem tests * Add database test for GetByName * re-add comments * client tests added * Add GetExternalServicePublicKey tests * Add other test case to GetExternalServicePublicKey * client_credentials grant test * Add test to jwtbearer grant * Test Comments * Add handleKeyOptions tests * Add RSA key generation test * Add ECDSA by default to EmbeddedSigningKeysService * Clean up org id scope and audiences * Add audiences to the DB * Fix check on Audience * Fix double import * Add AC Store mock and align oauthserver tests * Fix test after rebase * Adding missing store function to mock * Fix double import * Add CODEOWNER * Fix some linting errors * errors don't need type assertion * Typo codeowners * use mockery for oauthserver store * Add feature toggle check * Fix db tests to handle the feature flag * Adding call to DeleteExternalServiceRole * Fix flaky test * Re-organize routes comments and plan futur work * Add client_id check to Extended JWT client * Clean up * Fix * Remove background service registry instantiation of the OAuth server * Comment cleanup * Remove unused client function * Update go.mod to use the latest ory/fosite commit * Remove oauth2_server related configs from defaults.ini * Add audiences to DTO * Fix flaky test * Remove registration endpoint and demo scripts. Document code * Rename packages * Remove the OAuthService vs OAuthServer confusion * fix incorrect import ext_jwt_test * Comments and order * Comment basic auth * Remove unecessary todo * Clean api * Moving ParsePublicKeyPem to utils * re ordering functions in service.go * Fix comment * comment on the redirect uri * Add RBAC actions, not only scopes * Fix tests * re-import featuremgmt in migrations * Fix wire * Fix scopes in test * Fix flaky test * Remove todo, the intersection should always return the minimal set * Remove unecessary check from intersection code * Allow env overrides on settings * remove the term app name * Remove app keyword for client instead and use Name instead of ExternalServiceName * LogID remove ExternalService ref * Use Name instead of ExternalServiceName * Imports order * Inline * Using ExternalService and ExternalServiceDTO * Remove xorm tags * comment * Rename client files * client -> external service * comments * Move test to correct package * slimmer test * cachedUser -> cachedExternalService * Fix aggregate store test * PluginAuthSession -> AuthSession * Revert the nil cehcks * Remove unecessary extra * Removing custom session * fix typo in test * Use constants for tests * Simplify HandleToken tests * Refactor the HandleTokenRequest test * test message * Review test * Prevent flacky test on client as well * go imports * Revert changes from 526e48ad4550fed7e2b753b9d0a0cc6097155f58 * AuthN: Change the External Service registration form (#68649) * AuthN: change the External Service registration form * Gen default permissions * Change demo script registration form * Remove unecessary comment * Nit. * Reduce cyclomatic complexity * Remove demo_scripts * Handle case with no service account * Comments * Group key gen * Nit. * Check the SaveExternalService test * Rename cachedUser to cachedClient in test * One more test case to database test * Comments * Remove last org scope Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com> * Update pkg/services/oauthserver/utils/utils_test.go * Update pkg/services/sqlstore/migrations/oauthserver/migrations.go Remove comment * Update pkg/setting/setting.go Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com> --------- Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com>
2023-05-25 08:38:30 -05:00
// We can ignore gosec G101 since this does not contain any credentials.
// nolint:gosec
ActionUsersAuthTokenList = "users.authtoken:read"
// We can ignore gosec G101 since this does not contain any credentials.
// nolint:gosec
ActionUsersAuthTokenUpdate = "users.authtoken:write"
// We can ignore gosec G101 since this does not contain any credentials.
// nolint:gosec
ActionUsersPasswordUpdate = "users.password:write"
ActionUsersDelete = "users:delete"
ActionUsersCreate = "users:create"
ActionUsersEnable = "users:enable"
ActionUsersDisable = "users:disable"
ActionUsersPermissionsUpdate = "users.permissions:write"
ActionUsersLogout = "users:logout"
ActionUsersQuotasList = "users.quotas:read"
ActionUsersQuotasUpdate = "users.quotas:write"
ActionUsersPermissionsRead = "users.permissions:read"
// Org actions
ActionOrgsRead = "orgs:read"
ActionOrgsPreferencesRead = "orgs.preferences:read"
ActionOrgsQuotasRead = "orgs.quotas:read"
ActionOrgsWrite = "orgs:write"
ActionOrgsPreferencesWrite = "orgs.preferences:write"
ActionOrgsQuotasWrite = "orgs.quotas:write"
ActionOrgsDelete = "orgs:delete"
ActionOrgsCreate = "orgs:create"
ActionOrgUsersRead = "org.users:read"
ActionOrgUsersAdd = "org.users:add"
ActionOrgUsersRemove = "org.users:remove"
ActionOrgUsersWrite = "org.users:write"
// 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"
ActionSettingsWrite = "settings:write"
// Datasources actions
ActionDatasourcesExplore = "datasources:explore"
// Global Scopes
ScopeGlobalUsersAll = "global.users:*"
// APIKeys scope
ScopeAPIKeysAll = "apikeys:*"
// Users scope
AuthN: Embed an OAuth2 server for external service authentication (#68086) * Moving POC files from #64283 to a new branch Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com> * Adding missing permission definition Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com> * Force the service instantiation while client isn't merged Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com> * Merge conf with main Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com> * Leave go-sqlite3 version unchanged Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com> * tidy Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com> * User SearchUserPermissions instead of SearchUsersPermissions * Replace DummyKeyService with signingkeys.Service * Use user:id:<id> as subject * Fix introspection endpoint issue * Add X-Grafana-Org-Id to get_resources.bash script * Regenerate toggles_gen.go * Fix basic.go * Add GetExternalService tests * Add GetPublicKeyScopes tests * Add GetScopesOnUser tests * Add GetScopes tests * Add ParsePublicKeyPem tests * Add database test for GetByName * re-add comments * client tests added * Add GetExternalServicePublicKey tests * Add other test case to GetExternalServicePublicKey * client_credentials grant test * Add test to jwtbearer grant * Test Comments * Add handleKeyOptions tests * Add RSA key generation test * Add ECDSA by default to EmbeddedSigningKeysService * Clean up org id scope and audiences * Add audiences to the DB * Fix check on Audience * Fix double import * Add AC Store mock and align oauthserver tests * Fix test after rebase * Adding missing store function to mock * Fix double import * Add CODEOWNER * Fix some linting errors * errors don't need type assertion * Typo codeowners * use mockery for oauthserver store * Add feature toggle check * Fix db tests to handle the feature flag * Adding call to DeleteExternalServiceRole * Fix flaky test * Re-organize routes comments and plan futur work * Add client_id check to Extended JWT client * Clean up * Fix * Remove background service registry instantiation of the OAuth server * Comment cleanup * Remove unused client function * Update go.mod to use the latest ory/fosite commit * Remove oauth2_server related configs from defaults.ini * Add audiences to DTO * Fix flaky test * Remove registration endpoint and demo scripts. Document code * Rename packages * Remove the OAuthService vs OAuthServer confusion * fix incorrect import ext_jwt_test * Comments and order * Comment basic auth * Remove unecessary todo * Clean api * Moving ParsePublicKeyPem to utils * re ordering functions in service.go * Fix comment * comment on the redirect uri * Add RBAC actions, not only scopes * Fix tests * re-import featuremgmt in migrations * Fix wire * Fix scopes in test * Fix flaky test * Remove todo, the intersection should always return the minimal set * Remove unecessary check from intersection code * Allow env overrides on settings * remove the term app name * Remove app keyword for client instead and use Name instead of ExternalServiceName * LogID remove ExternalService ref * Use Name instead of ExternalServiceName * Imports order * Inline * Using ExternalService and ExternalServiceDTO * Remove xorm tags * comment * Rename client files * client -> external service * comments * Move test to correct package * slimmer test * cachedUser -> cachedExternalService * Fix aggregate store test * PluginAuthSession -> AuthSession * Revert the nil cehcks * Remove unecessary extra * Removing custom session * fix typo in test * Use constants for tests * Simplify HandleToken tests * Refactor the HandleTokenRequest test * test message * Review test * Prevent flacky test on client as well * go imports * Revert changes from 526e48ad4550fed7e2b753b9d0a0cc6097155f58 * AuthN: Change the External Service registration form (#68649) * AuthN: change the External Service registration form * Gen default permissions * Change demo script registration form * Remove unecessary comment * Nit. * Reduce cyclomatic complexity * Remove demo_scripts * Handle case with no service account * Comments * Group key gen * Nit. * Check the SaveExternalService test * Rename cachedUser to cachedClient in test * One more test case to database test * Comments * Remove last org scope Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com> * Update pkg/services/oauthserver/utils/utils_test.go * Update pkg/services/sqlstore/migrations/oauthserver/migrations.go Remove comment * Update pkg/setting/setting.go Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com> --------- Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com>
2023-05-25 08:38:30 -05:00
ScopeUsersAll = "users:*"
ScopeUsersPrefix = "users:id:"
// Settings scope
ScopeSettingsAll = "settings:*"
ScopeSettingsSAML = "settings:auth.saml:*"
AccessControl: Implement teams resource service (#43951) * AccessControl: cover team permissions Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Add background service as a consumer to resource_services Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Define actions in roles.go Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Remove action from accesscontrol model Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * As suggested by kalle * move some changes from branch to the skeleton PR * Add background service as a consumer to resource_services Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * moving resourceservice to the main wire file pt2 * move team related actions so that they can be reused * PR feedback * fix * typo * Access Control: adding hooks for team member endpoints (#43991) * AccessControl: cover team permissions Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Add background service as a consumer to resource_services Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Define actions in roles.go Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Remove action from accesscontrol model Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * As suggested by kalle * add access control to list and add team member endpoint, and hooks for adding team members * member permission type is 0 * add ID scope for team permission checks * add more team actions, use Member for member permission name * protect team member update endpoint with FGAC permissions * update SQL functions for teams and the corresponding tests * also protect team member removal endpoint with FGAC permissions and add a hook to permission service * a few small fixes, provide team permission service to test setup * AccessControl: cover team permissions Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Add background service as a consumer to resource_services Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Define actions in roles.go Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Remove action from accesscontrol model Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * As suggested by kalle * move some changes from branch to the skeleton PR * remove resource services from wireexts * remove unneeded actions * linting fix * remove comments * feedback fixes * feedback * simplifying * remove team member within the same transaction * fix a mistake with the error * call the correct sql fction * linting * Access control: tests for team member endpoints (#44177) * tests for team member endpoints * clean up and fix the tests * fixing tests take 2 * don't import enterprise test license * don't import enterprise test license * remove unused variable Co-authored-by: gamab <gabi.mabs@gmail.com> Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com> Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com>
2022-01-26 08:48:41 -06:00
// Team related actions
ActionTeamsCreate = "teams:create"
ActionTeamsDelete = "teams:delete"
ActionTeamsRead = "teams:read"
ActionTeamsWrite = "teams:write"
ActionTeamsPermissionsRead = "teams.permissions:read"
ActionTeamsPermissionsWrite = "teams.permissions:write"
// Team related scopes
ScopeTeamsAll = "teams:*"
// Annotations related actions
ActionAnnotationsCreate = "annotations:create"
ActionAnnotationsDelete = "annotations:delete"
ActionAnnotationsRead = "annotations:read"
ActionAnnotationsWrite = "annotations:write"
// Alert scopes are divided into two groups. The internal (to Grafana) and the external ones.
// For the Grafana ones, given we have ACID control we're able to provide better granularity by defining CRUD options.
// For the external ones, we only have read and write permissions due to the lack of atomicity control of the external system.
// Alerting rules actions
ActionAlertingRuleCreate = "alert.rules:create"
ActionAlertingRuleRead = "alert.rules:read"
ActionAlertingRuleUpdate = "alert.rules:write"
ActionAlertingRuleDelete = "alert.rules:delete"
// Alerting instances (+silences) actions
ActionAlertingInstanceCreate = "alert.instances:create"
ActionAlertingInstanceUpdate = "alert.instances:write"
ActionAlertingInstanceRead = "alert.instances:read"
ActionAlertingSilencesRead = "alert.silences:read"
ActionAlertingSilencesCreate = "alert.silences:create"
ActionAlertingSilencesWrite = "alert.silences:write"
// Alerting Notification policies actions
ActionAlertingNotificationsRead = "alert.notifications:read"
ActionAlertingNotificationsWrite = "alert.notifications:write"
// Alerting notifications time interval actions
ActionAlertingNotificationsTimeIntervalsRead = "alert.notifications.time-intervals:read"
ActionAlertingNotificationsTimeIntervalsWrite = "alert.notifications.time-intervals:write"
// Alerting receiver actions
ActionAlertingReceiversList = "alert.notifications.receivers:list"
ActionAlertingReceiversRead = "alert.notifications.receivers:read"
ActionAlertingReceiversReadSecrets = "alert.notifications.receivers.secrets:read"
// External alerting rule actions. We can only narrow it down to writes or reads, as we don't control the atomicity in the external system.
ActionAlertingRuleExternalWrite = "alert.rules.external:write"
ActionAlertingRuleExternalRead = "alert.rules.external:read"
// External alerting instances actions. We can only narrow it down to writes or reads, as we don't control the atomicity in the external system.
ActionAlertingInstancesExternalWrite = "alert.instances.external:write"
ActionAlertingInstancesExternalRead = "alert.instances.external:read"
// External alerting notifications actions. We can only narrow it down to writes or reads, as we don't control the atomicity in the external system.
ActionAlertingNotificationsExternalWrite = "alert.notifications.external:write"
ActionAlertingNotificationsExternalRead = "alert.notifications.external:read"
// Alerting provisioning actions
ActionAlertingProvisioningRead = "alert.provisioning:read"
ActionAlertingProvisioningReadSecrets = "alert.provisioning.secrets:read"
ActionAlertingProvisioningWrite = "alert.provisioning:write"
// ActionAlertingProvisioningSetStatus Gives access to set provisioning status to alerting resources. Cannot be used alone. Only in conjunction with other permissions.
ActionAlertingProvisioningSetStatus = "alert.provisioning.provenance:write"
// Feature Management actions
2023-08-09 10:32:28 -05:00
ActionFeatureManagementRead = "featuremgmt.read"
ActionFeatureManagementWrite = "featuremgmt.write"
// Library Panel actions
ActionLibraryPanelsCreate = "library.panels:create"
ActionLibraryPanelsRead = "library.panels:read"
ActionLibraryPanelsWrite = "library.panels:write"
ActionLibraryPanelsDelete = "library.panels:delete"
// Usage stats actions
ActionUsageStatsRead = "server.usagestats.report:read"
AccessControl: Implement teams resource service (#43951) * AccessControl: cover team permissions Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Add background service as a consumer to resource_services Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Define actions in roles.go Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Remove action from accesscontrol model Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * As suggested by kalle * move some changes from branch to the skeleton PR * Add background service as a consumer to resource_services Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * moving resourceservice to the main wire file pt2 * move team related actions so that they can be reused * PR feedback * fix * typo * Access Control: adding hooks for team member endpoints (#43991) * AccessControl: cover team permissions Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Add background service as a consumer to resource_services Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Define actions in roles.go Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Remove action from accesscontrol model Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * As suggested by kalle * add access control to list and add team member endpoint, and hooks for adding team members * member permission type is 0 * add ID scope for team permission checks * add more team actions, use Member for member permission name * protect team member update endpoint with FGAC permissions * update SQL functions for teams and the corresponding tests * also protect team member removal endpoint with FGAC permissions and add a hook to permission service * a few small fixes, provide team permission service to test setup * AccessControl: cover team permissions Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Add background service as a consumer to resource_services Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Define actions in roles.go Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Remove action from accesscontrol model Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * As suggested by kalle * move some changes from branch to the skeleton PR * remove resource services from wireexts * remove unneeded actions * linting fix * remove comments * feedback fixes * feedback * simplifying * remove team member within the same transaction * fix a mistake with the error * call the correct sql fction * linting * Access control: tests for team member endpoints (#44177) * tests for team member endpoints * clean up and fix the tests * fixing tests take 2 * don't import enterprise test license * don't import enterprise test license * remove unused variable Co-authored-by: gamab <gabi.mabs@gmail.com> Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com> Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com>
2022-01-26 08:48:41 -06:00
)
var (
// Team scope
ScopeTeamsID = Scope("teams", "id", Parameter(":teamId"))
ScopeSettingsOAuth = func(provider string) string {
return Scope("settings", "auth."+provider, "*")
}
// Annotation scopes
ScopeAnnotationsRoot = "annotations"
ScopeAnnotationsProvider = NewScopeProvider(ScopeAnnotationsRoot)
ScopeAnnotationsAll = ScopeAnnotationsProvider.GetResourceAllScope()
ScopeAnnotationsID = Scope(ScopeAnnotationsRoot, "id", Parameter(":annotationId"))
ScopeAnnotationsTypeDashboard = ScopeAnnotationsProvider.GetResourceScopeType(annotations.Dashboard.String())
ScopeAnnotationsTypeOrganization = ScopeAnnotationsProvider.GetResourceScopeType(annotations.Organization.String())
)
func BuiltInRolesWithParents(builtInRoles []string) map[string]struct{} {
res := map[string]struct{}{}
for _, br := range builtInRoles {
res[br] = struct{}{}
if br != RoleGrafanaAdmin {
for _, parent := range org.RoleType(br).Parents() {
res[string(parent)] = struct{}{}
}
}
}
return res
}
// Evaluators
// TeamsAccessEvaluator is used to protect the "Configuration > Teams" page access
// grants access to a user when they can either create teams or can read and update a team
var TeamsAccessEvaluator = EvalAny(
EvalPermission(ActionTeamsCreate),
EvalAll(
EvalPermission(ActionTeamsRead),
EvalAny(
EvalPermission(ActionTeamsWrite),
EvalPermission(ActionTeamsPermissionsWrite),
EvalPermission(ActionTeamsPermissionsRead),
),
),
)
// TeamsEditAccessEvaluator is used to protect the "Configuration > Teams > edit" page access
var TeamsEditAccessEvaluator = EvalAll(
EvalPermission(ActionTeamsRead),
EvalAny(
EvalPermission(ActionTeamsCreate),
EvalPermission(ActionTeamsWrite),
EvalPermission(ActionTeamsPermissionsWrite),
),
)
// OrgPreferencesAccessEvaluator is used to protect the "Configure > Preferences" page access
var OrgPreferencesAccessEvaluator = EvalAny(
EvalAll(
EvalPermission(ActionOrgsRead),
EvalPermission(ActionOrgsWrite),
),
EvalAll(
EvalPermission(ActionOrgsPreferencesRead),
EvalPermission(ActionOrgsPreferencesWrite),
),
)
// OrgsAccessEvaluator is used to protect the "Server Admin > Orgs" page access
// (you need to have read access to update or delete orgs; read is the minimum)
var OrgsAccessEvaluator = EvalPermission(ActionOrgsRead)
// OrgsCreateAccessEvaluator is used to protect the "Server Admin > Orgs > New Org" page access
var OrgsCreateAccessEvaluator = EvalAll(
EvalPermission(ActionOrgsRead),
EvalPermission(ActionOrgsCreate),
)
// ApiKeyAccessEvaluator is used to protect the "Configuration > API keys" page access
var ApiKeyAccessEvaluator = EvalPermission(ActionAPIKeyRead)
type QueryWithOrg struct {
OrgId *int64 `json:"orgId"`
Global bool `json:"global"`
}