mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
RBAC: Remove workaround to check permissions on folders for dashboard actions (#50291)
* remove workaround to check permissions on folders for dashboard actions
This commit is contained in:
parent
19df6d52b7
commit
9fd9a2cded
@ -134,7 +134,6 @@ func ProvideDashboardPermissions(
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
InheritedScopePrefixes: []string{"folders:uid:"},
|
|
||||||
InheritedScopesSolver: func(ctx context.Context, orgID int64, resourceID string) ([]string, error) {
|
InheritedScopesSolver: func(ctx context.Context, orgID int64, resourceID string) ([]string, error) {
|
||||||
dashboard, err := getDashboard(ctx, orgID, resourceID)
|
dashboard, err := getDashboard(ctx, orgID, resourceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -29,30 +29,6 @@ func newApi(ac accesscontrol.AccessControl, router routing.RouteRegister, manage
|
|||||||
return &api{ac, router, manager, permissions}
|
return &api{ac, router, manager, permissions}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *api) getEvaluators(actionRead, actionWrite, scope string) (read, write accesscontrol.Evaluator) {
|
|
||||||
if a.service.options.InheritedScopesSolver == nil || a.service.options.InheritedScopePrefixes == nil {
|
|
||||||
read = accesscontrol.EvalPermission(actionRead, scope)
|
|
||||||
write = accesscontrol.EvalPermission(actionWrite, scope)
|
|
||||||
} else {
|
|
||||||
// Add inherited scopes to the evaluators protecting the endpoint.
|
|
||||||
// Scopes in the request context parameters are to be added by solveInheritedScopes.
|
|
||||||
// If a user got actionRead on any of the inherited scopes, they will be granted access to the endpoint.
|
|
||||||
// Ex: a user inherits dashboards:read from the containing folder (folders:uid:BCeknZL7k)
|
|
||||||
inheritedRead := []accesscontrol.Evaluator{accesscontrol.EvalPermission(actionRead, scope)}
|
|
||||||
inheritedWrite := []accesscontrol.Evaluator{accesscontrol.EvalPermission(actionWrite, scope)}
|
|
||||||
for _, scopePrefix := range a.service.options.InheritedScopePrefixes {
|
|
||||||
inheritedRead = append(inheritedRead,
|
|
||||||
accesscontrol.EvalPermission(actionRead, accesscontrol.Parameter(scopePrefix)))
|
|
||||||
inheritedWrite = append(inheritedWrite,
|
|
||||||
accesscontrol.EvalPermission(actionWrite, accesscontrol.Parameter(scopePrefix)))
|
|
||||||
}
|
|
||||||
|
|
||||||
read = accesscontrol.EvalAny(inheritedRead...)
|
|
||||||
write = accesscontrol.EvalAny(inheritedWrite...)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *api) registerEndpoints() {
|
func (a *api) registerEndpoints() {
|
||||||
auth := accesscontrol.Middleware(a.ac)
|
auth := accesscontrol.Middleware(a.ac)
|
||||||
disable := disableMiddleware(a.ac.IsDisabled())
|
disable := disableMiddleware(a.ac.IsDisabled())
|
||||||
@ -62,17 +38,16 @@ func (a *api) registerEndpoints() {
|
|||||||
actionRead := fmt.Sprintf("%s.permissions:read", a.service.options.Resource)
|
actionRead := fmt.Sprintf("%s.permissions:read", a.service.options.Resource)
|
||||||
actionWrite := fmt.Sprintf("%s.permissions:write", a.service.options.Resource)
|
actionWrite := fmt.Sprintf("%s.permissions:write", a.service.options.Resource)
|
||||||
scope := accesscontrol.Scope(a.service.options.Resource, a.service.options.ResourceAttribute, accesscontrol.Parameter(":resourceID"))
|
scope := accesscontrol.Scope(a.service.options.Resource, a.service.options.ResourceAttribute, accesscontrol.Parameter(":resourceID"))
|
||||||
readEvaluator, writeEvaluator := a.getEvaluators(actionRead, actionWrite, scope)
|
|
||||||
r.Get("/description", auth(disable, accesscontrol.EvalPermission(actionRead)), routing.Wrap(a.getDescription))
|
r.Get("/description", auth(disable, accesscontrol.EvalPermission(actionRead)), routing.Wrap(a.getDescription))
|
||||||
r.Get("/:resourceID", inheritanceSolver, auth(disable, readEvaluator), routing.Wrap(a.getPermissions))
|
r.Get("/:resourceID", inheritanceSolver, auth(disable, accesscontrol.EvalPermission(actionRead, scope)), routing.Wrap(a.getPermissions))
|
||||||
if a.service.options.Assignments.Users {
|
if a.service.options.Assignments.Users {
|
||||||
r.Post("/:resourceID/users/:userID", inheritanceSolver, auth(disable, writeEvaluator), routing.Wrap(a.setUserPermission))
|
r.Post("/:resourceID/users/:userID", inheritanceSolver, auth(disable, accesscontrol.EvalPermission(actionWrite, scope)), routing.Wrap(a.setUserPermission))
|
||||||
}
|
}
|
||||||
if a.service.options.Assignments.Teams {
|
if a.service.options.Assignments.Teams {
|
||||||
r.Post("/:resourceID/teams/:teamID", inheritanceSolver, auth(disable, writeEvaluator), routing.Wrap(a.setTeamPermission))
|
r.Post("/:resourceID/teams/:teamID", inheritanceSolver, auth(disable, accesscontrol.EvalPermission(actionWrite, scope)), routing.Wrap(a.setTeamPermission))
|
||||||
}
|
}
|
||||||
if a.service.options.Assignments.BuiltInRoles {
|
if a.service.options.Assignments.BuiltInRoles {
|
||||||
r.Post("/:resourceID/builtInRoles/:builtInRole", inheritanceSolver, auth(disable, writeEvaluator), routing.Wrap(a.setBuiltinRolePermission))
|
r.Post("/:resourceID/builtInRoles/:builtInRole", inheritanceSolver, auth(disable, accesscontrol.EvalPermission(actionWrite, scope)), routing.Wrap(a.setBuiltinRolePermission))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package resourcepermissions
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
@ -418,66 +417,6 @@ func TestApi_setUserPermission(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type inheritSolverTestCase struct {
|
|
||||||
desc string
|
|
||||||
resourceID string
|
|
||||||
expectedStatus int
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestApi_InheritSolver(t *testing.T) {
|
|
||||||
tests := []inheritSolverTestCase{
|
|
||||||
{
|
|
||||||
desc: "expect parents permission to apply",
|
|
||||||
resourceID: "resourceID",
|
|
||||||
expectedStatus: http.StatusOK,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "expect direct permissions to apply (no inheritance)",
|
|
||||||
resourceID: "orphanedID",
|
|
||||||
expectedStatus: http.StatusOK,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
desc: "expect 404 when resource is not found",
|
|
||||||
resourceID: "notfound",
|
|
||||||
expectedStatus: http.StatusNotFound,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.desc, func(t *testing.T) {
|
|
||||||
userPermissions := []*accesscontrol.Permission{
|
|
||||||
{Action: "dashboards.permissions:read", Scope: "parents:id:parentID"}, // Inherited permission
|
|
||||||
{Action: "dashboards.permissions:read", Scope: "dashboards:id:orphanedID"}, // Direct permission
|
|
||||||
{Action: accesscontrol.ActionTeamsRead, Scope: accesscontrol.ScopeTeamsAll},
|
|
||||||
{Action: accesscontrol.ActionOrgUsersRead, Scope: accesscontrol.ScopeUsersAll},
|
|
||||||
}
|
|
||||||
// Add the inheritance solver "resourceID -> [parentID]" "orphanedID -> []"
|
|
||||||
service, sql := setupTestEnvironment(t, userPermissions,
|
|
||||||
withInheritance(testOptions, testInheritedScopeSolver, testInheritedScopePrefixes),
|
|
||||||
)
|
|
||||||
server := setupTestServer(t, &models.SignedInUser{OrgId: 1, Permissions: map[int64]map[string][]string{
|
|
||||||
1: accesscontrol.GroupScopesByAction(userPermissions),
|
|
||||||
}}, service)
|
|
||||||
|
|
||||||
// Seed permissions for users/teams/built-in roles specific to the test case resourceID
|
|
||||||
seedPermissions(t, tt.resourceID, sql, service)
|
|
||||||
|
|
||||||
permissions, recorder := getPermission(t, server, testOptions.Resource, tt.resourceID)
|
|
||||||
require.Equal(t, tt.expectedStatus, recorder.Code)
|
|
||||||
|
|
||||||
if tt.expectedStatus == http.StatusOK {
|
|
||||||
checkSeededPermissions(t, permissions)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func withInheritance(options Options, solver InheritedScopesSolver, inheritedPrefixes []string) Options {
|
|
||||||
options.InheritedScopesSolver = solver
|
|
||||||
options.InheritedScopePrefixes = inheritedPrefixes
|
|
||||||
return options
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupTestServer(t *testing.T, user *models.SignedInUser, service *Service) *web.Mux {
|
func setupTestServer(t *testing.T, user *models.SignedInUser, service *Service) *web.Mux {
|
||||||
server := web.New()
|
server := web.New()
|
||||||
server.UseMiddleware(web.Renderer(path.Join(setting.StaticRootPath, "views"), "[[", "]]"))
|
server.UseMiddleware(web.Renderer(path.Join(setting.StaticRootPath, "views"), "[[", "]]"))
|
||||||
@ -518,17 +457,6 @@ var testOptions = Options{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var testInheritedScopePrefixes = []string{"parents:id:"}
|
|
||||||
var testInheritedScopeSolver = func(ctx context.Context, orgID int64, id string) ([]string, error) {
|
|
||||||
if id == "resourceID" { // Has parent
|
|
||||||
return []string{"parents:id:parentID"}, nil
|
|
||||||
}
|
|
||||||
if id == "orphanedID" { // Exists but with no parent
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return nil, errors.New("not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
func getPermission(t *testing.T, server *web.Mux, resource, resourceID string) ([]resourcePermissionDTO, *httptest.ResponseRecorder) {
|
func getPermission(t *testing.T, server *web.Mux, resource, resourceID string) ([]resourcePermissionDTO, *httptest.ResponseRecorder) {
|
||||||
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/api/access-control/%s/%s", resource, resourceID), nil)
|
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/api/access-control/%s/%s", resource, resourceID), nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -39,6 +39,4 @@ type Options struct {
|
|||||||
OnSetBuiltInRole func(session *sqlstore.DBSession, orgID int64, builtInRole, resourceID, permission string) error
|
OnSetBuiltInRole func(session *sqlstore.DBSession, orgID int64, builtInRole, resourceID, permission string) error
|
||||||
// InheritedScopesSolver if configured can generate additional scopes that will be used when fetching permissions for a resource
|
// InheritedScopesSolver if configured can generate additional scopes that will be used when fetching permissions for a resource
|
||||||
InheritedScopesSolver InheritedScopesSolver
|
InheritedScopesSolver InheritedScopesSolver
|
||||||
// InheritedScopePrefixes if configured are used to create evaluators with the scopes returned by InheritedScopesSolver
|
|
||||||
InheritedScopePrefixes []string
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user