IAM - Fix error messages for resource permissions endpoints (#85773)

* IAM: fix many error messages in access-related code to provide more information

* Remove debug statement

* Refactor resourcepermissions package to use errutil

* Replace a few more errors with errutil and wrap errors found in users and teams services

* Apply diff of openAPI spec
This commit is contained in:
Aaron Godin
2024-04-17 08:53:28 -05:00
committed by GitHub
parent 60abf01526
commit d409d8e860
9 changed files with 140 additions and 26 deletions
@@ -144,7 +144,7 @@ func (a *api) getPermissions(c *contextmodel.ReqContext) response.Response {
permissions, err := a.service.GetPermissions(c.Req.Context(), c.SignedInUser, resourceID)
if err != nil {
return response.ErrOrFallback(http.StatusInternalServerError, "failed to get permissions", err)
return response.ErrOrFallback(http.StatusInternalServerError, "Failed to get permissions", err)
}
if a.service.options.Assignments.BuiltInRoles && !a.service.license.FeatureEnabled("accesscontrol.enforcement") {
@@ -229,7 +229,7 @@ type SetResourcePermissionsForUserParams struct {
func (a *api) setUserPermission(c *contextmodel.ReqContext) response.Response {
userID, err := strconv.ParseInt(web.Params(c.Req)[":userID"], 10, 64)
if err != nil {
return response.Error(http.StatusBadRequest, "userID is invalid", err)
return response.Err(ErrInvalidParam.Build(ErrInvalidParamData("userID", err)))
}
resourceID := web.Params(c.Req)[":resourceID"]
@@ -240,7 +240,7 @@ func (a *api) setUserPermission(c *contextmodel.ReqContext) response.Response {
_, err = a.service.SetUserPermission(c.Req.Context(), c.SignedInUser.GetOrgID(), accesscontrol.User{ID: userID}, resourceID, cmd.Permission)
if err != nil {
return response.ErrOrFallback(http.StatusBadRequest, "failed to set user permission", err)
return response.Err(err)
}
return permissionSetResponse(cmd)
@@ -282,7 +282,7 @@ type SetResourcePermissionsForTeamParams struct {
func (a *api) setTeamPermission(c *contextmodel.ReqContext) response.Response {
teamID, err := strconv.ParseInt(web.Params(c.Req)[":teamID"], 10, 64)
if err != nil {
return response.Error(http.StatusBadRequest, "teamID is invalid", err)
return response.Err(ErrInvalidParam.Build(ErrInvalidParamData("teamID", err)))
}
resourceID := web.Params(c.Req)[":resourceID"]
@@ -293,7 +293,7 @@ func (a *api) setTeamPermission(c *contextmodel.ReqContext) response.Response {
_, err = a.service.SetTeamPermission(c.Req.Context(), c.SignedInUser.GetOrgID(), teamID, resourceID, cmd.Permission)
if err != nil {
return response.ErrOrFallback(http.StatusBadRequest, "failed to set team permission", err)
return response.Err(err)
}
return permissionSetResponse(cmd)
@@ -343,7 +343,7 @@ func (a *api) setBuiltinRolePermission(c *contextmodel.ReqContext) response.Resp
_, err := a.service.SetBuiltInRolePermission(c.Req.Context(), c.SignedInUser.GetOrgID(), builtInRole, resourceID, cmd.Permission)
if err != nil {
return response.ErrOrFallback(http.StatusBadRequest, "failed to set role permission", err)
return response.Err(err)
}
return permissionSetResponse(cmd)
@@ -383,12 +383,12 @@ func (a *api) setPermissions(c *contextmodel.ReqContext) response.Response {
cmd := setPermissionsCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
return response.Error(http.StatusBadRequest, "Bad request data: "+err.Error(), err)
}
_, err := a.service.SetPermissions(c.Req.Context(), c.SignedInUser.GetOrgID(), resourceID, cmd.Permissions...)
if err != nil {
return response.ErrOrFallback(http.StatusBadRequest, "failed to set permission", err)
return response.Err(err)
}
return response.Success("Permissions updated")
@@ -1,8 +1,56 @@
package resourcepermissions
import "errors"
import (
"github.com/grafana/grafana/pkg/util/errutil"
)
const (
invalidPermissionMessage = `Permission [{{ .Public.permission }}] is invalid for this resource type`
invalidAssignmentMessage = `Assignment [{{ .Public.assignment }}] is invalid for this resource type`
invalidParamMessage = `Param [{{ .Public.param }}] is invalid`
invalidRequestBody = `Request body is invalid: {{ .Public.reason }}`
)
var (
ErrInvalidPermission = errors.New("invalid permission")
ErrInvalidAssignment = errors.New("invalid assignment")
ErrInvalidParam = errutil.BadRequest("resourcePermissions.invalidParam").
MustTemplate(invalidParamMessage, errutil.WithPublic(invalidParamMessage))
ErrInvalidRequestBody = errutil.BadRequest("resourcePermissions.invalidRequestBody").
MustTemplate(invalidRequestBody, errutil.WithPublic(invalidRequestBody))
ErrInvalidPermission = errutil.BadRequest("resourcePermissions.invalidPermission").
MustTemplate(invalidPermissionMessage, errutil.WithPublic(invalidPermissionMessage))
ErrInvalidAssignment = errutil.BadRequest("resourcePermissions.invalidAssignment").
MustTemplate(invalidAssignmentMessage, errutil.WithPublic(invalidAssignmentMessage))
)
func ErrInvalidParamData(param string, err error) errutil.TemplateData {
return errutil.TemplateData{
Public: map[string]any{
"param": param,
},
Error: err,
}
}
func ErrInvalidRequestBodyData(reason string) errutil.TemplateData {
return errutil.TemplateData{
Public: map[string]any{
"reason": reason,
},
}
}
func ErrInvalidPermissionData(permission string) errutil.TemplateData {
return errutil.TemplateData{
Public: map[string]any{
"permission": permission,
},
}
}
func ErrInvalidAssignmentData(assignment string) errutil.TemplateData {
return errutil.TemplateData{
Public: map[string]any{
"assignment": assignment,
},
}
}
@@ -2,6 +2,7 @@ package resourcepermissions
import (
"context"
"errors"
"fmt"
"sort"
@@ -285,7 +286,7 @@ func (s *Service) mapPermission(permission string) ([]string, error) {
return v, nil
}
}
return nil, ErrInvalidPermission
return nil, ErrInvalidPermission.Build(ErrInvalidPermissionData(permission))
}
func (s *Service) validateResource(ctx context.Context, orgID int64, resourceID string) error {
@@ -297,27 +298,37 @@ func (s *Service) validateResource(ctx context.Context, orgID int64, resourceID
func (s *Service) validateUser(ctx context.Context, orgID, userID int64) error {
if !s.options.Assignments.Users {
return ErrInvalidAssignment
return ErrInvalidAssignment.Build(ErrInvalidAssignmentData("users"))
}
_, err := s.userService.GetSignedInUser(ctx, &user.GetSignedInUserQuery{OrgID: orgID, UserID: userID})
return err
switch {
case errors.Is(err, user.ErrUserNotFound):
return accesscontrol.ErrAssignmentEntityNotFound.Build(accesscontrol.ErrAssignmentEntityNotFoundData("user"))
default:
return err
}
}
func (s *Service) validateTeam(ctx context.Context, orgID, teamID int64) error {
if !s.options.Assignments.Teams {
return ErrInvalidAssignment
return ErrInvalidAssignment.Build(ErrInvalidAssignmentData("teams"))
}
if _, err := s.teamService.GetTeamByID(ctx, &team.GetTeamByIDQuery{OrgID: orgID, ID: teamID}); err != nil {
return err
switch {
case errors.Is(err, team.ErrTeamNotFound):
return accesscontrol.ErrAssignmentEntityNotFound.Build(accesscontrol.ErrAssignmentEntityNotFoundData("team"))
default:
return err
}
}
return nil
}
func (s *Service) validateBuiltinRole(ctx context.Context, builtinRole string) error {
func (s *Service) validateBuiltinRole(_ context.Context, builtinRole string) error {
if !s.options.Assignments.BuiltInRoles {
return ErrInvalidAssignment
return ErrInvalidAssignment.Build(ErrInvalidAssignmentData("builtInRoles"))
}
if err := accesscontrol.ValidateBuiltInRoles([]string{builtinRole}); err != nil {