AccessControl: Compute metadata from context permissions (#45578)

* AccessControl: Compute metadata from context permissions

* Remove nil

Co-authored-by: Jguer <joao.guerreiro@grafana.com>

* Check user permissions are set

Co-authored-by: Jguer <joao.guerreiro@grafana.com>
This commit is contained in:
Gabriel MABILLE
2022-02-18 11:27:00 +01:00
committed by GitHub
co-authored by Jguer
parent a5fd35691b
commit 14bee49f9a
10 changed files with 213 additions and 281 deletions
+126 -97
View File
@@ -1,8 +1,10 @@
package api
import (
"fmt"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/setting"
)
@@ -29,49 +31,49 @@ const (
// API related scopes
var (
ScopeProvisionersAll = accesscontrol.Scope("provisioners", "*")
ScopeProvisionersDashboards = accesscontrol.Scope("provisioners", "dashboards")
ScopeProvisionersPlugins = accesscontrol.Scope("provisioners", "plugins")
ScopeProvisionersDatasources = accesscontrol.Scope("provisioners", "datasources")
ScopeProvisionersNotifications = accesscontrol.Scope("provisioners", "notifications")
ScopeProvisionersAll = ac.Scope("provisioners", "*")
ScopeProvisionersDashboards = ac.Scope("provisioners", "dashboards")
ScopeProvisionersPlugins = ac.Scope("provisioners", "plugins")
ScopeProvisionersDatasources = ac.Scope("provisioners", "datasources")
ScopeProvisionersNotifications = ac.Scope("provisioners", "notifications")
ScopeDatasourcesAll = accesscontrol.Scope("datasources", "*")
ScopeDatasourceID = accesscontrol.Scope("datasources", "id", accesscontrol.Parameter(":id"))
ScopeDatasourceUID = accesscontrol.Scope("datasources", "uid", accesscontrol.Parameter(":uid"))
ScopeDatasourceName = accesscontrol.Scope("datasources", "name", accesscontrol.Parameter(":name"))
ScopeDatasourcesAll = ac.Scope("datasources", "*")
ScopeDatasourceID = ac.Scope("datasources", "id", ac.Parameter(":id"))
ScopeDatasourceUID = ac.Scope("datasources", "uid", ac.Parameter(":uid"))
ScopeDatasourceName = ac.Scope("datasources", "name", ac.Parameter(":name"))
)
// declareFixedRoles declares to the AccessControl service fixed roles and their
// grants to organization roles ("Viewer", "Editor", "Admin") or "Grafana Admin"
// that HTTPServer needs
func (hs *HTTPServer) declareFixedRoles() error {
provisioningWriterRole := accesscontrol.RoleRegistration{
Role: accesscontrol.RoleDTO{
provisioningWriterRole := ac.RoleRegistration{
Role: ac.RoleDTO{
Version: 3,
Name: "fixed:provisioning:writer",
DisplayName: "Provisioning writer",
Description: "Reload provisioning.",
Group: "Provisioning",
Permissions: []accesscontrol.Permission{
Permissions: []ac.Permission{
{
Action: ActionProvisioningReload,
Scope: ScopeProvisionersAll,
},
},
},
Grants: []string{accesscontrol.RoleGrafanaAdmin},
Grants: []string{ac.RoleGrafanaAdmin},
}
datasourcesExplorerRole := accesscontrol.RoleRegistration{
Role: accesscontrol.RoleDTO{
datasourcesExplorerRole := ac.RoleRegistration{
Role: ac.RoleDTO{
Version: 4,
Name: "fixed:datasources:explorer",
DisplayName: "Data source explorer",
Description: "Enable the Explore feature. Data source permissions still apply; you can only query data sources for which you have query permissions.",
Group: "Data sources",
Permissions: []accesscontrol.Permission{
Permissions: []ac.Permission{
{
Action: accesscontrol.ActionDatasourcesExplore,
Action: ac.ActionDatasourcesExplore,
},
},
},
@@ -82,14 +84,14 @@ func (hs *HTTPServer) declareFixedRoles() error {
datasourcesExplorerRole.Grants = append(datasourcesExplorerRole.Grants, string(models.ROLE_VIEWER))
}
datasourcesReaderRole := accesscontrol.RoleRegistration{
Role: accesscontrol.RoleDTO{
datasourcesReaderRole := ac.RoleRegistration{
Role: ac.RoleDTO{
Version: 3,
Name: "fixed:datasources:reader",
DisplayName: "Data source reader",
Description: "Read and query all data sources.",
Group: "Data sources",
Permissions: []accesscontrol.Permission{
Permissions: []ac.Permission{
{
Action: ActionDatasourcesRead,
Scope: ScopeDatasourcesAll,
@@ -103,14 +105,14 @@ func (hs *HTTPServer) declareFixedRoles() error {
Grants: []string{string(models.ROLE_ADMIN)},
}
datasourcesWriterRole := accesscontrol.RoleRegistration{
Role: accesscontrol.RoleDTO{
datasourcesWriterRole := ac.RoleRegistration{
Role: ac.RoleDTO{
Version: 3,
Name: "fixed:datasources:writer",
DisplayName: "Data source writer",
Description: "Create, update, delete, read, or query data sources.",
Group: "Data sources",
Permissions: accesscontrol.ConcatPermissions(datasourcesReaderRole.Role.Permissions, []accesscontrol.Permission{
Permissions: ac.ConcatPermissions(datasourcesReaderRole.Role.Permissions, []ac.Permission{
{
Action: ActionDatasourcesWrite,
Scope: ScopeDatasourcesAll,
@@ -127,14 +129,14 @@ func (hs *HTTPServer) declareFixedRoles() error {
Grants: []string{string(models.ROLE_ADMIN)},
}
datasourcesIdReaderRole := accesscontrol.RoleRegistration{
Role: accesscontrol.RoleDTO{
datasourcesIdReaderRole := ac.RoleRegistration{
Role: ac.RoleDTO{
Version: 4,
Name: "fixed:datasources.id:reader",
DisplayName: "Data source ID reader",
Description: "Read the ID of a data source based on its name.",
Group: "Infrequently used",
Permissions: []accesscontrol.Permission{
Permissions: []ac.Permission{
{
Action: ActionDatasourcesIDRead,
Scope: ScopeDatasourcesAll,
@@ -144,14 +146,14 @@ func (hs *HTTPServer) declareFixedRoles() error {
Grants: []string{string(models.ROLE_VIEWER)},
}
datasourcesCompatibilityReaderRole := accesscontrol.RoleRegistration{
Role: accesscontrol.RoleDTO{
datasourcesCompatibilityReaderRole := ac.RoleRegistration{
Role: ac.RoleDTO{
Version: 3,
Name: "fixed:datasources:compatibility:querier",
DisplayName: "Data source compatibility querier",
Description: "Only used for open source compatibility. Query data sources.",
Group: "Infrequently used",
Permissions: []accesscontrol.Permission{
Permissions: []ac.Permission{
{Action: ActionDatasourcesQuery},
{Action: ActionDatasourcesRead},
},
@@ -159,29 +161,29 @@ func (hs *HTTPServer) declareFixedRoles() error {
Grants: []string{string(models.ROLE_VIEWER)},
}
orgReaderRole := accesscontrol.RoleRegistration{
Role: accesscontrol.RoleDTO{
orgReaderRole := ac.RoleRegistration{
Role: ac.RoleDTO{
Version: 5,
Name: "fixed:organization:reader",
DisplayName: "Organization reader",
Description: "Read an organization, such as its ID, name, address, or quotas.",
Group: "Organizations",
Permissions: []accesscontrol.Permission{
Permissions: []ac.Permission{
{Action: ActionOrgsRead},
{Action: ActionOrgsQuotasRead},
},
},
Grants: []string{string(models.ROLE_VIEWER), accesscontrol.RoleGrafanaAdmin},
Grants: []string{string(models.ROLE_VIEWER), ac.RoleGrafanaAdmin},
}
orgWriterRole := accesscontrol.RoleRegistration{
Role: accesscontrol.RoleDTO{
orgWriterRole := ac.RoleRegistration{
Role: ac.RoleDTO{
Version: 5,
Name: "fixed:organization:writer",
DisplayName: "Organization writer",
Description: "Read an organization, its quotas, or its preferences. Update organization properties, or its preferences.",
Group: "Organizations",
Permissions: accesscontrol.ConcatPermissions(orgReaderRole.Role.Permissions, []accesscontrol.Permission{
Permissions: ac.ConcatPermissions(orgReaderRole.Role.Permissions, []ac.Permission{
{Action: ActionOrgsPreferencesRead},
{Action: ActionOrgsWrite},
{Action: ActionOrgsPreferencesWrite},
@@ -190,71 +192,71 @@ func (hs *HTTPServer) declareFixedRoles() error {
Grants: []string{string(models.ROLE_ADMIN)},
}
orgMaintainerRole := accesscontrol.RoleRegistration{
Role: accesscontrol.RoleDTO{
orgMaintainerRole := ac.RoleRegistration{
Role: ac.RoleDTO{
Version: 5,
Name: "fixed:organization:maintainer",
DisplayName: "Organization maintainer",
Description: "Create, read, write, or delete an organization. Read or write an organization's quotas. Needs to be assigned globally.",
Group: "Organizations",
Permissions: accesscontrol.ConcatPermissions(orgReaderRole.Role.Permissions, []accesscontrol.Permission{
Permissions: ac.ConcatPermissions(orgReaderRole.Role.Permissions, []ac.Permission{
{Action: ActionOrgsCreate},
{Action: ActionOrgsWrite},
{Action: ActionOrgsDelete},
{Action: ActionOrgsQuotasWrite},
}),
},
Grants: []string{string(accesscontrol.RoleGrafanaAdmin)},
Grants: []string{string(ac.RoleGrafanaAdmin)},
}
teamCreatorGrants := []string{string(models.ROLE_ADMIN)}
if hs.Cfg.EditorsCanAdmin {
teamCreatorGrants = append(teamCreatorGrants, string(models.ROLE_EDITOR))
}
teamsCreatorRole := accesscontrol.RoleRegistration{
Role: accesscontrol.RoleDTO{
teamsCreatorRole := ac.RoleRegistration{
Role: ac.RoleDTO{
Name: "fixed:teams:creator",
DisplayName: "Team creator",
Description: "Create teams and read organisation users (required to manage the created teams).",
Group: "Teams",
Version: 2,
Permissions: []accesscontrol.Permission{
{Action: accesscontrol.ActionTeamsCreate},
{Action: accesscontrol.ActionOrgUsersRead, Scope: accesscontrol.ScopeUsersAll},
Permissions: []ac.Permission{
{Action: ac.ActionTeamsCreate},
{Action: ac.ActionOrgUsersRead, Scope: ac.ScopeUsersAll},
},
},
Grants: teamCreatorGrants,
}
teamsWriterRole := accesscontrol.RoleRegistration{
Role: accesscontrol.RoleDTO{
teamsWriterRole := ac.RoleRegistration{
Role: ac.RoleDTO{
Name: "fixed:teams:writer",
DisplayName: "Team writer",
Description: "Create, read, write, or delete a team as well as controlling team memberships.",
Group: "Teams",
Version: 2,
Permissions: []accesscontrol.Permission{
{Action: accesscontrol.ActionTeamsCreate},
{Action: accesscontrol.ActionTeamsDelete, Scope: accesscontrol.ScopeTeamsAll},
{Action: accesscontrol.ActionTeamsPermissionsRead, Scope: accesscontrol.ScopeTeamsAll},
{Action: accesscontrol.ActionTeamsPermissionsWrite, Scope: accesscontrol.ScopeTeamsAll},
{Action: accesscontrol.ActionTeamsRead, Scope: accesscontrol.ScopeTeamsAll},
{Action: accesscontrol.ActionTeamsWrite, Scope: accesscontrol.ScopeTeamsAll},
Permissions: []ac.Permission{
{Action: ac.ActionTeamsCreate},
{Action: ac.ActionTeamsDelete, Scope: ac.ScopeTeamsAll},
{Action: ac.ActionTeamsPermissionsRead, Scope: ac.ScopeTeamsAll},
{Action: ac.ActionTeamsPermissionsWrite, Scope: ac.ScopeTeamsAll},
{Action: ac.ActionTeamsRead, Scope: ac.ScopeTeamsAll},
{Action: ac.ActionTeamsWrite, Scope: ac.ScopeTeamsAll},
},
},
Grants: []string{string(models.ROLE_ADMIN)},
}
annotationsReaderRole := accesscontrol.RoleRegistration{
Role: accesscontrol.RoleDTO{
annotationsReaderRole := ac.RoleRegistration{
Role: ac.RoleDTO{
Name: "fixed:annotations:reader",
DisplayName: "Annotation reader",
Description: "Read annotations and tags",
Group: "Annotations",
Version: 1,
Permissions: []accesscontrol.Permission{
{Action: accesscontrol.ActionAnnotationsRead, Scope: accesscontrol.ScopeAnnotationsAll},
{Action: accesscontrol.ActionAnnotationsTagsRead, Scope: accesscontrol.ScopeAnnotationsTagsAll},
Permissions: []ac.Permission{
{Action: ac.ActionAnnotationsRead, Scope: ac.ScopeAnnotationsAll},
{Action: ac.ActionAnnotationsTagsRead, Scope: ac.ScopeAnnotationsTagsAll},
},
},
Grants: []string{string(models.ROLE_VIEWER)},
@@ -271,69 +273,96 @@ func (hs *HTTPServer) declareFixedRoles() error {
// here is the list of complex evaluators we use in this package
// dataSourcesConfigurationAccessEvaluator is used to protect the "Configure > Data sources" tab access
var dataSourcesConfigurationAccessEvaluator = accesscontrol.EvalAll(
accesscontrol.EvalPermission(ActionDatasourcesRead),
accesscontrol.EvalAny(
accesscontrol.EvalPermission(ActionDatasourcesCreate),
accesscontrol.EvalPermission(ActionDatasourcesDelete),
accesscontrol.EvalPermission(ActionDatasourcesWrite),
var dataSourcesConfigurationAccessEvaluator = ac.EvalAll(
ac.EvalPermission(ActionDatasourcesRead),
ac.EvalAny(
ac.EvalPermission(ActionDatasourcesCreate),
ac.EvalPermission(ActionDatasourcesDelete),
ac.EvalPermission(ActionDatasourcesWrite),
),
)
// dataSourcesNewAccessEvaluator is used to protect the "Configure > Data sources > New" page access
var dataSourcesNewAccessEvaluator = accesscontrol.EvalAll(
accesscontrol.EvalPermission(ActionDatasourcesRead),
accesscontrol.EvalPermission(ActionDatasourcesCreate),
accesscontrol.EvalPermission(ActionDatasourcesWrite),
var dataSourcesNewAccessEvaluator = ac.EvalAll(
ac.EvalPermission(ActionDatasourcesRead),
ac.EvalPermission(ActionDatasourcesCreate),
ac.EvalPermission(ActionDatasourcesWrite),
)
// dataSourcesEditAccessEvaluator is used to protect the "Configure > Data sources > Edit" page access
var dataSourcesEditAccessEvaluator = accesscontrol.EvalAll(
accesscontrol.EvalPermission(ActionDatasourcesRead),
accesscontrol.EvalPermission(ActionDatasourcesWrite),
var dataSourcesEditAccessEvaluator = ac.EvalAll(
ac.EvalPermission(ActionDatasourcesRead),
ac.EvalPermission(ActionDatasourcesWrite),
)
// orgPreferencesAccessEvaluator is used to protect the "Configure > Preferences" page access
var orgPreferencesAccessEvaluator = accesscontrol.EvalAny(
accesscontrol.EvalAll(
accesscontrol.EvalPermission(ActionOrgsRead),
accesscontrol.EvalPermission(ActionOrgsWrite),
var orgPreferencesAccessEvaluator = ac.EvalAny(
ac.EvalAll(
ac.EvalPermission(ActionOrgsRead),
ac.EvalPermission(ActionOrgsWrite),
),
accesscontrol.EvalAll(
accesscontrol.EvalPermission(ActionOrgsPreferencesRead),
accesscontrol.EvalPermission(ActionOrgsPreferencesWrite),
ac.EvalAll(
ac.EvalPermission(ActionOrgsPreferencesRead),
ac.EvalPermission(ActionOrgsPreferencesWrite),
),
)
// orgsAccessEvaluator is used to protect the "Server Admin > Orgs" page access
// (you need to have read access to update or delete orgs; read is the minimum)
var orgsAccessEvaluator = accesscontrol.EvalPermission(ActionOrgsRead)
var orgsAccessEvaluator = ac.EvalPermission(ActionOrgsRead)
// orgsCreateAccessEvaluator is used to protect the "Server Admin > Orgs > New Org" page access
var orgsCreateAccessEvaluator = accesscontrol.EvalAll(
accesscontrol.EvalPermission(ActionOrgsRead),
accesscontrol.EvalPermission(ActionOrgsCreate),
var orgsCreateAccessEvaluator = ac.EvalAll(
ac.EvalPermission(ActionOrgsRead),
ac.EvalPermission(ActionOrgsCreate),
)
// teamsAccessEvaluator is used to protect the "Configuration > Teams" page access
// grants access to a user when they can either create teams or can read and update a team
var teamsAccessEvaluator = accesscontrol.EvalAny(
accesscontrol.EvalPermission(accesscontrol.ActionTeamsCreate),
accesscontrol.EvalAll(
accesscontrol.EvalPermission(accesscontrol.ActionTeamsRead),
accesscontrol.EvalAny(
accesscontrol.EvalPermission(accesscontrol.ActionTeamsWrite),
accesscontrol.EvalPermission(accesscontrol.ActionTeamsPermissionsWrite),
var teamsAccessEvaluator = ac.EvalAny(
ac.EvalPermission(ac.ActionTeamsCreate),
ac.EvalAll(
ac.EvalPermission(ac.ActionTeamsRead),
ac.EvalAny(
ac.EvalPermission(ac.ActionTeamsWrite),
ac.EvalPermission(ac.ActionTeamsPermissionsWrite),
),
),
)
// teamsEditAccessEvaluator is used to protect the "Configuration > Teams > edit" page access
var teamsEditAccessEvaluator = accesscontrol.EvalAll(
accesscontrol.EvalPermission(accesscontrol.ActionTeamsRead),
accesscontrol.EvalAny(
accesscontrol.EvalPermission(accesscontrol.ActionTeamsCreate),
accesscontrol.EvalPermission(accesscontrol.ActionTeamsWrite),
accesscontrol.EvalPermission(accesscontrol.ActionTeamsPermissionsWrite),
var teamsEditAccessEvaluator = ac.EvalAll(
ac.EvalPermission(ac.ActionTeamsRead),
ac.EvalAny(
ac.EvalPermission(ac.ActionTeamsCreate),
ac.EvalPermission(ac.ActionTeamsWrite),
ac.EvalPermission(ac.ActionTeamsPermissionsWrite),
),
)
// Metadata helpers
// getAccessControlMetadata returns the accesscontrol metadata associated with a given resource
func (hs *HTTPServer) getAccessControlMetadata(c *models.ReqContext, resource string, id int64) ac.Metadata {
key := fmt.Sprintf("%d", id)
ids := map[string]bool{key: true}
return hs.getMultiAccessControlMetadata(c, resource, ids)[key]
}
// getMultiAccessControlMetadata returns the accesscontrol metadata associated with a given set of resources
func (hs *HTTPServer) getMultiAccessControlMetadata(c *models.ReqContext, resource string, ids map[string]bool) map[string]ac.Metadata {
if hs.AccessControl.IsDisabled() || !c.QueryBool("accesscontrol") {
return map[string]ac.Metadata{}
}
if c.SignedInUser.Permissions == nil {
return map[string]ac.Metadata{}
}
permissions, ok := c.SignedInUser.Permissions[c.OrgId]
if !ok {
return map[string]ac.Metadata{}
}
return ac.GetResourcesMetadata(c.Req.Context(), permissions, resource, ids)
}
+3 -28
View File
@@ -17,7 +17,6 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins/adapters"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web"
)
@@ -71,23 +70,6 @@ func (hs *HTTPServer) GetDataSources(c *models.ReqContext) response.Response {
return response.JSON(200, &result)
}
func (hs *HTTPServer) getDataSourceAccessControlMetadata(c *models.ReqContext, dsID int64) (accesscontrol.Metadata, error) {
if hs.AccessControl.IsDisabled() || !c.QueryBool("accesscontrol") {
return nil, nil
}
userPermissions, err := hs.AccessControl.GetUserPermissions(c.Req.Context(), c.SignedInUser,
accesscontrol.Options{ReloadCache: false})
if err != nil || len(userPermissions) == 0 {
return nil, err
}
key := fmt.Sprintf("%d", dsID)
dsIDs := map[string]bool{key: true}
return accesscontrol.GetResourcesMetadata(c.Req.Context(), userPermissions, "datasources", dsIDs)[key], nil
}
// GET /api/datasources/:id
func (hs *HTTPServer) GetDataSourceById(c *models.ReqContext) response.Response {
id, err := strconv.ParseInt(web.Params(c.Req)[":id"], 10, 64)
@@ -115,12 +97,9 @@ func (hs *HTTPServer) GetDataSourceById(c *models.ReqContext) response.Response
}
dto := convertModelToDtos(filtered[0])
// Add accesscontrol metadata
metadata, err := hs.getDataSourceAccessControlMetadata(c, dto.Id)
if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to query metadata", err)
}
dto.AccessControl = metadata
dto.AccessControl = hs.getAccessControlMetadata(c, "datasources", dto.Id)
return response.JSON(200, &dto)
}
@@ -179,11 +158,7 @@ func (hs *HTTPServer) GetDataSourceByUID(c *models.ReqContext) response.Response
dto := convertModelToDtos(filtered[0])
// Add accesscontrol metadata
metadata, err := hs.getDataSourceAccessControlMetadata(c, dto.Id)
if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to query metadata", err)
}
dto.AccessControl = metadata
dto.AccessControl = hs.getAccessControlMetadata(c, "datasources", dto.Id)
return response.JSON(200, &dto)
}
+5 -25
View File
@@ -10,7 +10,6 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web"
)
@@ -113,19 +112,6 @@ func (hs *HTTPServer) GetOrgUsersForCurrentOrgLookup(c *models.ReqContext) respo
return response.JSON(200, result)
}
func (hs *HTTPServer) getUserAccessControlMetadata(c *models.ReqContext, resourceIDs map[string]bool) (map[string]accesscontrol.Metadata, error) {
if hs.AccessControl == nil || hs.AccessControl.IsDisabled() || !c.QueryBool("accesscontrol") {
return nil, nil
}
userPermissions, err := hs.AccessControl.GetUserPermissions(c.Req.Context(), c.SignedInUser, accesscontrol.Options{ReloadCache: false})
if err != nil || len(userPermissions) == 0 {
return nil, err
}
return accesscontrol.GetResourcesMetadata(c.Req.Context(), userPermissions, "users", resourceIDs), nil
}
// GET /api/orgs/:orgId/users
func (hs *HTTPServer) GetOrgUsers(c *models.ReqContext) response.Response {
orgId, err := strconv.ParseInt(web.Params(c.Req)[":orgId"], 10, 64)
@@ -164,17 +150,11 @@ func (hs *HTTPServer) getOrgUsersHelper(c *models.ReqContext, query *models.GetO
filteredUsers = append(filteredUsers, user)
}
accessControlMetadata, errAC := hs.getUserAccessControlMetadata(c, userIDs)
if errAC != nil {
hs.log.Error("Failed to get access control metadata", "error", errAC)
return filteredUsers, nil
} else if accessControlMetadata == nil {
return filteredUsers, nil
}
for i := range filteredUsers {
filteredUsers[i].AccessControl = accessControlMetadata[fmt.Sprint(filteredUsers[i].UserId)]
accessControlMetadata := hs.getMultiAccessControlMetadata(c, "users", userIDs)
if len(accessControlMetadata) > 0 {
for i := range filteredUsers {
filteredUsers[i].AccessControl = accessControlMetadata[fmt.Sprint(filteredUsers[i].UserId)]
}
}
return filteredUsers, nil
+4 -37
View File
@@ -2,14 +2,12 @@ package api
import (
"errors"
"fmt"
"net/http"
"strconv"
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web"
@@ -105,20 +103,6 @@ func (hs *HTTPServer) DeleteTeamByID(c *models.ReqContext) response.Response {
return response.Success("Team deleted")
}
func (hs *HTTPServer) getTeamsAccessControlMetadata(c *models.ReqContext, teamIDs map[string]bool) (map[string]accesscontrol.Metadata, error) {
if hs.AccessControl.IsDisabled() || !c.QueryBool("accesscontrol") {
return nil, nil
}
userPermissions, err := hs.AccessControl.GetUserPermissions(c.Req.Context(), c.SignedInUser, accesscontrol.Options{ReloadCache: false})
if err != nil || len(userPermissions) == 0 {
hs.log.Warn("could not fetch accesscontrol metadata for teams", "error", err)
return nil, err
}
return accesscontrol.GetResourcesMetadata(c.Req.Context(), userPermissions, "teams", teamIDs), nil
}
// GET /api/teams/search
func (hs *HTTPServer) SearchTeams(c *models.ReqContext) response.Response {
perPage := c.QueryInt("perpage")
@@ -157,8 +141,8 @@ func (hs *HTTPServer) SearchTeams(c *models.ReqContext) response.Response {
teamIDs[strconv.FormatInt(team.Id, 10)] = true
}
metadata, err := hs.getTeamsAccessControlMetadata(c, teamIDs)
if err == nil && len(metadata) != 0 {
metadata := hs.getMultiAccessControlMetadata(c, "teams", teamIDs)
if len(metadata) > 0 {
for _, team := range query.Result.Teams {
team.AccessControl = metadata[strconv.FormatInt(team.Id, 10)]
}
@@ -170,23 +154,6 @@ func (hs *HTTPServer) SearchTeams(c *models.ReqContext) response.Response {
return response.JSON(200, query.Result)
}
func (hs *HTTPServer) getTeamAccessControlMetadata(c *models.ReqContext, teamID int64) (accesscontrol.Metadata, error) {
if hs.AccessControl.IsDisabled() || !c.QueryBool("accesscontrol") {
return nil, nil
}
userPermissions, err := hs.AccessControl.GetUserPermissions(c.Req.Context(), c.SignedInUser, accesscontrol.Options{ReloadCache: false})
if err != nil || len(userPermissions) == 0 {
hs.log.Warn("could not fetch accesscontrol metadata", "team", teamID, "error", err)
return nil, err
}
key := fmt.Sprintf("%d", teamID)
teamIDs := map[string]bool{key: true}
return accesscontrol.GetResourcesMetadata(c.Req.Context(), userPermissions, "teams", teamIDs)[key], nil
}
// UserFilter returns the user ID used in a filter when querying a team
// 1. If the user is a viewer or editor, this will return the user's ID.
// 2. If the user is an admin, this will return models.FilterIgnoreUser (0)
@@ -227,8 +194,8 @@ func (hs *HTTPServer) GetTeamByID(c *models.ReqContext) response.Response {
return response.Error(500, "Failed to get Team", err)
}
metadata, _ := hs.getTeamAccessControlMetadata(c, query.Result.Id)
query.Result.AccessControl = metadata
// Add accesscontrol metadata
query.Result.AccessControl = hs.getAccessControlMetadata(c, "teams", query.Result.Id)
query.Result.AvatarUrl = dtos.GetGravatarUrlWithDefault(query.Result.Email, query.Result.Name)
return response.JSON(200, &query.Result)
+1 -24
View File
@@ -3,14 +3,12 @@ package api
import (
"context"
"errors"
"fmt"
"net/http"
"strconv"
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web"
@@ -48,33 +46,12 @@ func (hs *HTTPServer) getUserUserProfile(c *models.ReqContext, userID int64) res
query.Result.IsExternal = true
}
accessControlMetadata, errAC := hs.getGlobalUserAccessControlMetadata(c, userID)
if errAC != nil {
hs.log.Error("Failed to get access control metadata", "error", errAC)
}
query.Result.AccessControl = accessControlMetadata
query.Result.AccessControl = hs.getAccessControlMetadata(c, "global:users", userID)
query.Result.AvatarUrl = dtos.GetGravatarUrl(query.Result.Email)
return response.JSON(200, query.Result)
}
func (hs *HTTPServer) getGlobalUserAccessControlMetadata(c *models.ReqContext, userID int64) (accesscontrol.Metadata, error) {
if hs.AccessControl == nil || hs.AccessControl.IsDisabled() || !c.QueryBool("accesscontrol") {
return nil, nil
}
userPermissions, err := hs.AccessControl.GetUserPermissions(c.Req.Context(), c.SignedInUser, accesscontrol.Options{ReloadCache: false})
if err != nil || len(userPermissions) == 0 {
return nil, err
}
key := fmt.Sprintf("%d", userID)
userIDs := map[string]bool{key: true}
return accesscontrol.GetResourcesMetadata(c.Req.Context(), userPermissions, "global:users", userIDs)[key], nil
}
// GET /api/users/lookup
func (hs *HTTPServer) GetUserByLoginOrEmail(c *models.ReqContext) response.Response {
query := models.GetUserByLoginQuery{LoginOrEmail: c.Query("loginOrEmail")}
+12 -11
View File
@@ -8,32 +8,33 @@ import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/oauth2"
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
"github.com/grafana/grafana/pkg/services/login/authinfoservice"
authinfostore "github.com/grafana/grafana/pkg/services/login/authinfoservice/database"
"github.com/grafana/grafana/pkg/services/searchusers"
"github.com/grafana/grafana/pkg/services/searchusers/filters"
"github.com/grafana/grafana/pkg/services/secrets/database"
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/setting"
"golang.org/x/oauth2"
"github.com/grafana/grafana/pkg/services/searchusers"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestUserAPIEndpoint_userLoggedIn(t *testing.T) {
settings := setting.NewCfg()
sqlStore := sqlstore.InitTestDB(t)
hs := &HTTPServer{
Cfg: settings,
SQLStore: sqlStore,
Cfg: settings,
SQLStore: sqlStore,
AccessControl: &acmock.Mock{},
}
mockResult := models.SearchUserQueryResult{