RBAC Search: Replace userLogin filter by namespacedID filter (#81810)

* Add namespace ID

* Refactor and add tests

* Rename maxOneOption -> atMostOneOption

* Add ToDo

* Remove UserLogin & UserID for NamespaceID

Co-authored-by: jguer <joao.guerreiro@grafana.com>

* Remove unecessary import of the userSvc

* Update pkg/services/accesscontrol/acimpl/service.go

* fix 1 -> userID

* Update pkg/services/accesscontrol/accesscontrol.go

---------

Co-authored-by: jguer <joao.guerreiro@grafana.com>
This commit is contained in:
Gabriel MABILLE
2024-02-16 11:42:36 +01:00
committed by GitHub
co-authored by jguer
parent fe0fc08b93
commit 846eadff63
13 changed files with 78 additions and 126 deletions
+3 -17
View File
@@ -2,7 +2,6 @@ package api
import (
"net/http"
"strconv"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing"
@@ -69,30 +68,17 @@ func (api *AccessControlAPI) getUserPermissions(c *contextmodel.ReqContext) resp
// GET /api/access-control/users/permissions/search
func (api *AccessControlAPI) searchUsersPermissions(c *contextmodel.ReqContext) response.Response {
searchOptions := ac.SearchOptions{
UserLogin: c.Query("userLogin"),
ActionPrefix: c.Query("actionPrefix"),
Action: c.Query("action"),
Scope: c.Query("scope"),
}
userIDString := c.Query("userId")
if userIDString != "" {
userID, err := strconv.ParseInt(userIDString, 10, 64)
if err != nil {
return response.Error(http.StatusBadRequest, "user ID is invalid", err)
}
searchOptions.UserID = userID
NamespacedID: c.Query("namespacedId"),
}
// Validate inputs
if (searchOptions.ActionPrefix != "") && (searchOptions.Action != "") {
if searchOptions.ActionPrefix != "" && searchOptions.Action != "" {
return response.JSON(http.StatusBadRequest, "'action' and 'actionPrefix' are mutually exclusive")
}
if (searchOptions.UserLogin != "") && (searchOptions.UserID > 0) {
return response.JSON(http.StatusBadRequest, "'userId' and 'userLogin' are mutually exclusive")
}
if searchOptions.UserID <= 0 && searchOptions.UserLogin == "" &&
searchOptions.ActionPrefix == "" && searchOptions.Action == "" {
if searchOptions.NamespacedID == "" && searchOptions.ActionPrefix == "" && searchOptions.Action == "" {
return response.JSON(http.StatusBadRequest, "at least one search option must be provided")
}
+4 -14
View File
@@ -139,31 +139,21 @@ func TestAccessControlAPI_searchUsersPermissions(t *testing.T) {
expectedCode: http.StatusBadRequest,
},
{
desc: "Should reject if conflicting user filters are provided",
filters: "?userLogin=admin&userId=2",
expectedCode: http.StatusBadRequest,
},
{
desc: "Should reject if invalid userID is provided",
filters: "?userId=invalid",
expectedCode: http.StatusBadRequest,
},
{
desc: "Should work with valid filter provided",
filters: "?userId=2",
desc: "Should work with valid namespacedId filter provided",
filters: "?namespacedId=service-account:2",
permissions: map[int64][]ac.Permission{2: {{Action: "users:read", Scope: "users:*"}}},
expectedCode: http.StatusOK,
expectedOutput: map[int64]map[string][]string{2: {"users:read": {"users:*"}}},
},
{
desc: "Should reduce permissions",
filters: "?userId=2",
filters: "?namespacedId=service-account:2",
permissions: map[int64][]ac.Permission{2: {{Action: "users:read", Scope: "users:id:1"}, {Action: "users:read", Scope: "users:*"}}},
expectedCode: http.StatusOK,
expectedOutput: map[int64]map[string][]string{2: {"users:read": {"users:*"}}},
},
{
desc: "Should work with valid action filter",
desc: "Should work with valid action prefix filter",
filters: "?actionPrefix=users:",
permissions: map[int64][]ac.Permission{
1: {{Action: "users:write", Scope: "users:id:1"}},