API: Restrict anonymous user information access (#18422)
Existing /api/alert-notifications now requires at least editor access. Existing /api/alert-notifiers now requires at least editor access. New /api/alert-notifications/lookup returns less information than /api/alert-notifications and can be access by any authenticated user. Existing /api/org/users now requires org admin role. New /api/org/users/lookup returns less information than /api/org/users and can be access by users that are org admins, admin in any folder or admin of any team. UserPicker component now uses /api/org/users/lookup instead of /api/org/users. Fixes #17318
This commit is contained in:
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/infra/metrics"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/search"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
@@ -25,17 +25,18 @@ func init() {
|
||||
bus.AddHandler("sql", GetDashboardsBySlug)
|
||||
bus.AddHandler("sql", ValidateDashboardBeforeSave)
|
||||
bus.AddHandler("sql", HasEditPermissionInFolders)
|
||||
bus.AddHandler("sql", HasAdminPermissionInFolders)
|
||||
}
|
||||
|
||||
var generateNewUid func() string = util.GenerateShortUID
|
||||
|
||||
func SaveDashboard(cmd *m.SaveDashboardCommand) error {
|
||||
func SaveDashboard(cmd *models.SaveDashboardCommand) error {
|
||||
return inTransaction(func(sess *DBSession) error {
|
||||
return saveDashboard(sess, cmd)
|
||||
})
|
||||
}
|
||||
|
||||
func saveDashboard(sess *DBSession, cmd *m.SaveDashboardCommand) error {
|
||||
func saveDashboard(sess *DBSession, cmd *models.SaveDashboardCommand) error {
|
||||
dash := cmd.GetDashboardModel()
|
||||
|
||||
userId := cmd.UserId
|
||||
@@ -45,13 +46,13 @@ func saveDashboard(sess *DBSession, cmd *m.SaveDashboardCommand) error {
|
||||
}
|
||||
|
||||
if dash.Id > 0 {
|
||||
var existing m.Dashboard
|
||||
var existing models.Dashboard
|
||||
dashWithIdExists, err := sess.Where("id=? AND org_id=?", dash.Id, dash.OrgId).Get(&existing)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !dashWithIdExists {
|
||||
return m.ErrDashboardNotFound
|
||||
return models.ErrDashboardNotFound
|
||||
}
|
||||
|
||||
// check for is someone else has written in between
|
||||
@@ -59,13 +60,13 @@ func saveDashboard(sess *DBSession, cmd *m.SaveDashboardCommand) error {
|
||||
if cmd.Overwrite {
|
||||
dash.SetVersion(existing.Version)
|
||||
} else {
|
||||
return m.ErrDashboardVersionMismatch
|
||||
return models.ErrDashboardVersionMismatch
|
||||
}
|
||||
}
|
||||
|
||||
// do not allow plugin dashboard updates without overwrite flag
|
||||
if existing.PluginId != "" && !cmd.Overwrite {
|
||||
return m.UpdatePluginDashboardError{PluginId: existing.PluginId}
|
||||
return models.UpdatePluginDashboardError{PluginId: existing.PluginId}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,10 +109,10 @@ func saveDashboard(sess *DBSession, cmd *m.SaveDashboardCommand) error {
|
||||
}
|
||||
|
||||
if affectedRows == 0 {
|
||||
return m.ErrDashboardNotFound
|
||||
return models.ErrDashboardNotFound
|
||||
}
|
||||
|
||||
dashVersion := &m.DashboardVersion{
|
||||
dashVersion := &models.DashboardVersion{
|
||||
DashboardId: dash.Id,
|
||||
ParentVersion: parentVersion,
|
||||
RestoredFrom: cmd.RestoredFrom,
|
||||
@@ -126,7 +127,7 @@ func saveDashboard(sess *DBSession, cmd *m.SaveDashboardCommand) error {
|
||||
if affectedRows, err = sess.Insert(dashVersion); err != nil {
|
||||
return err
|
||||
} else if affectedRows == 0 {
|
||||
return m.ErrDashboardNotFound
|
||||
return models.ErrDashboardNotFound
|
||||
}
|
||||
|
||||
// delete existing tags
|
||||
@@ -154,7 +155,7 @@ func generateNewDashboardUid(sess *DBSession, orgId int64) (string, error) {
|
||||
for i := 0; i < 3; i++ {
|
||||
uid := generateNewUid()
|
||||
|
||||
exists, err := sess.Where("org_id=? AND uid=?", orgId, uid).Get(&m.Dashboard{})
|
||||
exists, err := sess.Where("org_id=? AND uid=?", orgId, uid).Get(&models.Dashboard{})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -164,17 +165,17 @@ func generateNewDashboardUid(sess *DBSession, orgId int64) (string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return "", m.ErrDashboardFailedGenerateUniqueUid
|
||||
return "", models.ErrDashboardFailedGenerateUniqueUid
|
||||
}
|
||||
|
||||
func GetDashboard(query *m.GetDashboardQuery) error {
|
||||
dashboard := m.Dashboard{Slug: query.Slug, OrgId: query.OrgId, Id: query.Id, Uid: query.Uid}
|
||||
func GetDashboard(query *models.GetDashboardQuery) error {
|
||||
dashboard := models.Dashboard{Slug: query.Slug, OrgId: query.OrgId, Id: query.Id, Uid: query.Uid}
|
||||
has, err := x.Get(&dashboard)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !has {
|
||||
return m.ErrDashboardNotFound
|
||||
return models.ErrDashboardNotFound
|
||||
}
|
||||
|
||||
dashboard.SetId(dashboard.Id)
|
||||
@@ -262,7 +263,7 @@ func makeQueryResult(query *search.FindPersistedDashboardsQuery, res []Dashboard
|
||||
Uid: item.Uid,
|
||||
Title: item.Title,
|
||||
Uri: "db/" + item.Slug,
|
||||
Url: m.GetDashboardFolderUrl(item.IsFolder, item.Uid, item.Slug),
|
||||
Url: models.GetDashboardFolderUrl(item.IsFolder, item.Uid, item.Slug),
|
||||
Type: getHitType(item),
|
||||
FolderId: item.FolderId,
|
||||
FolderUid: item.FolderUid,
|
||||
@@ -271,7 +272,7 @@ func makeQueryResult(query *search.FindPersistedDashboardsQuery, res []Dashboard
|
||||
}
|
||||
|
||||
if item.FolderId > 0 {
|
||||
hit.FolderUrl = m.GetFolderUrl(item.FolderUid, item.FolderSlug)
|
||||
hit.FolderUrl = models.GetFolderUrl(item.FolderUid, item.FolderSlug)
|
||||
}
|
||||
|
||||
query.Result = append(query.Result, hit)
|
||||
@@ -283,7 +284,7 @@ func makeQueryResult(query *search.FindPersistedDashboardsQuery, res []Dashboard
|
||||
}
|
||||
}
|
||||
|
||||
func GetDashboardTags(query *m.GetDashboardTagsQuery) error {
|
||||
func GetDashboardTags(query *models.GetDashboardTagsQuery) error {
|
||||
sql := `SELECT
|
||||
COUNT(*) as count,
|
||||
term
|
||||
@@ -293,20 +294,20 @@ func GetDashboardTags(query *m.GetDashboardTagsQuery) error {
|
||||
GROUP BY term
|
||||
ORDER BY term`
|
||||
|
||||
query.Result = make([]*m.DashboardTagCloudItem, 0)
|
||||
query.Result = make([]*models.DashboardTagCloudItem, 0)
|
||||
sess := x.SQL(sql, query.OrgId)
|
||||
err := sess.Find(&query.Result)
|
||||
return err
|
||||
}
|
||||
|
||||
func DeleteDashboard(cmd *m.DeleteDashboardCommand) error {
|
||||
func DeleteDashboard(cmd *models.DeleteDashboardCommand) error {
|
||||
return inTransaction(func(sess *DBSession) error {
|
||||
dashboard := m.Dashboard{Id: cmd.Id, OrgId: cmd.OrgId}
|
||||
dashboard := models.Dashboard{Id: cmd.Id, OrgId: cmd.OrgId}
|
||||
has, err := sess.Get(&dashboard)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !has {
|
||||
return m.ErrDashboardNotFound
|
||||
return models.ErrDashboardNotFound
|
||||
}
|
||||
|
||||
deletes := []string{
|
||||
@@ -354,12 +355,12 @@ func DeleteDashboard(cmd *m.DeleteDashboardCommand) error {
|
||||
})
|
||||
}
|
||||
|
||||
func GetDashboards(query *m.GetDashboardsQuery) error {
|
||||
func GetDashboards(query *models.GetDashboardsQuery) error {
|
||||
if len(query.DashboardIds) == 0 {
|
||||
return m.ErrCommandValidationFailed
|
||||
return models.ErrCommandValidationFailed
|
||||
}
|
||||
|
||||
var dashboards = make([]*m.Dashboard, 0)
|
||||
var dashboards = make([]*models.Dashboard, 0)
|
||||
|
||||
err := x.In("id", query.DashboardIds).Find(&dashboards)
|
||||
query.Result = dashboards
|
||||
@@ -368,18 +369,18 @@ func GetDashboards(query *m.GetDashboardsQuery) error {
|
||||
|
||||
// GetDashboardPermissionsForUser returns the maximum permission the specified user has for a dashboard(s)
|
||||
// The function takes in a list of dashboard ids and the user id and role
|
||||
func GetDashboardPermissionsForUser(query *m.GetDashboardPermissionsForUserQuery) error {
|
||||
func GetDashboardPermissionsForUser(query *models.GetDashboardPermissionsForUserQuery) error {
|
||||
if len(query.DashboardIds) == 0 {
|
||||
return m.ErrCommandValidationFailed
|
||||
return models.ErrCommandValidationFailed
|
||||
}
|
||||
|
||||
if query.OrgRole == m.ROLE_ADMIN {
|
||||
var permissions = make([]*m.DashboardPermissionForUser, 0)
|
||||
if query.OrgRole == models.ROLE_ADMIN {
|
||||
var permissions = make([]*models.DashboardPermissionForUser, 0)
|
||||
for _, d := range query.DashboardIds {
|
||||
permissions = append(permissions, &m.DashboardPermissionForUser{
|
||||
permissions = append(permissions, &models.DashboardPermissionForUser{
|
||||
DashboardId: d,
|
||||
Permission: m.PERMISSION_ADMIN,
|
||||
PermissionName: m.PERMISSION_ADMIN.String(),
|
||||
Permission: models.PERMISSION_ADMIN,
|
||||
PermissionName: models.PERMISSION_ADMIN.String(),
|
||||
})
|
||||
}
|
||||
query.Result = permissions
|
||||
@@ -436,8 +437,8 @@ func GetDashboardPermissionsForUser(query *m.GetDashboardPermissionsForUserQuery
|
||||
return err
|
||||
}
|
||||
|
||||
func GetDashboardsByPluginId(query *m.GetDashboardsByPluginIdQuery) error {
|
||||
var dashboards = make([]*m.Dashboard, 0)
|
||||
func GetDashboardsByPluginId(query *models.GetDashboardsByPluginIdQuery) error {
|
||||
var dashboards = make([]*models.Dashboard, 0)
|
||||
whereExpr := "org_id=? AND plugin_id=? AND is_folder=" + dialect.BooleanStr(false)
|
||||
|
||||
err := x.Where(whereExpr, query.OrgId, query.PluginId).Find(&dashboards)
|
||||
@@ -449,7 +450,7 @@ type DashboardSlugDTO struct {
|
||||
Slug string
|
||||
}
|
||||
|
||||
func GetDashboardSlugById(query *m.GetDashboardSlugByIdQuery) error {
|
||||
func GetDashboardSlugById(query *models.GetDashboardSlugByIdQuery) error {
|
||||
var rawSql = `SELECT slug from dashboard WHERE Id=?`
|
||||
var slug = DashboardSlugDTO{}
|
||||
|
||||
@@ -458,15 +459,15 @@ func GetDashboardSlugById(query *m.GetDashboardSlugByIdQuery) error {
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !exists {
|
||||
return m.ErrDashboardNotFound
|
||||
return models.ErrDashboardNotFound
|
||||
}
|
||||
|
||||
query.Result = slug.Slug
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetDashboardsBySlug(query *m.GetDashboardsBySlugQuery) error {
|
||||
var dashboards []*m.Dashboard
|
||||
func GetDashboardsBySlug(query *models.GetDashboardsBySlugQuery) error {
|
||||
var dashboards []*models.Dashboard
|
||||
|
||||
if err := x.Where("org_id=? AND slug=?", query.OrgId, query.Slug).Find(&dashboards); err != nil {
|
||||
return err
|
||||
@@ -476,28 +477,28 @@ func GetDashboardsBySlug(query *m.GetDashboardsBySlugQuery) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetDashboardUIDById(query *m.GetDashboardRefByIdQuery) error {
|
||||
func GetDashboardUIDById(query *models.GetDashboardRefByIdQuery) error {
|
||||
var rawSql = `SELECT uid, slug from dashboard WHERE Id=?`
|
||||
|
||||
us := &m.DashboardRef{}
|
||||
us := &models.DashboardRef{}
|
||||
|
||||
exists, err := x.SQL(rawSql, query.Id).Get(us)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !exists {
|
||||
return m.ErrDashboardNotFound
|
||||
return models.ErrDashboardNotFound
|
||||
}
|
||||
|
||||
query.Result = us
|
||||
return nil
|
||||
}
|
||||
|
||||
func getExistingDashboardByIdOrUidForUpdate(sess *DBSession, cmd *m.ValidateDashboardBeforeSaveCommand) (err error) {
|
||||
func getExistingDashboardByIdOrUidForUpdate(sess *DBSession, cmd *models.ValidateDashboardBeforeSaveCommand) (err error) {
|
||||
dash := cmd.Dashboard
|
||||
|
||||
dashWithIdExists := false
|
||||
var existingById m.Dashboard
|
||||
var existingById models.Dashboard
|
||||
|
||||
if dash.Id > 0 {
|
||||
dashWithIdExists, err = sess.Where("id=? AND org_id=?", dash.Id, dash.OrgId).Get(&existingById)
|
||||
@@ -506,7 +507,7 @@ func getExistingDashboardByIdOrUidForUpdate(sess *DBSession, cmd *m.ValidateDash
|
||||
}
|
||||
|
||||
if !dashWithIdExists {
|
||||
return m.ErrDashboardNotFound
|
||||
return models.ErrDashboardNotFound
|
||||
}
|
||||
|
||||
if dash.Uid == "" {
|
||||
@@ -515,7 +516,7 @@ func getExistingDashboardByIdOrUidForUpdate(sess *DBSession, cmd *m.ValidateDash
|
||||
}
|
||||
|
||||
dashWithUidExists := false
|
||||
var existingByUid m.Dashboard
|
||||
var existingByUid models.Dashboard
|
||||
|
||||
if dash.Uid != "" {
|
||||
dashWithUidExists, err = sess.Where("org_id=? AND uid=?", dash.OrgId, dash.Uid).Get(&existingByUid)
|
||||
@@ -525,14 +526,14 @@ func getExistingDashboardByIdOrUidForUpdate(sess *DBSession, cmd *m.ValidateDash
|
||||
}
|
||||
|
||||
if dash.FolderId > 0 {
|
||||
var existingFolder m.Dashboard
|
||||
var existingFolder models.Dashboard
|
||||
folderExists, folderErr := sess.Where("org_id=? AND id=? AND is_folder=?", dash.OrgId, dash.FolderId, dialect.BooleanStr(true)).Get(&existingFolder)
|
||||
if folderErr != nil {
|
||||
return folderErr
|
||||
}
|
||||
|
||||
if !folderExists {
|
||||
return m.ErrDashboardFolderNotFound
|
||||
return models.ErrDashboardFolderNotFound
|
||||
}
|
||||
}
|
||||
|
||||
@@ -541,7 +542,7 @@ func getExistingDashboardByIdOrUidForUpdate(sess *DBSession, cmd *m.ValidateDash
|
||||
}
|
||||
|
||||
if dashWithIdExists && dashWithUidExists && existingById.Id != existingByUid.Id {
|
||||
return m.ErrDashboardWithSameUIDExists
|
||||
return models.ErrDashboardWithSameUIDExists
|
||||
}
|
||||
|
||||
existing := existingById
|
||||
@@ -558,7 +559,7 @@ func getExistingDashboardByIdOrUidForUpdate(sess *DBSession, cmd *m.ValidateDash
|
||||
|
||||
if (existing.IsFolder && !dash.IsFolder) ||
|
||||
(!existing.IsFolder && dash.IsFolder) {
|
||||
return m.ErrDashboardTypeMismatch
|
||||
return models.ErrDashboardTypeMismatch
|
||||
}
|
||||
|
||||
if !dash.IsFolder && dash.FolderId != existing.FolderId {
|
||||
@@ -570,21 +571,21 @@ func getExistingDashboardByIdOrUidForUpdate(sess *DBSession, cmd *m.ValidateDash
|
||||
if cmd.Overwrite {
|
||||
dash.SetVersion(existing.Version)
|
||||
} else {
|
||||
return m.ErrDashboardVersionMismatch
|
||||
return models.ErrDashboardVersionMismatch
|
||||
}
|
||||
}
|
||||
|
||||
// do not allow plugin dashboard updates without overwrite flag
|
||||
if existing.PluginId != "" && !cmd.Overwrite {
|
||||
return m.UpdatePluginDashboardError{PluginId: existing.PluginId}
|
||||
return models.UpdatePluginDashboardError{PluginId: existing.PluginId}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getExistingDashboardByTitleAndFolder(sess *DBSession, cmd *m.ValidateDashboardBeforeSaveCommand) error {
|
||||
func getExistingDashboardByTitleAndFolder(sess *DBSession, cmd *models.ValidateDashboardBeforeSaveCommand) error {
|
||||
dash := cmd.Dashboard
|
||||
var existing m.Dashboard
|
||||
var existing models.Dashboard
|
||||
|
||||
exists, err := sess.Where("org_id=? AND slug=? AND (is_folder=? OR folder_id=?)", dash.OrgId, dash.Slug, dialect.BooleanStr(true), dash.FolderId).Get(&existing)
|
||||
if err != nil {
|
||||
@@ -593,11 +594,11 @@ func getExistingDashboardByTitleAndFolder(sess *DBSession, cmd *m.ValidateDashbo
|
||||
|
||||
if exists && dash.Id != existing.Id {
|
||||
if existing.IsFolder && !dash.IsFolder {
|
||||
return m.ErrDashboardWithSameNameAsFolder
|
||||
return models.ErrDashboardWithSameNameAsFolder
|
||||
}
|
||||
|
||||
if !existing.IsFolder && dash.IsFolder {
|
||||
return m.ErrDashboardFolderWithSameNameAsDashboard
|
||||
return models.ErrDashboardFolderWithSameNameAsDashboard
|
||||
}
|
||||
|
||||
if !dash.IsFolder && (dash.FolderId != existing.FolderId || dash.Id == 0) {
|
||||
@@ -609,15 +610,15 @@ func getExistingDashboardByTitleAndFolder(sess *DBSession, cmd *m.ValidateDashbo
|
||||
dash.SetUid(existing.Uid)
|
||||
dash.SetVersion(existing.Version)
|
||||
} else {
|
||||
return m.ErrDashboardWithSameNameInFolderExists
|
||||
return models.ErrDashboardWithSameNameInFolderExists
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ValidateDashboardBeforeSave(cmd *m.ValidateDashboardBeforeSaveCommand) (err error) {
|
||||
cmd.Result = &m.ValidateDashboardBeforeSaveResult{}
|
||||
func ValidateDashboardBeforeSave(cmd *models.ValidateDashboardBeforeSaveCommand) (err error) {
|
||||
cmd.Result = &models.ValidateDashboardBeforeSaveResult{}
|
||||
return inTransaction(func(sess *DBSession) error {
|
||||
if err = getExistingDashboardByIdOrUidForUpdate(sess, cmd); err != nil {
|
||||
return err
|
||||
@@ -631,15 +632,39 @@ func ValidateDashboardBeforeSave(cmd *m.ValidateDashboardBeforeSaveCommand) (err
|
||||
})
|
||||
}
|
||||
|
||||
func HasEditPermissionInFolders(query *m.HasEditPermissionInFoldersQuery) error {
|
||||
if query.SignedInUser.HasRole(m.ROLE_EDITOR) {
|
||||
func HasEditPermissionInFolders(query *models.HasEditPermissionInFoldersQuery) error {
|
||||
if query.SignedInUser.HasRole(models.ROLE_EDITOR) {
|
||||
query.Result = true
|
||||
return nil
|
||||
}
|
||||
|
||||
builder := &SqlBuilder{}
|
||||
builder.Write("SELECT COUNT(dashboard.id) AS count FROM dashboard WHERE dashboard.org_id = ? AND dashboard.is_folder = ?", query.SignedInUser.OrgId, dialect.BooleanStr(true))
|
||||
builder.writeDashboardPermissionFilter(query.SignedInUser, m.PERMISSION_EDIT)
|
||||
builder.writeDashboardPermissionFilter(query.SignedInUser, models.PERMISSION_EDIT)
|
||||
|
||||
type folderCount struct {
|
||||
Count int64
|
||||
}
|
||||
|
||||
resp := make([]*folderCount, 0)
|
||||
if err := x.SQL(builder.GetSqlString(), builder.params...).Find(&resp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
query.Result = len(resp) > 0 && resp[0].Count > 0
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func HasAdminPermissionInFolders(query *models.HasAdminPermissionInFoldersQuery) error {
|
||||
if query.SignedInUser.HasRole(models.ROLE_ADMIN) {
|
||||
query.Result = true
|
||||
return nil
|
||||
}
|
||||
|
||||
builder := &SqlBuilder{}
|
||||
builder.Write("SELECT COUNT(dashboard.id) AS count FROM dashboard WHERE dashboard.org_id = ? AND dashboard.is_folder = ?", query.SignedInUser.OrgId, dialect.BooleanStr(true))
|
||||
builder.writeDashboardPermissionFilter(query.SignedInUser, models.PERMISSION_ADMIN)
|
||||
|
||||
type folderCount struct {
|
||||
Count int64
|
||||
|
||||
Reference in New Issue
Block a user