mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat: #11067 prevent removing last grafana admin permissions
This commit is contained in:
parent
e9a8185da1
commit
d1b8f13c66
@ -76,6 +76,7 @@ func AdminUpdateUserPassword(c *m.ReqContext, form dtos.AdminUpdateUserPasswordF
|
||||
c.JsonOK("User password updated")
|
||||
}
|
||||
|
||||
// PUT /api/admin/users/:id/permissions
|
||||
func AdminUpdateUserPermissions(c *m.ReqContext, form dtos.AdminUpdateUserPermissionsForm) {
|
||||
userID := c.ParamsInt64(":id")
|
||||
|
||||
@ -85,6 +86,11 @@ func AdminUpdateUserPermissions(c *m.ReqContext, form dtos.AdminUpdateUserPermis
|
||||
}
|
||||
|
||||
if err := bus.Dispatch(&cmd); err != nil {
|
||||
if err == m.ErrLastGrafanaAdmin {
|
||||
c.JsonApiErr(400, m.ErrLastGrafanaAdmin.Error(), nil)
|
||||
return
|
||||
}
|
||||
|
||||
c.JsonApiErr(500, "Failed to update user permissions", err)
|
||||
return
|
||||
}
|
||||
|
50
pkg/api/admin_users_test.go
Normal file
50
pkg/api/admin_users_test.go
Normal file
@ -0,0 +1,50 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestAdminApiEndpoint(t *testing.T) {
|
||||
role := m.ROLE_ADMIN
|
||||
Convey("Given a server admin attempts to remove themself as an admin", t, func() {
|
||||
|
||||
updateCmd := dtos.AdminUpdateUserPermissionsForm{
|
||||
IsGrafanaAdmin: false,
|
||||
}
|
||||
|
||||
bus.AddHandler("test", func(cmd *m.UpdateUserPermissionsCommand) error {
|
||||
return m.ErrLastGrafanaAdmin
|
||||
})
|
||||
|
||||
putAdminScenario("When calling PUT on", "/api/admin/users/1/permissions", "/api/admin/users/:id/permissions", role, updateCmd, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 400)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func putAdminScenario(desc string, url string, routePattern string, role m.RoleType, cmd dtos.AdminUpdateUserPermissionsForm, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
defer bus.ClearBusHandlers()
|
||||
|
||||
sc := setupScenarioContext(url)
|
||||
sc.defaultHandler = Wrap(func(c *m.ReqContext) {
|
||||
sc.context = c
|
||||
sc.context.UserId = TestUserID
|
||||
sc.context.OrgId = TestOrgID
|
||||
sc.context.OrgRole = role
|
||||
|
||||
AdminUpdateUserPermissions(c, cmd)
|
||||
})
|
||||
|
||||
sc.m.Put(routePattern, sc.defaultHandler)
|
||||
|
||||
fn(sc)
|
||||
})
|
||||
}
|
@ -7,7 +7,8 @@ import (
|
||||
|
||||
// Typed errors
|
||||
var (
|
||||
ErrUserNotFound = errors.New("User not found")
|
||||
ErrUserNotFound = errors.New("User not found")
|
||||
ErrLastGrafanaAdmin = errors.New("Cannot remove last grafana admin")
|
||||
)
|
||||
|
||||
type Password string
|
||||
|
@ -504,8 +504,18 @@ func UpdateUserPermissions(cmd *m.UpdateUserPermissionsCommand) error {
|
||||
|
||||
user.IsAdmin = cmd.IsGrafanaAdmin
|
||||
sess.UseBool("is_admin")
|
||||
|
||||
_, err := sess.ID(user.Id).Update(&user)
|
||||
return err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// validate that after update there is at least one server admin
|
||||
if err := validateOneAdminLeft(sess); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@ -522,3 +532,17 @@ func SetUserHelpFlag(cmd *m.SetUserHelpFlagCommand) error {
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func validateOneAdminLeft(sess *DBSession) error {
|
||||
// validate that there is an admin user left
|
||||
count, err := sess.Where("is_admin=?", true).Count(&m.User{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
return m.ErrLastGrafanaAdmin
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -155,6 +155,32 @@ func TestUserDataAccess(t *testing.T) {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Given one grafana admin user", func() {
|
||||
var err error
|
||||
createUserCmd := &m.CreateUserCommand{
|
||||
Email: fmt.Sprint("admin", "@test.com"),
|
||||
Name: fmt.Sprint("admin"),
|
||||
Login: fmt.Sprint("admin"),
|
||||
IsAdmin: true,
|
||||
}
|
||||
err = CreateUser(context.Background(), createUserCmd)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Cannot make themselves a non-admin", func() {
|
||||
updateUserPermsCmd := m.UpdateUserPermissionsCommand{IsGrafanaAdmin: false, UserId: 1}
|
||||
updatePermsError := UpdateUserPermissions(&updateUserPermsCmd)
|
||||
|
||||
So(updatePermsError, ShouldEqual, m.ErrLastGrafanaAdmin)
|
||||
|
||||
query := m.GetUserByIdQuery{Id: createUserCmd.Result.Id}
|
||||
getUserError := GetUserById(&query)
|
||||
|
||||
So(getUserError, ShouldBeNil)
|
||||
|
||||
So(query.Result.IsAdmin, ShouldEqual, true)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user