mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
RBAC: remove some IsDisabled checks (#69272)
* remove some access contorl IsDisabled() checks * cleaning up tests * update tests * linting
This commit is contained in:
@@ -104,12 +104,8 @@ type User struct {
|
||||
}
|
||||
|
||||
// HasGlobalAccess checks user access with globally assigned permissions only
|
||||
func HasGlobalAccess(ac AccessControl, service Service, c *contextmodel.ReqContext) func(fallback func(*contextmodel.ReqContext) bool, evaluator Evaluator) bool {
|
||||
return func(fallback func(*contextmodel.ReqContext) bool, evaluator Evaluator) bool {
|
||||
if ac.IsDisabled() {
|
||||
return fallback(c)
|
||||
}
|
||||
|
||||
func HasGlobalAccess(ac AccessControl, service Service, c *contextmodel.ReqContext) func(evaluator Evaluator) bool {
|
||||
return func(evaluator Evaluator) bool {
|
||||
userCopy := *c.SignedInUser
|
||||
userCopy.OrgID = GlobalOrgID
|
||||
userCopy.OrgRole = ""
|
||||
|
||||
@@ -105,7 +105,7 @@ func (s *ServiceImpl) getAdminNode(c *contextmodel.ReqContext) (*navtree.NavLink
|
||||
})
|
||||
}
|
||||
|
||||
if hasGlobalAccess(ac.ReqGrafanaAdmin, orgsAccessEvaluator) {
|
||||
if hasGlobalAccess(orgsAccessEvaluator) {
|
||||
configNodes = append(configNodes, &navtree.NavLink{
|
||||
Text: "Organizations", SubTitle: "Isolated instances of Grafana running on the same server", Id: "global-orgs", Url: s.cfg.AppSubURL + "/admin/orgs", Icon: "building",
|
||||
})
|
||||
|
||||
@@ -237,8 +237,7 @@ func (s *ServiceImpl) addPluginToSection(c *contextmodel.ReqContext, treeRoot *n
|
||||
func (s *ServiceImpl) hasAccessToInclude(c *contextmodel.ReqContext, pluginID string) func(include *plugins.Includes) bool {
|
||||
hasAccess := ac.HasAccess(s.accessControl, c)
|
||||
return func(include *plugins.Includes) bool {
|
||||
useRBAC := s.features.IsEnabled(featuremgmt.FlagAccessControlOnCall) &&
|
||||
!s.accessControl.IsDisabled() && include.RequiresRBACAction()
|
||||
useRBAC := s.features.IsEnabled(featuremgmt.FlagAccessControlOnCall) && include.RequiresRBACAction()
|
||||
if useRBAC && !hasAccess(ac.EvalPermission(include.Action)) {
|
||||
s.log.Debug("plugin include is covered by RBAC, user doesn't have access",
|
||||
"plugin", pluginID,
|
||||
|
||||
@@ -51,7 +51,7 @@ var (
|
||||
// Returns http.StatusUnauthorized if user does not have access to any of the rules that match the filter.
|
||||
// Returns http.StatusBadRequest if all rules that match the filter and the user is authorized to delete are provisioned.
|
||||
func (srv RulerSrv) RouteDeleteAlertRules(c *contextmodel.ReqContext, namespaceTitle string, group string) response.Response {
|
||||
namespace, err := srv.store.GetNamespaceByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.OrgID, c.SignedInUser, true)
|
||||
namespace, err := srv.store.GetNamespaceByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.OrgID, c.SignedInUser)
|
||||
if err != nil {
|
||||
return toNamespaceErrorResponse(err)
|
||||
}
|
||||
@@ -148,7 +148,7 @@ func (srv RulerSrv) RouteDeleteAlertRules(c *contextmodel.ReqContext, namespaceT
|
||||
|
||||
// RouteGetNamespaceRulesConfig returns all rules in a specific folder that user has access to
|
||||
func (srv RulerSrv) RouteGetNamespaceRulesConfig(c *contextmodel.ReqContext, namespaceTitle string) response.Response {
|
||||
namespace, err := srv.store.GetNamespaceByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.OrgID, c.SignedInUser, false)
|
||||
namespace, err := srv.store.GetNamespaceByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.OrgID, c.SignedInUser)
|
||||
if err != nil {
|
||||
return toNamespaceErrorResponse(err)
|
||||
}
|
||||
@@ -191,7 +191,7 @@ func (srv RulerSrv) RouteGetNamespaceRulesConfig(c *contextmodel.ReqContext, nam
|
||||
// RouteGetRulesGroupConfig returns rules that belong to a specific group in a specific namespace (folder).
|
||||
// If user does not have access to at least one of the rule in the group, returns status 401 Unauthorized
|
||||
func (srv RulerSrv) RouteGetRulesGroupConfig(c *contextmodel.ReqContext, namespaceTitle string, ruleGroup string) response.Response {
|
||||
namespace, err := srv.store.GetNamespaceByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.OrgID, c.SignedInUser, false)
|
||||
namespace, err := srv.store.GetNamespaceByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.OrgID, c.SignedInUser)
|
||||
if err != nil {
|
||||
return toNamespaceErrorResponse(err)
|
||||
}
|
||||
@@ -297,7 +297,7 @@ func (srv RulerSrv) RouteGetRulesConfig(c *contextmodel.ReqContext) response.Res
|
||||
}
|
||||
|
||||
func (srv RulerSrv) RoutePostNameRulesConfig(c *contextmodel.ReqContext, ruleGroupConfig apimodels.PostableRuleGroupConfig, namespaceTitle string) response.Response {
|
||||
namespace, err := srv.store.GetNamespaceByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.OrgID, c.SignedInUser, true)
|
||||
namespace, err := srv.store.GetNamespaceByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.OrgID, c.SignedInUser)
|
||||
if err != nil {
|
||||
return toNamespaceErrorResponse(err)
|
||||
}
|
||||
@@ -336,14 +336,11 @@ func (srv RulerSrv) updateAlertRulesInGroup(c *contextmodel.ReqContext, groupKey
|
||||
return nil
|
||||
}
|
||||
|
||||
// if RBAC is disabled the permission are limited to folder access that is done upstream
|
||||
if !srv.ac.IsDisabled() {
|
||||
err = authorizeRuleChanges(groupChanges, func(evaluator accesscontrol.Evaluator) bool {
|
||||
return hasAccess(evaluator)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = authorizeRuleChanges(groupChanges, func(evaluator accesscontrol.Evaluator) bool {
|
||||
return hasAccess(evaluator)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := verifyProvisionedRulesNotAffected(c.Req.Context(), srv.provenanceStore, c.OrgID, groupChanges); err != nil {
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
// RuleStore is the interface for persisting alert rules and instances
|
||||
type RuleStore interface {
|
||||
GetUserVisibleNamespaces(context.Context, int64, *user.SignedInUser) (map[string]*folder.Folder, error)
|
||||
GetNamespaceByTitle(context.Context, string, int64, *user.SignedInUser, bool) (*folder.Folder, error)
|
||||
GetNamespaceByTitle(context.Context, string, int64, *user.SignedInUser) (*folder.Folder, error)
|
||||
GetAlertRulesGroupByRuleUID(ctx context.Context, query *ngmodels.GetAlertRulesGroupByRuleUIDQuery) ([]*ngmodels.AlertRule, error)
|
||||
ListAlertRules(ctx context.Context, query *ngmodels.ListAlertRulesQuery) (ngmodels.RulesGroup, error)
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ func (p *AlertingProxy) createProxyContext(ctx *contextmodel.ReqContext, request
|
||||
// Some data sources require legacy Editor role in order to perform mutating operations. In this case, we elevate permissions for the context that we
|
||||
// will provide downstream.
|
||||
// TODO (yuri) remove this after RBAC for plugins is implemented
|
||||
if !p.ac.IsDisabled() && !ctx.SignedInUser.HasRole(org.RoleEditor) {
|
||||
if !ctx.SignedInUser.HasRole(org.RoleEditor) {
|
||||
newUser := *ctx.SignedInUser
|
||||
newUser.OrgRole = org.RoleEditor
|
||||
cpy.SignedInUser = &newUser
|
||||
|
||||
@@ -139,26 +139,6 @@ func TestAlertingProxy_createProxyContext(t *testing.T) {
|
||||
}
|
||||
})
|
||||
})
|
||||
t.Run("if access control is disabled", func(t *testing.T) {
|
||||
t.Run("should not alter user", func(t *testing.T) {
|
||||
proxy := AlertingProxy{
|
||||
DataProxy: nil,
|
||||
ac: accesscontrolmock.New().WithDisabled(),
|
||||
}
|
||||
|
||||
req := &http.Request{}
|
||||
resp := &response.NormalResponse{}
|
||||
|
||||
for _, roleType := range []org.RoleType{org.RoleViewer, org.RoleEditor, org.RoleAdmin} {
|
||||
roleCtx := *ctx
|
||||
roleCtx.SignedInUser = &user.SignedInUser{
|
||||
OrgRole: roleType,
|
||||
}
|
||||
newCtx := proxy.createProxyContext(&roleCtx, req, resp)
|
||||
require.Equalf(t, roleCtx.SignedInUser, newCtx.SignedInUser, "user should not be altered if access control is disabled and role is %s", roleType)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_containsProvisionedAlerts(t *testing.T) {
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
"github.com/grafana/grafana/pkg/services/search/model"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
@@ -387,27 +386,12 @@ func (st DBstore) GetUserVisibleNamespaces(ctx context.Context, orgID int64, use
|
||||
}
|
||||
|
||||
// GetNamespaceByTitle is a handler for retrieving a namespace by its title. Alerting rules follow a Grafana folder-like structure which we call namespaces.
|
||||
func (st DBstore) GetNamespaceByTitle(ctx context.Context, namespace string, orgID int64, user *user.SignedInUser, withCanSave bool) (*folder.Folder, error) {
|
||||
func (st DBstore) GetNamespaceByTitle(ctx context.Context, namespace string, orgID int64, user *user.SignedInUser) (*folder.Folder, error) {
|
||||
folder, err := st.FolderService.Get(ctx, &folder.GetFolderQuery{OrgID: orgID, Title: &namespace, SignedInUser: user})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// if access control is disabled, check that the user is allowed to save in the folder.
|
||||
if withCanSave && st.AccessControl.IsDisabled() {
|
||||
g, err := guardian.NewByUID(ctx, folder.UID, orgID, user)
|
||||
if err != nil {
|
||||
return folder, err
|
||||
}
|
||||
|
||||
if canSave, err := g.CanSave(); err != nil || !canSave {
|
||||
if err != nil {
|
||||
st.Logger.Error("checking can save permission has failed", "userId", user.UserID, "username", user.Login, "namespace", namespace, "orgId", orgID, "error", err)
|
||||
}
|
||||
return nil, ngmodels.ErrCannotEditNamespace
|
||||
}
|
||||
}
|
||||
|
||||
return folder, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -245,7 +245,7 @@ func (f *RuleStore) GetUserVisibleNamespaces(_ context.Context, orgID int64, _ *
|
||||
return namespacesMap, nil
|
||||
}
|
||||
|
||||
func (f *RuleStore) GetNamespaceByTitle(_ context.Context, title string, orgID int64, _ *user.SignedInUser, _ bool) (*folder.Folder, error) {
|
||||
func (f *RuleStore) GetNamespaceByTitle(_ context.Context, title string, orgID int64, _ *user.SignedInUser) (*folder.Folder, error) {
|
||||
folders := f.Folders[orgID]
|
||||
for _, folder := range folders {
|
||||
if folder.Title == title {
|
||||
|
||||
@@ -110,18 +110,16 @@ func (api *ServiceAccountsAPI) CreateServiceAccount(c *contextmodel.ReqContext)
|
||||
return response.ErrOrFallback(http.StatusInternalServerError, "Failed to create service account", err)
|
||||
}
|
||||
|
||||
if !api.accesscontrol.IsDisabled() {
|
||||
if c.SignedInUser.IsRealUser() {
|
||||
if _, err := api.permissionService.SetUserPermission(c.Req.Context(), c.OrgID, accesscontrol.User{ID: c.SignedInUser.UserID}, strconv.FormatInt(serviceAccount.Id, 10), "Admin"); err != nil {
|
||||
return response.Error(http.StatusInternalServerError, "Failed to set permissions for service account creator", err)
|
||||
}
|
||||
if c.SignedInUser.IsRealUser() {
|
||||
if _, err := api.permissionService.SetUserPermission(c.Req.Context(), c.OrgID, accesscontrol.User{ID: c.SignedInUser.UserID}, strconv.FormatInt(serviceAccount.Id, 10), "Admin"); err != nil {
|
||||
return response.Error(http.StatusInternalServerError, "Failed to set permissions for service account creator", err)
|
||||
}
|
||||
|
||||
// Clear permission cache for the user who's created the service account, so that new permissions are fetched for their next call
|
||||
// Required for cases when caller wants to immediately interact with the newly created object
|
||||
api.accesscontrolService.ClearUserPermissionCache(c.SignedInUser)
|
||||
}
|
||||
|
||||
// Clear permission cache for the user who's created the service account, so that new permissions are fetched for their next call
|
||||
// Required for cases when caller wants to immediately interact with the newly created object
|
||||
api.accesscontrolService.ClearUserPermissionCache(c.SignedInUser)
|
||||
|
||||
return response.JSON(http.StatusCreated, serviceAccount)
|
||||
}
|
||||
|
||||
@@ -339,7 +337,7 @@ func (api *ServiceAccountsAPI) ConvertToServiceAccount(ctx *contextmodel.ReqCont
|
||||
}
|
||||
|
||||
func (api *ServiceAccountsAPI) getAccessControlMetadata(c *contextmodel.ReqContext, saIDs map[string]bool) map[string]accesscontrol.Metadata {
|
||||
if api.accesscontrol.IsDisabled() || !c.QueryBool("accesscontrol") {
|
||||
if !c.QueryBool("accesscontrol") {
|
||||
return map[string]accesscontrol.Metadata{}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,10 +77,8 @@ func ProvideService(
|
||||
return s, nil
|
||||
}
|
||||
|
||||
if !accessControl.IsDisabled() {
|
||||
if err := s.declareFixedRoles(accesscontrolService); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := s.declareFixedRoles(accesscontrolService); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.registerAPIEndpoints(httpServer, routeRegister)
|
||||
|
||||
Reference in New Issue
Block a user