LibraryPanels: Adds folder checks and permissions (#31473)

* Refactor: adds permissions for library panel creation

* Refactor: checks folder permissions for patch requests

* Chore: changes after PR comments

* Refactor: adds permissions to delete

* Refactor: moves get all permission tests out of get all tests

* Chore: move out get all tests to a separate file

* Refactor: adds permissions to get handler

* Refactor: fixes a bug with getting library panels in General folder

* Refactor: adds permissions for connect/disconnect

* Refactor: adds permissions and tests for get connected dashboards

* Tests: adds tests for connected dashboards in General Folder
This commit is contained in:
Hugo Häggmark
2021-03-01 15:33:17 +01:00
committed by GitHub
parent 475fd994a0
commit 583b94557b
12 changed files with 1333 additions and 690 deletions
+76 -15
View File
@@ -66,6 +66,9 @@ func (lps *LibraryPanelService) createLibraryPanel(c *models.ReqContext, cmd cre
}
err := lps.SQLStore.WithTransactionalDbSession(c.Context.Req.Context(), func(session *sqlstore.DBSession) error {
if err := requirePermissionsOnFolder(c.SignedInUser, cmd.FolderID); err != nil {
return err
}
if _, err := session.Insert(&libraryPanel); err != nil {
if lps.SQLStore.Dialect.IsUniqueConstraintViolation(err) {
return errLibraryPanelAlreadyExists
@@ -108,6 +111,9 @@ func connectDashboard(session *sqlstore.DBSession, dialect migrator.Dialect, use
if err != nil {
return err
}
if err := requirePermissionsOnFolder(user, panel.FolderID); err != nil {
return err
}
// TODO add check that dashboard exists
@@ -161,7 +167,9 @@ func (lps *LibraryPanelService) deleteLibraryPanel(c *models.ReqContext, uid str
if err != nil {
return err
}
if err := requirePermissionsOnFolder(c.SignedInUser, panel.FolderID); err != nil {
return err
}
if _, err := session.Exec("DELETE FROM library_panel_dashboard WHERE librarypanel_id=?", panel.ID); err != nil {
return err
}
@@ -187,6 +195,9 @@ func (lps *LibraryPanelService) disconnectDashboard(c *models.ReqContext, uid st
if err != nil {
return err
}
if err := requirePermissionsOnFolder(c.SignedInUser, panel.FolderID); err != nil {
return err
}
result, err := session.Exec("DELETE FROM library_panel_dashboard WHERE librarypanel_id=? and dashboard_id=?", panel.ID, dashboardID)
if err != nil {
@@ -242,9 +253,31 @@ func getLibraryPanel(session *sqlstore.DBSession, uid string, orgID int64) (Libr
func (lps *LibraryPanelService) getLibraryPanel(c *models.ReqContext, uid string) (LibraryPanelDTO, error) {
var libraryPanel LibraryPanelWithMeta
err := lps.SQLStore.WithDbSession(c.Context.Req.Context(), func(session *sqlstore.DBSession) error {
var err error
libraryPanel, err = getLibraryPanel(session, uid, c.SignedInUser.OrgId)
return err
libraryPanels := make([]LibraryPanelWithMeta, 0)
builder := sqlstore.SQLBuilder{}
builder.Write(sqlStatmentLibrayPanelDTOWithMeta)
builder.Write(` WHERE lp.uid=? AND lp.org_id=? AND lp.folder_id=0`, uid, c.SignedInUser.OrgId)
builder.Write(" UNION ")
builder.Write(sqlStatmentLibrayPanelDTOWithMeta)
builder.Write(" INNER JOIN dashboard AS dashboard on lp.folder_id = dashboard.id AND lp.folder_id <> 0")
builder.Write(` WHERE lp.uid=? AND lp.org_id=?`, uid, c.SignedInUser.OrgId)
if c.SignedInUser.OrgRole != models.ROLE_ADMIN {
builder.WriteDashboardPermissionFilter(c.SignedInUser, models.PERMISSION_VIEW)
}
builder.Write(` OR dashboard.id=0`)
if err := session.SQL(builder.GetSQLString(), builder.GetParams()...).Find(&libraryPanels); err != nil {
return err
}
if len(libraryPanels) == 0 {
return errLibraryPanelNotFound
}
if len(libraryPanels) > 1 {
return fmt.Errorf("found %d panels, while expecting at most one", len(libraryPanels))
}
libraryPanel = libraryPanels[0]
return nil
})
dto := LibraryPanelDTO{
@@ -281,8 +314,11 @@ func (lps *LibraryPanelService) getAllLibraryPanels(c *models.ReqContext, limit
err := lps.SQLStore.WithDbSession(c.Context.Req.Context(), func(session *sqlstore.DBSession) error {
builder := sqlstore.SQLBuilder{}
builder.Write(sqlStatmentLibrayPanelDTOWithMeta)
builder.Write(" LEFT JOIN dashboard AS dashboard on lp.folder_id = dashboard.id")
builder.Write(` WHERE lp.org_id = ?`, c.SignedInUser.OrgId)
builder.Write(` WHERE lp.org_id=? AND lp.folder_id=0`, c.SignedInUser.OrgId)
builder.Write(" UNION ")
builder.Write(sqlStatmentLibrayPanelDTOWithMeta)
builder.Write(" INNER JOIN dashboard AS dashboard on lp.folder_id = dashboard.id AND lp.folder_id<>0")
builder.Write(` WHERE lp.org_id=?`, c.SignedInUser.OrgId)
if c.SignedInUser.OrgRole != models.ROLE_ADMIN {
builder.WriteDashboardPermissionFilter(c.SignedInUser, models.PERMISSION_VIEW)
}
@@ -336,12 +372,15 @@ func (lps *LibraryPanelService) getConnectedDashboards(c *models.ReqContext, uid
if err != nil {
return err
}
var libraryPanelDashboards []libraryPanelDashboard
session.Table("library_panel_dashboard")
session.Where("librarypanel_id=?", panel.ID)
err = session.Find(&libraryPanelDashboards)
if err != nil {
builder := sqlstore.SQLBuilder{}
builder.Write("SELECT lpd.* FROM library_panel_dashboard lpd")
builder.Write(" INNER JOIN dashboard AS dashboard on lpd.dashboard_id = dashboard.id")
builder.Write(` WHERE lpd.librarypanel_id=?`, panel.ID)
if c.SignedInUser.OrgRole != models.ROLE_ADMIN {
builder.WriteDashboardPermissionFilter(c.SignedInUser, models.PERMISSION_VIEW)
}
if err := session.SQL(builder.GetSQLString(), builder.GetParams()...).Find(&libraryPanelDashboards); err != nil {
return err
}
@@ -399,6 +438,29 @@ func (lps *LibraryPanelService) getLibraryPanelsForDashboardID(c *models.ReqCont
return libraryPanelMap, err
}
func handleFolderIDPatches(panelToPatch *LibraryPanel, fromFolderID int64, toFolderID int64, user *models.SignedInUser) error {
// FolderID was not provided in the PATCH request
if toFolderID == -1 {
toFolderID = fromFolderID
}
// FolderID was provided in the PATCH request
if toFolderID != -1 && toFolderID != fromFolderID {
if err := requirePermissionsOnFolder(user, toFolderID); err != nil {
return err
}
}
// Always check permissions for the folder where library panel resides
if err := requirePermissionsOnFolder(user, fromFolderID); err != nil {
return err
}
panelToPatch.FolderID = toFolderID
return nil
}
// patchLibraryPanel updates a Library Panel.
func (lps *LibraryPanelService) patchLibraryPanel(c *models.ReqContext, cmd patchLibraryPanelCommand, uid string) (LibraryPanelDTO, error) {
var dto LibraryPanelDTO
@@ -421,19 +483,18 @@ func (lps *LibraryPanelService) patchLibraryPanel(c *models.ReqContext, cmd patc
UpdatedBy: c.SignedInUser.UserId,
}
if cmd.FolderID == 0 {
libraryPanel.FolderID = panelInDB.FolderID
}
if cmd.Name == "" {
libraryPanel.Name = panelInDB.Name
}
if cmd.Model == nil {
libraryPanel.Model = panelInDB.Model
}
if err := handleFolderIDPatches(&libraryPanel, panelInDB.FolderID, cmd.FolderID, c.SignedInUser); err != nil {
return err
}
if err := syncTitleWithName(&libraryPanel); err != nil {
return err
}
if rowsAffected, err := session.ID(panelInDB.ID).Update(&libraryPanel); err != nil {
if lps.SQLStore.Dialect.IsUniqueConstraintViolation(err) {
return errLibraryPanelAlreadyExists