mirror of
https://github.com/grafana/grafana.git
synced 2025-02-20 11:48:34 -06:00
* Chore: Add user service method SetUsingOrg * Chore: Add user service method GetSignedInUserWithCacheCtx * Use method GetSignedInUserWithCacheCtx from user service * Fix lint after rebase * Fix lint * Fix lint error * roll back some changes * Roll back changes in api and middleware * Add xorm tags to SignedInUser ID fields
205 lines
6.4 KiB
Go
205 lines
6.4 KiB
Go
package ossaccesscontrol
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/grafana/grafana/pkg/api/routing"
|
|
"github.com/grafana/grafana/pkg/infra/log"
|
|
"github.com/grafana/grafana/pkg/infra/metrics"
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol/api"
|
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
|
"github.com/grafana/grafana/pkg/services/user"
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
)
|
|
|
|
func ProvideService(
|
|
features featuremgmt.FeatureToggles, cfg *setting.Cfg,
|
|
store accesscontrol.PermissionsStore, routeRegister routing.RouteRegister,
|
|
) (*OSSAccessControlService, error) {
|
|
var errDeclareRoles error
|
|
s := ProvideOSSAccessControl(cfg, store)
|
|
if !s.IsDisabled() {
|
|
api := api.AccessControlAPI{
|
|
RouteRegister: routeRegister,
|
|
AccessControl: s,
|
|
}
|
|
api.RegisterAPIEndpoints()
|
|
|
|
errDeclareRoles = accesscontrol.DeclareFixedRoles(s)
|
|
}
|
|
|
|
return s, errDeclareRoles
|
|
}
|
|
|
|
func ProvideOSSAccessControl(cfg *setting.Cfg, store accesscontrol.PermissionsStore) *OSSAccessControlService {
|
|
s := &OSSAccessControlService{
|
|
cfg: cfg,
|
|
store: store,
|
|
log: log.New("accesscontrol"),
|
|
scopeResolvers: accesscontrol.NewScopeResolvers(),
|
|
roles: accesscontrol.BuildBasicRoleDefinitions(),
|
|
}
|
|
|
|
return s
|
|
}
|
|
|
|
// OSSAccessControlService is the service implementing role based access control.
|
|
type OSSAccessControlService struct {
|
|
log log.Logger
|
|
cfg *setting.Cfg
|
|
scopeResolvers accesscontrol.ScopeResolvers
|
|
store accesscontrol.PermissionsStore
|
|
registrations accesscontrol.RegistrationList
|
|
roles map[string]*accesscontrol.RoleDTO
|
|
}
|
|
|
|
func (ac *OSSAccessControlService) IsDisabled() bool {
|
|
if ac.cfg == nil {
|
|
return true
|
|
}
|
|
return !ac.cfg.RBACEnabled
|
|
}
|
|
|
|
func (ac *OSSAccessControlService) GetUsageStats(_ context.Context) map[string]interface{} {
|
|
return map[string]interface{}{
|
|
"stats.oss.accesscontrol.enabled.count": ac.getUsageMetrics(),
|
|
}
|
|
}
|
|
|
|
func (ac *OSSAccessControlService) getUsageMetrics() interface{} {
|
|
if ac.IsDisabled() {
|
|
return 0
|
|
}
|
|
|
|
return 1
|
|
}
|
|
|
|
// Evaluate evaluates access to the given resources
|
|
func (ac *OSSAccessControlService) Evaluate(ctx context.Context, user *user.SignedInUser, evaluator accesscontrol.Evaluator) (bool, error) {
|
|
timer := prometheus.NewTimer(metrics.MAccessEvaluationsSummary)
|
|
defer timer.ObserveDuration()
|
|
metrics.MAccessEvaluationCount.Inc()
|
|
|
|
if user.Permissions == nil {
|
|
user.Permissions = map[int64]map[string][]string{}
|
|
}
|
|
|
|
if _, ok := user.Permissions[user.OrgID]; !ok {
|
|
permissions, err := ac.GetUserPermissions(ctx, user, accesscontrol.Options{ReloadCache: true})
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
user.Permissions[user.OrgID] = accesscontrol.GroupScopesByAction(permissions)
|
|
}
|
|
|
|
attributeMutator := ac.scopeResolvers.GetScopeAttributeMutator(user.OrgID)
|
|
resolvedEvaluator, err := evaluator.MutateScopes(ctx, attributeMutator)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return resolvedEvaluator.Evaluate(user.Permissions[user.OrgID]), nil
|
|
}
|
|
|
|
// GetUserPermissions returns user permissions based on built-in roles
|
|
func (ac *OSSAccessControlService) GetUserPermissions(ctx context.Context, user *user.SignedInUser, _ accesscontrol.Options) ([]accesscontrol.Permission, error) {
|
|
timer := prometheus.NewTimer(metrics.MAccessPermissionsSummary)
|
|
defer timer.ObserveDuration()
|
|
|
|
permissions := ac.getFixedPermissions(ctx, user)
|
|
|
|
dbPermissions, err := ac.store.GetUserPermissions(ctx, accesscontrol.GetUserPermissionsQuery{
|
|
OrgID: user.OrgID,
|
|
UserID: user.UserID,
|
|
Roles: accesscontrol.GetOrgRoles(ac.cfg, user),
|
|
Actions: append(TeamAdminActions, append(DashboardAdminActions, FolderAdminActions...)...),
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
permissions = append(permissions, dbPermissions...)
|
|
keywordMutator := ac.scopeResolvers.GetScopeKeywordMutator(user)
|
|
for i := range permissions {
|
|
// if the permission has a keyword in its scope it will be resolved
|
|
permissions[i].Scope, err = keywordMutator(ctx, permissions[i].Scope)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return permissions, nil
|
|
}
|
|
|
|
func (ac *OSSAccessControlService) getFixedPermissions(ctx context.Context, user *user.SignedInUser) []accesscontrol.Permission {
|
|
permissions := make([]accesscontrol.Permission, 0)
|
|
|
|
for _, builtin := range accesscontrol.GetOrgRoles(ac.cfg, user) {
|
|
if basicRole, ok := ac.roles[builtin]; ok {
|
|
permissions = append(permissions, basicRole.Permissions...)
|
|
}
|
|
}
|
|
|
|
return permissions
|
|
}
|
|
|
|
// RegisterFixedRoles registers all declared roles in RAM
|
|
func (ac *OSSAccessControlService) RegisterFixedRoles(ctx context.Context) error {
|
|
// If accesscontrol is disabled no need to register roles
|
|
if ac.IsDisabled() {
|
|
return nil
|
|
}
|
|
ac.registrations.Range(func(registration accesscontrol.RoleRegistration) bool {
|
|
ac.registerFixedRole(registration.Role, registration.Grants)
|
|
return true
|
|
})
|
|
return nil
|
|
}
|
|
|
|
// RegisterFixedRole saves a fixed role and assigns it to built-in roles
|
|
func (ac *OSSAccessControlService) registerFixedRole(role accesscontrol.RoleDTO, builtInRoles []string) {
|
|
for br := range accesscontrol.BuiltInRolesWithParents(builtInRoles) {
|
|
if basicRole, ok := ac.roles[br]; ok {
|
|
basicRole.Permissions = append(basicRole.Permissions, role.Permissions...)
|
|
} else {
|
|
ac.log.Error("Unknown builtin role", "builtInRole", br)
|
|
}
|
|
}
|
|
}
|
|
|
|
// DeclareFixedRoles allow the caller to declare, to the service, fixed roles and their assignments
|
|
// to organization roles ("Viewer", "Editor", "Admin") or "Grafana Admin"
|
|
func (ac *OSSAccessControlService) DeclareFixedRoles(registrations ...accesscontrol.RoleRegistration) error {
|
|
// If accesscontrol is disabled no need to register roles
|
|
if ac.IsDisabled() {
|
|
return nil
|
|
}
|
|
|
|
for _, r := range registrations {
|
|
err := accesscontrol.ValidateFixedRole(r.Role)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = accesscontrol.ValidateBuiltInRoles(r.Grants)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
ac.registrations.Append(r)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// RegisterScopeAttributeResolver allows the caller to register scope resolvers for a
|
|
// specific scope prefix (ex: datasources:name:)
|
|
func (ac *OSSAccessControlService) RegisterScopeAttributeResolver(scopePrefix string, resolver accesscontrol.ScopeAttributeResolver) {
|
|
ac.scopeResolvers.AddScopeAttributeResolver(scopePrefix, resolver)
|
|
}
|
|
|
|
func (ac *OSSAccessControlService) DeleteUserPermissions(ctx context.Context, userID int64) error {
|
|
return ac.store.DeleteUserPermissions(ctx, userID)
|
|
}
|