AccessControl: Replace IsEnterprise checks with license checks (#49572) (#49646)

(cherry picked from commit 5caf97be40)

Co-authored-by: Karl Persson <kalle.persson@grafana.com>
This commit is contained in:
Grot (@grafanabot)
2022-05-25 20:59:47 +02:00
committed by GitHub
co-authored by Karl Persson
parent 1d4e2d12da
commit 4bd6f62dfd
11 changed files with 98 additions and 25 deletions
+2 -2
View File
@@ -250,15 +250,15 @@ func (hs *HTTPServer) registerRoutes() {
// current org without requirement of user to be org admin // current org without requirement of user to be org admin
apiRoute.Group("/org", func(orgRoute routing.RouteRegister) { apiRoute.Group("/org", func(orgRoute routing.RouteRegister) {
lookupEvaluator := func() ac.Evaluator { lookupEvaluator := func() ac.Evaluator {
if hs.Cfg.IsEnterprise { if hs.License.FeatureEnabled("accesscontrol.enforcement") {
return ac.EvalPermission(ac.ActionOrgUsersRead) return ac.EvalPermission(ac.ActionOrgUsersRead)
} }
// For oss we allow users with access to update permissions on either folders, teams or dashboards to perform the lookup // For oss we allow users with access to update permissions on either folders, teams or dashboards to perform the lookup
return ac.EvalAny( return ac.EvalAny(
ac.EvalPermission(ac.ActionOrgUsersRead), ac.EvalPermission(ac.ActionOrgUsersRead),
ac.EvalPermission(ac.ActionTeamsPermissionsWrite), ac.EvalPermission(ac.ActionTeamsPermissionsWrite),
ac.EvalPermission(dashboards.ActionDashboardsPermissionsWrite),
ac.EvalPermission(dashboards.ActionFoldersPermissionsWrite), ac.EvalPermission(dashboards.ActionFoldersPermissionsWrite),
ac.EvalPermission(dashboards.ActionDashboardsPermissionsWrite),
) )
} }
orgRoute.Get("/users/lookup", authorize(reqOrgAdminFolderAdminOrTeamAdmin, lookupEvaluator()), routing.Wrap(hs.GetOrgUsersForCurrentOrgLookup)) orgRoute.Get("/users/lookup", authorize(reqOrgAdminFolderAdminOrTeamAdmin, lookupEvaluator()), routing.Wrap(hs.GetOrgUsersForCurrentOrgLookup))
+5 -2
View File
@@ -236,6 +236,7 @@ func setupAccessControlScenarioContext(t *testing.T, cfg *setting.Cfg, url strin
hs := &HTTPServer{ hs := &HTTPServer{
Cfg: cfg, Cfg: cfg,
Live: newTestLive(t, store), Live: newTestLive(t, store),
License: &licensing.OSSLicensingService{},
Features: featuremgmt.WithFeatures(), Features: featuremgmt.WithFeatures(),
QuotaService: &quota.QuotaService{Cfg: cfg}, QuotaService: &quota.QuotaService{Cfg: cfg},
RouteRegister: routing.NewRouteRegister(), RouteRegister: routing.NewRouteRegister(),
@@ -325,6 +326,7 @@ func setupSimpleHTTPServer(features *featuremgmt.FeatureManager) *HTTPServer {
return &HTTPServer{ return &HTTPServer{
Cfg: cfg, Cfg: cfg,
Features: features, Features: features,
License: &licensing.OSSLicensingService{},
AccessControl: accesscontrolmock.New().WithDisabled(), AccessControl: accesscontrolmock.New().WithDisabled(),
} }
} }
@@ -388,7 +390,7 @@ func setupHTTPServerWithCfgDb(t *testing.T, useFakeAccessControl, enableAccessCo
acmock = acmock.WithDisabled() acmock = acmock.WithDisabled()
} }
hs.AccessControl = acmock hs.AccessControl = acmock
teamPermissionService, err := ossaccesscontrol.ProvideTeamPermissions(cfg, routeRegister, db, acmock, database.ProvideService(db)) teamPermissionService, err := ossaccesscontrol.ProvideTeamPermissions(cfg, routeRegister, db, acmock, database.ProvideService(db), hs.License)
require.NoError(t, err) require.NoError(t, err)
hs.teamPermissionsService = teamPermissionService hs.teamPermissionsService = teamPermissionService
} else { } else {
@@ -400,7 +402,7 @@ func setupHTTPServerWithCfgDb(t *testing.T, useFakeAccessControl, enableAccessCo
require.NoError(t, err) require.NoError(t, err)
err = ac.RegisterFixedRoles(context.Background()) err = ac.RegisterFixedRoles(context.Background())
require.NoError(t, err) require.NoError(t, err)
teamPermissionService, err := ossaccesscontrol.ProvideTeamPermissions(cfg, routeRegister, db, ac, database.ProvideService(db)) teamPermissionService, err := ossaccesscontrol.ProvideTeamPermissions(cfg, routeRegister, db, ac, database.ProvideService(db), hs.License)
require.NoError(t, err) require.NoError(t, err)
hs.teamPermissionsService = teamPermissionService hs.teamPermissionsService = teamPermissionService
} }
@@ -464,6 +466,7 @@ func SetupAPITestServer(t *testing.T, opts ...APITestServerOption) *webtest.Serv
hs := &HTTPServer{ hs := &HTTPServer{
RouteRegister: routing.NewRouteRegister(), RouteRegister: routing.NewRouteRegister(),
Cfg: setting.NewCfg(), Cfg: setting.NewCfg(),
License: &licensing.OSSLicensingService{},
AccessControl: accesscontrolmock.New().WithDisabled(), AccessControl: accesscontrolmock.New().WithDisabled(),
Features: featuremgmt.WithFeatures(), Features: featuremgmt.WithFeatures(),
searchUsersService: &searchusers.OSSService{}, searchUsersService: &searchusers.OSSService{},
+5 -4
View File
@@ -89,10 +89,11 @@ func (hs *HTTPServer) GetOrgUsersForCurrentOrg(c *models.ReqContext) response.Re
// GET /api/org/users/lookup // GET /api/org/users/lookup
func (hs *HTTPServer) GetOrgUsersForCurrentOrgLookup(c *models.ReqContext) response.Response { func (hs *HTTPServer) GetOrgUsersForCurrentOrgLookup(c *models.ReqContext) response.Response {
orgUsers, err := hs.getOrgUsersHelper(c, &models.GetOrgUsersQuery{ orgUsers, err := hs.getOrgUsersHelper(c, &models.GetOrgUsersQuery{
OrgId: c.OrgId, OrgId: c.OrgId,
Query: c.Query("query"), Query: c.Query("query"),
Limit: c.QueryInt("limit"), Limit: c.QueryInt("limit"),
User: c.SignedInUser, User: c.SignedInUser,
DontEnforceAccessControl: !hs.License.FeatureEnabled("accesscontrol.enforcement"),
}, c.SignedInUser) }, c.SignedInUser)
if err != nil { if err != nil {
+2
View File
@@ -119,6 +119,8 @@ type GetOrgUsersQuery struct {
OrgId int64 OrgId int64
Query string Query string
Limit int Limit int
// Flag used to allow oss edition to query users without access control
DontEnforceAccessControl bool
User *SignedInUser User *SignedInUser
Result []*OrgUserDTO Result []*OrgUserDTO
@@ -35,7 +35,7 @@ var (
func ProvideTeamPermissions( func ProvideTeamPermissions(
cfg *setting.Cfg, router routing.RouteRegister, sql *sqlstore.SQLStore, cfg *setting.Cfg, router routing.RouteRegister, sql *sqlstore.SQLStore,
ac accesscontrol.AccessControl, store resourcepermissions.Store, ac accesscontrol.AccessControl, store resourcepermissions.Store, license models.Licensing,
) (*TeamPermissionsService, error) { ) (*TeamPermissionsService, error) {
options := resourcepermissions.Options{ options := resourcepermissions.Options{
Resource: "teams", Resource: "teams",
@@ -91,7 +91,7 @@ func ProvideTeamPermissions(
}, },
} }
srv, err := resourcepermissions.New(options, cfg, router, ac, store, sql) srv, err := resourcepermissions.New(options, cfg, router, license, ac, store, sql)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -109,7 +109,7 @@ var DashboardAdminActions = append(DashboardEditActions, []string{dashboards.Act
func ProvideDashboardPermissions( func ProvideDashboardPermissions(
cfg *setting.Cfg, router routing.RouteRegister, sql *sqlstore.SQLStore, cfg *setting.Cfg, router routing.RouteRegister, sql *sqlstore.SQLStore,
ac accesscontrol.AccessControl, store resourcepermissions.Store, ac accesscontrol.AccessControl, store resourcepermissions.Store,
dashboardStore dashboards.Store, license models.Licensing, dashboardStore dashboards.Store,
) (*DashboardPermissionsService, error) { ) (*DashboardPermissionsService, error) {
getDashboard := func(ctx context.Context, orgID int64, resourceID string) (*models.Dashboard, error) { getDashboard := func(ctx context.Context, orgID int64, resourceID string) (*models.Dashboard, error) {
query := &models.GetDashboardQuery{Uid: resourceID, OrgId: orgID} query := &models.GetDashboardQuery{Uid: resourceID, OrgId: orgID}
@@ -164,7 +164,7 @@ func ProvideDashboardPermissions(
RoleGroup: "Dashboards", RoleGroup: "Dashboards",
} }
srv, err := resourcepermissions.New(options, cfg, router, ac, store, sql) srv, err := resourcepermissions.New(options, cfg, router, license, ac, store, sql)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -182,7 +182,7 @@ var FolderAdminActions = append(FolderEditActions, []string{dashboards.ActionFol
func ProvideFolderPermissions( func ProvideFolderPermissions(
cfg *setting.Cfg, router routing.RouteRegister, sql *sqlstore.SQLStore, cfg *setting.Cfg, router routing.RouteRegister, sql *sqlstore.SQLStore,
accesscontrol accesscontrol.AccessControl, store resourcepermissions.Store, accesscontrol accesscontrol.AccessControl, store resourcepermissions.Store,
dashboardStore dashboards.Store, license models.Licensing, dashboardStore dashboards.Store,
) (*FolderPermissionsService, error) { ) (*FolderPermissionsService, error) {
options := resourcepermissions.Options{ options := resourcepermissions.Options{
Resource: "folders", Resource: "folders",
@@ -213,7 +213,7 @@ func ProvideFolderPermissions(
WriterRoleName: "Folder permission writer", WriterRoleName: "Folder permission writer",
RoleGroup: "Folders", RoleGroup: "Folders",
} }
srv, err := resourcepermissions.New(options, cfg, router, accesscontrol, store, sql) srv, err := resourcepermissions.New(options, cfg, router, license, accesscontrol, store, sql)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -118,7 +118,7 @@ func (a *api) getPermissions(c *models.ReqContext) response.Response {
return response.Error(http.StatusInternalServerError, "failed to get permissions", err) return response.Error(http.StatusInternalServerError, "failed to get permissions", err)
} }
if a.service.options.Assignments.BuiltInRoles && !a.service.cfg.IsEnterprise { if a.service.options.Assignments.BuiltInRoles && !a.service.license.FeatureEnabled("accesscontrol.enforcement") {
permissions = append(permissions, accesscontrol.ResourcePermission{ permissions = append(permissions, accesscontrol.ResourcePermission{
Actions: a.service.actions, Actions: a.service.actions,
Scope: "*", Scope: "*",
@@ -46,7 +46,10 @@ type Store interface {
GetResourcePermissions(ctx context.Context, orgID int64, query types.GetResourcePermissionsQuery) ([]accesscontrol.ResourcePermission, error) GetResourcePermissions(ctx context.Context, orgID int64, query types.GetResourcePermissionsQuery) ([]accesscontrol.ResourcePermission, error)
} }
func New(options Options, cfg *setting.Cfg, router routing.RouteRegister, ac accesscontrol.AccessControl, store Store, sqlStore *sqlstore.SQLStore) (*Service, error) { func New(
options Options, cfg *setting.Cfg, router routing.RouteRegister, license models.Licensing,
ac accesscontrol.AccessControl, store Store, sqlStore *sqlstore.SQLStore,
) (*Service, error) {
var permissions []string var permissions []string
actionSet := make(map[string]struct{}) actionSet := make(map[string]struct{})
for permission, actions := range options.PermissionsToActions { for permission, actions := range options.PermissionsToActions {
@@ -71,6 +74,7 @@ func New(options Options, cfg *setting.Cfg, router routing.RouteRegister, ac acc
cfg: cfg, cfg: cfg,
store: store, store: store,
options: options, options: options,
license: license,
permissions: permissions, permissions: permissions,
actions: actions, actions: actions,
sqlStore: sqlStore, sqlStore: sqlStore,
@@ -89,10 +93,11 @@ func New(options Options, cfg *setting.Cfg, router routing.RouteRegister, ac acc
// Service is used to create access control sub system including api / and service for managed resource permission // Service is used to create access control sub system including api / and service for managed resource permission
type Service struct { type Service struct {
cfg *setting.Cfg cfg *setting.Cfg
ac accesscontrol.AccessControl ac accesscontrol.AccessControl
store Store store Store
api *api api *api
license models.Licensing
options Options options Options
permissions []string permissions []string
@@ -12,6 +12,7 @@ import (
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/database" "github.com/grafana/grafana/pkg/services/accesscontrol/database"
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
"github.com/grafana/grafana/pkg/services/licensing/licensingtest"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
@@ -221,8 +222,12 @@ func setupTestEnvironment(t *testing.T, permissions []*accesscontrol.Permission,
sql := sqlstore.InitTestDB(t) sql := sqlstore.InitTestDB(t)
store := database.ProvideService(sql) store := database.ProvideService(sql)
cfg := setting.NewCfg() cfg := setting.NewCfg()
cfg.IsEnterprise = true license := licensingtest.NewFakeLicensing()
service, err := New(ops, cfg, routing.NewRouteRegister(), accesscontrolmock.New().WithPermissions(permissions), store, sql) license.On("FeatureEnabled", "accesscontrol.enforcement").Return(true).Maybe()
service, err := New(
ops, cfg, routing.NewRouteRegister(), license,
accesscontrolmock.New().WithPermissions(permissions), store, sql,
)
require.NoError(t, err) require.NoError(t, err)
return service, sql return service, sql
@@ -17,6 +17,7 @@ import (
"github.com/grafana/grafana/pkg/services/accesscontrol/ossaccesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol/ossaccesscontrol"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
dashdb "github.com/grafana/grafana/pkg/services/dashboards/database" dashdb "github.com/grafana/grafana/pkg/services/dashboards/database"
"github.com/grafana/grafana/pkg/services/licensing/licensingtest"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
@@ -594,11 +595,14 @@ func setupAccessControlGuardianTest(t *testing.T, uid string, permissions []*acc
}) })
require.NoError(t, err) require.NoError(t, err)
ac := accesscontrolmock.New().WithPermissions(permissions) ac := accesscontrolmock.New().WithPermissions(permissions)
license := licensingtest.NewFakeLicensing()
license.On("FeatureEnabled", "accesscontrol.enforcement").Return(true).Maybe()
folderPermissions, err := ossaccesscontrol.ProvideFolderPermissions( folderPermissions, err := ossaccesscontrol.ProvideFolderPermissions(
setting.NewCfg(), routing.NewRouteRegister(), store, ac, database.ProvideService(store), &dashboards.FakeDashboardStore{}) setting.NewCfg(), routing.NewRouteRegister(), store, ac, database.ProvideService(store), license, &dashboards.FakeDashboardStore{})
require.NoError(t, err) require.NoError(t, err)
dashboardPermissions, err := ossaccesscontrol.ProvideDashboardPermissions( dashboardPermissions, err := ossaccesscontrol.ProvideDashboardPermissions(
setting.NewCfg(), routing.NewRouteRegister(), store, ac, database.ProvideService(store), &dashboards.FakeDashboardStore{}) setting.NewCfg(), routing.NewRouteRegister(), store, ac, database.ProvideService(store), license, &dashboards.FakeDashboardStore{})
require.NoError(t, err) require.NoError(t, err)
if dashboardSvc == nil { if dashboardSvc == nil {
dashboardSvc = &dashboards.FakeDashboardService{} dashboardSvc = &dashboards.FakeDashboardService{}
@@ -0,0 +1,52 @@
package licensingtest
import (
"github.com/stretchr/testify/mock"
"github.com/grafana/grafana/pkg/models"
)
var _ models.Licensing = new(FakeLicensing)
func NewFakeLicensing() *FakeLicensing {
return &FakeLicensing{&mock.Mock{}}
}
type FakeLicensing struct {
*mock.Mock
}
func (f *FakeLicensing) Expiry() int64 {
mockedArgs := f.Called()
return mockedArgs.Get(0).(int64)
}
func (f *FakeLicensing) Edition() string {
mockedArgs := f.Called()
return mockedArgs.Get(0).(string)
}
func (f *FakeLicensing) ContentDeliveryPrefix() string {
mockedArgs := f.Called()
return mockedArgs.Get(0).(string)
}
func (f *FakeLicensing) LicenseURL(showAdminLicensingPage bool) string {
mockedArgs := f.Called(showAdminLicensingPage)
return mockedArgs.Get(0).(string)
}
func (f *FakeLicensing) StateInfo() string {
mockedArgs := f.Called()
return mockedArgs.Get(0).(string)
}
func (f *FakeLicensing) EnabledFeatures() map[string]bool {
mockedArgs := f.Called()
return mockedArgs.Get(0).(map[string]bool)
}
func (f *FakeLicensing) FeatureEnabled(feature string) bool {
mockedArgs := f.Called(feature)
return mockedArgs.Get(0).(bool)
}
+2 -1
View File
@@ -112,7 +112,8 @@ func (ss *SQLStore) GetOrgUsers(ctx context.Context, query *models.GetOrgUsersQu
if query.User == nil { if query.User == nil {
ss.log.Warn("Query user not set for filtering.") ss.log.Warn("Query user not set for filtering.")
} }
if ss.Cfg.IsEnterprise && !accesscontrol.IsDisabled(ss.Cfg) {
if !query.DontEnforceAccessControl && !accesscontrol.IsDisabled(ss.Cfg) {
acFilter, err := accesscontrol.Filter(query.User, "org_user.user_id", "users:id:", accesscontrol.ActionOrgUsersRead) acFilter, err := accesscontrol.Filter(query.User, "org_user.user_id", "users:id:", accesscontrol.ActionOrgUsersRead)
if err != nil { if err != nil {
return err return err