mirror of
https://github.com/grafana/grafana.git
synced 2025-07-31 13:52:12 +08:00
Add auth spans and remove deduplication code for scopes (#89804)
Adds more spans for timing in accesscontrol and remove permission deduplicating code after benchmarking --------- Signed-off-by: Dave Henderson <dave.henderson@grafana.com> Co-authored-by: Dave Henderson <dave.henderson@grafana.com> Co-authored-by: Ieva <ieva.vasiljeva@grafana.com>
This commit is contained in:
@ -250,12 +250,12 @@ func setupScenarioContextSamlLogout(t *testing.T, url string) *scenarioContext {
|
||||
|
||||
// FIXME: This user should not be anonymous
|
||||
func authedUserWithPermissions(userID, orgID int64, permissions []accesscontrol.Permission) *user.SignedInUser {
|
||||
return &user.SignedInUser{UserID: userID, OrgID: orgID, OrgRole: org.RoleViewer, Permissions: map[int64]map[string][]string{orgID: accesscontrol.GroupScopesByAction(permissions)}}
|
||||
return &user.SignedInUser{UserID: userID, OrgID: orgID, OrgRole: org.RoleViewer, Permissions: map[int64]map[string][]string{orgID: accesscontrol.GroupScopesByActionContext(context.Background(), permissions)}}
|
||||
}
|
||||
|
||||
// FIXME: This user should not be anonymous
|
||||
func userWithPermissions(orgID int64, permissions []accesscontrol.Permission) *user.SignedInUser {
|
||||
return &user.SignedInUser{IsAnonymous: true, OrgID: orgID, OrgRole: org.RoleViewer, Permissions: map[int64]map[string][]string{orgID: accesscontrol.GroupScopesByAction(permissions)}}
|
||||
return &user.SignedInUser{IsAnonymous: true, OrgID: orgID, OrgRole: org.RoleViewer, Permissions: map[int64]map[string][]string{orgID: accesscontrol.GroupScopesByActionContext(context.Background(), permissions)}}
|
||||
}
|
||||
|
||||
func setupSimpleHTTPServer(features featuremgmt.FeatureToggles) *HTTPServer {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@ -282,7 +283,7 @@ func TestHTTPServer_FolderMetadata(t *testing.T) {
|
||||
|
||||
req := server.NewGetRequest("/api/folders/folderUid?accesscontrol=true")
|
||||
webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{
|
||||
1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{
|
||||
1: accesscontrol.GroupScopesByActionContext(context.Background(), []accesscontrol.Permission{
|
||||
{Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersAll},
|
||||
{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("folderUid")},
|
||||
}),
|
||||
@ -311,7 +312,7 @@ func TestHTTPServer_FolderMetadata(t *testing.T) {
|
||||
|
||||
req := server.NewGetRequest("/api/folders/folderUid?accesscontrol=true")
|
||||
webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{
|
||||
1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{
|
||||
1: accesscontrol.GroupScopesByActionContext(context.Background(), []accesscontrol.Permission{
|
||||
{Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersAll},
|
||||
{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("parentUid")},
|
||||
{Action: dashboards.ActionDashboardsCreate, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("folderUid")},
|
||||
@ -336,7 +337,7 @@ func TestHTTPServer_FolderMetadata(t *testing.T) {
|
||||
|
||||
req := server.NewGetRequest("/api/folders/folderUid")
|
||||
webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{
|
||||
1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{
|
||||
1: accesscontrol.GroupScopesByActionContext(context.Background(), []accesscontrol.Permission{
|
||||
{Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersAll},
|
||||
{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("folderUid")},
|
||||
}),
|
||||
|
@ -1,6 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
@ -220,7 +221,7 @@ func TestAPIEndpoint_DeleteOrgs(t *testing.T) {
|
||||
expectedIdentity := &authn.Identity{
|
||||
OrgID: 1,
|
||||
Permissions: map[int64]map[string][]string{
|
||||
1: accesscontrol.GroupScopesByAction(tt.permission),
|
||||
1: accesscontrol.GroupScopesByActionContext(context.Background(), tt.permission),
|
||||
},
|
||||
}
|
||||
|
||||
@ -269,8 +270,8 @@ func TestAPIEndpoint_GetOrg(t *testing.T) {
|
||||
ID: authn.MustParseNamespaceID("user:1"),
|
||||
OrgID: 1,
|
||||
Permissions: map[int64]map[string][]string{
|
||||
0: accesscontrol.GroupScopesByAction(tt.permissions),
|
||||
1: accesscontrol.GroupScopesByAction(tt.permissions),
|
||||
0: accesscontrol.GroupScopesByActionContext(context.Background(), tt.permissions),
|
||||
1: accesscontrol.GroupScopesByActionContext(context.Background(), tt.permissions),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,7 @@ func TestCallResource(t *testing.T) {
|
||||
t.Run("Test successful response is received for valid request", func(t *testing.T) {
|
||||
req := srv.NewPostRequest("/api/plugins/grafana-testdata-datasource/resources/test", strings.NewReader(`{"test": "true"}`))
|
||||
webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{
|
||||
1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{
|
||||
1: accesscontrol.GroupScopesByActionContext(context.Background(), []accesscontrol.Permission{
|
||||
{Action: pluginaccesscontrol.ActionAppAccess, Scope: pluginaccesscontrol.ScopeProvider.GetResourceAllScope()},
|
||||
}),
|
||||
}})
|
||||
@ -92,7 +92,7 @@ func TestCallResource(t *testing.T) {
|
||||
t.Run("Test successful response is received for valid request with the colon character", func(t *testing.T) {
|
||||
req := srv.NewPostRequest("/api/plugins/grafana-testdata-datasource/resources/test-*,*:test-*/_mapping", strings.NewReader(`{"test": "true"}`))
|
||||
webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{
|
||||
1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{
|
||||
1: accesscontrol.GroupScopesByActionContext(context.Background(), []accesscontrol.Permission{
|
||||
{Action: pluginaccesscontrol.ActionAppAccess, Scope: pluginaccesscontrol.ScopeProvider.GetResourceAllScope()},
|
||||
}),
|
||||
}})
|
||||
@ -146,7 +146,7 @@ func TestCallResource(t *testing.T) {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
req := srv.NewPostRequest(tc.url, strings.NewReader(`{"test": "true"}`))
|
||||
webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{
|
||||
1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{
|
||||
1: accesscontrol.GroupScopesByActionContext(context.Background(), []accesscontrol.Permission{
|
||||
{Action: pluginaccesscontrol.ActionAppAccess, Scope: pluginaccesscontrol.ScopeProvider.GetResourceAllScope()},
|
||||
}),
|
||||
}})
|
||||
@ -192,7 +192,7 @@ func TestCallResource(t *testing.T) {
|
||||
t.Run("Test error is properly propagated to API response", func(t *testing.T) {
|
||||
req := srv.NewGetRequest("/api/plugins/grafana-testdata-datasource/resources/scenarios")
|
||||
webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{
|
||||
1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{
|
||||
1: accesscontrol.GroupScopesByActionContext(context.Background(), []accesscontrol.Permission{
|
||||
{Action: pluginaccesscontrol.ActionAppAccess, Scope: pluginaccesscontrol.ScopeProvider.GetResourceAllScope()},
|
||||
}),
|
||||
}})
|
||||
|
@ -104,7 +104,7 @@ func Test_PluginsInstallAndUninstall(t *testing.T) {
|
||||
Permissions: map[int64]map[string][]string{},
|
||||
OrgRoles: map[int64]org.RoleType{},
|
||||
}
|
||||
expectedIdentity.Permissions[tc.permissionOrg] = ac.GroupScopesByAction(tc.permissions)
|
||||
expectedIdentity.Permissions[tc.permissionOrg] = ac.GroupScopesByActionContext(context.Background(), tc.permissions)
|
||||
hs.authnService = &authntest.FakeService{
|
||||
ExpectedIdentity: expectedIdentity,
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
@ -156,7 +157,7 @@ func TestAPIEndpoint_PutOrgQuotas(t *testing.T) {
|
||||
Permissions: map[int64]map[string][]string{},
|
||||
}
|
||||
for orgID, permissions := range tt.permissions {
|
||||
expectedIdentity.Permissions[orgID] = accesscontrol.GroupScopesByAction(permissions)
|
||||
expectedIdentity.Permissions[orgID] = accesscontrol.GroupScopesByActionContext(context.Background(), permissions)
|
||||
}
|
||||
|
||||
server := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||
|
@ -12,8 +12,13 @@ import (
|
||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
var tracer = otel.Tracer("github.com/grafana/grafana/pkg/services/accesscontrol")
|
||||
|
||||
type AccessControl interface {
|
||||
// Evaluate evaluates access to the given resources.
|
||||
Evaluate(ctx context.Context, user identity.Requester, evaluator Evaluator) (bool, error)
|
||||
@ -232,30 +237,24 @@ func BuildPermissionsMap(permissions []Permission) map[string]bool {
|
||||
}
|
||||
|
||||
// GroupScopesByAction will group scopes on action
|
||||
//
|
||||
// Deprecated: use GroupScopesByActionContext instead
|
||||
func GroupScopesByAction(permissions []Permission) map[string][]string {
|
||||
// Use a map to deduplicate scopes.
|
||||
// User can have the same permission from multiple sources (e.g. team, basic role, directly assigned etc).
|
||||
// User will also have duplicate permissions if action sets are used, as we will be double writing permissions for a while.
|
||||
m := make(map[string]map[string]struct{})
|
||||
return GroupScopesByActionContext(context.Background(), permissions)
|
||||
}
|
||||
|
||||
// GroupScopesByAction will group scopes on action
|
||||
func GroupScopesByActionContext(ctx context.Context, permissions []Permission) map[string][]string {
|
||||
_, span := tracer.Start(ctx, "accesscontrol.GroupScopesByActionContext", trace.WithAttributes(
|
||||
attribute.Int("permissions_count", len(permissions)),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
m := make(map[string][]string)
|
||||
for i := range permissions {
|
||||
if _, ok := m[permissions[i].Action]; !ok {
|
||||
m[permissions[i].Action] = make(map[string]struct{})
|
||||
}
|
||||
m[permissions[i].Action][permissions[i].Scope] = struct{}{}
|
||||
m[permissions[i].Action] = append(m[permissions[i].Action], permissions[i].Scope)
|
||||
}
|
||||
|
||||
res := make(map[string][]string, len(m))
|
||||
for action, scopes := range m {
|
||||
scopeList := make([]string, len(scopes))
|
||||
i := 0
|
||||
for scope := range scopes {
|
||||
scopeList[i] = scope
|
||||
i++
|
||||
}
|
||||
res[action] = scopeList
|
||||
}
|
||||
|
||||
return res
|
||||
return m
|
||||
}
|
||||
|
||||
// Reduce will reduce a list of permissions to its minimal form, grouping scopes by action
|
||||
|
@ -1,8 +1,11 @@
|
||||
package accesscontrol
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
// this import is needed for github.com/grafana/grafana/pkg/web hack_wrap to work
|
||||
@ -125,3 +128,54 @@ func TestReduce(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGroupScopesByActionContext(t *testing.T) {
|
||||
// test data = 3 actions with 2+i scopes each, including a duplicate
|
||||
permissions := []Permission{}
|
||||
for i := 0; i < 3; i++ {
|
||||
for j := 0; j < 2+i; j++ {
|
||||
permissions = append(permissions, Permission{
|
||||
Action: fmt.Sprintf("action:%d", i),
|
||||
Scope: fmt.Sprintf("scope:%d_%d", i, j),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
expected := map[string][]string{}
|
||||
for i := 0; i < 3; i++ {
|
||||
action := fmt.Sprintf("action:%d", i)
|
||||
scopes := []string{}
|
||||
for j := 0; j < 2+i; j++ {
|
||||
scopes = append(scopes, fmt.Sprintf("scope:%d_%d", i, j))
|
||||
}
|
||||
expected[action] = scopes
|
||||
}
|
||||
|
||||
assert.EqualValues(t, expected, GroupScopesByActionContext(context.Background(), permissions))
|
||||
}
|
||||
|
||||
func BenchmarkGroupScopesByAction(b *testing.B) {
|
||||
// create a big list of permissions with a bunch of duplicates
|
||||
permissions := []Permission{}
|
||||
for i := 0; i < 100; i++ {
|
||||
for j := 0; j < 500+i; j++ {
|
||||
permissions = append(permissions, Permission{
|
||||
Action: fmt.Sprintf("action:%d", i),
|
||||
Scope: fmt.Sprintf("scope:%d_%d", i, j),
|
||||
})
|
||||
}
|
||||
// add duplicate scopes
|
||||
for j := 0; j < 10; j++ {
|
||||
permissions = append(permissions, Permission{
|
||||
Action: fmt.Sprintf("action:%d", i),
|
||||
Scope: fmt.Sprintf("scope:%d_%d", i, 0),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
GroupScopesByActionContext(context.Background(), permissions)
|
||||
}
|
||||
}
|
||||
|
@ -114,6 +114,7 @@ func (s *Service) GetUsageStats(_ context.Context) map[string]any {
|
||||
func (s *Service) GetUserPermissions(ctx context.Context, user identity.Requester, options accesscontrol.Options) ([]accesscontrol.Permission, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authz.GetUserPermissionsOSS")
|
||||
defer span.End()
|
||||
|
||||
timer := prometheus.NewTimer(metrics.MAccessPermissionsSummary)
|
||||
defer timer.ObserveDuration()
|
||||
|
||||
@ -125,6 +126,9 @@ func (s *Service) GetUserPermissions(ctx context.Context, user identity.Requeste
|
||||
}
|
||||
|
||||
func (s *Service) getUserPermissions(ctx context.Context, user identity.Requester, options accesscontrol.Options) ([]accesscontrol.Permission, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authz.getUserPermissions")
|
||||
defer span.End()
|
||||
|
||||
permissions := make([]accesscontrol.Permission, 0)
|
||||
for _, builtin := range accesscontrol.GetOrgRoles(user) {
|
||||
if basicRole, ok := s.roles[builtin]; ok {
|
||||
@ -265,8 +269,10 @@ func (s *Service) getCachedBasicRolesPermissions(ctx context.Context, user ident
|
||||
defer span.End()
|
||||
|
||||
basicRoles := accesscontrol.GetOrgRoles(user)
|
||||
span.SetAttributes(attribute.Int("roles", len(basicRoles)))
|
||||
for _, role := range basicRoles {
|
||||
perms, err := s.getCachedBasicRolePermissions(ctx, role, user.GetOrgID(), options)
|
||||
span.SetAttributes(attribute.Int(fmt.Sprintf("role_%s_permissions", role), len(perms)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -301,12 +307,13 @@ type getPermissionsFunc = func(ctx context.Context) ([]accesscontrol.Permission,
|
||||
|
||||
// Generic method for getting various permissions from cache
|
||||
func (s *Service) getCachedPermissions(ctx context.Context, key string, getPermissionsFn getPermissionsFunc, options accesscontrol.Options) ([]accesscontrol.Permission, error) {
|
||||
_, span := s.tracer.Start(ctx, "authz.getCachedPermissions")
|
||||
ctx, span := s.tracer.Start(ctx, "authz.getCachedPermissions")
|
||||
defer span.End()
|
||||
|
||||
if !options.ReloadCache {
|
||||
permissions, ok := s.cache.Get(key)
|
||||
if ok {
|
||||
span.SetAttributes(attribute.Int("num_permissions_cached", len(permissions.([]accesscontrol.Permission))))
|
||||
metrics.MAccessPermissionsCacheUsage.WithLabelValues(accesscontrol.CacheHit).Inc()
|
||||
return permissions.([]accesscontrol.Permission), nil
|
||||
}
|
||||
@ -315,6 +322,7 @@ func (s *Service) getCachedPermissions(ctx context.Context, key string, getPermi
|
||||
span.AddEvent("cache miss")
|
||||
metrics.MAccessPermissionsCacheUsage.WithLabelValues(accesscontrol.CacheMiss).Inc()
|
||||
permissions, err := getPermissionsFn(ctx)
|
||||
span.SetAttributes(attribute.Int("num_permissions_fetched", len(permissions)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -338,6 +346,7 @@ func (s *Service) getCachedTeamsPermissions(ctx context.Context, user identity.R
|
||||
teamPermissions, ok := s.cache.Get(key)
|
||||
if ok {
|
||||
metrics.MAccessPermissionsCacheUsage.WithLabelValues(accesscontrol.CacheHit).Inc()
|
||||
span.SetAttributes(attribute.Int("num_permissions_cached", len(teamPermissions.([]accesscontrol.Permission))))
|
||||
permissions = append(permissions, teamPermissions.([]accesscontrol.Permission)...)
|
||||
} else {
|
||||
miss = append(miss, teamID)
|
||||
@ -349,6 +358,7 @@ func (s *Service) getCachedTeamsPermissions(ctx context.Context, user identity.R
|
||||
span.AddEvent("cache miss")
|
||||
metrics.MAccessPermissionsCacheUsage.WithLabelValues(accesscontrol.CacheMiss).Inc()
|
||||
teamsPermissions, err := s.getTeamsPermissions(ctx, miss, orgID)
|
||||
span.SetAttributes(attribute.Int("num_permissions_fetched", len(teamsPermissions)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -369,10 +379,16 @@ func (s *Service) ClearUserPermissionCache(user identity.Requester) {
|
||||
}
|
||||
|
||||
func (s *Service) DeleteUserPermissions(ctx context.Context, orgID int64, userID int64) error {
|
||||
ctx, span := s.tracer.Start(ctx, "authz.DeleteUserPermissions")
|
||||
defer span.End()
|
||||
|
||||
return s.store.DeleteUserPermissions(ctx, orgID, userID)
|
||||
}
|
||||
|
||||
func (s *Service) DeleteTeamPermissions(ctx context.Context, orgID int64, teamID int64) error {
|
||||
ctx, span := s.tracer.Start(ctx, "authz.DeleteTeamPermissions")
|
||||
defer span.End()
|
||||
|
||||
return s.store.DeleteTeamPermissions(ctx, orgID, teamID)
|
||||
}
|
||||
|
||||
@ -398,6 +414,9 @@ func (s *Service) DeclareFixedRoles(registrations ...accesscontrol.RoleRegistrat
|
||||
|
||||
// RegisterFixedRoles registers all declared roles in RAM
|
||||
func (s *Service) RegisterFixedRoles(ctx context.Context) error {
|
||||
_, span := s.tracer.Start(ctx, "authz.RegisterFixedRoles")
|
||||
defer span.End()
|
||||
|
||||
s.registrations.Range(func(registration accesscontrol.RoleRegistration) bool {
|
||||
for br := range accesscontrol.BuiltInRolesWithParents(registration.Grants) {
|
||||
if basicRole, ok := s.roles[br]; ok {
|
||||
@ -421,6 +440,9 @@ func (s *Service) RegisterFixedRoles(ctx context.Context) error {
|
||||
// DeclarePluginRoles allow the caller to declare, to the service, plugin roles and their assignments
|
||||
// to organization roles ("Viewer", "Editor", "Admin") or "Grafana Admin"
|
||||
func (s *Service) DeclarePluginRoles(ctx context.Context, ID, name string, regs []plugins.RoleRegistration) error {
|
||||
ctx, span := s.tracer.Start(ctx, "authz.DeclarePluginRoles")
|
||||
defer span.End()
|
||||
|
||||
// Protect behind feature toggle
|
||||
if !s.features.IsEnabled(ctx, featuremgmt.FlagAccessControlOnCall) {
|
||||
return nil
|
||||
@ -455,6 +477,9 @@ func GetActionFilter(options accesscontrol.SearchOptions) func(action string) bo
|
||||
|
||||
// SearchUsersPermissions returns all users' permissions filtered by action prefixes
|
||||
func (s *Service) SearchUsersPermissions(ctx context.Context, usr identity.Requester, options accesscontrol.SearchOptions) (map[int64][]accesscontrol.Permission, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authz.SearchUsersPermissions")
|
||||
defer span.End()
|
||||
|
||||
// Limit roles to available in OSS
|
||||
options.RolePrefixes = OSSRolesPrefixes
|
||||
if options.NamespacedID != "" {
|
||||
@ -566,6 +591,9 @@ func (s *Service) SearchUsersPermissions(ctx context.Context, usr identity.Reque
|
||||
}
|
||||
|
||||
func (s *Service) SearchUserPermissions(ctx context.Context, orgID int64, searchOptions accesscontrol.SearchOptions) ([]accesscontrol.Permission, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authz.SearchUserPermissions")
|
||||
defer span.End()
|
||||
|
||||
timer := prometheus.NewTimer(metrics.MAccessPermissionsSummary)
|
||||
defer timer.ObserveDuration()
|
||||
|
||||
@ -573,13 +601,16 @@ func (s *Service) SearchUserPermissions(ctx context.Context, orgID int64, search
|
||||
return nil, fmt.Errorf("expected namespaced ID to be specified")
|
||||
}
|
||||
|
||||
if permissions, success := s.searchUserPermissionsFromCache(orgID, searchOptions); success {
|
||||
if permissions, success := s.searchUserPermissionsFromCache(ctx, orgID, searchOptions); success {
|
||||
return permissions, nil
|
||||
}
|
||||
return s.searchUserPermissions(ctx, orgID, searchOptions)
|
||||
}
|
||||
|
||||
func (s *Service) searchUserPermissions(ctx context.Context, orgID int64, searchOptions accesscontrol.SearchOptions) ([]accesscontrol.Permission, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authz.searchUserPermissions")
|
||||
defer span.End()
|
||||
|
||||
userID, err := searchOptions.ComputeUserID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -629,7 +660,10 @@ func (s *Service) searchUserPermissions(ctx context.Context, orgID int64, search
|
||||
return permissions, nil
|
||||
}
|
||||
|
||||
func (s *Service) searchUserPermissionsFromCache(orgID int64, searchOptions accesscontrol.SearchOptions) ([]accesscontrol.Permission, bool) {
|
||||
func (s *Service) searchUserPermissionsFromCache(ctx context.Context, orgID int64, searchOptions accesscontrol.SearchOptions) ([]accesscontrol.Permission, bool) {
|
||||
_, span := s.tracer.Start(ctx, "authz.searchUserPermissionsFromCache")
|
||||
defer span.End()
|
||||
|
||||
userID, err := searchOptions.ComputeUserID()
|
||||
if err != nil {
|
||||
return nil, false
|
||||
@ -669,6 +703,9 @@ func PermissionMatchesSearchOptions(permission accesscontrol.Permission, searchO
|
||||
}
|
||||
|
||||
func (s *Service) SaveExternalServiceRole(ctx context.Context, cmd accesscontrol.SaveExternalServiceRoleCommand) error {
|
||||
ctx, span := s.tracer.Start(ctx, "authz.SaveExternalServiceRole")
|
||||
defer span.End()
|
||||
|
||||
if !s.features.IsEnabled(ctx, featuremgmt.FlagExternalServiceAccounts) {
|
||||
s.log.Debug("Registering an external service role is behind a feature flag, enable it to use this feature.")
|
||||
return nil
|
||||
@ -682,6 +719,9 @@ func (s *Service) SaveExternalServiceRole(ctx context.Context, cmd accesscontrol
|
||||
}
|
||||
|
||||
func (s *Service) DeleteExternalServiceRole(ctx context.Context, externalServiceID string) error {
|
||||
ctx, span := s.tracer.Start(ctx, "authz.DeleteExternalServiceRole")
|
||||
defer span.End()
|
||||
|
||||
if !s.features.IsEnabled(ctx, featuremgmt.FlagExternalServiceAccounts) {
|
||||
s.log.Debug("Deleting an external service role is behind a feature flag, enable it to use this feature.")
|
||||
return nil
|
||||
@ -697,6 +737,9 @@ func (*Service) SyncUserRoles(ctx context.Context, orgID int64, cmd accesscontro
|
||||
}
|
||||
|
||||
func (s *Service) GetRoleByName(ctx context.Context, orgID int64, roleName string) (*accesscontrol.RoleDTO, error) {
|
||||
_, span := s.tracer.Start(ctx, "authz.GetRoleByName")
|
||||
defer span.End()
|
||||
|
||||
err := accesscontrol.ErrRoleNotFound
|
||||
if _, ok := s.roles[roleName]; ok {
|
||||
return nil, err
|
||||
|
@ -42,6 +42,7 @@ func setupTestEnv(t testing.TB) *Service {
|
||||
registrations: accesscontrol.RegistrationList{},
|
||||
roles: accesscontrol.BuildBasicRoleDefinitions(),
|
||||
store: database.ProvideService(db.InitTestDB(t)),
|
||||
tracer: tracing.InitializeTracerForTest(),
|
||||
}
|
||||
require.NoError(t, ac.RegisterFixedRoles(context.Background()))
|
||||
return ac
|
||||
|
@ -62,7 +62,7 @@ func (api *AccessControlAPI) getUserPermissions(c *contextmodel.ReqContext) resp
|
||||
return response.JSON(http.StatusInternalServerError, err)
|
||||
}
|
||||
|
||||
return response.JSON(http.StatusOK, ac.GroupScopesByAction(permissions))
|
||||
return response.JSON(http.StatusOK, ac.GroupScopesByActionContext(c.Req.Context(), permissions))
|
||||
}
|
||||
|
||||
// GET /api/access-control/users/permissions/search
|
||||
|
@ -120,7 +120,7 @@ func (m *Mock) Evaluate(ctx context.Context, usr identity.Requester, evaluator a
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
permissions = accesscontrol.GroupScopesByAction(userPermissions)
|
||||
permissions = accesscontrol.GroupScopesByActionContext(ctx, userPermissions)
|
||||
}
|
||||
|
||||
if evaluator.Evaluate(permissions) {
|
||||
|
@ -111,7 +111,7 @@ func TestApi_getDescription(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
service, _, _ := setupTestEnvironment(t, tt.options)
|
||||
server := setupTestServer(t, &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(tt.permissions)}}, service)
|
||||
server := setupTestServer(t, &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByActionContext(context.Background(), tt.permissions)}}, service)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/api/access-control/%s/description", tt.options.Resource), nil)
|
||||
require.NoError(t, err)
|
||||
@ -158,7 +158,7 @@ func TestApi_getPermissions(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
service, usrSvc, teamSvc := setupTestEnvironment(t, testOptions)
|
||||
server := setupTestServer(t, &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(tt.permissions)}}, service)
|
||||
server := setupTestServer(t, &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByActionContext(context.Background(), tt.permissions)}}, service)
|
||||
|
||||
seedPermissions(t, tt.resourceID, usrSvc, teamSvc, service)
|
||||
|
||||
@ -235,7 +235,7 @@ func TestApi_setBuiltinRolePermission(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
service, _, _ := setupTestEnvironment(t, testOptions)
|
||||
server := setupTestServer(t, &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(tt.permissions)}}, service)
|
||||
server := setupTestServer(t, &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByActionContext(context.Background(), tt.permissions)}}, service)
|
||||
|
||||
recorder := setPermission(t, server, testOptions.Resource, tt.resourceID, tt.permission, "builtInRoles", tt.builtInRole)
|
||||
assert.Equal(t, tt.expectedStatus, recorder.Code)
|
||||
@ -313,7 +313,7 @@ func TestApi_setTeamPermission(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
service, _, teamSvc := setupTestEnvironment(t, testOptions)
|
||||
server := setupTestServer(t, &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(tt.permissions)}}, service)
|
||||
server := setupTestServer(t, &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByActionContext(context.Background(), tt.permissions)}}, service)
|
||||
|
||||
// seed team
|
||||
_, err := teamSvc.CreateTeam(context.Background(), "test", "test@test.com", 1)
|
||||
@ -398,7 +398,7 @@ func TestApi_setUserPermission(t *testing.T) {
|
||||
service, usrSvc, _ := setupTestEnvironment(t, testOptions)
|
||||
server := setupTestServer(t, &user.SignedInUser{
|
||||
OrgID: 1,
|
||||
Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(tt.permissions)},
|
||||
Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByActionContext(context.Background(), tt.permissions)},
|
||||
}, service)
|
||||
|
||||
_, err := usrSvc.Create(context.Background(), &user.CreateUserCommand{Login: "test", OrgID: 1})
|
||||
|
@ -195,7 +195,7 @@ func TestIntegrationAnnotationListingWithInheritedRBAC(t *testing.T) {
|
||||
usr := &user.SignedInUser{
|
||||
UserID: 1,
|
||||
OrgID: orgID,
|
||||
Permissions: map[int64]map[string][]string{orgID: accesscontrol.GroupScopesByAction(permissions)},
|
||||
Permissions: map[int64]map[string][]string{orgID: accesscontrol.GroupScopesByActionContext(context.Background(), permissions)},
|
||||
}
|
||||
|
||||
var role *accesscontrol.Role
|
||||
|
@ -3,6 +3,7 @@ package authnimpl
|
||||
import (
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/remotecache"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/login/social"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/apikey"
|
||||
@ -36,6 +37,7 @@ func ProvideRegistration(
|
||||
features *featuremgmt.FeatureManager, oauthTokenService oauthtoken.OAuthTokenService,
|
||||
socialService social.Service, cache *remotecache.RemoteCache,
|
||||
ldapService service.LDAP, settingsProviderService setting.Provider,
|
||||
tracer tracing.Tracer,
|
||||
) Registration {
|
||||
logger := log.New("authn.registration")
|
||||
|
||||
@ -95,16 +97,16 @@ func ProvideRegistration(
|
||||
}
|
||||
|
||||
// FIXME (jguer): move to User package
|
||||
userSync := sync.ProvideUserSync(userService, userProtectionService, authInfoService, quotaService)
|
||||
orgSync := sync.ProvideOrgSync(userService, orgService, accessControlService, cfg)
|
||||
userSync := sync.ProvideUserSync(userService, userProtectionService, authInfoService, quotaService, tracer)
|
||||
orgSync := sync.ProvideOrgSync(userService, orgService, accessControlService, cfg, tracer)
|
||||
authnSvc.RegisterPostAuthHook(userSync.SyncUserHook, 10)
|
||||
authnSvc.RegisterPostAuthHook(userSync.EnableUserHook, 20)
|
||||
authnSvc.RegisterPostAuthHook(orgSync.SyncOrgRolesHook, 30)
|
||||
authnSvc.RegisterPostAuthHook(userSync.SyncLastSeenHook, 130)
|
||||
authnSvc.RegisterPostAuthHook(sync.ProvideOAuthTokenSync(oauthTokenService, sessionService, socialService).SyncOauthTokenHook, 60)
|
||||
authnSvc.RegisterPostAuthHook(sync.ProvideOAuthTokenSync(oauthTokenService, sessionService, socialService, tracer).SyncOauthTokenHook, 60)
|
||||
authnSvc.RegisterPostAuthHook(userSync.FetchSyncedUserHook, 100)
|
||||
|
||||
rbacSync := sync.ProvideRBACSync(accessControlService)
|
||||
rbacSync := sync.ProvideRBACSync(accessControlService, tracer)
|
||||
if features.IsEnabledGlobally(featuremgmt.FlagCloudRBACRoles) {
|
||||
authnSvc.RegisterPostAuthHook(rbacSync.SyncCloudRoles, 110)
|
||||
authnSvc.RegisterPreLogoutHook(gcomsso.ProvideGComSSOService(cfg).LogoutHook, 50)
|
||||
|
@ -323,6 +323,9 @@ Default:
|
||||
}
|
||||
|
||||
func (s *Service) ResolveIdentity(ctx context.Context, orgID int64, namespaceID authn.NamespaceID) (*authn.Identity, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authn.ResolveIdentity")
|
||||
defer span.End()
|
||||
|
||||
r := &authn.Request{}
|
||||
r.OrgID = orgID
|
||||
// hack to not update last seen
|
||||
@ -358,6 +361,9 @@ func (s *Service) IsClientEnabled(name string) bool {
|
||||
}
|
||||
|
||||
func (s *Service) SyncIdentity(ctx context.Context, identity *authn.Identity) error {
|
||||
ctx, span := s.tracer.Start(ctx, "authn.SyncIdentity")
|
||||
defer span.End()
|
||||
|
||||
r := &authn.Request{OrgID: identity.OrgID}
|
||||
// hack to not update last seen on external syncs
|
||||
r.SetMeta(authn.MetaKeyIsLogin, "true")
|
||||
@ -365,6 +371,9 @@ func (s *Service) SyncIdentity(ctx context.Context, identity *authn.Identity) er
|
||||
}
|
||||
|
||||
func (s *Service) resolveIdenity(ctx context.Context, orgID int64, namespaceID authn.NamespaceID) (*authn.Identity, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "authn.resolveIdentity")
|
||||
defer span.End()
|
||||
|
||||
if namespaceID.IsNamespace(authn.NamespaceUser) {
|
||||
return &authn.Identity{
|
||||
OrgID: orgID,
|
||||
|
@ -9,19 +9,21 @@ import (
|
||||
"golang.org/x/sync/singleflight"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/login/social"
|
||||
"github.com/grafana/grafana/pkg/services/auth"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
"github.com/grafana/grafana/pkg/services/oauthtoken"
|
||||
)
|
||||
|
||||
func ProvideOAuthTokenSync(service oauthtoken.OAuthTokenService, sessionService auth.UserTokenService, socialService social.Service) *OAuthTokenSync {
|
||||
func ProvideOAuthTokenSync(service oauthtoken.OAuthTokenService, sessionService auth.UserTokenService, socialService social.Service, tracer tracing.Tracer) *OAuthTokenSync {
|
||||
return &OAuthTokenSync{
|
||||
log.New("oauth_token.sync"),
|
||||
service,
|
||||
sessionService,
|
||||
socialService,
|
||||
new(singleflight.Group),
|
||||
tracer,
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,9 +33,13 @@ type OAuthTokenSync struct {
|
||||
sessionService auth.UserTokenService
|
||||
socialService social.Service
|
||||
singleflightGroup *singleflight.Group
|
||||
tracer tracing.Tracer
|
||||
}
|
||||
|
||||
func (s *OAuthTokenSync) SyncOauthTokenHook(ctx context.Context, identity *authn.Identity, _ *authn.Request) error {
|
||||
ctx, span := s.tracer.Start(ctx, "oauth.sync.SyncOauthTokenHook")
|
||||
defer span.End()
|
||||
|
||||
// only perform oauth token check if identity is a user
|
||||
if !identity.ID.IsNamespace(authn.NamespaceUser) {
|
||||
return nil
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"golang.org/x/sync/singleflight"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/login/social"
|
||||
"github.com/grafana/grafana/pkg/login/social/socialtest"
|
||||
"github.com/grafana/grafana/pkg/services/auth"
|
||||
@ -128,6 +129,7 @@ func TestOAuthTokenSync_SyncOAuthTokenHook(t *testing.T) {
|
||||
sessionService: sessionService,
|
||||
socialService: socialService,
|
||||
singleflightGroup: new(singleflight.Group),
|
||||
tracer: tracing.InitializeTracerForTest(),
|
||||
}
|
||||
|
||||
err := sync.SyncOauthTokenHook(context.Background(), tt.identity, nil)
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"sort"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
@ -14,8 +15,8 @@ import (
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
func ProvideOrgSync(userService user.Service, orgService org.Service, accessControl accesscontrol.Service, cfg *setting.Cfg) *OrgSync {
|
||||
return &OrgSync{userService, orgService, accessControl, cfg, log.New("org.sync")}
|
||||
func ProvideOrgSync(userService user.Service, orgService org.Service, accessControl accesscontrol.Service, cfg *setting.Cfg, tracer tracing.Tracer) *OrgSync {
|
||||
return &OrgSync{userService, orgService, accessControl, cfg, log.New("org.sync"), tracer}
|
||||
}
|
||||
|
||||
type OrgSync struct {
|
||||
@ -23,11 +24,14 @@ type OrgSync struct {
|
||||
orgService org.Service
|
||||
accessControl accesscontrol.Service
|
||||
cfg *setting.Cfg
|
||||
|
||||
log log.Logger
|
||||
log log.Logger
|
||||
tracer tracing.Tracer
|
||||
}
|
||||
|
||||
func (s *OrgSync) SyncOrgRolesHook(ctx context.Context, id *authn.Identity, _ *authn.Request) error {
|
||||
ctx, span := s.tracer.Start(ctx, "org.sync.SyncOrgRolesHook")
|
||||
defer span.End()
|
||||
|
||||
if !id.ClientParams.SyncOrgRoles {
|
||||
return nil
|
||||
}
|
||||
@ -131,6 +135,9 @@ func (s *OrgSync) SyncOrgRolesHook(ctx context.Context, id *authn.Identity, _ *a
|
||||
}
|
||||
|
||||
func (s *OrgSync) SetDefaultOrgHook(ctx context.Context, currentIdentity *authn.Identity, r *authn.Request, err error) {
|
||||
ctx, span := s.tracer.Start(ctx, "org.sync.SetDefaultOrgHook")
|
||||
defer span.End()
|
||||
|
||||
if s.cfg.LoginDefaultOrgId < 1 || currentIdentity == nil || err != nil {
|
||||
return
|
||||
}
|
||||
@ -166,6 +173,9 @@ func (s *OrgSync) SetDefaultOrgHook(ctx context.Context, currentIdentity *authn.
|
||||
}
|
||||
|
||||
func (s *OrgSync) validateUsingOrg(ctx context.Context, userID int64, orgID int64) (bool, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "org.sync.validateUsingOrg")
|
||||
defer span.End()
|
||||
|
||||
query := org.GetUserOrgListQuery{UserID: userID}
|
||||
|
||||
result, err := s.orgService.GetUserOrgList(ctx, &query)
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
@ -116,6 +117,7 @@ func TestOrgSync_SyncOrgRolesHook(t *testing.T) {
|
||||
orgService: tt.fields.orgService,
|
||||
accessControl: tt.fields.accessControl,
|
||||
log: tt.fields.log,
|
||||
tracer: tracing.InitializeTracerForTest(),
|
||||
}
|
||||
if err := s.SyncOrgRolesHook(tt.args.ctx, tt.args.id, nil); (err != nil) != tt.wantErr {
|
||||
t.Errorf("OrgSync.SyncOrgRolesHook() error = %v, wantErr %v", err, tt.wantErr)
|
||||
@ -214,6 +216,7 @@ func TestOrgSync_SetDefaultOrgHook(t *testing.T) {
|
||||
accessControl: actest.FakeService{},
|
||||
log: log.NewNopLogger(),
|
||||
cfg: cfg,
|
||||
tracer: tracing.InitializeTracerForTest(),
|
||||
}
|
||||
|
||||
s.SetDefaultOrgHook(context.Background(), tt.identity, nil, tt.inputErr)
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/errutil"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
"github.com/grafana/grafana/pkg/services/login"
|
||||
@ -17,19 +18,24 @@ var (
|
||||
errSyncPermissionsForbidden = errutil.Forbidden("permissions.sync.forbidden")
|
||||
)
|
||||
|
||||
func ProvideRBACSync(acService accesscontrol.Service) *RBACSync {
|
||||
func ProvideRBACSync(acService accesscontrol.Service, tracer tracing.Tracer) *RBACSync {
|
||||
return &RBACSync{
|
||||
ac: acService,
|
||||
log: log.New("permissions.sync"),
|
||||
ac: acService,
|
||||
log: log.New("permissions.sync"),
|
||||
tracer: tracer,
|
||||
}
|
||||
}
|
||||
|
||||
type RBACSync struct {
|
||||
ac accesscontrol.Service
|
||||
log log.Logger
|
||||
ac accesscontrol.Service
|
||||
log log.Logger
|
||||
tracer tracing.Tracer
|
||||
}
|
||||
|
||||
func (s *RBACSync) SyncPermissionsHook(ctx context.Context, ident *authn.Identity, _ *authn.Request) error {
|
||||
ctx, span := s.tracer.Start(ctx, "rbac.sync.SyncPermissionsHook")
|
||||
defer span.End()
|
||||
|
||||
if !ident.ClientParams.SyncPermissions {
|
||||
return nil
|
||||
}
|
||||
@ -43,7 +49,8 @@ func (s *RBACSync) SyncPermissionsHook(ctx context.Context, ident *authn.Identit
|
||||
if ident.Permissions == nil {
|
||||
ident.Permissions = make(map[int64]map[string][]string, 1)
|
||||
}
|
||||
grouped := accesscontrol.GroupScopesByAction(permissions)
|
||||
|
||||
grouped := accesscontrol.GroupScopesByActionContext(ctx, permissions)
|
||||
|
||||
// Restrict access to the list of actions
|
||||
actionsLookup := ident.ClientParams.FetchPermissionsParams.ActionsLookup
|
||||
@ -56,12 +63,15 @@ func (s *RBACSync) SyncPermissionsHook(ctx context.Context, ident *authn.Identit
|
||||
}
|
||||
grouped = filtered
|
||||
}
|
||||
|
||||
ident.Permissions[ident.OrgID] = grouped
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *RBACSync) fetchPermissions(ctx context.Context, ident *authn.Identity) ([]accesscontrol.Permission, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "rbac.sync.fetchPermissions")
|
||||
defer span.End()
|
||||
|
||||
permissions := make([]accesscontrol.Permission, 0, 8)
|
||||
roles := ident.ClientParams.FetchPermissionsParams.Roles
|
||||
if len(roles) > 0 {
|
||||
@ -94,6 +104,9 @@ var fixedCloudRoles = map[org.RoleType]string{
|
||||
}
|
||||
|
||||
func (s *RBACSync) SyncCloudRoles(ctx context.Context, ident *authn.Identity, r *authn.Request) error {
|
||||
ctx, span := s.tracer.Start(ctx, "rbac.sync.SyncCloudRoles")
|
||||
defer span.End()
|
||||
|
||||
// we only want to run this hook during login and if the module used is grafana com
|
||||
if r.GetMeta(authn.MetaKeyAuthModule) != login.GrafanaComAuthModule {
|
||||
return nil
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
@ -45,7 +46,7 @@ func TestRBACSync_SyncPermission(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 1, len(tt.identity.Permissions))
|
||||
assert.Equal(t, accesscontrol.GroupScopesByAction(tt.expectedPermissions), tt.identity.Permissions[tt.identity.OrgID])
|
||||
assert.Equal(t, accesscontrol.GroupScopesByActionContext(context.Background(), tt.expectedPermissions), tt.identity.Permissions[tt.identity.OrgID])
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -127,7 +128,8 @@ func TestRBACSync_SyncCloudRoles(t *testing.T) {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
log: log.NewNopLogger(),
|
||||
log: log.NewNopLogger(),
|
||||
tracer: tracing.InitializeTracerForTest(),
|
||||
}
|
||||
|
||||
req := &authn.Request{}
|
||||
@ -149,8 +151,9 @@ func setupTestEnv() *RBACSync {
|
||||
},
|
||||
}
|
||||
s := &RBACSync{
|
||||
ac: acMock,
|
||||
log: log.NewNopLogger(),
|
||||
ac: acMock,
|
||||
log: log.NewNopLogger(),
|
||||
tracer: tracing.InitializeTracerForTest(),
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/errutil"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
"github.com/grafana/grafana/pkg/services/login"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
@ -47,15 +48,14 @@ var (
|
||||
errSignupNotAllowed = errors.New("system administrator has disabled signup")
|
||||
)
|
||||
|
||||
func ProvideUserSync(userService user.Service,
|
||||
userProtectionService login.UserProtectionService,
|
||||
authInfoService login.AuthInfoService, quotaService quota.Service) *UserSync {
|
||||
func ProvideUserSync(userService user.Service, userProtectionService login.UserProtectionService, authInfoService login.AuthInfoService, quotaService quota.Service, tracer tracing.Tracer) *UserSync {
|
||||
return &UserSync{
|
||||
userService: userService,
|
||||
authInfoService: authInfoService,
|
||||
userProtectionService: userProtectionService,
|
||||
quotaService: quotaService,
|
||||
log: log.New("user.sync"),
|
||||
tracer: tracer,
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,10 +65,14 @@ type UserSync struct {
|
||||
userProtectionService login.UserProtectionService
|
||||
quotaService quota.Service
|
||||
log log.Logger
|
||||
tracer tracing.Tracer
|
||||
}
|
||||
|
||||
// SyncUserHook syncs a user with the database
|
||||
func (s *UserSync) SyncUserHook(ctx context.Context, id *authn.Identity, _ *authn.Request) error {
|
||||
ctx, span := s.tracer.Start(ctx, "user.sync.SyncUserHook")
|
||||
defer span.End()
|
||||
|
||||
if !id.ClientParams.SyncUser {
|
||||
return nil
|
||||
}
|
||||
@ -106,6 +110,9 @@ func (s *UserSync) SyncUserHook(ctx context.Context, id *authn.Identity, _ *auth
|
||||
}
|
||||
|
||||
func (s *UserSync) FetchSyncedUserHook(ctx context.Context, identity *authn.Identity, r *authn.Request) error {
|
||||
ctx, span := s.tracer.Start(ctx, "user.sync.FetchSyncedUserHook")
|
||||
defer span.End()
|
||||
|
||||
if !identity.ClientParams.FetchSyncedUser {
|
||||
return nil
|
||||
}
|
||||
@ -143,6 +150,9 @@ func (s *UserSync) FetchSyncedUserHook(ctx context.Context, identity *authn.Iden
|
||||
}
|
||||
|
||||
func (s *UserSync) SyncLastSeenHook(ctx context.Context, identity *authn.Identity, r *authn.Request) error {
|
||||
ctx, span := s.tracer.Start(ctx, "user.sync.SyncLastSeenHook")
|
||||
defer span.End()
|
||||
|
||||
if r.GetMeta(authn.MetaKeyIsLogin) != "" {
|
||||
// Do not sync last seen for login requests
|
||||
return nil
|
||||
@ -177,6 +187,9 @@ func (s *UserSync) SyncLastSeenHook(ctx context.Context, identity *authn.Identit
|
||||
}
|
||||
|
||||
func (s *UserSync) EnableUserHook(ctx context.Context, identity *authn.Identity, _ *authn.Request) error {
|
||||
ctx, span := s.tracer.Start(ctx, "user.sync.EnableUserHook")
|
||||
defer span.End()
|
||||
|
||||
if !identity.ClientParams.EnableUser {
|
||||
return nil
|
||||
}
|
||||
@ -196,6 +209,9 @@ func (s *UserSync) EnableUserHook(ctx context.Context, identity *authn.Identity,
|
||||
}
|
||||
|
||||
func (s *UserSync) upsertAuthConnection(ctx context.Context, userID int64, identity *authn.Identity, createConnection bool) error {
|
||||
ctx, span := s.tracer.Start(ctx, "user.sync.upsertAuthConnection")
|
||||
defer span.End()
|
||||
|
||||
if identity.AuthenticatedBy == "" {
|
||||
return nil
|
||||
}
|
||||
@ -222,6 +238,9 @@ func (s *UserSync) upsertAuthConnection(ctx context.Context, userID int64, ident
|
||||
}
|
||||
|
||||
func (s *UserSync) updateUserAttributes(ctx context.Context, usr *user.User, id *authn.Identity, userAuth *login.UserAuth) error {
|
||||
ctx, span := s.tracer.Start(ctx, "user.sync.updateUserAttributes")
|
||||
defer span.End()
|
||||
|
||||
if errProtection := s.userProtectionService.AllowUserMapping(usr, id.AuthenticatedBy); errProtection != nil {
|
||||
return errUserProtection.Errorf("user mapping not allowed: %w", errProtection)
|
||||
}
|
||||
@ -273,6 +292,8 @@ func (s *UserSync) updateUserAttributes(ctx context.Context, usr *user.User, id
|
||||
}
|
||||
|
||||
func (s *UserSync) createUser(ctx context.Context, id *authn.Identity) (*user.User, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "user.sync.createUser")
|
||||
defer span.End()
|
||||
// FIXME(jguer): this should be done in the user service
|
||||
// quota check: we can have quotas on both global and org level
|
||||
// therefore we need to query check quota for both user and org services
|
||||
@ -312,6 +333,9 @@ func (s *UserSync) createUser(ctx context.Context, id *authn.Identity) (*user.Us
|
||||
}
|
||||
|
||||
func (s *UserSync) getUser(ctx context.Context, identity *authn.Identity) (*user.User, *login.UserAuth, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "user.sync.getUser")
|
||||
defer span.End()
|
||||
|
||||
// Check auth info fist
|
||||
if identity.AuthID != "" && identity.AuthenticatedBy != "" {
|
||||
query := &login.GetAuthInfoQuery{AuthId: identity.AuthID, AuthModule: identity.AuthenticatedBy}
|
||||
@ -361,6 +385,9 @@ func (s *UserSync) getUser(ctx context.Context, identity *authn.Identity) (*user
|
||||
}
|
||||
|
||||
func (s *UserSync) lookupByOneOf(ctx context.Context, params login.UserLookupParams) (*user.User, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "user.sync.lookupByOneOf")
|
||||
defer span.End()
|
||||
|
||||
var usr *user.User
|
||||
var err error
|
||||
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
"github.com/grafana/grafana/pkg/services/login"
|
||||
"github.com/grafana/grafana/pkg/services/login/authinfoimpl"
|
||||
@ -426,7 +427,7 @@ func TestUserSync_SyncUserHook(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := ProvideUserSync(tt.fields.userService, userProtection, tt.fields.authInfoService, tt.fields.quotaService)
|
||||
s := ProvideUserSync(tt.fields.userService, userProtection, tt.fields.authInfoService, tt.fields.quotaService, tracing.InitializeTracerForTest())
|
||||
err := s.SyncUserHook(tt.args.ctx, tt.args.id, nil)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
@ -462,7 +463,9 @@ func TestUserSync_FetchSyncedUserHook(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
s := UserSync{}
|
||||
s := UserSync{
|
||||
tracer: tracing.InitializeTracerForTest(),
|
||||
}
|
||||
err := s.FetchSyncedUserHook(context.Background(), tt.identity, tt.req)
|
||||
require.ErrorIs(t, err, tt.expectedErr)
|
||||
})
|
||||
@ -515,7 +518,7 @@ func TestUserSync_EnableDisabledUserHook(t *testing.T) {
|
||||
return nil
|
||||
}
|
||||
|
||||
s := UserSync{userService: userSvc}
|
||||
s := UserSync{userService: userSvc, tracer: tracing.InitializeTracerForTest()}
|
||||
err := s.EnableUserHook(context.Background(), tt.identity, nil)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.enableUser, called)
|
||||
|
@ -288,7 +288,7 @@ func TestIntegrationDashboardInheritedFolderRBAC(t *testing.T) {
|
||||
UserID: u.ID,
|
||||
OrgID: u.OrgID,
|
||||
OrgRole: org.RoleAdmin,
|
||||
Permissions: map[int64]map[string][]string{u.OrgID: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{
|
||||
Permissions: map[int64]map[string][]string{u.OrgID: accesscontrol.GroupScopesByActionContext(context.Background(), []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersCreate,
|
||||
}, {
|
||||
|
@ -126,7 +126,7 @@ func (a *authenticator) getSignedInUser(ctx context.Context, token string) (*use
|
||||
if err != nil {
|
||||
a.logger.Error("failed fetching permissions for user", "userID", signedInUser.UserID, "error", err)
|
||||
}
|
||||
signedInUser.Permissions[signedInUser.OrgID] = accesscontrol.GroupScopesByAction(permissions)
|
||||
signedInUser.Permissions[signedInUser.OrgID] = accesscontrol.GroupScopesByActionContext(context.Background(), permissions)
|
||||
}
|
||||
|
||||
return signedInUser, nil
|
||||
|
@ -1,6 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
@ -663,5 +664,5 @@ search_base_dns = ["dc=grafana,dc=org"]`)
|
||||
}
|
||||
|
||||
func userWithPermissions(orgID int64, permissions []accesscontrol.Permission) *user.SignedInUser {
|
||||
return &user.SignedInUser{OrgID: orgID, OrgRole: org.RoleViewer, Permissions: map[int64]map[string][]string{orgID: accesscontrol.GroupScopesByAction(permissions)}}
|
||||
return &user.SignedInUser{OrgID: orgID, OrgRole: org.RoleViewer, Permissions: map[int64]map[string][]string{orgID: accesscontrol.GroupScopesByActionContext(context.Background(), permissions)}}
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ func TestIntegrationListPublicDashboard(t *testing.T) {
|
||||
{Action: dashboards.ActionDashboardsRead, Scope: fmt.Sprintf("dashboards:uid:%s", cDash.UID)},
|
||||
}
|
||||
|
||||
usr := &user.SignedInUser{UserID: 1, OrgID: orgId, Permissions: map[int64]map[string][]string{orgId: accesscontrol.GroupScopesByAction(permissions)}}
|
||||
usr := &user.SignedInUser{UserID: 1, OrgID: orgId, Permissions: map[int64]map[string][]string{orgId: accesscontrol.GroupScopesByActionContext(context.Background(), permissions)}}
|
||||
|
||||
actest.AddUserPermissionToDB(t, sqlStore, usr)
|
||||
|
||||
@ -120,7 +120,7 @@ func TestIntegrationListPublicDashboard(t *testing.T) {
|
||||
{Action: dashboards.ActionDashboardsRead, Scope: fmt.Sprintf("dashboards:uid:%s", cDash.UID)},
|
||||
}
|
||||
|
||||
usr := &user.SignedInUser{UserID: 1, OrgID: orgId, Permissions: map[int64]map[string][]string{orgId: accesscontrol.GroupScopesByAction(permissions)}}
|
||||
usr := &user.SignedInUser{UserID: 1, OrgID: orgId, Permissions: map[int64]map[string][]string{orgId: accesscontrol.GroupScopesByActionContext(context.Background(), permissions)}}
|
||||
|
||||
actest.AddUserPermissionToDB(t, sqlStore, usr)
|
||||
|
||||
@ -148,7 +148,7 @@ func TestIntegrationListPublicDashboard(t *testing.T) {
|
||||
{Action: dashboards.ActionDashboardsRead, Scope: "dashboards:uid:another-dashboard-2-uid"},
|
||||
}
|
||||
|
||||
usr := &user.SignedInUser{UserID: 1, OrgID: orgId, Permissions: map[int64]map[string][]string{orgId: accesscontrol.GroupScopesByAction(permissions)}}
|
||||
usr := &user.SignedInUser{UserID: 1, OrgID: orgId, Permissions: map[int64]map[string][]string{orgId: accesscontrol.GroupScopesByActionContext(context.Background(), permissions)}}
|
||||
|
||||
actest.AddUserPermissionToDB(t, sqlStore, usr)
|
||||
|
||||
|
@ -199,7 +199,7 @@ func (s *StandardSearchService) getUser(ctx context.Context, backendUser *backen
|
||||
return nil, errors.New("auth error")
|
||||
}
|
||||
|
||||
usr.Permissions[orgId] = accesscontrol.GroupScopesByAction(permissions)
|
||||
usr.Permissions[orgId] = accesscontrol.GroupScopesByActionContext(ctx, permissions)
|
||||
return usr, nil
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@ -87,7 +88,7 @@ func TestServiceAccountsAPI_CreateServiceAccount(t *testing.T) {
|
||||
req := server.NewRequest(http.MethodPost, "/api/serviceaccounts/", strings.NewReader(tt.body))
|
||||
webtest.RequestWithSignedInUser(req, &user.SignedInUser{
|
||||
OrgRole: tt.basicRole, OrgID: 1, IsAnonymous: true,
|
||||
Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(tt.permissions)}})
|
||||
Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByActionContext(context.Background(), tt.permissions)}})
|
||||
res, err := server.SendJSON(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -124,7 +125,7 @@ func TestServiceAccountsAPI_DeleteServiceAccount(t *testing.T) {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
server := setupTests(t)
|
||||
req := server.NewRequest(http.MethodDelete, fmt.Sprintf("/api/serviceaccounts/%d", tt.id), nil)
|
||||
webtest.RequestWithSignedInUser(req, &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(tt.permissions)}})
|
||||
webtest.RequestWithSignedInUser(req, &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByActionContext(context.Background(), tt.permissions)}})
|
||||
res, err := server.Send(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -165,7 +166,7 @@ func TestServiceAccountsAPI_RetrieveServiceAccount(t *testing.T) {
|
||||
a.service = &satests.FakeServiceAccountService{ExpectedServiceAccountProfile: tt.expectedSA}
|
||||
})
|
||||
req := server.NewGetRequest(fmt.Sprintf("/api/serviceaccounts/%d", tt.id))
|
||||
webtest.RequestWithSignedInUser(req, &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(tt.permissions)}})
|
||||
webtest.RequestWithSignedInUser(req, &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByActionContext(context.Background(), tt.permissions)}})
|
||||
res, err := server.Send(req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.expectedCode, res.StatusCode)
|
||||
@ -228,7 +229,7 @@ func TestServiceAccountsAPI_UpdateServiceAccount(t *testing.T) {
|
||||
})
|
||||
|
||||
req := server.NewRequest(http.MethodPatch, fmt.Sprintf("/api/serviceaccounts/%d", tt.id), strings.NewReader(tt.body))
|
||||
webtest.RequestWithSignedInUser(req, &user.SignedInUser{OrgRole: tt.basicRole, OrgID: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(tt.permissions)}})
|
||||
webtest.RequestWithSignedInUser(req, &user.SignedInUser{OrgRole: tt.basicRole, OrgID: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByActionContext(context.Background(), tt.permissions)}})
|
||||
res, err := server.SendJSON(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -282,7 +283,7 @@ func TestServiceAccountsAPI_MigrateApiKeysToServiceAccounts(t *testing.T) {
|
||||
})
|
||||
|
||||
req := server.NewRequest(http.MethodPost, "/api/serviceaccounts/migrate", nil)
|
||||
webtest.RequestWithSignedInUser(req, &user.SignedInUser{OrgRole: tt.basicRole, OrgID: tt.orgId, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(tt.permissions)}})
|
||||
webtest.RequestWithSignedInUser(req, &user.SignedInUser{OrgRole: tt.basicRole, OrgID: tt.orgId, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByActionContext(context.Background(), tt.permissions)}})
|
||||
res, err := server.SendJSON(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
@ -47,7 +48,7 @@ func TestServiceAccountsAPI_ListTokens(t *testing.T) {
|
||||
a.service = &satests.FakeServiceAccountService{}
|
||||
})
|
||||
req := server.NewGetRequest(fmt.Sprintf("/api/serviceaccounts/%d/tokens", tt.id))
|
||||
webtest.RequestWithSignedInUser(req, &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(tt.permissions)}})
|
||||
webtest.RequestWithSignedInUser(req, &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByActionContext(context.Background(), tt.permissions)}})
|
||||
res, err := server.Send(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -116,7 +117,7 @@ func TestServiceAccountsAPI_CreateToken(t *testing.T) {
|
||||
}
|
||||
})
|
||||
req := server.NewRequest(http.MethodPost, fmt.Sprintf("/api/serviceaccounts/%d/tokens", tt.id), strings.NewReader(tt.body))
|
||||
webtest.RequestWithSignedInUser(req, &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(tt.permissions)}})
|
||||
webtest.RequestWithSignedInUser(req, &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByActionContext(context.Background(), tt.permissions)}})
|
||||
res, err := server.SendJSON(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -168,7 +169,7 @@ func TestServiceAccountsAPI_DeleteToken(t *testing.T) {
|
||||
})
|
||||
|
||||
req := server.NewRequest(http.MethodDelete, fmt.Sprintf("/api/serviceaccounts/%d/tokens/%d", tt.saID, tt.apikeyID), nil)
|
||||
webtest.RequestWithSignedInUser(req, &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(tt.permissions)}})
|
||||
webtest.RequestWithSignedInUser(req, &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByActionContext(context.Background(), tt.permissions)}})
|
||||
res, err := server.SendJSON(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
@ -173,7 +173,7 @@ func TestIntegration_DashboardPermissionFilter(t *testing.T) {
|
||||
recursiveQueriesAreSupported, err := store.RecursiveQueriesAreSupported()
|
||||
require.NoError(t, err)
|
||||
|
||||
usr := &user.SignedInUser{OrgID: 1, OrgRole: org.RoleViewer, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(tt.permissions)}}
|
||||
usr := &user.SignedInUser{OrgID: 1, OrgRole: org.RoleViewer, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByActionContext(context.Background(), tt.permissions)}}
|
||||
|
||||
for _, features := range []featuremgmt.FeatureToggles{featuremgmt.WithFeatures(), featuremgmt.WithFeatures(featuremgmt.FlagPermissionsFilterRemoveSubquery)} {
|
||||
m := features.GetEnabled(context.Background())
|
||||
@ -345,7 +345,7 @@ func TestIntegration_DashboardPermissionFilter_WithSelfContainedPermissions(t *t
|
||||
recursiveQueriesAreSupported, err := store.RecursiveQueriesAreSupported()
|
||||
require.NoError(t, err)
|
||||
|
||||
usr := &user.SignedInUser{OrgID: 1, OrgRole: org.RoleViewer, AuthenticatedBy: login.ExtendedJWTModule, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(tt.signedInUserPermissions)}}
|
||||
usr := &user.SignedInUser{OrgID: 1, OrgRole: org.RoleViewer, AuthenticatedBy: login.ExtendedJWTModule, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByActionContext(context.Background(), tt.signedInUserPermissions)}}
|
||||
|
||||
for _, features := range []featuremgmt.FeatureToggles{featuremgmt.WithFeatures(), featuremgmt.WithFeatures(featuremgmt.FlagPermissionsFilterRemoveSubquery)} {
|
||||
m := features.GetEnabled(context.Background())
|
||||
@ -456,7 +456,7 @@ func TestIntegration_DashboardNestedPermissionFilter(t *testing.T) {
|
||||
Action: dashboards.ActionFoldersWrite,
|
||||
Scope: dashboards.ScopeFoldersAll,
|
||||
})
|
||||
usr := &user.SignedInUser{OrgID: orgID, OrgRole: org.RoleViewer, Permissions: map[int64]map[string][]string{orgID: accesscontrol.GroupScopesByAction(tc.permissions)}}
|
||||
usr := &user.SignedInUser{OrgID: orgID, OrgRole: org.RoleViewer, Permissions: map[int64]map[string][]string{orgID: accesscontrol.GroupScopesByActionContext(context.Background(), tc.permissions)}}
|
||||
|
||||
for _, features := range []featuremgmt.FeatureToggles{featuremgmt.WithFeatures(append(tc.features, featuremgmt.FlagAccessActionSets)...), featuremgmt.WithFeatures(tc.features...), featuremgmt.WithFeatures(append(tc.features, featuremgmt.FlagPermissionsFilterRemoveSubquery)...)} {
|
||||
m := features.GetEnabled(context.Background())
|
||||
@ -564,7 +564,7 @@ func TestIntegration_DashboardNestedPermissionFilter_WithSelfContainedPermission
|
||||
|
||||
for _, tc := range testCases {
|
||||
helperUser := &user.SignedInUser{OrgID: orgID, OrgRole: org.RoleViewer, AuthenticatedBy: login.ExtendedJWTModule,
|
||||
Permissions: map[int64]map[string][]string{orgID: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{
|
||||
Permissions: map[int64]map[string][]string{orgID: accesscontrol.GroupScopesByActionContext(context.Background(), []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersCreate,
|
||||
},
|
||||
@ -583,7 +583,7 @@ func TestIntegration_DashboardNestedPermissionFilter_WithSelfContainedPermission
|
||||
}
|
||||
|
||||
t.Run(tc.desc+" with features "+strings.Join(keys, ","), func(t *testing.T) {
|
||||
usr := &user.SignedInUser{OrgID: orgID, OrgRole: org.RoleViewer, AuthenticatedBy: login.ExtendedJWTModule, Permissions: map[int64]map[string][]string{orgID: accesscontrol.GroupScopesByAction(tc.signedInUserPermissions)}}
|
||||
usr := &user.SignedInUser{OrgID: orgID, OrgRole: org.RoleViewer, AuthenticatedBy: login.ExtendedJWTModule, Permissions: map[int64]map[string][]string{orgID: accesscontrol.GroupScopesByActionContext(context.Background(), tc.signedInUserPermissions)}}
|
||||
db := setupNestedTest(t, helperUser, []accesscontrol.Permission{}, orgID, features)
|
||||
recursiveQueriesAreSupported, err := db.RecursiveQueriesAreSupported()
|
||||
require.NoError(t, err)
|
||||
@ -693,7 +693,7 @@ func TestIntegration_DashboardNestedPermissionFilter_WithActionSets(t *testing.T
|
||||
Scope: "folders:uid:unrelated"}, accesscontrol.Permission{
|
||||
Action: dashboards.ActionDashboardsCreate,
|
||||
Scope: "folders:uid:unrelated"})
|
||||
usr := &user.SignedInUser{OrgID: orgID, OrgRole: org.RoleViewer, Permissions: map[int64]map[string][]string{orgID: accesscontrol.GroupScopesByAction(tc.signedInUserPermissions)}}
|
||||
usr := &user.SignedInUser{OrgID: orgID, OrgRole: org.RoleViewer, Permissions: map[int64]map[string][]string{orgID: accesscontrol.GroupScopesByActionContext(context.Background(), tc.signedInUserPermissions)}}
|
||||
|
||||
for _, features := range []featuremgmt.FeatureToggles{featuremgmt.WithFeatures(tc.features...), featuremgmt.WithFeatures(append(tc.features, featuremgmt.FlagPermissionsFilterRemoveSubquery)...)} {
|
||||
m := features.GetEnabled(context.Background())
|
||||
|
@ -34,7 +34,7 @@ import (
|
||||
|
||||
func benchmarkDashboardPermissionFilter(b *testing.B, numUsers, numDashboards, numFolders, nestingLevel int) {
|
||||
usr := user.SignedInUser{UserID: 1, OrgID: 1, OrgRole: org.RoleViewer, Permissions: map[int64]map[string][]string{
|
||||
1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{
|
||||
1: accesscontrol.GroupScopesByActionContext(context.Background(), []accesscontrol.Permission{
|
||||
{
|
||||
Action: dashboards.ActionFoldersCreate,
|
||||
},
|
||||
|
@ -320,7 +320,7 @@ func TestBuilder_RBAC(t *testing.T) {
|
||||
for _, tc := range testsCases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if len(tc.userPermissions) > 0 {
|
||||
user.Permissions = map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(tc.userPermissions)}
|
||||
user.Permissions = map[int64]map[string][]string{1: accesscontrol.GroupScopesByActionContext(context.Background(), tc.userPermissions)}
|
||||
}
|
||||
|
||||
builder := &searchstore.Builder{
|
||||
|
@ -2,6 +2,7 @@ package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -550,7 +551,7 @@ func TestSSOSettingsAPI_List(t *testing.T) {
|
||||
|
||||
func getPermissionsForActionAndScope(action, scope string) map[int64]map[string][]string {
|
||||
return map[int64]map[string][]string{
|
||||
1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{{
|
||||
1: accesscontrol.GroupScopesByActionContext(context.Background(), []accesscontrol.Permission{{
|
||||
Action: action, Scope: scope,
|
||||
}}),
|
||||
}
|
||||
|
@ -281,5 +281,5 @@ func Test_getTeamMembershipUpdates(t *testing.T) {
|
||||
}
|
||||
|
||||
func authedUserWithPermissions(userID, orgID int64, permissions []accesscontrol.Permission) *user.SignedInUser {
|
||||
return &user.SignedInUser{UserID: userID, OrgID: orgID, OrgRole: org.RoleViewer, Permissions: map[int64]map[string][]string{orgID: accesscontrol.GroupScopesByAction(permissions)}}
|
||||
return &user.SignedInUser{UserID: userID, OrgID: orgID, OrgRole: org.RoleViewer, Permissions: map[int64]map[string][]string{orgID: accesscontrol.GroupScopesByActionContext(context.Background(), permissions)}}
|
||||
}
|
||||
|
Reference in New Issue
Block a user