Public dashboards: fix public dashboard permissions so that annotations are displayed (#85091)

* fix public dashboard anonymous user permissions so they include the new annotation permissions

* test fix
This commit is contained in:
Ieva 2024-03-25 17:42:40 +00:00 committed by GitHub
parent fb01ef749f
commit df40e13333
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 28 additions and 8 deletions

View File

@ -334,7 +334,7 @@ func TestIntegrationUnauthenticatedUserCanGetPubdashPanelQueryData(t *testing.T)
license := licensingtest.NewFakeLicensing()
license.On("FeatureEnabled", FeaturePublicDashboardsEmailSharing).Return(false)
pds := publicdashboardsService.ProvideService(cfg, store, qds, annotationsService, ac, ws, dashService, license)
pds := publicdashboardsService.ProvideService(cfg, featuremgmt.WithFeatures(), store, qds, annotationsService, ac, ws, dashService, license)
pubdash, err := pds.Create(context.Background(), &user.SignedInUser{}, savePubDashboardCmd)
require.NoError(t, err)

View File

@ -47,5 +47,6 @@ func newPublicDashboardServiceImpl(
store: publicDashboardStore,
serviceWrapper: serviceWrapper,
license: license,
features: featuremgmt.WithFeatures(),
}, sqlStore
}

View File

@ -13,6 +13,7 @@ import (
"github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/publicdashboards/models"
"github.com/grafana/grafana/pkg/services/publicdashboards/validation"
"github.com/grafana/grafana/pkg/services/user"
@ -36,7 +37,7 @@ func (pd *PublicDashboardServiceImpl) FindAnnotations(ctx context.Context, reqDT
return nil, models.ErrInternalServerError.Errorf("FindAnnotations: failed to unmarshal dashboard annotations: %w", err)
}
anonymousUser := buildAnonymousUser(ctx, dash)
anonymousUser := buildAnonymousUser(ctx, dash, pd.features)
uniqueEvents := make(map[int64]models.AnnotationEvent, 0)
for _, anno := range annoDto.Annotations.List {
@ -138,7 +139,7 @@ func (pd *PublicDashboardServiceImpl) GetQueryDataResponse(ctx context.Context,
return nil, models.ErrPanelQueriesNotFound.Errorf("GetQueryDataResponse: failed to extract queries from panel")
}
anonymousUser := buildAnonymousUser(ctx, dashboard)
anonymousUser := buildAnonymousUser(ctx, dashboard, pd.features)
res, err := pd.QueryDataService.QueryData(ctx, anonymousUser, skipDSCache, metricReq)
reqDatasources := metricReq.GetUniqueDatasourceTypes()
@ -180,7 +181,7 @@ func (pd *PublicDashboardServiceImpl) buildMetricRequest(dashboard *dashboards.D
}
// buildAnonymousUser creates a user with permissions to read from all datasources used in the dashboard
func buildAnonymousUser(ctx context.Context, dashboard *dashboards.Dashboard) *user.SignedInUser {
func buildAnonymousUser(ctx context.Context, dashboard *dashboards.Dashboard, features featuremgmt.FeatureToggles) *user.SignedInUser {
datasourceUids := getUniqueDashboardDatasourceUids(dashboard.Data)
// Create a user with blank permissions
@ -204,8 +205,12 @@ func buildAnonymousUser(ctx context.Context, dashboard *dashboards.Dashboard) *u
permissions := make(map[string][]string)
permissions[datasources.ActionQuery] = queryScopes
permissions[datasources.ActionRead] = readScopes
permissions[accesscontrol.ActionAnnotationsRead] = annotationScopes
permissions[dashboards.ActionDashboardsRead] = dashboardScopes
permissions[accesscontrol.ActionAnnotationsRead] = annotationScopes
if features.IsEnabled(ctx, featuremgmt.FlagAnnotationPermissionUpdate) {
permissions[accesscontrol.ActionAnnotationsRead] = dashboardScopes
}
anonymousUser.Permissions[dashboard.OrgID] = permissions

View File

@ -732,6 +732,7 @@ func TestGetQueryDataResponse(t *testing.T) {
func TestFindAnnotations(t *testing.T) {
color := "red"
name := "annoName"
features := featuremgmt.WithFeatures(featuremgmt.FlagAnnotationPermissionUpdate)
t.Run("will build anonymous user with correct permissions to get annotations", func(t *testing.T) {
fakeStore := &FakePublicDashboardStore{}
fakeStore.On("FindByAccessToken", mock.Anything, mock.AnythingOfType("string")).
@ -747,7 +748,7 @@ func TestFindAnnotations(t *testing.T) {
dash := dashboards.NewDashboard("testDashboard")
items, _ := service.FindAnnotations(context.Background(), reqDTO, "abc123")
anonUser := buildAnonymousUser(context.Background(), dash)
anonUser := buildAnonymousUser(context.Background(), dash, features)
assert.Equal(t, "dashboards:*", anonUser.Permissions[0]["dashboards:read"][0])
assert.Len(t, items, 0)
@ -1323,9 +1324,10 @@ func TestBuildAnonymousUser(t *testing.T) {
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore), quotatest.New(false, nil))
require.NoError(t, err)
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, "", true, []map[string]interface{}{}, nil)
features := featuremgmt.WithFeatures()
t.Run("will add datasource read and query permissions to user for each datasource in dashboard", func(t *testing.T) {
user := buildAnonymousUser(context.Background(), dashboard)
user := buildAnonymousUser(context.Background(), dashboard, features)
require.Equal(t, dashboard.OrgID, user.OrgID)
require.Equal(t, "datasources:uid:ds1", user.Permissions[user.OrgID]["datasources:query"][0])
@ -1334,12 +1336,20 @@ func TestBuildAnonymousUser(t *testing.T) {
require.Equal(t, "datasources:uid:ds3", user.Permissions[user.OrgID]["datasources:read"][1])
})
t.Run("will add dashboard and annotation permissions needed for getting annotations", func(t *testing.T) {
user := buildAnonymousUser(context.Background(), dashboard)
user := buildAnonymousUser(context.Background(), dashboard, features)
require.Equal(t, dashboard.OrgID, user.OrgID)
require.Equal(t, "annotations:type:dashboard", user.Permissions[user.OrgID]["annotations:read"][0])
require.Equal(t, "dashboards:*", user.Permissions[user.OrgID]["dashboards:read"][0])
})
t.Run("will add dashboard and annotation permissions needed for getting annotations when FlagAnnotationPermissionUpdate is enabled", func(t *testing.T) {
features = featuremgmt.WithFeatures(featuremgmt.FlagAnnotationPermissionUpdate)
user := buildAnonymousUser(context.Background(), dashboard, features)
require.Equal(t, dashboard.OrgID, user.OrgID)
require.Equal(t, "dashboards:*", user.Permissions[user.OrgID]["annotations:read"][0])
require.Equal(t, "dashboards:*", user.Permissions[user.OrgID]["dashboards:read"][0])
})
}
func TestGroupQueriesByPanelId(t *testing.T) {

View File

@ -15,6 +15,7 @@ import (
"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/licensing"
"github.com/grafana/grafana/pkg/services/publicdashboards"
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
@ -32,6 +33,7 @@ import (
type PublicDashboardServiceImpl struct {
log log.Logger
cfg *setting.Cfg
features featuremgmt.FeatureToggles
store publicdashboards.Store
intervalCalculator intervalv2.Calculator
QueryDataService query.Service
@ -52,6 +54,7 @@ var _ publicdashboards.Service = (*PublicDashboardServiceImpl)(nil)
// builds the service, and api, and configures routes
func ProvideService(
cfg *setting.Cfg,
features featuremgmt.FeatureToggles,
store publicdashboards.Store,
qds query.Service,
anno annotations.Repository,
@ -63,6 +66,7 @@ func ProvideService(
return &PublicDashboardServiceImpl{
log: log.New(LogPrefix),
cfg: cfg,
features: features,
store: store,
intervalCalculator: intervalv2.NewCalculator(),
QueryDataService: qds,