diff --git a/pkg/api/api.go b/pkg/api/api.go index 39b332aeb9f..dcbc3a7c58f 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -234,13 +234,13 @@ func (hs *HTTPServer) registerRoutes() { datasourceRoute.Get("/", Wrap(GetDataSources)) datasourceRoute.Post("/", quota("data_source"), bind(m.AddDataSourceCommand{}), Wrap(AddDataSource)) datasourceRoute.Put("/:id", bind(m.UpdateDataSourceCommand{}), Wrap(UpdateDataSource)) - datasourceRoute.Delete("/:id", Wrap(DeleteDataSourceByID)) + datasourceRoute.Delete("/:id", Wrap(DeleteDataSourceById)) datasourceRoute.Delete("/name/:name", Wrap(DeleteDataSourceByName)) - datasourceRoute.Get("/:id", Wrap(GetDataSourceByID)) + datasourceRoute.Get("/:id", Wrap(GetDataSourceById)) datasourceRoute.Get("/name/:name", Wrap(GetDataSourceByName)) }, reqOrgAdmin) - apiRoute.Get("/datasources/id/:name", Wrap(GetDataSourceIDByName), reqSignedIn) + apiRoute.Get("/datasources/id/:name", Wrap(GetDataSourceIdByName), reqSignedIn) apiRoute.Get("/plugins", Wrap(GetPluginList)) apiRoute.Get("/plugins/:pluginId/settings", Wrap(GetPluginSettingByID)) diff --git a/pkg/api/datasources.go b/pkg/api/datasources.go index 23dbb221d71..b1b13d7abfd 100644 --- a/pkg/api/datasources.go +++ b/pkg/api/datasources.go @@ -20,8 +20,8 @@ func GetDataSources(c *m.ReqContext) Response { result := make(dtos.DataSourceList, 0) for _, ds := range query.Result { dsItem := dtos.DataSourceListItemDTO{ - Id: ds.Id, OrgId: ds.OrgId, + Id: ds.Id, Name: ds.Name, Url: ds.Url, Type: ds.Type, @@ -49,7 +49,27 @@ func GetDataSources(c *m.ReqContext) Response { return JSON(200, &result) } -func GetDataSourceByID(c *m.ReqContext) Response { +func hasRequiredDatasourcePermission(dsId int64, permission m.DataSourcePermissionType, user *m.SignedInUser) Response { + query := m.HasRequiredDataSourcePermissionQuery{ + Id: dsId, + User: user, + RequiredPermission: permission, + } + + if err := bus.Dispatch(&query); err != nil { + if err == bus.ErrHandlerNotFound { + return nil + } + if err == m.ErrDataSourceAccessDenied { + return Error(403, err.Error(), nil) + } + return Error(500, "Failed to check data source permissions", err) + } + + return nil +} + +func GetDataSourceById(c *m.ReqContext) Response { query := m.GetDataSourceByIdQuery{ Id: c.ParamsInt64(":id"), OrgId: c.OrgId, @@ -68,14 +88,14 @@ func GetDataSourceByID(c *m.ReqContext) Response { return JSON(200, &dtos) } -func DeleteDataSourceByID(c *m.ReqContext) Response { +func DeleteDataSourceById(c *m.ReqContext) Response { id := c.ParamsInt64(":id") if id <= 0 { return Error(400, "Missing valid datasource id", nil) } - ds, err := getRawDataSourceByID(id, c.OrgId) + ds, err := getRawDataSourceById(id, c.OrgId) if err != nil { return Error(400, "Failed to delete datasource", nil) } @@ -186,7 +206,7 @@ func fillWithSecureJSONData(cmd *m.UpdateDataSourceCommand) error { return nil } - ds, err := getRawDataSourceByID(cmd.Id, cmd.OrgId) + ds, err := getRawDataSourceById(cmd.Id, cmd.OrgId) if err != nil { return err } @@ -206,7 +226,7 @@ func fillWithSecureJSONData(cmd *m.UpdateDataSourceCommand) error { return nil } -func getRawDataSourceByID(id int64, orgID int64) (*m.DataSource, error) { +func getRawDataSourceById(id int64, orgID int64) (*m.DataSource, error) { query := m.GetDataSourceByIdQuery{ Id: id, OrgId: orgID, @@ -236,7 +256,7 @@ func GetDataSourceByName(c *m.ReqContext) Response { } // Get /api/datasources/id/:name -func GetDataSourceIDByName(c *m.ReqContext) Response { +func GetDataSourceIdByName(c *m.ReqContext) Response { query := m.GetDataSourceByNameQuery{Name: c.Params(":name"), OrgId: c.OrgId} if err := bus.Dispatch(&query); err != nil { diff --git a/pkg/cmd/grafana-server/server.go b/pkg/cmd/grafana-server/server.go index b2f4a620208..8794d7d8338 100644 --- a/pkg/cmd/grafana-server/server.go +++ b/pkg/cmd/grafana-server/server.go @@ -32,7 +32,6 @@ import ( _ "github.com/grafana/grafana/pkg/plugins" _ "github.com/grafana/grafana/pkg/services/alerting" _ "github.com/grafana/grafana/pkg/services/cleanup" - _ "github.com/grafana/grafana/pkg/services/datasources" _ "github.com/grafana/grafana/pkg/services/notifications" _ "github.com/grafana/grafana/pkg/services/provisioning" _ "github.com/grafana/grafana/pkg/services/rendering" diff --git a/pkg/models/datasource.go b/pkg/models/datasource.go index cbdd0136f4d..d602acb3ed2 100644 --- a/pkg/models/datasource.go +++ b/pkg/models/datasource.go @@ -29,6 +29,7 @@ var ( ErrDataSourceNameExists = errors.New("Data source with same name already exists") ErrDataSourceUpdatingOldVersion = errors.New("Trying to update old version of datasource") ErrDatasourceIsReadOnly = errors.New("Data source is readonly. Can only be updated from configuration.") + ErrDataSourceAccessDenied = errors.New("Data source access denied") ) type DsAccess string @@ -165,6 +166,7 @@ type DeleteDataSourceByNameCommand struct { type GetDataSourcesQuery struct { OrgId int64 + User *SignedInUser Result []*DataSource } @@ -185,6 +187,26 @@ type GetDataSourceByNameQuery struct { } // --------------------- -// EVENTS -type DataSourceCreatedEvent struct { +// Permissions +// --------------------- + +type DataSourcePermissionType int + +const ( + DsPermissionQuery DataSourcePermissionType = 1 << iota + DsPermissionAdmin +) + +func (p DataSourcePermissionType) String() string { + names := map[int]string{ + int(DsPermissionQuery): "Query", + int(DsPermissionAdmin): "Admin", + } + return names[int(p)] +} + +type HasRequiredDataSourcePermissionQuery struct { + Id int64 + User *SignedInUser + RequiredPermission DataSourcePermissionType } diff --git a/pkg/services/datasources/datasource_service.go b/pkg/services/datasources/datasource_service.go deleted file mode 100644 index 2fba0bb5b87..00000000000 --- a/pkg/services/datasources/datasource_service.go +++ /dev/null @@ -1,50 +0,0 @@ -package datasources - -import ( - "github.com/grafana/grafana/pkg/log" - "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/registry" - "github.com/grafana/grafana/pkg/setting" -) - -type DataSourceService interface { - GetById(id int64, user *models.SignedInUser) (*models.DataSource, error) -} - -type DataSourceServiceImpl struct { - log log.Logger - Cfg *setting.Cfg `inject:""` - Guardian DataSourceGuardian `inject:""` -} - -func init() { - registry.RegisterService(&DataSourceServiceImpl{}) - registry.RegisterService(&DataSourceGuardianNoop{}) -} - -func (srv *DataSourceServiceImpl) Init() error { - srv.log = log.New("datasources") - srv.log.Info("hello", "guardian", srv.Guardian.GetPermission(0, nil)) - return nil -} - -func (srv *DataSourceServiceImpl) GetById(id int64, user *models.SignedInUser) { - // check cache - // Get by id from db - // check permissions -} - -type DataSourceGuardian interface { - GetPermission(id int64, user *models.SignedInUser) bool -} - -type DataSourceGuardianNoop struct { -} - -func (dsg *DataSourceGuardianNoop) Init() error { - return nil -} - -func (dsg *DataSourceGuardianNoop) GetPermission(id int64, user *models.SignedInUser) bool { - return false -} diff --git a/pkg/services/sqlstore/datasource.go b/pkg/services/sqlstore/datasource.go index 00d520bcfc6..7f70e5c25fc 100644 --- a/pkg/services/sqlstore/datasource.go +++ b/pkg/services/sqlstore/datasource.go @@ -27,6 +27,7 @@ func GetDataSourceById(query *m.GetDataSourceByIdQuery) error { datasource := m.DataSource{OrgId: query.OrgId, Id: query.Id} has, err := x.Get(&datasource) + if err != nil { return err }