AccessControl: Resource permission translator (#95423)
* Standardize Resource Translator in options * Add resource UID translator for resource permissions * fix comments * fix comments
This commit is contained in:
@@ -42,6 +42,9 @@ func ProvideReceiverPermissionsService(
|
||||
options := resourcepermissions.Options{
|
||||
Resource: "receivers",
|
||||
ResourceAttribute: "uid",
|
||||
ResourceTranslator: func(ctx context.Context, orgID int64, resourceID string) (string, error) {
|
||||
return alertingac.ScopeReceiversProvider.GetResourceIDFromUID(resourceID), nil
|
||||
},
|
||||
Assignments: resourcepermissions.Assignments{
|
||||
Users: true,
|
||||
Teams: true,
|
||||
|
||||
@@ -41,8 +41,9 @@ func ProvideServiceAccountPermissions(
|
||||
teamService team.Service, userService user.Service, actionSetService resourcepermissions.ActionSetService,
|
||||
) (*ServiceAccountPermissionsService, error) {
|
||||
options := resourcepermissions.Options{
|
||||
Resource: "serviceaccounts",
|
||||
ResourceAttribute: "id",
|
||||
Resource: "serviceaccounts",
|
||||
ResourceAttribute: "id",
|
||||
ResourceTranslator: serviceaccounts.UIDToIDHandler(serviceAccountRetrieverService),
|
||||
ResourceValidator: func(ctx context.Context, orgID int64, resourceID string) error {
|
||||
ctx, span := tracer.Start(ctx, "accesscontrol.ossaccesscontrol.ProvideServiceAccountPermissions.ResourceValidator")
|
||||
defer span.End()
|
||||
|
||||
@@ -41,9 +41,10 @@ func ProvideTeamPermissions(
|
||||
teamService team.Service, userService user.Service, actionSetService resourcepermissions.ActionSetService,
|
||||
) (*TeamPermissionsService, error) {
|
||||
options := resourcepermissions.Options{
|
||||
Resource: "teams",
|
||||
ResourceAttribute: "id",
|
||||
OnlyManaged: true,
|
||||
Resource: "teams",
|
||||
ResourceAttribute: "id",
|
||||
OnlyManaged: true,
|
||||
ResourceTranslator: team.UIDToIDHandler(teamService),
|
||||
ResourceValidator: func(ctx context.Context, orgID int64, resourceID string) error {
|
||||
ctx, span := tracer.Start(ctx, "accesscontrol.ossaccesscontrol.ProvideTeamerPermissions.ResourceValidator")
|
||||
defer span.End()
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||
alertingac "github.com/grafana/grafana/pkg/services/ngalert/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/team"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
@@ -46,29 +45,40 @@ func (a *api) registerEndpoints() {
|
||||
}
|
||||
|
||||
teamUIDResolver := team.MiddlewareTeamUIDResolver(a.service.teamService, ":teamID")
|
||||
teamUIDResolverResource := func() web.Handler { return func(c *contextmodel.ReqContext) {} }() // no-op
|
||||
if a.service.options.Resource == "teams" {
|
||||
teamUIDResolverResource = team.MiddlewareTeamUIDResolver(a.service.teamService, ":resourceID")
|
||||
}
|
||||
if a.service.options.Resource == "receivers" {
|
||||
teamUIDResolverResource = MiddlewareReceiverUIDResolver(":resourceID")
|
||||
}
|
||||
resourceResolver := func(resTranslator ResourceTranslator) web.Handler {
|
||||
return func(c *contextmodel.ReqContext) {
|
||||
// no-op
|
||||
if resTranslator == nil {
|
||||
return
|
||||
}
|
||||
|
||||
gotParams := web.Params(c.Req)
|
||||
resourceID := gotParams[":resourceID"]
|
||||
resourceID, err := resTranslator(c.Req.Context(), c.OrgID, resourceID)
|
||||
if err == nil {
|
||||
gotParams[":resourceID"] = resourceID
|
||||
web.SetURLParams(c.Req, gotParams)
|
||||
} else {
|
||||
c.JsonApiErr(http.StatusNotFound, "Not found", nil)
|
||||
}
|
||||
}
|
||||
}(a.service.options.ResourceTranslator)
|
||||
|
||||
a.router.Group(fmt.Sprintf("/api/access-control/%s", a.service.options.Resource), func(r routing.RouteRegister) {
|
||||
actionRead := fmt.Sprintf("%s.permissions:read", 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"))
|
||||
r.Get("/description", auth(accesscontrol.EvalPermission(actionRead)), routing.Wrap(a.getDescription))
|
||||
r.Get("/:resourceID", teamUIDResolverResource, auth(accesscontrol.EvalPermission(actionRead, scope)), routing.Wrap(a.getPermissions))
|
||||
r.Post("/:resourceID", teamUIDResolverResource, licenseMW, auth(accesscontrol.EvalPermission(actionWrite, scope)), routing.Wrap(a.setPermissions))
|
||||
r.Get("/:resourceID", resourceResolver, auth(accesscontrol.EvalPermission(actionRead, scope)), routing.Wrap(a.getPermissions))
|
||||
r.Post("/:resourceID", resourceResolver, licenseMW, auth(accesscontrol.EvalPermission(actionWrite, scope)), routing.Wrap(a.setPermissions))
|
||||
if a.service.options.Assignments.Users {
|
||||
r.Post("/:resourceID/users/:userID", licenseMW, teamUIDResolverResource, auth(accesscontrol.EvalPermission(actionWrite, scope)), routing.Wrap(a.setUserPermission))
|
||||
r.Post("/:resourceID/users/:userID", licenseMW, resourceResolver, auth(accesscontrol.EvalPermission(actionWrite, scope)), routing.Wrap(a.setUserPermission))
|
||||
}
|
||||
if a.service.options.Assignments.Teams {
|
||||
r.Post("/:resourceID/teams/:teamID", licenseMW, teamUIDResolverResource, teamUIDResolver, auth(accesscontrol.EvalPermission(actionWrite, scope)), routing.Wrap(a.setTeamPermission))
|
||||
r.Post("/:resourceID/teams/:teamID", licenseMW, resourceResolver, teamUIDResolver, auth(accesscontrol.EvalPermission(actionWrite, scope)), routing.Wrap(a.setTeamPermission))
|
||||
}
|
||||
if a.service.options.Assignments.BuiltInRoles {
|
||||
r.Post("/:resourceID/builtInRoles/:builtInRole", teamUIDResolverResource, licenseMW, auth(accesscontrol.EvalPermission(actionWrite, scope)), routing.Wrap(a.setBuiltinRolePermission))
|
||||
r.Post("/:resourceID/builtInRoles/:builtInRole", resourceResolver, licenseMW, auth(accesscontrol.EvalPermission(actionWrite, scope)), routing.Wrap(a.setBuiltinRolePermission))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -435,13 +445,3 @@ func permissionSetResponse(cmd setPermissionCommand) response.Response {
|
||||
}
|
||||
return response.Success(message)
|
||||
}
|
||||
|
||||
func MiddlewareReceiverUIDResolver(paramName string) web.Handler {
|
||||
return func(c *contextmodel.ReqContext) {
|
||||
gotParams := web.Params(c.Req)
|
||||
if uid, ok := gotParams[paramName]; ok {
|
||||
gotParams[paramName] = alertingac.ScopeReceiversProvider.GetResourceIDFromUID(uid)
|
||||
web.SetURLParams(c.Req, gotParams)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
type ResourceValidator func(ctx context.Context, orgID int64, resourceID string) error
|
||||
type InheritedScopesSolver func(ctx context.Context, orgID int64, resourceID string) ([]string, error)
|
||||
|
||||
type ResourceTranslator func(ctx context.Context, orgID int64, resourceID string) (string, error)
|
||||
type Options struct {
|
||||
// Resource is the action and scope prefix that is generated
|
||||
Resource string
|
||||
@@ -18,6 +18,9 @@ type Options struct {
|
||||
ResourceAttribute string
|
||||
// OnlyManaged will tell the service to return all permissions if set to false and only managed permissions if set to true
|
||||
OnlyManaged bool
|
||||
// ResourceTranslator is a translator function that will be called before each action, it can be used to translate a resource id to a different format.
|
||||
// If set to nil the translator will be skipped
|
||||
ResourceTranslator ResourceTranslator
|
||||
// ResourceValidator is a validator function that will be called before each assignment.
|
||||
// If set to nil the validator will be skipped
|
||||
ResourceValidator ResourceValidator
|
||||
|
||||
Reference in New Issue
Block a user