/
githubmirror
/
grafana
Обзор
Документация
Войти
/
githubmirror
/
grafana
Код
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
pkg/services/annotations/accesscontrol/accesscontrol.go
152 строки
5 KB
Craig O'Donnell
fix(annotations): avoid mutating annotation item query within repository (#127499)
30 июн 2026, 18:58
Не верифицирован
30 июн 2026, 18:58
f255fe3
Код
Авторство
О чём код?
package accesscontrol import ( "context" "github.com/grafana/grafana/pkg/apimachinery/errutil" "github.com/grafana/grafana/pkg/infra/db" ac "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/annotations" "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/search/model" "github.com/grafana/grafana/pkg/setting" ) var ( ErrReadForbidden = errutil.NewBase( errutil.StatusForbidden, "annotations.accesscontrol.read", errutil.WithPublicMessage("User missing permissions"), ) ErrAccessControlInternal = errutil.NewBase( errutil.StatusInternal, "annotations.accesscontrol.internal", errutil.WithPublicMessage("Internal error while checking permissions"), ) ) type Authorizer interface { Authorize(ctx context.Context, query annotations.ItemQuery) (*AccessResources, error) } var _ Authorizer = (*AuthService)(nil) type AuthService struct { db db.DB features featuremgmt.FeatureToggles dashSvc dashboards.DashboardService searchDashboardsPageLimit int64 maxDepth int } func NewAuthService(db db.DB, features featuremgmt.FeatureToggles, dashSvc dashboards.DashboardService, cfg *setting.Cfg) *AuthService { section := cfg.Raw.Section("annotations") searchDashboardsPageLimit := section.Key("search_dashboards_page_limit").MustInt64(1000) return &AuthService{ db: db, features: features, dashSvc: dashSvc, searchDashboardsPageLimit: searchDashboardsPageLimit, maxDepth: cfg.MaxNestedFolderDepth, } } // Authorize checks if the user has permission to read annotations, then returns a struct containing dashboards and scope types that the user has access to. func (authz *AuthService) Authorize(ctx context.Context, query annotations.ItemQuery) (*AccessResources, error) { user := query.SignedInUser if user == nil || user.IsNil() { return nil, ErrReadForbidden.Errorf("missing user") } scopes, has := user.GetPermissions()[ac.ActionAnnotationsRead] if !has { return nil, ErrReadForbidden.Errorf("user does not have permission to read annotations") } scopeTypes := annotationScopeTypes(scopes) _, canAccessOrgAnnotations := scopeTypes[annotations.Organization.String()] if query.AnnotationID != 0 { annotationDashboardUID, err := authz.getAnnotationDashboard(ctx, query) if err != nil { return nil, ErrAccessControlInternal.Errorf("failed to fetch annotations: %w", err) } query.DashboardUID = annotationDashboardUID } visibleDashboards, err := authz.dashboardsWithVisibleAnnotations(ctx, query) if err != nil { return nil, ErrAccessControlInternal.Errorf("failed to fetch dashboards: %w", err) } return &AccessResources{ Dashboards: visibleDashboards, CanAccessOrgAnnotations: canAccessOrgAnnotations, }, nil } func (authz *AuthService) getAnnotationDashboard(ctx context.Context, query annotations.ItemQuery) (string, error) { var items []annotations.Item params := make([]any, 0) err := authz.db.WithDbSession(ctx, func(sess *db.Session) error { sql := ` SELECT a.id, a.org_id, a.dashboard_uid FROM annotation as a WHERE a.org_id = ? AND a.id = ? ` params = append(params, query.OrgID, query.AnnotationID) return sess.SQL(sql, params...).Find(&items) }) if err != nil { return "", err } if len(items) == 0 { return "", ErrAccessControlInternal.Errorf("annotation not found") } return items[0].DashboardUID, nil } func (authz *AuthService) dashboardsWithVisibleAnnotations(ctx context.Context, query annotations.ItemQuery) (map[string]int64, error) { var dashboardUIDs []string if query.DashboardUID != "" { dashboardUIDs = []string{query.DashboardUID} } dashs, err := authz.dashSvc.SearchDashboards(ctx, &dashboards.FindPersistedDashboardsQuery{ DashboardUIDs: dashboardUIDs, OrgId: query.SignedInUser.GetOrgID(), SignedInUser: query.SignedInUser, Page: query.Page, Type: model.TypeAnnotation, Limit: authz.searchDashboardsPageLimit, }) if err != nil { return nil, err } visibleDashboards := make(map[string]int64) for _, d := range dashs { visibleDashboards[d.UID] = d.ID } return visibleDashboards, nil } func annotationScopeTypes(scopes []string) map[any]struct{} { allScopeTypes := map[any]struct{}{ annotations.Dashboard.String(): {}, annotations.Organization.String(): {}, } types, hasWildcardScope := ac.ParseScopes(ac.ScopeAnnotationsProvider.GetResourceScopeType(""), scopes) if hasWildcardScope { types = allScopeTypes } return types }