mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Adding FGAC annotations validation for creation and deletion (#46736)
Access Control: Adding FGAC annotations validation for creation and deletion Co-authored-by: IevaVasiljeva <ieva.vasiljeva@grafana.com>
This commit is contained in:
parent
7ab1ef8d6e
commit
c717320942
@ -274,15 +274,17 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
||||
Grants: []string{string(models.ROLE_VIEWER)},
|
||||
}
|
||||
|
||||
localAnnotationsWriterRole := ac.RoleRegistration{
|
||||
dashboardAnnotationsWriterRole := ac.RoleRegistration{
|
||||
Role: ac.RoleDTO{
|
||||
Name: "fixed:annotations.local:writer",
|
||||
DisplayName: "Local annotation writer",
|
||||
Name: "fixed:annotations.dashboard:writer",
|
||||
DisplayName: "Dashboard annotation writer",
|
||||
Description: "Update annotations associated with dashboards.",
|
||||
Group: "Annotations",
|
||||
Version: 1,
|
||||
Version: 2,
|
||||
Permissions: []ac.Permission{
|
||||
{Action: ac.ActionAnnotationsWrite, Scope: ac.ScopeAnnotationsTypeLocal},
|
||||
{Action: ac.ActionAnnotationsCreate},
|
||||
{Action: ac.ActionAnnotationsDelete, Scope: ac.ScopeAnnotationsTypeDashboard},
|
||||
{Action: ac.ActionAnnotationsWrite, Scope: ac.ScopeAnnotationsTypeDashboard},
|
||||
},
|
||||
},
|
||||
Grants: []string{string(models.ROLE_VIEWER)},
|
||||
@ -296,6 +298,8 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
||||
Group: "Annotations",
|
||||
Version: 1,
|
||||
Permissions: []ac.Permission{
|
||||
{Action: ac.ActionAnnotationsCreate},
|
||||
{Action: ac.ActionAnnotationsDelete, Scope: ac.ScopeAnnotationsAll},
|
||||
{Action: ac.ActionAnnotationsWrite, Scope: ac.ScopeAnnotationsAll},
|
||||
},
|
||||
},
|
||||
@ -405,7 +409,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
||||
provisioningWriterRole, datasourcesReaderRole, datasourcesWriterRole, datasourcesIdReaderRole,
|
||||
datasourcesCompatibilityReaderRole, orgReaderRole, orgWriterRole,
|
||||
orgMaintainerRole, teamsCreatorRole, teamsWriterRole, datasourcesExplorerRole,
|
||||
annotationsReaderRole, localAnnotationsWriterRole, annotationsWriterRole,
|
||||
annotationsReaderRole, dashboardAnnotationsWriterRole, annotationsWriterRole,
|
||||
dashboardsCreatorRole, dashboardsReaderRole, dashboardsWriterRole,
|
||||
foldersCreatorRole, foldersReaderRole, foldersWriterRole, apikeyWriterRole,
|
||||
)
|
||||
|
@ -66,10 +66,18 @@ func (hs *HTTPServer) PostAnnotation(c *models.ReqContext) response.Response {
|
||||
var canSave bool
|
||||
var err error
|
||||
if cmd.DashboardId != 0 {
|
||||
canSave, err = canSaveLocalAnnotation(c, cmd.DashboardId)
|
||||
} else {
|
||||
canSave = canSaveGlobalAnnotation(c)
|
||||
canSave, err = canSaveDashboardAnnotation(c, cmd.DashboardId)
|
||||
} else { // organization annotations
|
||||
if !hs.Features.IsEnabled(featuremgmt.FlagAccesscontrol) {
|
||||
canSave = canSaveOrganizationAnnotation(c)
|
||||
} else {
|
||||
// This is an additional validation needed only for FGAC Organization Annotations.
|
||||
// It is not possible to do it in the middleware because we need to look
|
||||
// into the request to determine if this is a Organization annotation or not
|
||||
canSave, err = hs.canCreateOrganizationAnnotation(c)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil || !canSave {
|
||||
return dashboardGuardianResponse(err)
|
||||
}
|
||||
@ -190,13 +198,14 @@ func (hs *HTTPServer) UpdateAnnotation(c *models.ReqContext) response.Response {
|
||||
}
|
||||
|
||||
canSave := true
|
||||
if annotation.GetType() == annotations.Local {
|
||||
canSave, err = canSaveLocalAnnotation(c, annotation.DashboardId)
|
||||
if annotation.GetType() == annotations.Dashboard {
|
||||
canSave, err = canSaveDashboardAnnotation(c, annotation.DashboardId)
|
||||
} else {
|
||||
if !hs.Features.IsEnabled(featuremgmt.FlagAccesscontrol) {
|
||||
canSave = canSaveGlobalAnnotation(c)
|
||||
canSave = canSaveOrganizationAnnotation(c)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil || !canSave {
|
||||
return dashboardGuardianResponse(err)
|
||||
}
|
||||
@ -236,11 +245,11 @@ func (hs *HTTPServer) PatchAnnotation(c *models.ReqContext) response.Response {
|
||||
}
|
||||
|
||||
canSave := true
|
||||
if annotation.GetType() == annotations.Local {
|
||||
canSave, err = canSaveLocalAnnotation(c, annotation.DashboardId)
|
||||
if annotation.GetType() == annotations.Dashboard {
|
||||
canSave, err = canSaveDashboardAnnotation(c, annotation.DashboardId)
|
||||
} else {
|
||||
if !hs.Features.IsEnabled(featuremgmt.FlagAccesscontrol) {
|
||||
canSave = canSaveGlobalAnnotation(c)
|
||||
canSave = canSaveOrganizationAnnotation(c)
|
||||
}
|
||||
}
|
||||
if err != nil || !canSave {
|
||||
@ -314,12 +323,15 @@ func (hs *HTTPServer) DeleteAnnotationByID(c *models.ReqContext) response.Respon
|
||||
return resp
|
||||
}
|
||||
|
||||
var canSave bool
|
||||
if annotation.GetType() == annotations.Local {
|
||||
canSave, err = canSaveLocalAnnotation(c, annotation.DashboardId)
|
||||
canSave := true
|
||||
if annotation.GetType() == annotations.Dashboard {
|
||||
canSave, err = canSaveDashboardAnnotation(c, annotation.DashboardId)
|
||||
} else {
|
||||
canSave = canSaveGlobalAnnotation(c)
|
||||
if !hs.Features.IsEnabled(featuremgmt.FlagAccesscontrol) {
|
||||
canSave = canSaveOrganizationAnnotation(c)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil || !canSave {
|
||||
return dashboardGuardianResponse(err)
|
||||
}
|
||||
@ -335,7 +347,7 @@ func (hs *HTTPServer) DeleteAnnotationByID(c *models.ReqContext) response.Respon
|
||||
return response.Success("Annotation deleted")
|
||||
}
|
||||
|
||||
func canSaveLocalAnnotation(c *models.ReqContext, dashboardID int64) (bool, error) {
|
||||
func canSaveDashboardAnnotation(c *models.ReqContext, dashboardID int64) (bool, error) {
|
||||
guard := guardian.New(c.Req.Context(), dashboardID, c.OrgId, c.SignedInUser)
|
||||
if canEdit, err := guard.CanEdit(); err != nil || !canEdit {
|
||||
return false, err
|
||||
@ -344,7 +356,7 @@ func canSaveLocalAnnotation(c *models.ReqContext, dashboardID int64) (bool, erro
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func canSaveGlobalAnnotation(c *models.ReqContext) bool {
|
||||
func canSaveOrganizationAnnotation(c *models.ReqContext) bool {
|
||||
return c.SignedInUser.HasRole(models.ROLE_EDITOR)
|
||||
}
|
||||
|
||||
@ -399,11 +411,16 @@ func AnnotationTypeScopeResolver() (string, accesscontrol.AttributeScopeResolveF
|
||||
return "", err
|
||||
}
|
||||
|
||||
if annotation.GetType() == annotations.Global {
|
||||
return accesscontrol.ScopeAnnotationsTypeGlobal, nil
|
||||
if annotation.GetType() == annotations.Organization {
|
||||
return accesscontrol.ScopeAnnotationsTypeOrganization, nil
|
||||
} else {
|
||||
return accesscontrol.ScopeAnnotationsTypeLocal, nil
|
||||
return accesscontrol.ScopeAnnotationsTypeDashboard, nil
|
||||
}
|
||||
}
|
||||
return accesscontrol.ScopeAnnotationsProvider.GetResourceScope(""), annotationTypeResolver
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) canCreateOrganizationAnnotation(c *models.ReqContext) (bool, error) {
|
||||
evaluator := accesscontrol.EvalPermission(accesscontrol.ActionAnnotationsCreate, accesscontrol.ScopeAnnotationsTypeOrganization)
|
||||
return hs.AccessControl.Evaluate(c.Req.Context(), c.SignedInUser, evaluator)
|
||||
}
|
||||
|
@ -396,20 +396,47 @@ func TestAPI_Annotations_AccessControl(t *testing.T) {
|
||||
_, err := sc.db.CreateOrgWithMember("TestOrg", testUserID)
|
||||
require.NoError(t, err)
|
||||
|
||||
repo := annotations.GetRepository()
|
||||
dashboardAnnotation := annotations.ItemDTO{Id: 1, DashboardId: 1}
|
||||
organizationAnnotation := annotations.ItemDTO{Id: 2, DashboardId: 0}
|
||||
|
||||
localAnnotation := annotations.Item{
|
||||
OrgId: sc.initCtx.OrgId,
|
||||
fakeAnnoRepo = &fakeAnnotationsRepo{
|
||||
annotations: map[int64]annotations.ItemDTO{1: dashboardAnnotation, 2: organizationAnnotation},
|
||||
}
|
||||
annotations.SetRepository(fakeAnnoRepo)
|
||||
|
||||
postOrganizationCmd := dtos.PostAnnotationsCmd{
|
||||
Time: 1000,
|
||||
Text: "annotation text",
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
PanelId: 1,
|
||||
}
|
||||
|
||||
postDashboardCmd := dtos.PostAnnotationsCmd{
|
||||
Time: 1000,
|
||||
Text: "annotation text",
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
DashboardId: 1,
|
||||
}
|
||||
globalAnnotation := annotations.Item{
|
||||
OrgId: sc.initCtx.OrgId,
|
||||
PanelId: 1,
|
||||
}
|
||||
|
||||
err = repo.Save(&localAnnotation)
|
||||
require.NoError(t, err)
|
||||
err = repo.Save(&globalAnnotation)
|
||||
require.NoError(t, err)
|
||||
updateCmd := dtos.UpdateAnnotationsCmd{
|
||||
Time: 1000,
|
||||
Text: "annotation text",
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
}
|
||||
|
||||
patchCmd := dtos.PatchAnnotationsCmd{
|
||||
Time: 1000,
|
||||
Text: "annotation text",
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
}
|
||||
|
||||
postGraphiteCmd := dtos.PostGraphiteAnnotationsCmd{
|
||||
When: 1000,
|
||||
What: "annotation text",
|
||||
Data: "Deploy",
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
}
|
||||
|
||||
type args struct {
|
||||
permissions []*accesscontrol.Permission
|
||||
@ -459,10 +486,217 @@ func TestAPI_Annotations_AccessControl(t *testing.T) {
|
||||
},
|
||||
want: http.StatusForbidden,
|
||||
},
|
||||
{
|
||||
name: "AccessControl update dashboard annotation with permissions is allowed",
|
||||
args: args{
|
||||
permissions: []*accesscontrol.Permission{{
|
||||
Action: accesscontrol.ActionAnnotationsWrite, Scope: accesscontrol.ScopeAnnotationsTypeDashboard,
|
||||
}},
|
||||
url: "/api/annotations/1",
|
||||
method: http.MethodPut,
|
||||
body: mockRequestBody(updateCmd),
|
||||
},
|
||||
want: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "AccessControl update dashboard annotation without permissions is forbidden",
|
||||
args: args{
|
||||
permissions: []*accesscontrol.Permission{},
|
||||
url: "/api/annotations/1",
|
||||
method: http.MethodPut,
|
||||
body: mockRequestBody(updateCmd),
|
||||
},
|
||||
want: http.StatusForbidden,
|
||||
},
|
||||
{
|
||||
name: "AccessControl update organization annotation with permissions is allowed",
|
||||
args: args{
|
||||
permissions: []*accesscontrol.Permission{{
|
||||
Action: accesscontrol.ActionAnnotationsWrite, Scope: accesscontrol.ScopeAnnotationsAll,
|
||||
}},
|
||||
url: "/api/annotations/2",
|
||||
method: http.MethodPut,
|
||||
body: mockRequestBody(updateCmd),
|
||||
},
|
||||
want: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "AccessControl update organization annotation without permissions is forbidden",
|
||||
args: args{
|
||||
permissions: []*accesscontrol.Permission{{
|
||||
Action: accesscontrol.ActionAnnotationsWrite, Scope: accesscontrol.ScopeAnnotationsTypeDashboard,
|
||||
}},
|
||||
url: "/api/annotations/2",
|
||||
method: http.MethodPut,
|
||||
body: mockRequestBody(updateCmd),
|
||||
},
|
||||
want: http.StatusForbidden,
|
||||
},
|
||||
{
|
||||
name: "AccessControl patch dashboard annotation with permissions is allowed",
|
||||
args: args{
|
||||
permissions: []*accesscontrol.Permission{{
|
||||
Action: accesscontrol.ActionAnnotationsWrite, Scope: accesscontrol.ScopeAnnotationsTypeDashboard,
|
||||
}},
|
||||
url: "/api/annotations/1",
|
||||
method: http.MethodPatch,
|
||||
body: mockRequestBody(patchCmd),
|
||||
},
|
||||
want: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "AccessControl patch dashboard annotation without permissions is forbidden",
|
||||
args: args{
|
||||
permissions: []*accesscontrol.Permission{},
|
||||
url: "/api/annotations/1",
|
||||
method: http.MethodPatch,
|
||||
body: mockRequestBody(patchCmd),
|
||||
},
|
||||
want: http.StatusForbidden,
|
||||
},
|
||||
{
|
||||
name: "AccessControl patch organization annotation with permissions is allowed",
|
||||
args: args{
|
||||
permissions: []*accesscontrol.Permission{{
|
||||
Action: accesscontrol.ActionAnnotationsWrite, Scope: accesscontrol.ScopeAnnotationsAll,
|
||||
}},
|
||||
url: "/api/annotations/2",
|
||||
method: http.MethodPatch,
|
||||
body: mockRequestBody(patchCmd),
|
||||
},
|
||||
want: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "AccessControl patch organization annotation without permissions is forbidden",
|
||||
args: args{
|
||||
permissions: []*accesscontrol.Permission{{
|
||||
Action: accesscontrol.ActionAnnotationsWrite, Scope: accesscontrol.ScopeAnnotationsTypeDashboard,
|
||||
}},
|
||||
url: "/api/annotations/2",
|
||||
method: http.MethodPatch,
|
||||
body: mockRequestBody(patchCmd),
|
||||
},
|
||||
want: http.StatusForbidden,
|
||||
},
|
||||
{
|
||||
name: "AccessControl create dashboard annotation with permissions is allowed",
|
||||
args: args{
|
||||
permissions: []*accesscontrol.Permission{{
|
||||
Action: accesscontrol.ActionAnnotationsCreate, Scope: accesscontrol.ScopeAnnotationsTypeDashboard,
|
||||
}},
|
||||
url: "/api/annotations",
|
||||
method: http.MethodPost,
|
||||
body: mockRequestBody(postDashboardCmd),
|
||||
},
|
||||
want: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "AccessControl create dashboard annotation without permissions is forbidden",
|
||||
args: args{
|
||||
permissions: []*accesscontrol.Permission{},
|
||||
url: "/api/annotations",
|
||||
method: http.MethodPost,
|
||||
body: mockRequestBody(postDashboardCmd),
|
||||
},
|
||||
want: http.StatusForbidden,
|
||||
},
|
||||
{
|
||||
name: "AccessControl create organization annotation with permissions is allowed",
|
||||
args: args{
|
||||
permissions: []*accesscontrol.Permission{{
|
||||
Action: accesscontrol.ActionAnnotationsCreate, Scope: accesscontrol.ScopeAnnotationsAll,
|
||||
}},
|
||||
url: "/api/annotations",
|
||||
method: http.MethodPost,
|
||||
body: mockRequestBody(postOrganizationCmd),
|
||||
},
|
||||
want: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "AccessControl create organization annotation without permissions is forbidden",
|
||||
args: args{
|
||||
permissions: []*accesscontrol.Permission{{
|
||||
Action: accesscontrol.ActionAnnotationsCreate, Scope: accesscontrol.ScopeAnnotationsTypeDashboard,
|
||||
}},
|
||||
url: "/api/annotations",
|
||||
method: http.MethodPost,
|
||||
body: mockRequestBody(postOrganizationCmd),
|
||||
},
|
||||
want: http.StatusForbidden,
|
||||
},
|
||||
{
|
||||
name: "AccessControl delete dashboard annotation with permissions is allowed",
|
||||
args: args{
|
||||
permissions: []*accesscontrol.Permission{{
|
||||
Action: accesscontrol.ActionAnnotationsDelete, Scope: accesscontrol.ScopeAnnotationsTypeDashboard,
|
||||
}},
|
||||
url: "/api/annotations/1",
|
||||
method: http.MethodDelete,
|
||||
},
|
||||
want: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "AccessControl delete dashboard annotation without permissions is forbidden",
|
||||
args: args{
|
||||
permissions: []*accesscontrol.Permission{},
|
||||
url: "/api/annotations/1",
|
||||
method: http.MethodDelete,
|
||||
},
|
||||
want: http.StatusForbidden,
|
||||
},
|
||||
{
|
||||
name: "AccessControl delete organization annotation with permissions is allowed",
|
||||
args: args{
|
||||
permissions: []*accesscontrol.Permission{{
|
||||
Action: accesscontrol.ActionAnnotationsDelete, Scope: accesscontrol.ScopeAnnotationsAll,
|
||||
}},
|
||||
url: "/api/annotations/2",
|
||||
method: http.MethodDelete,
|
||||
},
|
||||
want: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "AccessControl delete organization annotation without permissions is forbidden",
|
||||
args: args{
|
||||
permissions: []*accesscontrol.Permission{{
|
||||
Action: accesscontrol.ActionAnnotationsDelete, Scope: accesscontrol.ScopeAnnotationsTypeDashboard,
|
||||
}},
|
||||
url: "/api/annotations/2",
|
||||
method: http.MethodDelete,
|
||||
},
|
||||
want: http.StatusForbidden,
|
||||
},
|
||||
{
|
||||
name: "AccessControl create graphite annotation with permissions is allowed",
|
||||
args: args{
|
||||
permissions: []*accesscontrol.Permission{{
|
||||
Action: accesscontrol.ActionAnnotationsCreate, Scope: accesscontrol.ScopeAnnotationsAll,
|
||||
}},
|
||||
url: "/api/annotations/graphite",
|
||||
method: http.MethodPost,
|
||||
body: mockRequestBody(postGraphiteCmd),
|
||||
},
|
||||
want: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "AccessControl create organization annotation without permissions is forbidden",
|
||||
args: args{
|
||||
permissions: []*accesscontrol.Permission{{
|
||||
Action: accesscontrol.ActionAnnotationsCreate, Scope: accesscontrol.ScopeAnnotationsTypeDashboard,
|
||||
}},
|
||||
url: "/api/annotations/graphite",
|
||||
method: http.MethodPost,
|
||||
body: mockRequestBody(postGraphiteCmd),
|
||||
},
|
||||
want: http.StatusForbidden,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
setUpACL()
|
||||
sc.acmock.RegisterAttributeScopeResolver(AnnotationTypeScopeResolver())
|
||||
setAccessControlPermissions(sc.acmock, tt.args.permissions, sc.initCtx.OrgId)
|
||||
|
||||
r := callAPI(sc.server, tt.args.method, tt.args.url, tt.args.body, t)
|
||||
assert.Equalf(t, tt.want, r.Code, "Annotations API(%v)", tt.args.url)
|
||||
})
|
||||
@ -479,15 +713,15 @@ func TestService_AnnotationTypeScopeResolver(t *testing.T) {
|
||||
|
||||
testCases := []testCaseResolver{
|
||||
{
|
||||
desc: "correctly resolves local annotations",
|
||||
desc: "correctly resolves dashboard annotations",
|
||||
given: "annotations:id:1",
|
||||
want: accesscontrol.ScopeAnnotationsTypeLocal,
|
||||
want: accesscontrol.ScopeAnnotationsTypeDashboard,
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
desc: "correctly resolves global annotations",
|
||||
desc: "correctly resolves organization annotations",
|
||||
given: "annotations:id:2",
|
||||
want: accesscontrol.ScopeAnnotationsTypeGlobal,
|
||||
want: accesscontrol.ScopeAnnotationsTypeOrganization,
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
@ -504,11 +738,11 @@ func TestService_AnnotationTypeScopeResolver(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
localAnnotation := annotations.ItemDTO{Id: 1, DashboardId: 1}
|
||||
globalAnnotation := annotations.ItemDTO{Id: 2}
|
||||
dashboardAnnotation := annotations.ItemDTO{Id: 1, DashboardId: 1}
|
||||
organizationAnnotation := annotations.ItemDTO{Id: 2}
|
||||
|
||||
fakeAnnoRepo = &fakeAnnotationsRepo{
|
||||
annotations: map[int64]annotations.ItemDTO{1: localAnnotation, 2: globalAnnotation},
|
||||
annotations: map[int64]annotations.ItemDTO{1: dashboardAnnotation, 2: organizationAnnotation},
|
||||
}
|
||||
annotations.SetRepository(fakeAnnoRepo)
|
||||
|
||||
|
@ -440,11 +440,11 @@ func (hs *HTTPServer) registerRoutes() {
|
||||
apiRoute.Post("/annotations/mass-delete", reqOrgAdmin, routing.Wrap(hs.DeleteAnnotations))
|
||||
|
||||
apiRoute.Group("/annotations", func(annotationsRoute routing.RouteRegister) {
|
||||
annotationsRoute.Post("/", routing.Wrap(hs.PostAnnotation))
|
||||
annotationsRoute.Delete("/:annotationId", routing.Wrap(hs.DeleteAnnotationByID))
|
||||
annotationsRoute.Post("/", authorize(reqSignedIn, ac.EvalPermission(ac.ActionAnnotationsCreate)), routing.Wrap(hs.PostAnnotation))
|
||||
annotationsRoute.Delete("/:annotationId", authorize(reqSignedIn, ac.EvalPermission(ac.ActionAnnotationsDelete, ac.ScopeAnnotationsID)), routing.Wrap(hs.DeleteAnnotationByID))
|
||||
annotationsRoute.Put("/:annotationId", authorize(reqSignedIn, ac.EvalPermission(ac.ActionAnnotationsWrite, ac.ScopeAnnotationsID)), routing.Wrap(hs.UpdateAnnotation))
|
||||
annotationsRoute.Patch("/:annotationId", authorize(reqSignedIn, ac.EvalPermission(ac.ActionAnnotationsWrite, ac.ScopeAnnotationsID)), routing.Wrap(hs.PatchAnnotation))
|
||||
annotationsRoute.Post("/graphite", reqEditorRole, routing.Wrap(hs.PostGraphiteAnnotation))
|
||||
annotationsRoute.Post("/graphite", authorize(reqEditorRole, ac.EvalPermission(ac.ActionAnnotationsCreate, ac.ScopeAnnotationsTypeOrganization)), routing.Wrap(hs.PostGraphiteAnnotation))
|
||||
annotationsRoute.Get("/tags", authorize(reqSignedIn, ac.EvalPermission(ac.ActionAnnotationsTagsRead, ac.ScopeAnnotationsTagsAll)), routing.Wrap(hs.GetAnnotationTags))
|
||||
})
|
||||
|
||||
|
@ -141,7 +141,7 @@ type GetAnnotationsParams struct {
|
||||
// in:query
|
||||
// required:false
|
||||
Limit int64 `json:"limit"`
|
||||
// Use this to filter global annotations. Global annotations are annotations from an annotation data source that are not connected specifically to a dashboard or panel. You can filter by multiple tags.
|
||||
// Use this to filter global annotations. Organization annotations are annotations from an annotation data source that are not connected specifically to a dashboard or panel. You can filter by multiple tags.
|
||||
// in:query
|
||||
// required:false
|
||||
// type: array
|
||||
|
@ -130,7 +130,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
||||
|
||||
t.Run("When matching route path", func(t *testing.T) {
|
||||
ctx, req := setUp()
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/v4/some/method", cfg, httpClientProvider,
|
||||
&oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
@ -143,7 +143,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
||||
|
||||
t.Run("When matching route path and has dynamic url", func(t *testing.T) {
|
||||
ctx, req := setUp()
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/common/some/method", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
proxy.matchedRoute = routes[3]
|
||||
@ -155,7 +155,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
||||
|
||||
t.Run("When matching route path with no url", func(t *testing.T) {
|
||||
ctx, req := setUp()
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
proxy.matchedRoute = routes[4]
|
||||
@ -166,7 +166,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
||||
|
||||
t.Run("When matching route path and has dynamic body", func(t *testing.T) {
|
||||
ctx, req := setUp()
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/body", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
proxy.matchedRoute = routes[5]
|
||||
@ -180,7 +180,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
||||
t.Run("Validating request", func(t *testing.T) {
|
||||
t.Run("plugin route with valid role", func(t *testing.T) {
|
||||
ctx, _ := setUp()
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/v4/some/method", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
err = proxy.validateRequest()
|
||||
@ -189,7 +189,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
||||
|
||||
t.Run("plugin route with admin role and user is editor", func(t *testing.T) {
|
||||
ctx, _ := setUp()
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/admin", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
err = proxy.validateRequest()
|
||||
@ -199,7 +199,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
||||
t.Run("plugin route with admin role and user is admin", func(t *testing.T) {
|
||||
ctx, _ := setUp()
|
||||
ctx.SignedInUser.OrgRole = models.ROLE_ADMIN
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/admin", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
err = proxy.validateRequest()
|
||||
@ -290,7 +290,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "pathwithtoken1", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, routes[0], dsInfo, cfg)
|
||||
@ -306,7 +306,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
||||
req, err := http.NewRequest("GET", "http://localhost/asd", nil)
|
||||
require.NoError(t, err)
|
||||
client = newFakeHTTPClient(t, json2)
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "pathwithtoken2", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, routes[1], dsInfo, cfg)
|
||||
@ -323,7 +323,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
client = newFakeHTTPClient(t, []byte{})
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "pathwithtoken1", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, routes[0], dsInfo, cfg)
|
||||
@ -345,7 +345,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
||||
ctx := &models.ReqContext{}
|
||||
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{BuildVersion: "5.3.0"}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
||||
@ -371,7 +371,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
||||
ctx := &models.ReqContext{}
|
||||
var routes []*plugins.Route
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -395,7 +395,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
||||
ctx := &models.ReqContext{}
|
||||
var routes []*plugins.Route
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -423,7 +423,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
||||
ctx := &models.ReqContext{}
|
||||
var pluginRoutes []*plugins.Route
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(ds, pluginRoutes, ctx, "", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -446,7 +446,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
||||
ctx := &models.ReqContext{}
|
||||
var routes []*plugins.Route
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/to/folder/", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
||||
@ -510,7 +510,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
||||
|
||||
var routes []*plugins.Route
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/to/folder/", &setting.Cfg{}, httpClientProvider, &mockAuthToken, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
req, err = http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
||||
@ -643,7 +643,7 @@ func TestDataSourceProxy_requestHandling(t *testing.T) {
|
||||
ctx, ds := setUp(t)
|
||||
var routes []*plugins.Route
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -661,7 +661,7 @@ func TestDataSourceProxy_requestHandling(t *testing.T) {
|
||||
})
|
||||
var routes []*plugins.Route
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -675,7 +675,7 @@ func TestDataSourceProxy_requestHandling(t *testing.T) {
|
||||
ctx, ds := setUp(t)
|
||||
var routes []*plugins.Route
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -697,7 +697,7 @@ func TestDataSourceProxy_requestHandling(t *testing.T) {
|
||||
})
|
||||
var routes []*plugins.Route
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -722,7 +722,7 @@ func TestDataSourceProxy_requestHandling(t *testing.T) {
|
||||
ctx.Req = httptest.NewRequest("GET", "/api/datasources/proxy/1/path/%2Ftest%2Ftest%2F?query=%2Ftest%2Ftest%2F", nil)
|
||||
var routes []*plugins.Route
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/%2Ftest%2Ftest%2F", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -746,7 +746,7 @@ func TestDataSourceProxy_requestHandling(t *testing.T) {
|
||||
ctx.Req = httptest.NewRequest("GET", "/api/datasources/proxy/1/path/%2Ftest%2Ftest%2F?query=%2Ftest%2Ftest%2F", nil)
|
||||
var routes []*plugins.Route
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/%2Ftest%2Ftest%2F", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -771,7 +771,7 @@ func TestNewDataSourceProxy_InvalidURL(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
var routes []*plugins.Route
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
_, err = NewDataSourceProxy(&ds, routes, &ctx, "api/method", &cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.Error(t, err)
|
||||
assert.True(t, strings.HasPrefix(err.Error(), `validation of data source URL "://host/root" failed`))
|
||||
@ -792,7 +792,7 @@ func TestNewDataSourceProxy_ProtocolLessURL(t *testing.T) {
|
||||
|
||||
var routes []*plugins.Route
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
_, err = NewDataSourceProxy(&ds, routes, &ctx, "api/method", &cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
|
||||
require.NoError(t, err)
|
||||
@ -835,7 +835,7 @@ func TestNewDataSourceProxy_MSSQL(t *testing.T) {
|
||||
|
||||
var routes []*plugins.Route
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
p, err := NewDataSourceProxy(&ds, routes, &ctx, "api/method", &cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
if tc.err == nil {
|
||||
require.NoError(t, err)
|
||||
@ -862,7 +862,7 @@ func getDatasourceProxiedRequest(t *testing.T, ctx *models.ReqContext, cfg *sett
|
||||
|
||||
var routes []*plugins.Route
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "", cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
||||
@ -986,7 +986,7 @@ func runDatasourceAuthTest(t *testing.T, secretsService secrets.Service, test *t
|
||||
require.NoError(t, err)
|
||||
|
||||
var routes []*plugins.Route
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(test.datasource, routes, ctx, "", &setting.Cfg{}, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -1028,7 +1028,7 @@ func Test_PathCheck(t *testing.T) {
|
||||
}
|
||||
ctx, _ := setUp()
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
proxy, err := NewDataSourceProxy(&models.DataSource{}, routes, ctx, "b", &setting.Cfg{}, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer, secretsService)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
@ -34,7 +34,7 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) {
|
||||
hs := &HTTPServer{
|
||||
Cfg: settings,
|
||||
SQLStore: sqlStore,
|
||||
AccessControl: &acmock.Mock{},
|
||||
AccessControl: acmock.New(),
|
||||
}
|
||||
|
||||
mockResult := models.SearchUserQueryResult{
|
||||
|
@ -46,6 +46,8 @@ type Mock struct {
|
||||
GetUserBuiltInRolesFunc func(user *models.SignedInUser) []string
|
||||
RegisterFixedRolesFunc func() error
|
||||
RegisterAttributeScopeResolverFunc func(string, accesscontrol.AttributeScopeResolveFunc)
|
||||
|
||||
scopeResolver accesscontrol.ScopeResolver
|
||||
}
|
||||
|
||||
// Ensure the mock stays in line with the interface
|
||||
@ -53,10 +55,11 @@ var _ fullAccessControl = New()
|
||||
|
||||
func New() *Mock {
|
||||
mock := &Mock{
|
||||
Calls: Calls{},
|
||||
disabled: false,
|
||||
permissions: []*accesscontrol.Permission{},
|
||||
builtInRoles: []string{},
|
||||
Calls: Calls{},
|
||||
disabled: false,
|
||||
permissions: []*accesscontrol.Permission{},
|
||||
builtInRoles: []string{},
|
||||
scopeResolver: accesscontrol.NewScopeResolver(),
|
||||
}
|
||||
|
||||
return mock
|
||||
@ -90,13 +93,18 @@ func (m *Mock) Evaluate(ctx context.Context, user *models.SignedInUser, evaluato
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return evaluator.Evaluate(accesscontrol.GroupScopesByAction(permissions))
|
||||
|
||||
attributeMutator := m.scopeResolver.GetResolveAttributeScopeMutator(user.OrgId)
|
||||
resolvedEvaluator, err := evaluator.MutateScopes(ctx, attributeMutator)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return resolvedEvaluator.Evaluate(accesscontrol.GroupScopesByAction(permissions))
|
||||
}
|
||||
|
||||
// GetUserPermissions returns user permissions.
|
||||
// This mock return m.permissions unless an override is provided.
|
||||
func (m *Mock) GetUserPermissions(ctx context.Context, user *models.SignedInUser,
|
||||
opts accesscontrol.Options) ([]*accesscontrol.Permission, error) {
|
||||
func (m *Mock) GetUserPermissions(ctx context.Context, user *models.SignedInUser, opts accesscontrol.Options) ([]*accesscontrol.Permission, error) {
|
||||
m.Calls.GetUserPermissions = append(m.Calls.GetUserPermissions, []interface{}{ctx, user, opts})
|
||||
// Use override if provided
|
||||
if m.GetUserPermissionsFunc != nil {
|
||||
@ -169,6 +177,7 @@ func (m *Mock) RegisterFixedRoles() error {
|
||||
// RegisterAttributeScopeResolver allows the caller to register a scope resolver for a
|
||||
// specific scope prefix (ex: datasources:name:)
|
||||
func (m *Mock) RegisterAttributeScopeResolver(scopePrefix string, resolver accesscontrol.AttributeScopeResolveFunc) {
|
||||
m.scopeResolver.AddAttributeResolver(scopePrefix, resolver)
|
||||
m.Calls.RegisterAttributeScopeResolver = append(m.Calls.RegisterAttributeScopeResolver, []struct{}{})
|
||||
// Use override if provided
|
||||
if m.RegisterAttributeScopeResolverFunc != nil {
|
||||
|
@ -319,6 +319,8 @@ const (
|
||||
ScopeTeamsAll = "teams:*"
|
||||
|
||||
// Annotations related actions
|
||||
ActionAnnotationsCreate = "annotations:create"
|
||||
ActionAnnotationsDelete = "annotations:delete"
|
||||
ActionAnnotationsRead = "annotations:read"
|
||||
ActionAnnotationsWrite = "annotations:write"
|
||||
ActionAnnotationsTagsRead = "annotations.tags:read"
|
||||
@ -373,12 +375,12 @@ var (
|
||||
ScopeTeamsID = Scope("teams", "id", Parameter(":teamId"))
|
||||
|
||||
// Annotation scopes
|
||||
ScopeAnnotationsRoot = "annotations"
|
||||
ScopeAnnotationsProvider = NewScopeProvider(ScopeAnnotationsRoot)
|
||||
ScopeAnnotationsAll = ScopeAnnotationsProvider.GetResourceAllScope()
|
||||
ScopeAnnotationsID = Scope(ScopeAnnotationsRoot, "id", Parameter(":annotationId"))
|
||||
ScopeAnnotationsTypeLocal = ScopeAnnotationsProvider.GetResourceScopeType("dashboard")
|
||||
ScopeAnnotationsTypeGlobal = ScopeAnnotationsProvider.GetResourceScopeType("organization")
|
||||
ScopeAnnotationsRoot = "annotations"
|
||||
ScopeAnnotationsProvider = NewScopeProvider(ScopeAnnotationsRoot)
|
||||
ScopeAnnotationsAll = ScopeAnnotationsProvider.GetResourceAllScope()
|
||||
ScopeAnnotationsID = Scope(ScopeAnnotationsRoot, "id", Parameter(":annotationId"))
|
||||
ScopeAnnotationsTypeDashboard = ScopeAnnotationsProvider.GetResourceScopeType("dashboard")
|
||||
ScopeAnnotationsTypeOrganization = ScopeAnnotationsProvider.GetResourceScopeType("organization")
|
||||
|
||||
// Annotation tag scopes
|
||||
ScopeAnnotationsTagsAll = "annotations:tags:*"
|
||||
|
@ -149,13 +149,13 @@ type ItemDTO struct {
|
||||
type annotationType int
|
||||
|
||||
const (
|
||||
Global annotationType = iota
|
||||
Local
|
||||
Organization annotationType = iota
|
||||
Dashboard
|
||||
)
|
||||
|
||||
func (annotation *ItemDTO) GetType() annotationType {
|
||||
if annotation.DashboardId != 0 {
|
||||
return Local
|
||||
return Dashboard
|
||||
}
|
||||
return Global
|
||||
return Organization
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ func TestService(t *testing.T) {
|
||||
})
|
||||
|
||||
secretsService := secretsManager.SetupTestService(t, database.ProvideSecretsStore(sqlStore))
|
||||
s := ProvideService(bus.New(), sqlStore, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
s := ProvideService(bus.New(), sqlStore, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
|
||||
var ds *models.DataSource
|
||||
|
||||
@ -234,7 +234,7 @@ func TestService_GetHttpTransport(t *testing.T) {
|
||||
}
|
||||
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
|
||||
rt1, err := dsService.GetHTTPTransport(&ds, provider)
|
||||
require.NoError(t, err)
|
||||
@ -267,7 +267,7 @@ func TestService_GetHttpTransport(t *testing.T) {
|
||||
json.Set("tlsAuthWithCACert", true)
|
||||
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
|
||||
tlsCaCert, err := secretsService.Encrypt(context.Background(), []byte(caCert), secrets.WithoutScope())
|
||||
require.NoError(t, err)
|
||||
@ -317,7 +317,7 @@ func TestService_GetHttpTransport(t *testing.T) {
|
||||
json.Set("tlsAuth", true)
|
||||
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
|
||||
tlsClientCert, err := secretsService.Encrypt(context.Background(), []byte(clientCert), secrets.WithoutScope())
|
||||
require.NoError(t, err)
|
||||
@ -360,7 +360,7 @@ func TestService_GetHttpTransport(t *testing.T) {
|
||||
json.Set("serverName", "server-name")
|
||||
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
|
||||
tlsCaCert, err := secretsService.Encrypt(context.Background(), []byte(caCert), secrets.WithoutScope())
|
||||
require.NoError(t, err)
|
||||
@ -397,7 +397,7 @@ func TestService_GetHttpTransport(t *testing.T) {
|
||||
json.Set("tlsSkipVerify", true)
|
||||
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
|
||||
ds := models.DataSource{
|
||||
Id: 1,
|
||||
@ -428,7 +428,7 @@ func TestService_GetHttpTransport(t *testing.T) {
|
||||
})
|
||||
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
|
||||
encryptedData, err := secretsService.Encrypt(context.Background(), []byte(`Bearer xf5yhfkpsnmgo`), secrets.WithoutScope())
|
||||
require.NoError(t, err)
|
||||
@ -487,7 +487,7 @@ func TestService_GetHttpTransport(t *testing.T) {
|
||||
})
|
||||
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
|
||||
ds := models.DataSource{
|
||||
Id: 1,
|
||||
@ -520,7 +520,7 @@ func TestService_GetHttpTransport(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
|
||||
ds := models.DataSource{
|
||||
Type: models.DS_ES,
|
||||
@ -554,7 +554,7 @@ func TestService_getTimeout(t *testing.T) {
|
||||
}
|
||||
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
|
||||
for _, tc := range testCases {
|
||||
ds := &models.DataSource{
|
||||
@ -567,7 +567,7 @@ func TestService_getTimeout(t *testing.T) {
|
||||
func TestService_DecryptedValue(t *testing.T) {
|
||||
t.Run("When datasource hasn't been updated, encrypted JSON should be fetched from cache", func(t *testing.T) {
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
|
||||
encryptedJsonData, err := secretsService.EncryptJsonData(
|
||||
context.Background(),
|
||||
@ -621,7 +621,7 @@ func TestService_DecryptedValue(t *testing.T) {
|
||||
SecureJsonData: encryptedJsonData,
|
||||
}
|
||||
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
|
||||
// Populate cache
|
||||
password, ok := dsService.DecryptedValue(&ds, "password")
|
||||
@ -657,7 +657,7 @@ func TestService_HTTPClientOptions(t *testing.T) {
|
||||
t.Cleanup(func() { ds.JsonData = emptyJsonData; ds.SecureJsonData = emptySecureJsonData })
|
||||
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
|
||||
opts, err := dsService.httpClientOptions(&ds)
|
||||
require.NoError(t, err)
|
||||
@ -675,7 +675,7 @@ func TestService_HTTPClientOptions(t *testing.T) {
|
||||
})
|
||||
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
|
||||
opts, err := dsService.httpClientOptions(&ds)
|
||||
require.NoError(t, err)
|
||||
@ -694,7 +694,7 @@ func TestService_HTTPClientOptions(t *testing.T) {
|
||||
})
|
||||
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
|
||||
_, err := dsService.httpClientOptions(&ds)
|
||||
assert.Error(t, err)
|
||||
@ -708,7 +708,7 @@ func TestService_HTTPClientOptions(t *testing.T) {
|
||||
})
|
||||
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
|
||||
opts, err := dsService.httpClientOptions(&ds)
|
||||
require.NoError(t, err)
|
||||
|
@ -56,7 +56,7 @@ func TestAnnotations(t *testing.T) {
|
||||
assert.Equal(t, int64(20), annotation2.Epoch)
|
||||
assert.Equal(t, int64(21), annotation2.EpochEnd)
|
||||
|
||||
globalAnnotation1 := &annotations.Item{
|
||||
organizationAnnotation1 := &annotations.Item{
|
||||
OrgId: 1,
|
||||
UserId: 1,
|
||||
Text: "deploy",
|
||||
@ -64,9 +64,9 @@ func TestAnnotations(t *testing.T) {
|
||||
Epoch: 15,
|
||||
Tags: []string{"deploy"},
|
||||
}
|
||||
err = repo.Save(globalAnnotation1)
|
||||
err = repo.Save(organizationAnnotation1)
|
||||
require.NoError(t, err)
|
||||
assert.Greater(t, globalAnnotation1.Id, int64(0))
|
||||
assert.Greater(t, organizationAnnotation1.Id, int64(0))
|
||||
|
||||
globalAnnotation2 := &annotations.Item{
|
||||
OrgId: 1,
|
||||
|
@ -37,7 +37,7 @@ func TestHandleRequest(t *testing.T) {
|
||||
return backend.NewQueryDataResponse(), nil
|
||||
}
|
||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), &acmock.Mock{}, acmock.NewPermissionsServicesMock())
|
||||
dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, featuremgmt.WithFeatures(), acmock.New(), acmock.NewPermissionsServicesMock())
|
||||
s := ProvideService(client, nil, dsService)
|
||||
|
||||
ds := &models.DataSource{Id: 12, Type: "unregisteredType", JsonData: simplejson.New()}
|
||||
|
Loading…
Reference in New Issue
Block a user