mirror of
https://github.com/grafana/grafana.git
synced 2024-12-02 13:39:19 -06:00
edf1775d49
* 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> 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 526e48ad45
* 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>
518 lines
15 KiB
Go
518 lines
15 KiB
Go
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"
|
|
)
|
|
|
|
var ErrInternal = errutil.NewBase(errutil.StatusInternal, "accesscontrol.internal")
|
|
|
|
// 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(),
|
|
})
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
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"`
|
|
|
|
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
|
|
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
|
|
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 {
|
|
OrgID int64
|
|
Global bool
|
|
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)
|
|
|
|
if (cmd.OrgID == GlobalOrgID) != cmd.Global {
|
|
return fmt.Errorf("invalid org id %d for global role %t", cmd.OrgID, cmd.Global)
|
|
}
|
|
|
|
// 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
|
|
FixedRolePrefix = "fixed:"
|
|
ManagedRolePrefix = "managed:"
|
|
BasicRolePrefix = "basic:"
|
|
PluginRolePrefix = "plugins:"
|
|
ExternalServiceRolePrefix = "externalservice:"
|
|
BasicRoleUIDPrefix = "basic_"
|
|
ExternalServiceRoleUIDPrefix = "externalservice_"
|
|
RoleGrafanaAdmin = "Grafana Admin"
|
|
|
|
GeneralFolderUID = "general"
|
|
|
|
// Permission actions
|
|
|
|
ActionAPIKeyRead = "apikeys:read"
|
|
ActionAPIKeyCreate = "apikeys:create"
|
|
ActionAPIKeyDelete = "apikeys:delete"
|
|
|
|
// Users actions
|
|
ActionUsersRead = "users:read"
|
|
ActionUsersWrite = "users:write"
|
|
ActionUsersImpersonate = "users:impersonate"
|
|
|
|
// 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
|
|
ScopeUsersAll = "users:*"
|
|
ScopeUsersPrefix = "users:id:"
|
|
|
|
// Settings scope
|
|
ScopeSettingsAll = "settings:*"
|
|
ScopeSettingsAuth = "settings:auth:*"
|
|
ScopeSettingsSAML = "settings:auth.saml:*"
|
|
|
|
// 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"
|
|
|
|
// Alerting Notification policies actions
|
|
ActionAlertingNotificationsRead = "alert.notifications:read"
|
|
ActionAlertingNotificationsWrite = "alert.notifications:write"
|
|
|
|
// 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"
|
|
ActionAlertingProvisioningWrite = "alert.provisioning:write"
|
|
)
|
|
|
|
var (
|
|
// Team scope
|
|
ScopeTeamsID = Scope("teams", "id", Parameter(":teamId"))
|
|
|
|
// 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),
|
|
),
|
|
),
|
|
)
|
|
|
|
// 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)
|