mirror of
https://github.com/grafana/grafana.git
synced 2025-02-20 11:48:34 -06:00
* wip * scope active user to 1 org * remove TODOs * add render auth namespace * import cycle fix * make condition more readable * convert Evaluate to user Requester * only use active OrgID for SearchUserPermissions * add cache key to interface definition * change final SignedInUsers to interface * fix api key managed roles fetch * fix anon auth id parsing * Update pkg/services/accesscontrol/acimpl/accesscontrol.go Co-authored-by: Ieva <ieva.vasiljeva@grafana.com> --------- Co-authored-by: Ieva <ieva.vasiljeva@grafana.com>
237 lines
9.0 KiB
Go
237 lines
9.0 KiB
Go
package acimpl
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/grafana/grafana/pkg/infra/db"
|
|
"github.com/grafana/grafana/pkg/infra/log"
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol/database"
|
|
"github.com/grafana/grafana/pkg/services/org"
|
|
"github.com/grafana/grafana/pkg/services/user"
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
)
|
|
|
|
// setupBenchEnv will create userCount users, userCount managed roles with resourceCount managed permission each
|
|
// Example: setupBenchEnv(b, 2, 3):
|
|
// - will create 2 users and assign them 2 managed roles
|
|
// - each managed role will have 3 permissions {"resources:action2", "resources:id:x"} where x belongs to [1, 3]
|
|
func setupBenchEnv(b *testing.B, usersCount, resourceCount int) (accesscontrol.Service, *user.SignedInUser) {
|
|
now := time.Now()
|
|
sqlStore := db.InitTestDB(b)
|
|
store := database.ProvideService(sqlStore)
|
|
acService := &Service{
|
|
cfg: setting.NewCfg(),
|
|
log: log.New("accesscontrol-test"),
|
|
registrations: accesscontrol.RegistrationList{},
|
|
store: store,
|
|
roles: accesscontrol.BuildBasicRoleDefinitions(),
|
|
}
|
|
|
|
// Prepare default permissions
|
|
action1 := "resources:action1"
|
|
err := acService.DeclareFixedRoles(accesscontrol.RoleRegistration{
|
|
Role: accesscontrol.RoleDTO{Name: "fixed:test:role", Permissions: []accesscontrol.Permission{{Action: action1}}},
|
|
Grants: []string{string(org.RoleViewer)},
|
|
})
|
|
require.NoError(b, err)
|
|
err = acService.RegisterFixedRoles(context.Background())
|
|
require.NoError(b, err)
|
|
|
|
// Populate users, roles and assignments
|
|
if errInsert := actest.ConcurrentBatch(actest.Concurrency, usersCount, actest.BatchSize, func(start, end int) error {
|
|
n := end - start
|
|
users := make([]user.User, 0, n)
|
|
orgUsers := make([]org.OrgUser, 0, n)
|
|
roles := make([]accesscontrol.Role, 0, n)
|
|
userRoles := make([]accesscontrol.UserRole, 0, n)
|
|
for u := start + 1; u < end+1; u++ {
|
|
users = append(users, user.User{
|
|
ID: int64(u),
|
|
Name: fmt.Sprintf("user%v", u),
|
|
Login: fmt.Sprintf("user%v", u),
|
|
Email: fmt.Sprintf("user%v@example.org", u),
|
|
Created: now,
|
|
Updated: now,
|
|
})
|
|
orgUsers = append(orgUsers, org.OrgUser{
|
|
ID: int64(u),
|
|
UserID: int64(u),
|
|
OrgID: 1,
|
|
Role: org.RoleViewer,
|
|
Created: now,
|
|
Updated: now,
|
|
})
|
|
roles = append(roles, accesscontrol.Role{
|
|
ID: int64(u),
|
|
UID: fmt.Sprintf("managed_users_%v_permissions", u),
|
|
Name: fmt.Sprintf("managed:users:%v:permissions", u),
|
|
OrgID: 1,
|
|
Version: 1,
|
|
Created: now,
|
|
Updated: now,
|
|
})
|
|
userRoles = append(userRoles, accesscontrol.UserRole{
|
|
ID: int64(u),
|
|
OrgID: 1,
|
|
RoleID: int64(u),
|
|
UserID: int64(u),
|
|
Created: now,
|
|
})
|
|
}
|
|
err := sqlStore.WithDbSession(context.Background(), func(sess *db.Session) error {
|
|
if _, err := sess.Insert(users); err != nil {
|
|
return err
|
|
}
|
|
if _, err := sess.Insert(orgUsers); err != nil {
|
|
return err
|
|
}
|
|
if _, err := sess.Insert(roles); err != nil {
|
|
return err
|
|
}
|
|
_, err := sess.Insert(userRoles)
|
|
return err
|
|
})
|
|
return err
|
|
}); errInsert != nil {
|
|
require.NoError(b, errInsert, "could not insert users and roles")
|
|
return nil, nil
|
|
}
|
|
|
|
// Populate permissions
|
|
action2 := "resources:action2"
|
|
if errInsert := actest.ConcurrentBatch(actest.Concurrency, resourceCount*usersCount, actest.BatchSize, func(start, end int) error {
|
|
permissions := make([]accesscontrol.Permission, 0, end-start)
|
|
for i := start; i < end; i++ {
|
|
permissions = append(permissions, accesscontrol.Permission{
|
|
RoleID: int64(i/resourceCount + 1),
|
|
Action: action2,
|
|
Scope: fmt.Sprintf("resources:id:%v", i%resourceCount+1),
|
|
Created: now,
|
|
Updated: now,
|
|
})
|
|
}
|
|
|
|
return sqlStore.WithDbSession(context.Background(), func(sess *db.Session) error {
|
|
_, err := sess.Insert(permissions)
|
|
return err
|
|
})
|
|
}); errInsert != nil {
|
|
require.NoError(b, errInsert, "could not insert permissions")
|
|
return nil, nil
|
|
}
|
|
|
|
// Allow signed in user to view all users permissions in the worst way
|
|
userPermissions := map[string][]string{}
|
|
for u := 1; u < usersCount+1; u++ {
|
|
userPermissions[accesscontrol.ActionUsersPermissionsRead] =
|
|
append(userPermissions[accesscontrol.ActionUsersPermissionsRead], fmt.Sprintf("users:id:%v", u))
|
|
}
|
|
return acService, &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{1: userPermissions}}
|
|
}
|
|
|
|
func benchSearchUsersPermissions(b *testing.B, usersCount, resourceCount int) {
|
|
acService, siu := setupBenchEnv(b, usersCount, resourceCount)
|
|
b.ResetTimer()
|
|
|
|
for n := 0; n < b.N; n++ {
|
|
usersPermissions, err := acService.SearchUsersPermissions(context.Background(), siu, accesscontrol.SearchOptions{ActionPrefix: "resources:"})
|
|
require.NoError(b, err)
|
|
require.Len(b, usersPermissions, usersCount)
|
|
for _, permissions := range usersPermissions {
|
|
// action1 on all resource + action2
|
|
require.Len(b, permissions, resourceCount+1)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Lots of resources
|
|
func BenchmarkSearchUsersPermissions_10_1K(b *testing.B) { benchSearchUsersPermissions(b, 10, 1000) } // ~0.047s/op
|
|
func BenchmarkSearchUsersPermissions_10_10K(b *testing.B) { benchSearchUsersPermissions(b, 10, 10000) } // ~0.5s/op
|
|
func BenchmarkSearchUsersPermissions_10_100K(b *testing.B) {
|
|
if testing.Short() {
|
|
b.Skip("Skipping benchmark in short mode")
|
|
}
|
|
benchSearchUsersPermissions(b, 10, 100000)
|
|
} // ~4.6s/op
|
|
func BenchmarkSearchUsersPermissions_10_1M(b *testing.B) {
|
|
if testing.Short() {
|
|
b.Skip("Skipping benchmark in short mode")
|
|
}
|
|
benchSearchUsersPermissions(b, 10, 1000000)
|
|
} // ~55.36s/op
|
|
|
|
// Lots of users (most probable case)
|
|
func BenchmarkSearchUsersPermissions_1K_10(b *testing.B) { benchSearchUsersPermissions(b, 1000, 10) } // ~0.056s/op
|
|
func BenchmarkSearchUsersPermissions_10K_10(b *testing.B) { benchSearchUsersPermissions(b, 10000, 10) } // ~0.58s/op
|
|
func BenchmarkSearchUsersPermissions_100K_10(b *testing.B) {
|
|
if testing.Short() {
|
|
b.Skip("Skipping benchmark in short mode")
|
|
}
|
|
benchSearchUsersPermissions(b, 100000, 10)
|
|
} // ~6.21s/op
|
|
func BenchmarkSearchUsersPermissions_1M_10(b *testing.B) {
|
|
if testing.Short() {
|
|
b.Skip("Skipping benchmark in short mode")
|
|
}
|
|
benchSearchUsersPermissions(b, 1000000, 10)
|
|
} // ~57s/op
|
|
|
|
// Lots of both
|
|
func BenchmarkSearchUsersPermissions_10K_100(b *testing.B) {
|
|
if testing.Short() {
|
|
b.Skip("Skipping benchmark in short mode")
|
|
}
|
|
benchSearchUsersPermissions(b, 10000, 100)
|
|
} // ~1.45s/op
|
|
func BenchmarkSearchUsersPermissions_10K_1K(b *testing.B) {
|
|
if testing.Short() {
|
|
b.Skip("Skipping benchmark in short mode")
|
|
}
|
|
benchSearchUsersPermissions(b, 10000, 1000)
|
|
} // ~50s/op
|
|
|
|
// Benchmarking search when we specify Action and Scope
|
|
func benchSearchUsersWithPerm(b *testing.B, usersCount, resourceCount int) {
|
|
if testing.Short() {
|
|
b.Skip("Skipping benchmark in short mode")
|
|
}
|
|
acService, siu := setupBenchEnv(b, usersCount, resourceCount)
|
|
b.ResetTimer()
|
|
|
|
for n := 0; n < b.N; n++ {
|
|
usersPermissions, err := acService.SearchUsersPermissions(context.Background(), siu,
|
|
accesscontrol.SearchOptions{Action: "resources:action2", Scope: "resources:id:1"})
|
|
require.NoError(b, err)
|
|
require.Len(b, usersPermissions, usersCount)
|
|
for _, permissions := range usersPermissions {
|
|
require.Len(b, permissions, 1)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkSearchUsersWithPerm_1K_10(b *testing.B) { benchSearchUsersWithPerm(b, 1000, 10) } // ~0.045s/op
|
|
func BenchmarkSearchUsersWithPerm_1K_100(b *testing.B) { benchSearchUsersWithPerm(b, 1000, 100) } // ~0.038s/op
|
|
func BenchmarkSearchUsersWithPerm_1K_1K(b *testing.B) { benchSearchUsersWithPerm(b, 1000, 1000) } // ~0.033s/op
|
|
func BenchmarkSearchUsersWithPerm_1K_10K(b *testing.B) { benchSearchUsersWithPerm(b, 1000, 10000) } // ~0.033s/op
|
|
func BenchmarkSearchUsersWithPerm_1K_100K(b *testing.B) { benchSearchUsersWithPerm(b, 1000, 100000) } // ~0.056s/op
|
|
|
|
func BenchmarkSearchUsersWithPerm_10K_10(b *testing.B) { benchSearchUsersWithPerm(b, 10000, 10) } // ~0.11s/op
|
|
func BenchmarkSearchUsersWithPerm_10K_100(b *testing.B) { benchSearchUsersWithPerm(b, 10000, 100) } // ~0.12s/op
|
|
func BenchmarkSearchUsersWithPerm_10K_1K(b *testing.B) { benchSearchUsersWithPerm(b, 10000, 1000) } // ~0.12s/op
|
|
func BenchmarkSearchUsersWithPerm_10K_10K(b *testing.B) { benchSearchUsersWithPerm(b, 10000, 10000) } // ~0.17s/op
|
|
|
|
func BenchmarkSearchUsersWithPerm_20K_10(b *testing.B) { benchSearchUsersWithPerm(b, 20000, 10) } // ~0.22s/op
|
|
func BenchmarkSearchUsersWithPerm_20K_100(b *testing.B) { benchSearchUsersWithPerm(b, 20000, 100) } // ~0.22s/op
|
|
func BenchmarkSearchUsersWithPerm_20K_1K(b *testing.B) { benchSearchUsersWithPerm(b, 20000, 1000) } // ~0.25s/op
|
|
func BenchmarkSearchUsersWithPerm_20K_10K(b *testing.B) { benchSearchUsersWithPerm(b, 20000, 10000) } // ~s/op
|
|
|
|
func BenchmarkSearchUsersWithPerm_100K_10(b *testing.B) { benchSearchUsersWithPerm(b, 100000, 10) } // ~0.88s/op
|
|
func BenchmarkSearchUsersWithPerm_100K_100(b *testing.B) { benchSearchUsersWithPerm(b, 100000, 100) } // ~0.72s/op
|