RBAC: Fix authorize in org (#81552)
* RBAC: Fix authorize in org * Implement option 2 * Fix typo * Fix alerting test * Add test to cover the not member case
This commit is contained in:
@@ -39,13 +39,19 @@ func (a *AccessControl) Evaluate(ctx context.Context, user identity.Requester, e
|
||||
}
|
||||
|
||||
namespace, identifier := user.GetNamespacedID()
|
||||
if len(user.GetPermissions()) == 0 {
|
||||
|
||||
// If the user is in no organization, then the evaluation must happen based on the user's global permissions
|
||||
permissions := user.GetPermissions()
|
||||
if user.GetOrgID() == accesscontrol.NoOrgID {
|
||||
permissions = user.GetGlobalPermissions()
|
||||
}
|
||||
if len(permissions) == 0 {
|
||||
a.log.Debug("No permissions set for entity", "namespace", namespace, "id", identifier, "orgID", user.GetOrgID(), "login", user.GetLogin())
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Test evaluation without scope resolver first, this will prevent 403 for wildcard scopes when resource does not exist
|
||||
if evaluator.Evaluate(user.GetPermissions()) {
|
||||
if evaluator.Evaluate(permissions) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -57,7 +63,7 @@ func (a *AccessControl) Evaluate(ctx context.Context, user identity.Requester, e
|
||||
return false, err
|
||||
}
|
||||
|
||||
return resolvedEvaluator.Evaluate(user.GetPermissions()), nil
|
||||
return resolvedEvaluator.Evaluate(permissions), nil
|
||||
}
|
||||
|
||||
func (a *AccessControl) RegisterScopeAttributeResolver(prefix string, resolver accesscontrol.ScopeAttributeResolver) {
|
||||
|
||||
@@ -202,6 +202,24 @@ func TestAuthorizeInOrgMiddleware(t *testing.T) {
|
||||
teamService: &teamtest.FakeService{},
|
||||
expectedStatus: http.StatusForbidden,
|
||||
},
|
||||
{
|
||||
name: "should fetch global user permissions when user is not a member of the target org",
|
||||
orgIDGetter: func(c *contextmodel.ReqContext) (int64, error) {
|
||||
return 2, nil
|
||||
},
|
||||
evaluator: accesscontrol.EvalPermission("users:read", "users:*"),
|
||||
accessControl: ac,
|
||||
acService: &actest.FakeService{
|
||||
ExpectedPermissions: []accesscontrol.Permission{{Action: "users:read", Scope: "users:*"}},
|
||||
},
|
||||
userCache: &usertest.FakeUserService{
|
||||
GetSignedInUserFn: func(ctx context.Context, query *user.GetSignedInUserQuery) (*user.SignedInUser, error) {
|
||||
return &user.SignedInUser{UserID: 1, OrgID: -1, Permissions: map[int64]map[string][]string{}}, nil
|
||||
},
|
||||
},
|
||||
ctxSignedInUser: &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{1: {"users:write": {"users:*"}}}},
|
||||
expectedStatus: http.StatusOK,
|
||||
},
|
||||
}
|
||||
|
||||
// Run test cases
|
||||
|
||||
@@ -260,23 +260,32 @@ func makeTmpUser(ctx context.Context, service Service, cache userCache,
|
||||
tmpUser.OrgName = queryResult.OrgName
|
||||
tmpUser.OrgRole = queryResult.OrgRole
|
||||
|
||||
if teamService != nil {
|
||||
teamIDs, err := teamService.GetTeamIDsByUser(ctx, &team.GetTeamIDsByUserQuery{OrgID: targetOrgID, UserID: tmpUser.UserID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// Only fetch the team membership is the user is a member of the organization
|
||||
if queryResult.OrgID == targetOrgID {
|
||||
if teamService != nil {
|
||||
teamIDs, err := teamService.GetTeamIDsByUser(ctx, &team.GetTeamIDsByUserQuery{OrgID: targetOrgID, UserID: tmpUser.UserID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tmpUser.Teams = teamIDs
|
||||
}
|
||||
tmpUser.Teams = teamIDs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if tmpUser.Permissions[targetOrgID] == nil || len(tmpUser.Permissions[targetOrgID]) == 0 {
|
||||
// If the user is not a member of the organization
|
||||
// evaluation must happen based on global permissions.
|
||||
evaluationOrg := targetOrgID
|
||||
if tmpUser.OrgID == NoOrgID {
|
||||
evaluationOrg = GlobalOrgID
|
||||
}
|
||||
if tmpUser.Permissions[evaluationOrg] == nil || len(tmpUser.Permissions[evaluationOrg]) == 0 {
|
||||
permissions, err := service.GetUserPermissions(ctx, tmpUser, Options{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tmpUser.Permissions[targetOrgID] = GroupScopesByAction(permissions)
|
||||
tmpUser.Permissions[evaluationOrg] = GroupScopesByAction(permissions)
|
||||
}
|
||||
|
||||
return tmpUser, nil
|
||||
|
||||
@@ -330,6 +330,7 @@ func (cmd *SaveExternalServiceRoleCommand) Validate() error {
|
||||
|
||||
const (
|
||||
GlobalOrgID = 0
|
||||
NoOrgID = int64(-1)
|
||||
GeneralFolderUID = "general"
|
||||
RoleGrafanaAdmin = "Grafana Admin"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user