mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Move datasource scopes and actions to access control package (#46334)
* create scope provider * move datasource actions and scopes to datasource package + add provider * change usages to use datasource scopes and update data source name resolver to use provider * move folder permissions to dashboard package and update usages
This commit is contained in:
parent
6670257c5e
commit
314be36a7c
@ -5,6 +5,8 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -12,13 +14,6 @@ import (
|
|||||||
const (
|
const (
|
||||||
ActionProvisioningReload = "provisioning:reload"
|
ActionProvisioningReload = "provisioning:reload"
|
||||||
|
|
||||||
ActionDatasourcesRead = "datasources:read"
|
|
||||||
ActionDatasourcesQuery = "datasources:query"
|
|
||||||
ActionDatasourcesCreate = "datasources:create"
|
|
||||||
ActionDatasourcesWrite = "datasources:write"
|
|
||||||
ActionDatasourcesDelete = "datasources:delete"
|
|
||||||
ActionDatasourcesIDRead = "datasources.id:read"
|
|
||||||
|
|
||||||
ActionOrgsRead = "orgs:read"
|
ActionOrgsRead = "orgs:read"
|
||||||
ActionOrgsPreferencesRead = "orgs.preferences:read"
|
ActionOrgsPreferencesRead = "orgs.preferences:read"
|
||||||
ActionOrgsQuotasRead = "orgs.quotas:read"
|
ActionOrgsQuotasRead = "orgs.quotas:read"
|
||||||
@ -36,11 +31,6 @@ var (
|
|||||||
ScopeProvisionersPlugins = ac.Scope("provisioners", "plugins")
|
ScopeProvisionersPlugins = ac.Scope("provisioners", "plugins")
|
||||||
ScopeProvisionersDatasources = ac.Scope("provisioners", "datasources")
|
ScopeProvisionersDatasources = ac.Scope("provisioners", "datasources")
|
||||||
ScopeProvisionersNotifications = ac.Scope("provisioners", "notifications")
|
ScopeProvisionersNotifications = ac.Scope("provisioners", "notifications")
|
||||||
|
|
||||||
ScopeDatasourcesAll = ac.Scope("datasources", "*")
|
|
||||||
ScopeDatasourceID = ac.Scope("datasources", "id", ac.Parameter(":id"))
|
|
||||||
ScopeDatasourceUID = ac.Scope("datasources", "uid", ac.Parameter(":uid"))
|
|
||||||
ScopeDatasourceName = ac.Scope("datasources", "name", ac.Parameter(":name"))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// declareFixedRoles declares to the AccessControl service fixed roles and their
|
// declareFixedRoles declares to the AccessControl service fixed roles and their
|
||||||
@ -93,12 +83,12 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
|||||||
Group: "Data sources",
|
Group: "Data sources",
|
||||||
Permissions: []ac.Permission{
|
Permissions: []ac.Permission{
|
||||||
{
|
{
|
||||||
Action: ActionDatasourcesRead,
|
Action: datasources.ActionDatasourcesRead,
|
||||||
Scope: ScopeDatasourcesAll,
|
Scope: datasources.ScopeDatasourcesProvider.GetResourceAllScope(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Action: ActionDatasourcesQuery,
|
Action: datasources.ActionDatasourcesQuery,
|
||||||
Scope: ScopeDatasourcesAll,
|
Scope: datasources.ScopeDatasourcesAll,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -114,15 +104,15 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
|||||||
Group: "Data sources",
|
Group: "Data sources",
|
||||||
Permissions: ac.ConcatPermissions(datasourcesReaderRole.Role.Permissions, []ac.Permission{
|
Permissions: ac.ConcatPermissions(datasourcesReaderRole.Role.Permissions, []ac.Permission{
|
||||||
{
|
{
|
||||||
Action: ActionDatasourcesWrite,
|
Action: datasources.ActionDatasourcesWrite,
|
||||||
Scope: ScopeDatasourcesAll,
|
Scope: datasources.ScopeDatasourcesAll,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Action: ActionDatasourcesCreate,
|
Action: datasources.ActionDatasourcesCreate,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Action: ActionDatasourcesDelete,
|
Action: datasources.ActionDatasourcesDelete,
|
||||||
Scope: ScopeDatasourcesAll,
|
Scope: datasources.ScopeDatasourcesAll,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
@ -138,8 +128,8 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
|||||||
Group: "Infrequently used",
|
Group: "Infrequently used",
|
||||||
Permissions: []ac.Permission{
|
Permissions: []ac.Permission{
|
||||||
{
|
{
|
||||||
Action: ActionDatasourcesIDRead,
|
Action: datasources.ActionDatasourcesIDRead,
|
||||||
Scope: ScopeDatasourcesAll,
|
Scope: datasources.ScopeDatasourcesAll,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -154,8 +144,8 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
|||||||
Description: "Only used for open source compatibility. Query data sources.",
|
Description: "Only used for open source compatibility. Query data sources.",
|
||||||
Group: "Infrequently used",
|
Group: "Infrequently used",
|
||||||
Permissions: []ac.Permission{
|
Permissions: []ac.Permission{
|
||||||
{Action: ActionDatasourcesQuery},
|
{Action: datasources.ActionDatasourcesQuery},
|
||||||
{Action: ActionDatasourcesRead},
|
{Action: datasources.ActionDatasourcesRead},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Grants: []string{string(models.ROLE_VIEWER)},
|
Grants: []string{string(models.ROLE_VIEWER)},
|
||||||
@ -294,8 +284,8 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
|||||||
Description: "Create dashboard in general folder.",
|
Description: "Create dashboard in general folder.",
|
||||||
Group: "Dashboards",
|
Group: "Dashboards",
|
||||||
Permissions: []ac.Permission{
|
Permissions: []ac.Permission{
|
||||||
{Action: ac.ActionFoldersRead, Scope: ac.Scope("folders", "id", "0")},
|
{Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersProvider.GetResourceScope("0")},
|
||||||
{Action: ac.ActionDashboardsCreate, Scope: ac.Scope("folders", "id", "0")},
|
{Action: ac.ActionDashboardsCreate, Scope: dashboards.ScopeFoldersProvider.GetResourceScope("0")},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Grants: []string{"Editor"},
|
Grants: []string{"Editor"},
|
||||||
@ -325,7 +315,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
|||||||
Permissions: ac.ConcatPermissions(dashboardsReaderRole.Role.Permissions, []ac.Permission{
|
Permissions: ac.ConcatPermissions(dashboardsReaderRole.Role.Permissions, []ac.Permission{
|
||||||
{Action: ac.ActionDashboardsWrite, Scope: ac.ScopeDashboardsAll},
|
{Action: ac.ActionDashboardsWrite, Scope: ac.ScopeDashboardsAll},
|
||||||
{Action: ac.ActionDashboardsDelete, Scope: ac.ScopeDashboardsAll},
|
{Action: ac.ActionDashboardsDelete, Scope: ac.ScopeDashboardsAll},
|
||||||
{Action: ac.ActionDashboardsCreate, Scope: ac.ScopeFoldersAll},
|
{Action: ac.ActionDashboardsCreate, Scope: dashboards.ScopeFoldersAll},
|
||||||
{Action: ac.ActionDashboardsPermissionsRead, Scope: ac.ScopeDashboardsAll},
|
{Action: ac.ActionDashboardsPermissionsRead, Scope: ac.ScopeDashboardsAll},
|
||||||
{Action: ac.ActionDashboardsPermissionsWrite, Scope: ac.ScopeDashboardsAll},
|
{Action: ac.ActionDashboardsPermissionsWrite, Scope: ac.ScopeDashboardsAll},
|
||||||
}),
|
}),
|
||||||
@ -341,7 +331,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
|||||||
Description: "Create folders.",
|
Description: "Create folders.",
|
||||||
Group: "Folders",
|
Group: "Folders",
|
||||||
Permissions: []ac.Permission{
|
Permissions: []ac.Permission{
|
||||||
{Action: ac.ActionFoldersCreate},
|
{Action: dashboards.ActionFoldersCreate},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Grants: []string{"Editor"},
|
Grants: []string{"Editor"},
|
||||||
@ -355,8 +345,8 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
|||||||
Description: "Read all folders and dashboards.",
|
Description: "Read all folders and dashboards.",
|
||||||
Group: "Folders",
|
Group: "Folders",
|
||||||
Permissions: []ac.Permission{
|
Permissions: []ac.Permission{
|
||||||
{Action: ac.ActionFoldersRead, Scope: ac.ScopeFoldersAll},
|
{Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersAll},
|
||||||
{Action: ac.ActionDashboardsRead, Scope: ac.ScopeFoldersAll},
|
{Action: ac.ActionDashboardsRead, Scope: dashboards.ScopeFoldersAll},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Grants: []string{"Admin"},
|
Grants: []string{"Admin"},
|
||||||
@ -372,14 +362,14 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
|||||||
Permissions: ac.ConcatPermissions(
|
Permissions: ac.ConcatPermissions(
|
||||||
foldersReaderRole.Role.Permissions,
|
foldersReaderRole.Role.Permissions,
|
||||||
[]ac.Permission{
|
[]ac.Permission{
|
||||||
{Action: ac.ActionFoldersCreate},
|
{Action: dashboards.ActionFoldersCreate},
|
||||||
{Action: ac.ActionFoldersWrite, Scope: ac.ScopeFoldersAll},
|
{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersAll},
|
||||||
{Action: ac.ActionFoldersDelete, Scope: ac.ScopeFoldersAll},
|
{Action: dashboards.ActionFoldersDelete, Scope: dashboards.ScopeFoldersAll},
|
||||||
{Action: ac.ActionDashboardsWrite, Scope: ac.ScopeFoldersAll},
|
{Action: ac.ActionDashboardsWrite, Scope: dashboards.ScopeFoldersAll},
|
||||||
{Action: ac.ActionDashboardsDelete, Scope: ac.ScopeFoldersAll},
|
{Action: ac.ActionDashboardsDelete, Scope: dashboards.ScopeFoldersAll},
|
||||||
{Action: ac.ActionDashboardsCreate, Scope: ac.ScopeFoldersAll},
|
{Action: ac.ActionDashboardsCreate, Scope: dashboards.ScopeFoldersAll},
|
||||||
{Action: ac.ActionDashboardsPermissionsRead, Scope: ac.ScopeFoldersAll},
|
{Action: ac.ActionDashboardsPermissionsRead, Scope: dashboards.ScopeFoldersAll},
|
||||||
{Action: ac.ActionDashboardsPermissionsWrite, Scope: ac.ScopeFoldersAll},
|
{Action: ac.ActionDashboardsPermissionsWrite, Scope: dashboards.ScopeFoldersAll},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
Grants: []string{"Admin"},
|
Grants: []string{"Admin"},
|
||||||
@ -399,25 +389,25 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
|||||||
|
|
||||||
// dataSourcesConfigurationAccessEvaluator is used to protect the "Configure > Data sources" tab access
|
// dataSourcesConfigurationAccessEvaluator is used to protect the "Configure > Data sources" tab access
|
||||||
var dataSourcesConfigurationAccessEvaluator = ac.EvalAll(
|
var dataSourcesConfigurationAccessEvaluator = ac.EvalAll(
|
||||||
ac.EvalPermission(ActionDatasourcesRead),
|
ac.EvalPermission(datasources.ActionDatasourcesRead),
|
||||||
ac.EvalAny(
|
ac.EvalAny(
|
||||||
ac.EvalPermission(ActionDatasourcesCreate),
|
ac.EvalPermission(datasources.ActionDatasourcesCreate),
|
||||||
ac.EvalPermission(ActionDatasourcesDelete),
|
ac.EvalPermission(datasources.ActionDatasourcesDelete),
|
||||||
ac.EvalPermission(ActionDatasourcesWrite),
|
ac.EvalPermission(datasources.ActionDatasourcesWrite),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
// dataSourcesNewAccessEvaluator is used to protect the "Configure > Data sources > New" page access
|
// dataSourcesNewAccessEvaluator is used to protect the "Configure > Data sources > New" page access
|
||||||
var dataSourcesNewAccessEvaluator = ac.EvalAll(
|
var dataSourcesNewAccessEvaluator = ac.EvalAll(
|
||||||
ac.EvalPermission(ActionDatasourcesRead),
|
ac.EvalPermission(datasources.ActionDatasourcesRead),
|
||||||
ac.EvalPermission(ActionDatasourcesCreate),
|
ac.EvalPermission(datasources.ActionDatasourcesCreate),
|
||||||
ac.EvalPermission(ActionDatasourcesWrite),
|
ac.EvalPermission(datasources.ActionDatasourcesWrite),
|
||||||
)
|
)
|
||||||
|
|
||||||
// dataSourcesEditAccessEvaluator is used to protect the "Configure > Data sources > Edit" page access
|
// dataSourcesEditAccessEvaluator is used to protect the "Configure > Data sources > Edit" page access
|
||||||
var dataSourcesEditAccessEvaluator = ac.EvalAll(
|
var dataSourcesEditAccessEvaluator = ac.EvalAll(
|
||||||
ac.EvalPermission(ActionDatasourcesRead),
|
ac.EvalPermission(datasources.ActionDatasourcesRead),
|
||||||
ac.EvalPermission(ActionDatasourcesWrite),
|
ac.EvalPermission(datasources.ActionDatasourcesWrite),
|
||||||
)
|
)
|
||||||
|
|
||||||
// orgPreferencesAccessEvaluator is used to protect the "Configure > Preferences" page access
|
// orgPreferencesAccessEvaluator is used to protect the "Configure > Preferences" page access
|
||||||
|
@ -12,6 +12,8 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
acmiddleware "github.com/grafana/grafana/pkg/services/accesscontrol/middleware"
|
acmiddleware "github.com/grafana/grafana/pkg/services/accesscontrol/middleware"
|
||||||
|
"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/featuremgmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -273,18 +275,18 @@ func (hs *HTTPServer) registerRoutes() {
|
|||||||
|
|
||||||
// Data sources
|
// Data sources
|
||||||
apiRoute.Group("/datasources", func(datasourceRoute routing.RouteRegister) {
|
apiRoute.Group("/datasources", func(datasourceRoute routing.RouteRegister) {
|
||||||
datasourceRoute.Get("/", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesRead)), routing.Wrap(hs.GetDataSources))
|
datasourceRoute.Get("/", authorize(reqOrgAdmin, ac.EvalPermission(datasources.ActionDatasourcesRead)), routing.Wrap(hs.GetDataSources))
|
||||||
datasourceRoute.Post("/", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesCreate)), quota("data_source"), routing.Wrap(hs.AddDataSource))
|
datasourceRoute.Post("/", authorize(reqOrgAdmin, ac.EvalPermission(datasources.ActionDatasourcesCreate)), quota("data_source"), routing.Wrap(hs.AddDataSource))
|
||||||
datasourceRoute.Put("/:id", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesWrite, ScopeDatasourceID)), routing.Wrap(hs.UpdateDataSource))
|
datasourceRoute.Put("/:id", authorize(reqOrgAdmin, ac.EvalPermission(datasources.ActionDatasourcesWrite, datasources.ScopeDatasourcesProvider.GetResourceScope(ac.Parameter(":id")))), routing.Wrap(hs.UpdateDataSource))
|
||||||
datasourceRoute.Delete("/:id", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesDelete, ScopeDatasourceID)), routing.Wrap(hs.DeleteDataSourceById))
|
datasourceRoute.Delete("/:id", authorize(reqOrgAdmin, ac.EvalPermission(datasources.ActionDatasourcesDelete, datasources.ScopeDatasourcesProvider.GetResourceScope(ac.Parameter(":id")))), routing.Wrap(hs.DeleteDataSourceById))
|
||||||
datasourceRoute.Delete("/uid/:uid", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesDelete, ScopeDatasourceUID)), routing.Wrap(hs.DeleteDataSourceByUID))
|
datasourceRoute.Delete("/uid/:uid", authorize(reqOrgAdmin, ac.EvalPermission(datasources.ActionDatasourcesDelete, datasources.ScopeDatasourcesProvider.GetResourceScopeUID(ac.Parameter(":uid")))), routing.Wrap(hs.DeleteDataSourceByUID))
|
||||||
datasourceRoute.Delete("/name/:name", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesDelete, ScopeDatasourceName)), routing.Wrap(hs.DeleteDataSourceByName))
|
datasourceRoute.Delete("/name/:name", authorize(reqOrgAdmin, ac.EvalPermission(datasources.ActionDatasourcesDelete, datasources.ScopeDatasourcesProvider.GetResourceScopeName(ac.Parameter(":name")))), routing.Wrap(hs.DeleteDataSourceByName))
|
||||||
datasourceRoute.Get("/:id", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesRead)), routing.Wrap(hs.GetDataSourceById))
|
datasourceRoute.Get("/:id", authorize(reqOrgAdmin, ac.EvalPermission(datasources.ActionDatasourcesRead)), routing.Wrap(hs.GetDataSourceById))
|
||||||
datasourceRoute.Get("/uid/:uid", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesRead)), routing.Wrap(hs.GetDataSourceByUID))
|
datasourceRoute.Get("/uid/:uid", authorize(reqOrgAdmin, ac.EvalPermission(datasources.ActionDatasourcesRead)), routing.Wrap(hs.GetDataSourceByUID))
|
||||||
datasourceRoute.Get("/name/:name", authorize(reqOrgAdmin, ac.EvalPermission(ActionDatasourcesRead)), routing.Wrap(hs.GetDataSourceByName))
|
datasourceRoute.Get("/name/:name", authorize(reqOrgAdmin, ac.EvalPermission(datasources.ActionDatasourcesRead)), routing.Wrap(hs.GetDataSourceByName))
|
||||||
})
|
})
|
||||||
|
|
||||||
apiRoute.Get("/datasources/id/:name", authorize(reqSignedIn, ac.EvalPermission(ActionDatasourcesIDRead, ScopeDatasourceName)), routing.Wrap(hs.GetDataSourceIdByName))
|
apiRoute.Get("/datasources/id/:name", authorize(reqSignedIn, ac.EvalPermission(datasources.ActionDatasourcesIDRead, datasources.ScopeDatasourcesProvider.GetResourceScopeName(ac.Parameter(":name")))), routing.Wrap(hs.GetDataSourceIdByName))
|
||||||
|
|
||||||
apiRoute.Get("/plugins", routing.Wrap(hs.GetPluginList))
|
apiRoute.Get("/plugins", routing.Wrap(hs.GetPluginList))
|
||||||
apiRoute.Get("/plugins/:pluginId/settings", routing.Wrap(hs.GetPluginSettingByID))
|
apiRoute.Get("/plugins/:pluginId/settings", routing.Wrap(hs.GetPluginSettingByID))
|
||||||
@ -306,26 +308,26 @@ func (hs *HTTPServer) registerRoutes() {
|
|||||||
}, reqOrgAdmin)
|
}, reqOrgAdmin)
|
||||||
|
|
||||||
apiRoute.Get("/frontend/settings/", hs.GetFrontendSettings)
|
apiRoute.Get("/frontend/settings/", hs.GetFrontendSettings)
|
||||||
apiRoute.Any("/datasources/proxy/:id/*", authorize(reqSignedIn, ac.EvalPermission(ActionDatasourcesQuery)), hs.ProxyDataSourceRequest)
|
apiRoute.Any("/datasources/proxy/:id/*", authorize(reqSignedIn, ac.EvalPermission(datasources.ActionDatasourcesQuery)), hs.ProxyDataSourceRequest)
|
||||||
apiRoute.Any("/datasources/proxy/:id", authorize(reqSignedIn, ac.EvalPermission(ActionDatasourcesQuery)), hs.ProxyDataSourceRequest)
|
apiRoute.Any("/datasources/proxy/:id", authorize(reqSignedIn, ac.EvalPermission(datasources.ActionDatasourcesQuery)), hs.ProxyDataSourceRequest)
|
||||||
apiRoute.Any("/datasources/:id/resources", authorize(reqSignedIn, ac.EvalPermission(ActionDatasourcesQuery)), hs.CallDatasourceResource)
|
apiRoute.Any("/datasources/:id/resources", authorize(reqSignedIn, ac.EvalPermission(datasources.ActionDatasourcesQuery)), hs.CallDatasourceResource)
|
||||||
apiRoute.Any("/datasources/:id/resources/*", authorize(reqSignedIn, ac.EvalPermission(ActionDatasourcesQuery)), hs.CallDatasourceResource)
|
apiRoute.Any("/datasources/:id/resources/*", authorize(reqSignedIn, ac.EvalPermission(datasources.ActionDatasourcesQuery)), hs.CallDatasourceResource)
|
||||||
apiRoute.Any("/datasources/:id/health", authorize(reqSignedIn, ac.EvalPermission(ActionDatasourcesQuery)), routing.Wrap(hs.CheckDatasourceHealth))
|
apiRoute.Any("/datasources/:id/health", authorize(reqSignedIn, ac.EvalPermission(datasources.ActionDatasourcesQuery)), routing.Wrap(hs.CheckDatasourceHealth))
|
||||||
|
|
||||||
// Folders
|
// Folders
|
||||||
apiRoute.Group("/folders", func(folderRoute routing.RouteRegister) {
|
apiRoute.Group("/folders", func(folderRoute routing.RouteRegister) {
|
||||||
folderRoute.Get("/", authorize(reqSignedIn, ac.EvalPermission(ac.ActionFoldersRead)), routing.Wrap(hs.GetFolders))
|
folderRoute.Get("/", authorize(reqSignedIn, ac.EvalPermission(dashboards.ActionFoldersRead)), routing.Wrap(hs.GetFolders))
|
||||||
folderRoute.Get("/id/:id", authorize(reqSignedIn, ac.EvalPermission(ac.ActionFoldersRead, ac.ScopeFolderID)), routing.Wrap(hs.GetFolderByID))
|
folderRoute.Get("/id/:id", authorize(reqSignedIn, ac.EvalPermission(dashboards.ActionFoldersRead, dashboards.ScopeFoldersProvider.GetResourceScope(ac.Parameter(":id")))), routing.Wrap(hs.GetFolderByID))
|
||||||
folderRoute.Post("/", authorize(reqSignedIn, ac.EvalPermission(ac.ActionFoldersCreate)), routing.Wrap(hs.CreateFolder))
|
folderRoute.Post("/", authorize(reqSignedIn, ac.EvalPermission(dashboards.ActionFoldersCreate)), routing.Wrap(hs.CreateFolder))
|
||||||
|
|
||||||
folderRoute.Group("/:uid", func(folderUidRoute routing.RouteRegister) {
|
folderRoute.Group("/:uid", func(folderUidRoute routing.RouteRegister) {
|
||||||
folderUidRoute.Get("/", authorize(reqSignedIn, ac.EvalPermission(ac.ActionFoldersRead)), routing.Wrap(hs.GetFolderByUID))
|
folderUidRoute.Get("/", authorize(reqSignedIn, ac.EvalPermission(dashboards.ActionFoldersRead)), routing.Wrap(hs.GetFolderByUID))
|
||||||
folderUidRoute.Put("/", authorize(reqSignedIn, ac.EvalPermission(ac.ActionFoldersWrite)), routing.Wrap(hs.UpdateFolder))
|
folderUidRoute.Put("/", authorize(reqSignedIn, ac.EvalPermission(dashboards.ActionFoldersWrite)), routing.Wrap(hs.UpdateFolder))
|
||||||
folderUidRoute.Delete("/", authorize(reqSignedIn, ac.EvalPermission(ac.ActionFoldersDelete)), routing.Wrap(hs.DeleteFolder))
|
folderUidRoute.Delete("/", authorize(reqSignedIn, ac.EvalPermission(dashboards.ActionFoldersDelete)), routing.Wrap(hs.DeleteFolder))
|
||||||
|
|
||||||
folderUidRoute.Group("/permissions", func(folderPermissionRoute routing.RouteRegister) {
|
folderUidRoute.Group("/permissions", func(folderPermissionRoute routing.RouteRegister) {
|
||||||
folderPermissionRoute.Get("/", authorize(reqSignedIn, ac.EvalPermission(ac.ActionFoldersPermissionsRead)), routing.Wrap(hs.GetFolderPermissionList))
|
folderPermissionRoute.Get("/", authorize(reqSignedIn, ac.EvalPermission(dashboards.ActionFoldersPermissionsRead)), routing.Wrap(hs.GetFolderPermissionList))
|
||||||
folderPermissionRoute.Post("/", authorize(reqSignedIn, ac.EvalPermission(ac.ActionFoldersPermissionsWrite)), routing.Wrap(hs.UpdateFolderPermissions))
|
folderPermissionRoute.Post("/", authorize(reqSignedIn, ac.EvalPermission(dashboards.ActionFoldersPermissionsWrite)), routing.Wrap(hs.UpdateFolderPermissions))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -384,13 +386,13 @@ func (hs *HTTPServer) registerRoutes() {
|
|||||||
apiRoute.Get("/search/", routing.Wrap(hs.Search))
|
apiRoute.Get("/search/", routing.Wrap(hs.Search))
|
||||||
|
|
||||||
// metrics
|
// metrics
|
||||||
apiRoute.Post("/tsdb/query", authorize(reqSignedIn, ac.EvalPermission(ActionDatasourcesQuery)), routing.Wrap(hs.QueryMetrics))
|
apiRoute.Post("/tsdb/query", authorize(reqSignedIn, ac.EvalPermission(datasources.ActionDatasourcesQuery)), routing.Wrap(hs.QueryMetrics))
|
||||||
|
|
||||||
// DataSource w/ expressions
|
// DataSource w/ expressions
|
||||||
apiRoute.Post("/ds/query", authorize(reqSignedIn, ac.EvalPermission(ActionDatasourcesQuery)), routing.Wrap(hs.QueryMetricsV2))
|
apiRoute.Post("/ds/query", authorize(reqSignedIn, ac.EvalPermission(datasources.ActionDatasourcesQuery)), routing.Wrap(hs.QueryMetricsV2))
|
||||||
|
|
||||||
// Validated query
|
// Validated query
|
||||||
apiRoute.Post("/dashboards/org/:orgId/uid/:dashboardUid/panels/:panelId/query", authorize(reqSignedIn, ac.EvalPermission(ActionDatasourcesQuery)), routing.Wrap(hs.QueryMetricsFromDashboard))
|
apiRoute.Post("/dashboards/org/:orgId/uid/:dashboardUid/panels/:panelId/query", authorize(reqSignedIn, ac.EvalPermission(datasources.ActionDatasourcesQuery)), routing.Wrap(hs.QueryMetricsFromDashboard))
|
||||||
|
|
||||||
apiRoute.Group("/alerts", func(alertsRoute routing.RouteRegister) {
|
apiRoute.Group("/alerts", func(alertsRoute routing.RouteRegister) {
|
||||||
alertsRoute.Post("/test", routing.Wrap(hs.AlertTest))
|
alertsRoute.Post("/test", routing.Wrap(hs.AlertTest))
|
||||||
|
@ -10,16 +10,17 @@ import (
|
|||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/api/response"
|
"github.com/grafana/grafana/pkg/api/response"
|
||||||
"github.com/grafana/grafana/pkg/api/routing"
|
"github.com/grafana/grafana/pkg/api/routing"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
"github.com/grafana/grafana/pkg/services/datasources"
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
"github.com/grafana/grafana/pkg/services/datasources/permissions"
|
"github.com/grafana/grafana/pkg/services/datasources/permissions"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -238,10 +239,10 @@ func TestAPI_Datasources_AccessControl(t *testing.T) {
|
|||||||
desc: "DatasourcesPut should return 404 if datasource not found",
|
desc: "DatasourcesPut should return 404 if datasource not found",
|
||||||
url: fmt.Sprintf("/api/datasources/%v", "12345678"),
|
url: fmt.Sprintf("/api/datasources/%v", "12345678"),
|
||||||
method: http.MethodPut,
|
method: http.MethodPut,
|
||||||
permissions: []*accesscontrol.Permission{
|
permissions: []*ac.Permission{
|
||||||
{
|
{
|
||||||
Action: ActionDatasourcesWrite,
|
Action: datasources.ActionDatasourcesWrite,
|
||||||
Scope: ScopeDatasourcesAll,
|
Scope: datasources.ScopeDatasourcesAll,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -253,7 +254,7 @@ func TestAPI_Datasources_AccessControl(t *testing.T) {
|
|||||||
desc: "DatasourcesGet should return 200 for user with correct permissions",
|
desc: "DatasourcesGet should return 200 for user with correct permissions",
|
||||||
url: "/api/datasources/",
|
url: "/api/datasources/",
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
permissions: []*accesscontrol.Permission{{Action: ActionDatasourcesRead, Scope: ScopeDatasourcesAll}},
|
permissions: []*ac.Permission{{Action: datasources.ActionDatasourcesRead, Scope: datasources.ScopeDatasourcesAll}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -262,7 +263,7 @@ func TestAPI_Datasources_AccessControl(t *testing.T) {
|
|||||||
desc: "DatasourcesGet should return 403 for user without required permissions",
|
desc: "DatasourcesGet should return 403 for user without required permissions",
|
||||||
url: "/api/datasources/",
|
url: "/api/datasources/",
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
permissions: []*accesscontrol.Permission{{Action: "wrong"}},
|
permissions: []*ac.Permission{{Action: "wrong"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -272,7 +273,7 @@ func TestAPI_Datasources_AccessControl(t *testing.T) {
|
|||||||
desc: "DatasourcesPost should return 200 for user with correct permissions",
|
desc: "DatasourcesPost should return 200 for user with correct permissions",
|
||||||
url: "/api/datasources/",
|
url: "/api/datasources/",
|
||||||
method: http.MethodPost,
|
method: http.MethodPost,
|
||||||
permissions: []*accesscontrol.Permission{{Action: ActionDatasourcesCreate}},
|
permissions: []*ac.Permission{{Action: datasources.ActionDatasourcesCreate}},
|
||||||
},
|
},
|
||||||
expectedDS: &testDatasource,
|
expectedDS: &testDatasource,
|
||||||
},
|
},
|
||||||
@ -282,7 +283,7 @@ func TestAPI_Datasources_AccessControl(t *testing.T) {
|
|||||||
desc: "DatasourcesPost should return 403 for user without required permissions",
|
desc: "DatasourcesPost should return 403 for user without required permissions",
|
||||||
url: "/api/datasources/",
|
url: "/api/datasources/",
|
||||||
method: http.MethodPost,
|
method: http.MethodPost,
|
||||||
permissions: []*accesscontrol.Permission{{Action: "wrong"}},
|
permissions: []*ac.Permission{{Action: "wrong"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -292,9 +293,9 @@ func TestAPI_Datasources_AccessControl(t *testing.T) {
|
|||||||
desc: "DatasourcesPut should return 200 for user with correct permissions",
|
desc: "DatasourcesPut should return 200 for user with correct permissions",
|
||||||
url: fmt.Sprintf("/api/datasources/%v", testDatasource.Id),
|
url: fmt.Sprintf("/api/datasources/%v", testDatasource.Id),
|
||||||
method: http.MethodPut,
|
method: http.MethodPut,
|
||||||
permissions: []*accesscontrol.Permission{
|
permissions: []*ac.Permission{
|
||||||
{
|
{
|
||||||
Action: ActionDatasourcesWrite,
|
Action: datasources.ActionDatasourcesWrite,
|
||||||
Scope: fmt.Sprintf("datasources:id:%v", testDatasource.Id),
|
Scope: fmt.Sprintf("datasources:id:%v", testDatasource.Id),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -307,7 +308,7 @@ func TestAPI_Datasources_AccessControl(t *testing.T) {
|
|||||||
desc: "DatasourcesPut should return 403 for user without required permissions",
|
desc: "DatasourcesPut should return 403 for user without required permissions",
|
||||||
url: fmt.Sprintf("/api/datasources/%v", testDatasource.Id),
|
url: fmt.Sprintf("/api/datasources/%v", testDatasource.Id),
|
||||||
method: http.MethodPut,
|
method: http.MethodPut,
|
||||||
permissions: []*accesscontrol.Permission{{Action: "wrong"}},
|
permissions: []*ac.Permission{{Action: "wrong"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -317,9 +318,9 @@ func TestAPI_Datasources_AccessControl(t *testing.T) {
|
|||||||
desc: "DatasourcesPut should return 403 for read only datasource",
|
desc: "DatasourcesPut should return 403 for read only datasource",
|
||||||
url: fmt.Sprintf("/api/datasources/%v", testDatasourceReadOnly.Id),
|
url: fmt.Sprintf("/api/datasources/%v", testDatasourceReadOnly.Id),
|
||||||
method: http.MethodPut,
|
method: http.MethodPut,
|
||||||
permissions: []*accesscontrol.Permission{
|
permissions: []*ac.Permission{
|
||||||
{
|
{
|
||||||
Action: ActionDatasourcesWrite,
|
Action: datasources.ActionDatasourcesWrite,
|
||||||
Scope: fmt.Sprintf("datasources:id:%v", testDatasourceReadOnly.Id),
|
Scope: fmt.Sprintf("datasources:id:%v", testDatasourceReadOnly.Id),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -332,9 +333,9 @@ func TestAPI_Datasources_AccessControl(t *testing.T) {
|
|||||||
desc: "DatasourcesDeleteByID should return 200 for user with correct permissions",
|
desc: "DatasourcesDeleteByID should return 200 for user with correct permissions",
|
||||||
url: fmt.Sprintf("/api/datasources/%v", testDatasource.Id),
|
url: fmt.Sprintf("/api/datasources/%v", testDatasource.Id),
|
||||||
method: http.MethodDelete,
|
method: http.MethodDelete,
|
||||||
permissions: []*accesscontrol.Permission{
|
permissions: []*ac.Permission{
|
||||||
{
|
{
|
||||||
Action: ActionDatasourcesDelete,
|
Action: datasources.ActionDatasourcesDelete,
|
||||||
Scope: fmt.Sprintf("datasources:id:%v", testDatasource.Id),
|
Scope: fmt.Sprintf("datasources:id:%v", testDatasource.Id),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -347,7 +348,7 @@ func TestAPI_Datasources_AccessControl(t *testing.T) {
|
|||||||
desc: "DatasourcesDeleteByID should return 403 for user without required permissions",
|
desc: "DatasourcesDeleteByID should return 403 for user without required permissions",
|
||||||
url: fmt.Sprintf("/api/datasources/%v", testDatasource.Id),
|
url: fmt.Sprintf("/api/datasources/%v", testDatasource.Id),
|
||||||
method: http.MethodDelete,
|
method: http.MethodDelete,
|
||||||
permissions: []*accesscontrol.Permission{{Action: "wrong"}},
|
permissions: []*ac.Permission{{Action: "wrong"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -356,9 +357,9 @@ func TestAPI_Datasources_AccessControl(t *testing.T) {
|
|||||||
desc: "DatasourcesDeleteByUID should return 200 for user with correct permissions",
|
desc: "DatasourcesDeleteByUID should return 200 for user with correct permissions",
|
||||||
url: fmt.Sprintf("/api/datasources/uid/%v", testDatasource.Uid),
|
url: fmt.Sprintf("/api/datasources/uid/%v", testDatasource.Uid),
|
||||||
method: http.MethodDelete,
|
method: http.MethodDelete,
|
||||||
permissions: []*accesscontrol.Permission{
|
permissions: []*ac.Permission{
|
||||||
{
|
{
|
||||||
Action: ActionDatasourcesDelete,
|
Action: datasources.ActionDatasourcesDelete,
|
||||||
Scope: fmt.Sprintf("datasources:uid:%v", testDatasource.Uid),
|
Scope: fmt.Sprintf("datasources:uid:%v", testDatasource.Uid),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -371,7 +372,7 @@ func TestAPI_Datasources_AccessControl(t *testing.T) {
|
|||||||
desc: "DatasourcesDeleteByUID should return 403 for user without required permissions",
|
desc: "DatasourcesDeleteByUID should return 403 for user without required permissions",
|
||||||
url: fmt.Sprintf("/api/datasources/uid/%v", testDatasource.Uid),
|
url: fmt.Sprintf("/api/datasources/uid/%v", testDatasource.Uid),
|
||||||
method: http.MethodDelete,
|
method: http.MethodDelete,
|
||||||
permissions: []*accesscontrol.Permission{{Action: "wrong"}},
|
permissions: []*ac.Permission{{Action: "wrong"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -380,9 +381,9 @@ func TestAPI_Datasources_AccessControl(t *testing.T) {
|
|||||||
desc: "DatasourcesDeleteByName should return 200 for user with correct permissions",
|
desc: "DatasourcesDeleteByName should return 200 for user with correct permissions",
|
||||||
url: fmt.Sprintf("/api/datasources/name/%v", testDatasource.Name),
|
url: fmt.Sprintf("/api/datasources/name/%v", testDatasource.Name),
|
||||||
method: http.MethodDelete,
|
method: http.MethodDelete,
|
||||||
permissions: []*accesscontrol.Permission{
|
permissions: []*ac.Permission{
|
||||||
{
|
{
|
||||||
Action: ActionDatasourcesDelete,
|
Action: datasources.ActionDatasourcesDelete,
|
||||||
Scope: fmt.Sprintf("datasources:name:%v", testDatasource.Name),
|
Scope: fmt.Sprintf("datasources:name:%v", testDatasource.Name),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -395,7 +396,7 @@ func TestAPI_Datasources_AccessControl(t *testing.T) {
|
|||||||
desc: "DatasourcesDeleteByName should return 403 for user without required permissions",
|
desc: "DatasourcesDeleteByName should return 403 for user without required permissions",
|
||||||
url: fmt.Sprintf("/api/datasources/name/%v", testDatasource.Name),
|
url: fmt.Sprintf("/api/datasources/name/%v", testDatasource.Name),
|
||||||
method: http.MethodDelete,
|
method: http.MethodDelete,
|
||||||
permissions: []*accesscontrol.Permission{{Action: "wrong"}},
|
permissions: []*ac.Permission{{Action: "wrong"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -404,9 +405,9 @@ func TestAPI_Datasources_AccessControl(t *testing.T) {
|
|||||||
desc: "DatasourcesGetByID should return 200 for user with correct permissions",
|
desc: "DatasourcesGetByID should return 200 for user with correct permissions",
|
||||||
url: fmt.Sprintf("/api/datasources/%v", testDatasource.Id),
|
url: fmt.Sprintf("/api/datasources/%v", testDatasource.Id),
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
permissions: []*accesscontrol.Permission{
|
permissions: []*ac.Permission{
|
||||||
{
|
{
|
||||||
Action: ActionDatasourcesRead,
|
Action: datasources.ActionDatasourcesRead,
|
||||||
Scope: fmt.Sprintf("datasources:id:%v", testDatasource.Id),
|
Scope: fmt.Sprintf("datasources:id:%v", testDatasource.Id),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -419,7 +420,7 @@ func TestAPI_Datasources_AccessControl(t *testing.T) {
|
|||||||
desc: "DatasourcesGetByID should return 403 for user without required permissions",
|
desc: "DatasourcesGetByID should return 403 for user without required permissions",
|
||||||
url: fmt.Sprintf("/api/datasources/%v", testDatasource.Id),
|
url: fmt.Sprintf("/api/datasources/%v", testDatasource.Id),
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
permissions: []*accesscontrol.Permission{{Action: "wrong"}},
|
permissions: []*ac.Permission{{Action: "wrong"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -428,9 +429,9 @@ func TestAPI_Datasources_AccessControl(t *testing.T) {
|
|||||||
desc: "DatasourcesGetByUID should return 200 for user with correct permissions",
|
desc: "DatasourcesGetByUID should return 200 for user with correct permissions",
|
||||||
url: fmt.Sprintf("/api/datasources/uid/%v", testDatasource.Uid),
|
url: fmt.Sprintf("/api/datasources/uid/%v", testDatasource.Uid),
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
permissions: []*accesscontrol.Permission{
|
permissions: []*ac.Permission{
|
||||||
{
|
{
|
||||||
Action: ActionDatasourcesRead,
|
Action: datasources.ActionDatasourcesRead,
|
||||||
Scope: fmt.Sprintf("datasources:uid:%v", testDatasource.Uid),
|
Scope: fmt.Sprintf("datasources:uid:%v", testDatasource.Uid),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -443,7 +444,7 @@ func TestAPI_Datasources_AccessControl(t *testing.T) {
|
|||||||
desc: "DatasourcesGetByUID should return 403 for user without required permissions",
|
desc: "DatasourcesGetByUID should return 403 for user without required permissions",
|
||||||
url: fmt.Sprintf("/api/datasources/uid/%v", testDatasource.Uid),
|
url: fmt.Sprintf("/api/datasources/uid/%v", testDatasource.Uid),
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
permissions: []*accesscontrol.Permission{{Action: "wrong"}},
|
permissions: []*ac.Permission{{Action: "wrong"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -452,9 +453,9 @@ func TestAPI_Datasources_AccessControl(t *testing.T) {
|
|||||||
desc: "DatasourcesGetByName should return 200 for user with correct permissions",
|
desc: "DatasourcesGetByName should return 200 for user with correct permissions",
|
||||||
url: fmt.Sprintf("/api/datasources/name/%v", testDatasource.Name),
|
url: fmt.Sprintf("/api/datasources/name/%v", testDatasource.Name),
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
permissions: []*accesscontrol.Permission{
|
permissions: []*ac.Permission{
|
||||||
{
|
{
|
||||||
Action: ActionDatasourcesRead,
|
Action: datasources.ActionDatasourcesRead,
|
||||||
Scope: fmt.Sprintf("datasources:name:%v", testDatasource.Name),
|
Scope: fmt.Sprintf("datasources:name:%v", testDatasource.Name),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -467,7 +468,7 @@ func TestAPI_Datasources_AccessControl(t *testing.T) {
|
|||||||
desc: "DatasourcesGetByName should return 403 for user without required permissions",
|
desc: "DatasourcesGetByName should return 403 for user without required permissions",
|
||||||
url: fmt.Sprintf("/api/datasources/name/%v", testDatasource.Name),
|
url: fmt.Sprintf("/api/datasources/name/%v", testDatasource.Name),
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
permissions: []*accesscontrol.Permission{{Action: "wrong"}},
|
permissions: []*ac.Permission{{Action: "wrong"}},
|
||||||
},
|
},
|
||||||
expectedDS: &testDatasource,
|
expectedDS: &testDatasource,
|
||||||
},
|
},
|
||||||
@ -477,9 +478,9 @@ func TestAPI_Datasources_AccessControl(t *testing.T) {
|
|||||||
desc: "DatasourcesGetIdByName should return 200 for user with correct permissions",
|
desc: "DatasourcesGetIdByName should return 200 for user with correct permissions",
|
||||||
url: fmt.Sprintf("/api/datasources/id/%v", testDatasource.Name),
|
url: fmt.Sprintf("/api/datasources/id/%v", testDatasource.Name),
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
permissions: []*accesscontrol.Permission{
|
permissions: []*ac.Permission{
|
||||||
{
|
{
|
||||||
Action: ActionDatasourcesIDRead,
|
Action: datasources.ActionDatasourcesIDRead,
|
||||||
Scope: fmt.Sprintf("datasources:name:%v", testDatasource.Name),
|
Scope: fmt.Sprintf("datasources:name:%v", testDatasource.Name),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -492,7 +493,7 @@ func TestAPI_Datasources_AccessControl(t *testing.T) {
|
|||||||
desc: "DatasourcesGetIdByName should return 403 for user without required permissions",
|
desc: "DatasourcesGetIdByName should return 403 for user without required permissions",
|
||||||
url: fmt.Sprintf("/api/datasources/id/%v", testDatasource.Name),
|
url: fmt.Sprintf("/api/datasources/id/%v", testDatasource.Name),
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
permissions: []*accesscontrol.Permission{{Action: "wrong"}},
|
permissions: []*ac.Permission{{Action: "wrong"}},
|
||||||
},
|
},
|
||||||
expectedDS: &testDatasource,
|
expectedDS: &testDatasource,
|
||||||
},
|
},
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/plugins"
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
@ -480,7 +481,7 @@ func (hs *HTTPServer) buildCreateNavLinks(c *models.ReqContext) []*dtos.NavLink
|
|||||||
children = append(children, &dtos.NavLink{Text: "Dashboard", Icon: "apps", Url: hs.Cfg.AppSubURL + "/dashboard/new", Id: "create-dashboard"})
|
children = append(children, &dtos.NavLink{Text: "Dashboard", Icon: "apps", Url: hs.Cfg.AppSubURL + "/dashboard/new", Id: "create-dashboard"})
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasAccess(ac.ReqOrgAdminOrEditor, ac.EvalPermission(ac.ActionFoldersCreate)) {
|
if hasAccess(ac.ReqOrgAdminOrEditor, ac.EvalPermission(dashboards.ActionFoldersCreate)) {
|
||||||
children = append(children, &dtos.NavLink{
|
children = append(children, &dtos.NavLink{
|
||||||
Text: "Folder", SubTitle: "Create a new folder to organize your dashboards", Id: "folder",
|
Text: "Folder", SubTitle: "Create a new folder to organize your dashboards", Id: "folder",
|
||||||
Icon: "folder-plus", Url: hs.Cfg.AppSubURL + "/dashboards/folder/new",
|
Icon: "folder-plus", Url: hs.Cfg.AppSubURL + "/dashboards/folder/new",
|
||||||
@ -553,7 +554,7 @@ func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewDat
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return hasEditPermissionInFoldersQuery.Result
|
return hasEditPermissionInFoldersQuery.Result
|
||||||
}, ac.EvalAny(ac.EvalPermission(ac.ActionDashboardsCreate), ac.EvalPermission(ac.ActionFoldersCreate)))
|
}, ac.EvalAny(ac.EvalPermission(ac.ActionDashboardsCreate), ac.EvalPermission(dashboards.ActionFoldersCreate)))
|
||||||
|
|
||||||
settings, err := hs.getFrontendSettingsMap(c)
|
settings, err := hs.getFrontendSettingsMap(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -346,17 +346,6 @@ const (
|
|||||||
|
|
||||||
// Dashboard scopes
|
// Dashboard scopes
|
||||||
ScopeDashboardsAll = "dashboards:*"
|
ScopeDashboardsAll = "dashboards:*"
|
||||||
|
|
||||||
// Folder actions
|
|
||||||
ActionFoldersCreate = "folders:create"
|
|
||||||
ActionFoldersRead = "folders:read"
|
|
||||||
ActionFoldersWrite = "folders:write"
|
|
||||||
ActionFoldersDelete = "folders:delete"
|
|
||||||
ActionFoldersPermissionsRead = "folders.permissions:read"
|
|
||||||
ActionFoldersPermissionsWrite = "folders.permissions:write"
|
|
||||||
|
|
||||||
// Folder scopes
|
|
||||||
ScopeFoldersAll = "folders:*"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -364,7 +353,9 @@ var (
|
|||||||
ScopeTeamsID = Scope("teams", "id", Parameter(":teamId"))
|
ScopeTeamsID = Scope("teams", "id", Parameter(":teamId"))
|
||||||
|
|
||||||
// Folder scopes
|
// Folder scopes
|
||||||
ScopeFolderID = Scope("folders", "id", Parameter(":id"))
|
|
||||||
|
// Datasource scopes
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const RoleGrafanaAdmin = "Grafana Admin"
|
const RoleGrafanaAdmin = "Grafana Admin"
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions"
|
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions"
|
||||||
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
@ -139,9 +140,9 @@ func ProvideTeamPermissions(
|
|||||||
var DashboardViewActions = []string{accesscontrol.ActionDashboardsRead}
|
var DashboardViewActions = []string{accesscontrol.ActionDashboardsRead}
|
||||||
var DashboardEditActions = append(DashboardViewActions, []string{accesscontrol.ActionDashboardsWrite, accesscontrol.ActionDashboardsDelete}...)
|
var DashboardEditActions = append(DashboardViewActions, []string{accesscontrol.ActionDashboardsWrite, accesscontrol.ActionDashboardsDelete}...)
|
||||||
var DashboardAdminActions = append(DashboardEditActions, []string{accesscontrol.ActionDashboardsPermissionsRead, accesscontrol.ActionDashboardsPermissionsWrite}...)
|
var DashboardAdminActions = append(DashboardEditActions, []string{accesscontrol.ActionDashboardsPermissionsRead, accesscontrol.ActionDashboardsPermissionsWrite}...)
|
||||||
var FolderViewActions = []string{accesscontrol.ActionFoldersRead}
|
var FolderViewActions = []string{dashboards.ActionFoldersRead}
|
||||||
var FolderEditActions = append(FolderViewActions, []string{accesscontrol.ActionFoldersWrite, accesscontrol.ActionFoldersDelete, accesscontrol.ActionDashboardsCreate}...)
|
var FolderEditActions = append(FolderViewActions, []string{dashboards.ActionFoldersWrite, dashboards.ActionFoldersDelete, accesscontrol.ActionDashboardsCreate}...)
|
||||||
var FolderAdminActions = append(FolderEditActions, []string{accesscontrol.ActionFoldersPermissionsRead, accesscontrol.ActionFoldersPermissionsWrite}...)
|
var FolderAdminActions = append(FolderEditActions, []string{dashboards.ActionFoldersPermissionsRead, dashboards.ActionFoldersPermissionsWrite}...)
|
||||||
|
|
||||||
func provideDashboardService(
|
func provideDashboardService(
|
||||||
cfg *setting.Cfg, router routing.RouteRegister, sql *sqlstore.SQLStore,
|
cfg *setting.Cfg, router routing.RouteRegister, sql *sqlstore.SQLStore,
|
||||||
|
@ -22,6 +22,14 @@ func GetResourceScope(resource string, resourceID string) string {
|
|||||||
return Scope(resource, "id", resourceID)
|
return Scope(resource, "id", resourceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetResourceScopeUID(resource string, resourceID string) string {
|
||||||
|
return Scope(resource, "uid", resourceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetResourceScopeName(resource string, resourceID string) string {
|
||||||
|
return Scope(resource, "name", resourceID)
|
||||||
|
}
|
||||||
|
|
||||||
func GetResourceAllScope(resource string) string {
|
func GetResourceAllScope(resource string) string {
|
||||||
return Scope(resource, "*")
|
return Scope(resource, "*")
|
||||||
}
|
}
|
||||||
@ -165,3 +173,48 @@ func ScopeInjector(params ScopeParams) ScopeMutator {
|
|||||||
return buf.String(), nil
|
return buf.String(), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ScopeProvider provides methods that construct scopes
|
||||||
|
type ScopeProvider interface {
|
||||||
|
GetResourceScope(resourceID string) string
|
||||||
|
GetResourceScopeUID(resourceID string) string
|
||||||
|
GetResourceScopeName(resourceID string) string
|
||||||
|
GetResourceAllScope() string
|
||||||
|
GetResourceAllIDScope() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type scopeProviderImpl struct {
|
||||||
|
root string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewScopeProvider creates a new ScopeProvider that is configured with specific root scope
|
||||||
|
func NewScopeProvider(root string) ScopeProvider {
|
||||||
|
return &scopeProviderImpl{
|
||||||
|
root: root,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResourceScope returns scope that has the format "<rootScope>:id:<resourceID>"
|
||||||
|
func (s scopeProviderImpl) GetResourceScope(resourceID string) string {
|
||||||
|
return GetResourceScope(s.root, resourceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResourceScopeUID returns scope that has the format "<rootScope>:uid:<resourceID>"
|
||||||
|
func (s scopeProviderImpl) GetResourceScopeUID(resourceID string) string {
|
||||||
|
return GetResourceScopeUID(s.root, resourceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResourceScopeName returns scope that has the format "<rootScope>:name:<resourceID>"
|
||||||
|
func (s scopeProviderImpl) GetResourceScopeName(resourceID string) string {
|
||||||
|
return GetResourceScopeName(s.root, resourceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResourceAllScope returns scope that has the format "<rootScope>:*"
|
||||||
|
func (s scopeProviderImpl) GetResourceAllScope() string {
|
||||||
|
return GetResourceAllScope(s.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResourceAllIDScope returns scope that has the format "<rootScope>:id:*"
|
||||||
|
func (s scopeProviderImpl) GetResourceAllIDScope() string {
|
||||||
|
return GetResourceAllIDScope(s.root)
|
||||||
|
}
|
||||||
|
19
pkg/services/dashboards/accesscontrol.go
Normal file
19
pkg/services/dashboards/accesscontrol.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package dashboards
|
||||||
|
|
||||||
|
import "github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
|
|
||||||
|
const (
|
||||||
|
ActionFoldersCreate = "folders:create"
|
||||||
|
ActionFoldersRead = "folders:read"
|
||||||
|
ActionFoldersWrite = "folders:write"
|
||||||
|
ActionFoldersDelete = "folders:delete"
|
||||||
|
ActionFoldersPermissionsRead = "folders.permissions:read"
|
||||||
|
ActionFoldersPermissionsWrite = "folders.permissions:write"
|
||||||
|
|
||||||
|
ScopeFoldersRoot = "folders"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ScopeFoldersAll = accesscontrol.GetResourceAllScope(ScopeFoldersRoot)
|
||||||
|
ScopeFoldersProvider = accesscontrol.NewScopeProvider(ScopeFoldersRoot)
|
||||||
|
)
|
@ -7,6 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
|
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
@ -21,10 +22,10 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
provisionerPermissions = map[string][]string{
|
provisionerPermissions = map[string][]string{
|
||||||
accesscontrol.ActionFoldersCreate: {},
|
m.ActionFoldersCreate: {},
|
||||||
accesscontrol.ActionFoldersWrite: {accesscontrol.ScopeFoldersAll},
|
m.ActionFoldersWrite: {m.ScopeFoldersAll},
|
||||||
accesscontrol.ActionDashboardsCreate: {accesscontrol.ScopeFoldersAll},
|
accesscontrol.ActionDashboardsCreate: {m.ScopeFoldersAll},
|
||||||
accesscontrol.ActionDashboardsWrite: {accesscontrol.ScopeFoldersAll},
|
accesscontrol.ActionDashboardsWrite: {m.ScopeFoldersAll},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
19
pkg/services/datasources/accesscontrol.go
Normal file
19
pkg/services/datasources/accesscontrol.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package datasources
|
||||||
|
|
||||||
|
import "github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
|
|
||||||
|
const (
|
||||||
|
ActionDatasourcesRead = "datasources:read"
|
||||||
|
ActionDatasourcesQuery = "datasources:query"
|
||||||
|
ActionDatasourcesCreate = "datasources:create"
|
||||||
|
ActionDatasourcesWrite = "datasources:write"
|
||||||
|
ActionDatasourcesDelete = "datasources:delete"
|
||||||
|
ActionDatasourcesIDRead = "datasources.id:read"
|
||||||
|
|
||||||
|
ScopeDatasourcesRoot = "datasources"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ScopeDatasourcesAll = accesscontrol.GetResourceAllScope(ScopeDatasourcesRoot)
|
||||||
|
ScopeDatasourcesProvider = accesscontrol.NewScopeProvider(ScopeDatasourcesRoot)
|
||||||
|
)
|
@ -11,11 +11,13 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/secrets"
|
"github.com/grafana/grafana/pkg/services/secrets"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
@ -96,14 +98,14 @@ type DataSourceRetriever interface {
|
|||||||
func NewNameScopeResolver(db DataSourceRetriever) (string, accesscontrol.AttributeScopeResolveFunc) {
|
func NewNameScopeResolver(db DataSourceRetriever) (string, accesscontrol.AttributeScopeResolveFunc) {
|
||||||
dsNameResolver := func(ctx context.Context, orgID int64, initialScope string) (string, error) {
|
dsNameResolver := func(ctx context.Context, orgID int64, initialScope string) (string, error) {
|
||||||
dsNames := strings.Split(initialScope, ":")
|
dsNames := strings.Split(initialScope, ":")
|
||||||
if dsNames[0] != "datasources" || len(dsNames) != 3 {
|
if dsNames[0] != datasources.ScopeDatasourcesRoot || len(dsNames) != 3 {
|
||||||
return "", accesscontrol.ErrInvalidScope
|
return "", accesscontrol.ErrInvalidScope
|
||||||
}
|
}
|
||||||
|
|
||||||
dsName := dsNames[2]
|
dsName := dsNames[2]
|
||||||
// Special wildcard case
|
// Special wildcard case
|
||||||
if dsName == "*" {
|
if dsName == "*" {
|
||||||
return accesscontrol.Scope("datasources", "id", "*"), nil
|
return datasources.ScopeDatasourcesProvider.GetResourceAllIDScope(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
query := models.GetDataSourceQuery{Name: dsName, OrgId: orgID}
|
query := models.GetDataSourceQuery{Name: dsName, OrgId: orgID}
|
||||||
@ -111,10 +113,10 @@ func NewNameScopeResolver(db DataSourceRetriever) (string, accesscontrol.Attribu
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return accesscontrol.Scope("datasources", "id", fmt.Sprintf("%v", query.Result.Id)), nil
|
return datasources.ScopeDatasourcesProvider.GetResourceScope(fmt.Sprintf("%v", query.Result.Id)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return "datasources:name:", dsNameResolver
|
return datasources.ScopeDatasourcesProvider.GetResourceScopeName(""), dsNameResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetDataSource(ctx context.Context, query *models.GetDataSourceQuery) error {
|
func (s *Service) GetDataSource(ctx context.Context, query *models.GetDataSourceQuery) error {
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
@ -48,7 +49,7 @@ func (a *AccessControlDashboardGuardian) CanSave() (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if a.dashboard.IsFolder {
|
if a.dashboard.IsFolder {
|
||||||
return a.ac.Evaluate(a.ctx, a.user, accesscontrol.EvalPermission(accesscontrol.ActionFoldersWrite, folderScope(a.dashboardID)))
|
return a.ac.Evaluate(a.ctx, a.user, accesscontrol.EvalPermission(dashboards.ActionFoldersWrite, folderScope(a.dashboardID)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.ac.Evaluate(a.ctx, a.user, accesscontrol.EvalAny(
|
return a.ac.Evaluate(a.ctx, a.user, accesscontrol.EvalAny(
|
||||||
@ -67,7 +68,7 @@ func (a *AccessControlDashboardGuardian) CanEdit() (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if a.dashboard.IsFolder {
|
if a.dashboard.IsFolder {
|
||||||
return a.ac.Evaluate(a.ctx, a.user, accesscontrol.EvalPermission(accesscontrol.ActionFoldersWrite, folderScope(a.dashboardID)))
|
return a.ac.Evaluate(a.ctx, a.user, accesscontrol.EvalPermission(dashboards.ActionFoldersWrite, folderScope(a.dashboardID)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.ac.Evaluate(a.ctx, a.user, accesscontrol.EvalAny(
|
return a.ac.Evaluate(a.ctx, a.user, accesscontrol.EvalAny(
|
||||||
@ -82,7 +83,7 @@ func (a *AccessControlDashboardGuardian) CanView() (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if a.dashboard.IsFolder {
|
if a.dashboard.IsFolder {
|
||||||
return a.ac.Evaluate(a.ctx, a.user, accesscontrol.EvalPermission(accesscontrol.ActionFoldersRead, folderScope(a.dashboardID)))
|
return a.ac.Evaluate(a.ctx, a.user, accesscontrol.EvalPermission(dashboards.ActionFoldersRead, folderScope(a.dashboardID)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.ac.Evaluate(a.ctx, a.user, accesscontrol.EvalAny(
|
return a.ac.Evaluate(a.ctx, a.user, accesscontrol.EvalAny(
|
||||||
@ -98,8 +99,8 @@ func (a *AccessControlDashboardGuardian) CanAdmin() (bool, error) {
|
|||||||
|
|
||||||
if a.dashboard.IsFolder {
|
if a.dashboard.IsFolder {
|
||||||
return a.ac.Evaluate(a.ctx, a.user, accesscontrol.EvalAll(
|
return a.ac.Evaluate(a.ctx, a.user, accesscontrol.EvalAll(
|
||||||
accesscontrol.EvalPermission(accesscontrol.ActionFoldersPermissionsRead, folderScope(a.dashboard.Id)),
|
accesscontrol.EvalPermission(dashboards.ActionFoldersPermissionsRead, folderScope(a.dashboard.Id)),
|
||||||
accesscontrol.EvalPermission(accesscontrol.ActionFoldersPermissionsWrite, folderScope(a.dashboard.Id)),
|
accesscontrol.EvalPermission(dashboards.ActionFoldersPermissionsWrite, folderScope(a.dashboard.Id)),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +122,7 @@ func (a *AccessControlDashboardGuardian) CanDelete() (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if a.dashboard.IsFolder {
|
if a.dashboard.IsFolder {
|
||||||
return a.ac.Evaluate(a.ctx, a.user, accesscontrol.EvalPermission(accesscontrol.ActionFoldersDelete, folderScope(a.dashboard.Id)))
|
return a.ac.Evaluate(a.ctx, a.user, accesscontrol.EvalPermission(dashboards.ActionFoldersDelete, folderScope(a.dashboard.Id)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.ac.Evaluate(a.ctx, a.user, accesscontrol.EvalAny(
|
return a.ac.Evaluate(a.ctx, a.user, accesscontrol.EvalAny(
|
||||||
@ -132,7 +133,7 @@ func (a *AccessControlDashboardGuardian) CanDelete() (bool, error) {
|
|||||||
|
|
||||||
func (a *AccessControlDashboardGuardian) CanCreate(folderID int64, isFolder bool) (bool, error) {
|
func (a *AccessControlDashboardGuardian) CanCreate(folderID int64, isFolder bool) (bool, error) {
|
||||||
if isFolder {
|
if isFolder {
|
||||||
return a.ac.Evaluate(a.ctx, a.user, accesscontrol.EvalPermission(accesscontrol.ActionFoldersCreate))
|
return a.ac.Evaluate(a.ctx, a.user, accesscontrol.EvalPermission(dashboards.ActionFoldersCreate))
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.ac.Evaluate(a.ctx, a.user, accesscontrol.EvalPermission(accesscontrol.ActionDashboardsCreate, folderScope(folderID)))
|
return a.ac.Evaluate(a.ctx, a.user, accesscontrol.EvalPermission(accesscontrol.ActionDashboardsCreate, folderScope(folderID)))
|
||||||
@ -251,5 +252,5 @@ func dashboardScope(dashboardID int64) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func folderScope(folderID int64) string {
|
func folderScope(folderID int64) string {
|
||||||
return accesscontrol.Scope("folders", "id", strconv.FormatInt(folderID, 10))
|
return dashboards.ScopeFoldersProvider.GetResourceScope(strconv.FormatInt(folderID, 10))
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/accesscontrol/database"
|
"github.com/grafana/grafana/pkg/services/accesscontrol/database"
|
||||||
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||||
"github.com/grafana/grafana/pkg/services/accesscontrol/ossaccesscontrol"
|
"github.com/grafana/grafana/pkg/services/accesscontrol/ossaccesscontrol"
|
||||||
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
dashdb "github.com/grafana/grafana/pkg/services/dashboards/database"
|
dashdb "github.com/grafana/grafana/pkg/services/dashboards/database"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
@ -516,7 +517,7 @@ func TestAccessControlDashboardGuardian_CanCreate(t *testing.T) {
|
|||||||
isFolder: true,
|
isFolder: true,
|
||||||
folderID: 0,
|
folderID: 0,
|
||||||
permissions: []*accesscontrol.Permission{
|
permissions: []*accesscontrol.Permission{
|
||||||
{Action: accesscontrol.ActionFoldersCreate},
|
{Action: dashboards.ActionFoldersCreate},
|
||||||
},
|
},
|
||||||
expected: true,
|
expected: true,
|
||||||
},
|
},
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
"github.com/grafana/grafana/pkg/services/search"
|
"github.com/grafana/grafana/pkg/services/search"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/permissions"
|
"github.com/grafana/grafana/pkg/services/sqlstore/permissions"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
|
||||||
@ -280,7 +281,7 @@ func deleteDashboard(cmd *models.DeleteDashboardCommand, sess *DBSession) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
// remove all access control permission with folder scope
|
// remove all access control permission with folder scope
|
||||||
_, err = sess.Exec("DELETE FROM permission WHERE scope = ?", ac.Scope("folders", "id", strconv.FormatInt(dashboard.Id, 10)))
|
_, err = sess.Exec("DELETE FROM permission WHERE scope = ?", dashboards.ScopeFoldersProvider.GetResourceScope(strconv.FormatInt(dashboard.Id, 10)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -35,21 +36,21 @@ var dashboardPermissionTranslation = map[models.PermissionType][]string{
|
|||||||
|
|
||||||
var folderPermissionTranslation = map[models.PermissionType][]string{
|
var folderPermissionTranslation = map[models.PermissionType][]string{
|
||||||
models.PERMISSION_VIEW: append(dashboardPermissionTranslation[models.PERMISSION_VIEW], []string{
|
models.PERMISSION_VIEW: append(dashboardPermissionTranslation[models.PERMISSION_VIEW], []string{
|
||||||
ac.ActionFoldersRead,
|
dashboards.ActionFoldersRead,
|
||||||
}...),
|
}...),
|
||||||
models.PERMISSION_EDIT: append(dashboardPermissionTranslation[models.PERMISSION_EDIT], []string{
|
models.PERMISSION_EDIT: append(dashboardPermissionTranslation[models.PERMISSION_EDIT], []string{
|
||||||
ac.ActionFoldersRead,
|
dashboards.ActionFoldersRead,
|
||||||
ac.ActionFoldersWrite,
|
dashboards.ActionFoldersWrite,
|
||||||
ac.ActionFoldersCreate,
|
dashboards.ActionFoldersCreate,
|
||||||
ac.ActionFoldersDelete,
|
dashboards.ActionFoldersDelete,
|
||||||
}...),
|
}...),
|
||||||
models.PERMISSION_ADMIN: append(dashboardPermissionTranslation[models.PERMISSION_ADMIN], []string{
|
models.PERMISSION_ADMIN: append(dashboardPermissionTranslation[models.PERMISSION_ADMIN], []string{
|
||||||
ac.ActionFoldersRead,
|
dashboards.ActionFoldersRead,
|
||||||
ac.ActionFoldersWrite,
|
dashboards.ActionFoldersWrite,
|
||||||
ac.ActionFoldersCreate,
|
dashboards.ActionFoldersCreate,
|
||||||
ac.ActionFoldersDelete,
|
dashboards.ActionFoldersDelete,
|
||||||
ac.ActionFoldersPermissionsRead,
|
dashboards.ActionFoldersPermissionsRead,
|
||||||
ac.ActionFoldersPermissionsWrite,
|
dashboards.ActionFoldersPermissionsWrite,
|
||||||
}...),
|
}...),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,7 +203,7 @@ func (m dashboardPermissionsMigrator) setPermissions(allRoles []*ac.Role, permis
|
|||||||
func (m dashboardPermissionsMigrator) mapPermission(id int64, p models.PermissionType, isFolder bool) []*ac.Permission {
|
func (m dashboardPermissionsMigrator) mapPermission(id int64, p models.PermissionType, isFolder bool) []*ac.Permission {
|
||||||
if isFolder {
|
if isFolder {
|
||||||
actions := folderPermissionTranslation[p]
|
actions := folderPermissionTranslation[p]
|
||||||
scope := ac.Scope("folders", "id", strconv.FormatInt(id, 10))
|
scope := dashboards.ScopeFoldersProvider.GetResourceScope(strconv.FormatInt(id, 10))
|
||||||
permissions := make([]*ac.Permission, 0, len(actions))
|
permissions := make([]*ac.Permission, 0, len(actions))
|
||||||
for _, action := range actions {
|
for _, action := range actions {
|
||||||
permissions = append(permissions, &ac.Permission{Action: action, Scope: scope})
|
permissions = append(permissions, &ac.Permission{Action: action, Scope: scope})
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -82,7 +83,7 @@ type AccessControlDashboardPermissionFilter struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f AccessControlDashboardPermissionFilter) Where() (string, []interface{}) {
|
func (f AccessControlDashboardPermissionFilter) Where() (string, []interface{}) {
|
||||||
folderAction := accesscontrol.ActionFoldersRead
|
folderAction := dashboards.ActionFoldersRead
|
||||||
dashboardAction := accesscontrol.ActionDashboardsRead
|
dashboardAction := accesscontrol.ActionDashboardsRead
|
||||||
if f.PermissionLevel == models.PERMISSION_EDIT {
|
if f.PermissionLevel == models.PERMISSION_EDIT {
|
||||||
folderAction = accesscontrol.ActionDashboardsCreate
|
folderAction = accesscontrol.ActionDashboardsCreate
|
||||||
|
Loading…
Reference in New Issue
Block a user