Auth: Move access control API to SignedInUser interface (#73144)

* move access control api to SignedInUser interface

* remove unused code

* add logic for reading perms from a specific org

* move the specific org logic to org_user.go

* add a comment

---------

Co-authored-by: IevaVasiljeva <ieva.vasiljeva@grafana.com>
This commit is contained in:
Jo
2023-08-18 11:42:18 +01:00
committed by GitHub
co-authored by IevaVasiljeva
parent 4c9469fc9e
commit 26339f978b
17 changed files with 50 additions and 41 deletions
+4 -4
View File
@@ -64,7 +64,7 @@ type SearchOptions struct {
}
type TeamPermissionsService interface {
GetPermissions(ctx context.Context, user *user.SignedInUser, resourceID string) ([]ResourcePermission, error)
GetPermissions(ctx context.Context, user identity.Requester, resourceID string) ([]ResourcePermission, error)
SetUserPermission(ctx context.Context, orgID int64, user User, resourceID, permission string) (*ResourcePermission, error)
}
@@ -86,7 +86,7 @@ type ServiceAccountPermissionsService interface {
type PermissionsService interface {
// GetPermissions returns all permissions for given resourceID
GetPermissions(ctx context.Context, user *user.SignedInUser, resourceID string) ([]ResourcePermission, error)
GetPermissions(ctx context.Context, user identity.Requester, resourceID string) ([]ResourcePermission, error)
// SetUserPermission sets permission on resource for a user
SetUserPermission(ctx context.Context, orgID int64, user User, resourceID, permission string) (*ResourcePermission, error)
// SetTeamPermission sets permission on resource for a team
@@ -151,13 +151,13 @@ var ReqSignedIn = func(c *contextmodel.ReqContext) bool {
}
var ReqGrafanaAdmin = func(c *contextmodel.ReqContext) bool {
return c.IsGrafanaAdmin
return c.SignedInUser.GetIsGrafanaAdmin()
}
// ReqHasRole generates a fallback to check whether the user has a role
// ReqHasRole(org.RoleAdmin) will always return true for Grafana server admins, eg, a Grafana Admin / Viewer role combination
func ReqHasRole(role org.RoleType) func(c *contextmodel.ReqContext) bool {
return func(c *contextmodel.ReqContext) bool { return c.HasRole(role) }
return func(c *contextmodel.ReqContext) bool { return c.SignedInUser.HasRole(role) }
}
func BuildPermissionsMap(permissions []Permission) map[string]bool {
+1 -2
View File
@@ -5,7 +5,6 @@ import (
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/user"
)
var _ accesscontrol.Service = new(FakeService)
@@ -121,7 +120,7 @@ type FakePermissionsService struct {
ExpectedMappedAction string
}
func (f *FakePermissionsService) GetPermissions(ctx context.Context, user *user.SignedInUser, resourceID string) ([]accesscontrol.ResourcePermission, error) {
func (f *FakePermissionsService) GetPermissions(ctx context.Context, user identity.Requester, resourceID string) ([]accesscontrol.ResourcePermission, error) {
return f.ExpectedPermissions, f.ExpectedErr
}
+2 -1
View File
@@ -114,7 +114,8 @@ func (api *AccessControlAPI) searchUserPermissions(c *contextmodel.ReqContext) r
return response.JSON(http.StatusBadRequest, "provide one of 'action' or 'actionPrefix'")
}
permissions, err := api.Service.SearchUserPermissions(c.Req.Context(), c.OrgID, searchOptions)
permissions, err := api.Service.SearchUserPermissions(c.Req.Context(),
c.SignedInUser.GetOrgID(), searchOptions)
if err != nil {
response.Error(http.StatusInternalServerError, "could not search user permissions", err)
}
+7 -4
View File
@@ -15,6 +15,7 @@ import (
"github.com/grafana/grafana/pkg/middleware/cookies"
"github.com/grafana/grafana/pkg/models/usertoken"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/authn"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/org"
@@ -30,7 +31,7 @@ func Middleware(ac AccessControl) func(Evaluator) web.Handler {
if c.AllowAnonymous {
forceLogin, _ := strconv.ParseBool(c.Req.URL.Query().Get("forceLogin")) // ignoring error, assuming false for non-true values is ok.
orgID, err := strconv.ParseInt(c.Req.URL.Query().Get("orgId"), 10, 64)
if err == nil && orgID > 0 && orgID != c.OrgID {
if err == nil && orgID > 0 && orgID != c.SignedInUser.GetOrgID() {
forceLogin = true
}
@@ -56,9 +57,9 @@ func Middleware(ac AccessControl) func(Evaluator) web.Handler {
}
}
func authorize(c *contextmodel.ReqContext, ac AccessControl, user *user.SignedInUser, evaluator Evaluator) {
func authorize(c *contextmodel.ReqContext, ac AccessControl, user identity.Requester, evaluator Evaluator) {
injected, err := evaluator.MutateScopes(c.Req.Context(), scopeInjector(scopeParams{
OrgID: c.OrgID,
OrgID: user.GetOrgID(),
URLParams: web.Params(c.Req),
}))
if err != nil {
@@ -78,9 +79,11 @@ func deny(c *contextmodel.ReqContext, evaluator Evaluator, err error) {
if err != nil {
c.Logger.Error("Error from access control system", "error", err, "accessErrorID", id)
} else {
namespace, identifier := c.SignedInUser.GetNamespacedID()
c.Logger.Info(
"Access denied",
"userID", c.UserID,
"namespace", namespace,
"userID", identifier,
"accessErrorID", id,
"permissions", evaluator.GoString(),
)
@@ -6,7 +6,7 @@ import (
"github.com/stretchr/testify/mock"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/services/auth/identity"
)
var _ accesscontrol.PermissionsService = new(MockPermissionsService)
@@ -19,7 +19,7 @@ type MockPermissionsService struct {
mock.Mock
}
func (m *MockPermissionsService) GetPermissions(ctx context.Context, user *user.SignedInUser, resourceID string) ([]accesscontrol.ResourcePermission, error) {
func (m *MockPermissionsService) GetPermissions(ctx context.Context, user identity.Requester, resourceID string) ([]accesscontrol.ResourcePermission, error) {
mockedArgs := m.Called(ctx, user, resourceID)
return mockedArgs.Get(0).([]accesscontrol.ResourcePermission), mockedArgs.Error(1)
}
@@ -10,6 +10,7 @@ import (
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/folder"
@@ -253,7 +254,7 @@ var _ accesscontrol.DatasourcePermissionsService = new(DatasourcePermissionsServ
type DatasourcePermissionsService struct{}
func (e DatasourcePermissionsService) GetPermissions(ctx context.Context, user *user.SignedInUser, resourceID string) ([]accesscontrol.ResourcePermission, error) {
func (e DatasourcePermissionsService) GetPermissions(ctx context.Context, user identity.Requester, resourceID string) ([]accesscontrol.ResourcePermission, error) {
return nil, nil
}
@@ -155,7 +155,7 @@ func (a *api) setUserPermission(c *contextmodel.ReqContext) response.Response {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
_, err = a.service.SetUserPermission(c.Req.Context(), c.OrgID, accesscontrol.User{ID: userID}, resourceID, cmd.Permission)
_, err = a.service.SetUserPermission(c.Req.Context(), c.SignedInUser.GetOrgID(), accesscontrol.User{ID: userID}, resourceID, cmd.Permission)
if err != nil {
return response.Error(http.StatusBadRequest, "failed to set user permission", err)
}
@@ -175,7 +175,7 @@ func (a *api) setTeamPermission(c *contextmodel.ReqContext) response.Response {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
_, err = a.service.SetTeamPermission(c.Req.Context(), c.OrgID, teamID, resourceID, cmd.Permission)
_, err = a.service.SetTeamPermission(c.Req.Context(), c.SignedInUser.GetOrgID(), teamID, resourceID, cmd.Permission)
if err != nil {
return response.Error(http.StatusBadRequest, "failed to set team permission", err)
}
@@ -192,7 +192,7 @@ func (a *api) setBuiltinRolePermission(c *contextmodel.ReqContext) response.Resp
return response.Error(http.StatusBadRequest, "bad request data", err)
}
_, err := a.service.SetBuiltInRolePermission(c.Req.Context(), c.OrgID, builtInRole, resourceID, cmd.Permission)
_, err := a.service.SetBuiltInRolePermission(c.Req.Context(), c.SignedInUser.GetOrgID(), builtInRole, resourceID, cmd.Permission)
if err != nil {
return response.Error(http.StatusBadRequest, "failed to set role permission", err)
}
@@ -208,7 +208,7 @@ func (a *api) setPermissions(c *contextmodel.ReqContext) response.Response {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
_, err := a.service.SetPermissions(c.Req.Context(), c.OrgID, resourceID, cmd.Permissions...)
_, err := a.service.SetPermissions(c.Req.Context(), c.SignedInUser.GetOrgID(), resourceID, cmd.Permissions...)
if err != nil {
return response.Error(http.StatusBadRequest, "failed to set permissions", err)
}
@@ -2,7 +2,7 @@ package resourcepermissions
import (
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/services/auth/identity"
)
type SetResourcePermissionCommand struct {
@@ -29,5 +29,5 @@ type GetResourcePermissionsQuery struct {
OnlyManaged bool
InheritedScopes []string
EnforceAccessControl bool
User *user.SignedInUser
User identity.Requester
}
@@ -8,6 +8,7 @@ import (
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/licensing"
"github.com/grafana/grafana/pkg/services/org"
@@ -115,17 +116,17 @@ type Service struct {
userService user.Service
}
func (s *Service) GetPermissions(ctx context.Context, user *user.SignedInUser, resourceID string) ([]accesscontrol.ResourcePermission, error) {
func (s *Service) GetPermissions(ctx context.Context, user identity.Requester, resourceID string) ([]accesscontrol.ResourcePermission, error) {
var inheritedScopes []string
if s.options.InheritedScopesSolver != nil {
var err error
inheritedScopes, err = s.options.InheritedScopesSolver(ctx, user.OrgID, resourceID)
inheritedScopes, err = s.options.InheritedScopesSolver(ctx, user.GetOrgID(), resourceID)
if err != nil {
return nil, err
}
}
return s.store.GetResourcePermissions(ctx, user.OrgID, GetResourcePermissionsQuery{
return s.store.GetResourcePermissions(ctx, user.GetOrgID(), GetResourcePermissionsQuery{
User: user,
Actions: s.actions,
Resource: s.options.Resource,