mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
WIP: delete permission in API
This commit is contained in:
parent
fff7b706d6
commit
fa18b0053d
@ -250,6 +250,8 @@ func (hs *HttpServer) registerRoutes() {
|
||||
|
||||
r.Group("/:id/acl", func() {
|
||||
r.Get("/", wrap(GetDashboardAcl))
|
||||
r.Delete("/user/:userId", wrap(DeleteDashboardAclByUser))
|
||||
r.Delete("/user-group/:userGroupId", wrap(DeleteDashboardAclByUserGroup))
|
||||
}, reqSignedIn)
|
||||
})
|
||||
|
||||
|
@ -29,3 +29,45 @@ func GetDashboardAcl(c *middleware.Context) Response {
|
||||
|
||||
return Json(200, &query.Result)
|
||||
}
|
||||
|
||||
func DeleteDashboardAclByUser(c *middleware.Context) Response {
|
||||
dashboardId := c.ParamsInt64(":id")
|
||||
userId := c.ParamsInt64(":userId")
|
||||
cmd := m.RemoveDashboardPermissionCommand{DashboardId: dashboardId, UserId: userId, OrgId: c.OrgId}
|
||||
|
||||
hasPermission, err := guardian.CanDeleteFromAcl(dashboardId, c.OrgRole, c.IsGrafanaAdmin, c.OrgId, c.UserId)
|
||||
if err != nil {
|
||||
return ApiError(500, "Failed to delete from Dashboard ACL", err)
|
||||
}
|
||||
|
||||
if !hasPermission {
|
||||
return Json(403, util.DynMap{"status": "Forbidden", "message": "Does not have access to this Dashboard ACL"})
|
||||
}
|
||||
|
||||
if err := bus.Dispatch(&cmd); err != nil {
|
||||
return ApiError(500, "Failed to delete permission for user", err)
|
||||
}
|
||||
|
||||
return Json(200, "")
|
||||
}
|
||||
|
||||
func DeleteDashboardAclByUserGroup(c *middleware.Context) Response {
|
||||
dashboardId := c.ParamsInt64(":id")
|
||||
userGroupId := c.ParamsInt64(":userGroupId")
|
||||
cmd := m.RemoveDashboardPermissionCommand{DashboardId: dashboardId, UserGroupId: userGroupId, OrgId: c.OrgId}
|
||||
|
||||
hasPermission, err := guardian.CanDeleteFromAcl(dashboardId, c.OrgRole, c.IsGrafanaAdmin, c.OrgId, c.UserId)
|
||||
if err != nil {
|
||||
return ApiError(500, "Failed to delete from Dashboard ACL", err)
|
||||
}
|
||||
|
||||
if !hasPermission {
|
||||
return Json(403, util.DynMap{"status": "Forbidden", "message": "Does not have access to this Dashboard ACL"})
|
||||
}
|
||||
|
||||
if err := bus.Dispatch(&cmd); err != nil {
|
||||
return ApiError(500, "Failed to delete permission for user", err)
|
||||
}
|
||||
|
||||
return Json(200, "")
|
||||
}
|
||||
|
@ -15,6 +15,8 @@ func TestDashboardAclApiEndpoint(t *testing.T) {
|
||||
mockResult := []*models.DashboardAclInfoDTO{
|
||||
{Id: 1, OrgId: 1, DashboardId: 1, UserId: 2, Permissions: models.PERMISSION_EDIT},
|
||||
{Id: 2, OrgId: 1, DashboardId: 1, UserId: 3, Permissions: models.PERMISSION_VIEW},
|
||||
{Id: 3, OrgId: 1, DashboardId: 1, UserGroupId: 1, Permissions: models.PERMISSION_EDIT},
|
||||
{Id: 4, OrgId: 1, DashboardId: 1, UserGroupId: 2, Permissions: models.PERMISSION_READ_ONLY_EDIT},
|
||||
}
|
||||
bus.AddHandler("test", func(query *models.GetDashboardPermissionsQuery) error {
|
||||
query.Result = mockResult
|
||||
@ -22,7 +24,7 @@ func TestDashboardAclApiEndpoint(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("When user is org admin", func() {
|
||||
loggedInUserScenarioWithRole("When calling GET on", "/api/dashboard/1/acl", models.ROLE_ADMIN, func(sc *scenarioContext) {
|
||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/1/acl", "/api/dashboards/:id/acl", models.ROLE_ADMIN, func(sc *scenarioContext) {
|
||||
Convey("Should be able to access ACL", func() {
|
||||
sc.handlerFunc = GetDashboardAcl
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||
@ -37,14 +39,68 @@ func TestDashboardAclApiEndpoint(t *testing.T) {
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When user is editor and not in the ACL", func() {
|
||||
loggedInUserScenarioWithRole("When calling GET on", "/api/dashboard/1/acl", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
Convey("When user is editor and in the ACL", func() {
|
||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/1/acl", "/api/dashboards/:id/acl", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
mockResult = append(mockResult, &models.DashboardAclInfoDTO{Id: 1, OrgId: 1, DashboardId: 1, UserId: 1, Permissions: models.PERMISSION_EDIT})
|
||||
|
||||
bus.AddHandler("test2", func(query *models.GetAllowedDashboardsQuery) error {
|
||||
query.Result = []int64{1}
|
||||
return nil
|
||||
})
|
||||
|
||||
Convey("Should be able to access ACL", func() {
|
||||
sc.handlerFunc = GetDashboardAcl
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
})
|
||||
})
|
||||
|
||||
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/1/acl/user/1", "/api/dashboards/:id/acl/user/:userId", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
mockResult = append(mockResult, &models.DashboardAclInfoDTO{Id: 1, OrgId: 1, DashboardId: 1, UserId: 1, Permissions: models.PERMISSION_EDIT})
|
||||
|
||||
bus.AddHandler("test3", func(cmd *models.RemoveDashboardPermissionCommand) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
Convey("Should be able to delete permission", func() {
|
||||
sc.handlerFunc = DeleteDashboardAclByUser
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
|
||||
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When user is a member of a user group in the ACL with edit permission", func() {
|
||||
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/1/acl/user/1", "/api/dashboards/:id/acl/user/:userId", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
|
||||
bus.AddHandler("test3", func(query *models.GetUserGroupsByUserQuery) error {
|
||||
query.Result = []*models.UserGroup{{Id: 1, OrgId: 1, Name: "UG1"}}
|
||||
return nil
|
||||
})
|
||||
|
||||
bus.AddHandler("test3", func(cmd *models.RemoveDashboardPermissionCommand) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
Convey("Should be able to delete permission", func() {
|
||||
sc.handlerFunc = DeleteDashboardAclByUser
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
|
||||
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When user is editor and not in the ACL", func() {
|
||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/1/acl", "/api/dashboards/:id/acl", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
|
||||
bus.AddHandler("test2", func(query *models.GetAllowedDashboardsQuery) error {
|
||||
query.Result = []int64{}
|
||||
return nil
|
||||
})
|
||||
|
||||
Convey("Should not be able to access ACL", func() {
|
||||
sc.handlerFunc = GetDashboardAcl
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||
@ -52,6 +108,20 @@ func TestDashboardAclApiEndpoint(t *testing.T) {
|
||||
So(sc.resp.Code, ShouldEqual, 403)
|
||||
})
|
||||
})
|
||||
|
||||
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/1/acl/user/1", "/api/dashboards/:id/acl/user/:userId", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
mockResult = append(mockResult, &models.DashboardAclInfoDTO{Id: 1, OrgId: 1, DashboardId: 1, UserId: 1, Permissions: models.PERMISSION_VIEW})
|
||||
bus.AddHandler("test3", func(cmd *models.RemoveDashboardPermissionCommand) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
Convey("Should be not be able to delete permission", func() {
|
||||
sc.handlerFunc = DeleteDashboardAclByUser
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
|
||||
|
||||
So(sc.resp.Code, ShouldEqual, 403)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -56,10 +56,10 @@ func TestDataSourcesProxy(t *testing.T) {
|
||||
}
|
||||
|
||||
func loggedInUserScenario(desc string, url string, fn scenarioFunc) {
|
||||
loggedInUserScenarioWithRole(desc, url, models.ROLE_EDITOR, fn)
|
||||
loggedInUserScenarioWithRole(desc, "GET", url, url, models.ROLE_EDITOR, fn)
|
||||
}
|
||||
|
||||
func loggedInUserScenarioWithRole(desc string, url string, role models.RoleType, fn scenarioFunc) {
|
||||
func loggedInUserScenarioWithRole(desc string, method string, url string, routePattern string, role models.RoleType, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
defer bus.ClearBusHandlers()
|
||||
|
||||
@ -89,7 +89,12 @@ func loggedInUserScenarioWithRole(desc string, url string, role models.RoleType,
|
||||
return nil
|
||||
})
|
||||
|
||||
sc.m.Get(url, sc.defaultHandler)
|
||||
switch method {
|
||||
case "GET":
|
||||
sc.m.Get(routePattern, sc.defaultHandler)
|
||||
case "DELETE":
|
||||
sc.m.Delete(routePattern, sc.defaultHandler)
|
||||
}
|
||||
|
||||
fn(sc)
|
||||
})
|
||||
|
@ -32,13 +32,45 @@ func CanViewAcl(dashboardId int64, role m.RoleType, isGrafanaAdmin bool, orgId i
|
||||
return false, err
|
||||
}
|
||||
|
||||
if len(filteredList) > 1 && filteredList[0] == dashboardId {
|
||||
if len(filteredList) > 0 && filteredList[0] == dashboardId {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// CanDeleteFromAcl determines if a user has permission to delete from a dashboard's ACL
|
||||
func CanDeleteFromAcl(dashboardId int64, role m.RoleType, isGrafanaAdmin bool, orgId int64, userId int64) (bool, error) {
|
||||
if role == m.ROLE_ADMIN || isGrafanaAdmin {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
permissions, err := getDashboardPermissions(dashboardId)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if len(permissions) == 0 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
userGroups, err := getUserGroupsByUser(userId)
|
||||
|
||||
for _, p := range permissions {
|
||||
if p.UserId == userId && p.Permissions == m.PERMISSION_EDIT {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
for _, ug := range userGroups {
|
||||
if ug.Id == p.UserGroupId && p.Permissions == m.PERMISSION_EDIT {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func getUser(userId int64) (*m.SignedInUser, error) {
|
||||
query := m.GetSignedInUserQuery{UserId: userId}
|
||||
err := bus.Dispatch(&query)
|
||||
@ -52,3 +84,17 @@ func getAllowedDashboards(dashList []int64, orgId int64, userId int64) ([]int64,
|
||||
|
||||
return query.Result, err
|
||||
}
|
||||
|
||||
func getDashboardPermissions(dashboardId int64) ([]*m.DashboardAclInfoDTO, error) {
|
||||
query := m.GetDashboardPermissionsQuery{DashboardId: dashboardId}
|
||||
err := bus.Dispatch(&query)
|
||||
|
||||
return query.Result, err
|
||||
}
|
||||
|
||||
func getUserGroupsByUser(userId int64) ([]*m.UserGroup, error) {
|
||||
query := m.GetUserGroupsByUserQuery{UserId: userId}
|
||||
err := bus.Dispatch(&query)
|
||||
|
||||
return query.Result, err
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user