diff --git a/pkg/api/dashboard.go b/pkg/api/dashboard.go index 466c2ce2409..5038c2e02ef 100644 --- a/pkg/api/dashboard.go +++ b/pkg/api/dashboard.go @@ -158,11 +158,8 @@ func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response } annotationPermissions := &dtos.AnnotationPermission{} - - if !hs.AccessControl.IsDisabled() { - hs.getAnnotationPermissionsByScope(c, &annotationPermissions.Dashboard, accesscontrol.ScopeAnnotationsTypeDashboard) - hs.getAnnotationPermissionsByScope(c, &annotationPermissions.Organization, accesscontrol.ScopeAnnotationsTypeOrganization) - } + hs.getAnnotationPermissionsByScope(c, &annotationPermissions.Dashboard, accesscontrol.ScopeAnnotationsTypeDashboard) + hs.getAnnotationPermissionsByScope(c, &annotationPermissions.Organization, accesscontrol.ScopeAnnotationsTypeOrganization) meta := dtos.DashboardMeta{ IsStarred: isStarred, @@ -488,7 +485,7 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S // Clear permission cache for the user who's created the dashboard, so that new permissions are fetched for their next call // Required for cases when caller wants to immediately interact with the newly created object - if newDashboard && !hs.accesscontrolService.IsDisabled() { + if newDashboard { hs.accesscontrolService.ClearUserPermissionCache(c.SignedInUser) } diff --git a/pkg/api/folder.go b/pkg/api/folder.go index 34497df298b..7c347dec3a5 100644 --- a/pkg/api/folder.go +++ b/pkg/api/folder.go @@ -158,9 +158,7 @@ func (hs *HTTPServer) CreateFolder(c *contextmodel.ReqContext) response.Response // Clear permission cache for the user who's created the folder, so that new permissions are fetched for their next call // Required for cases when caller wants to immediately interact with the newly created object - if !hs.AccessControl.IsDisabled() { - hs.accesscontrolService.ClearUserPermissionCache(c.SignedInUser) - } + hs.accesscontrolService.ClearUserPermissionCache(c.SignedInUser) g, err := guardian.NewByUID(c.Req.Context(), folder.UID, c.OrgID, c.SignedInUser) if err != nil { @@ -172,29 +170,23 @@ func (hs *HTTPServer) CreateFolder(c *contextmodel.ReqContext) response.Response } func (hs *HTTPServer) setDefaultFolderPermissions(ctx context.Context, orgID int64, user *user.SignedInUser, folder *folder.Folder) error { - isNested := folder.ParentUID != "" - var permissionErr error - if !accesscontrol.IsDisabled(hs.Cfg) { - var permissions []accesscontrol.SetResourcePermissionCommand - if user.IsRealUser() && !user.IsAnonymous { - permissions = append(permissions, accesscontrol.SetResourcePermissionCommand{ - UserID: user.UserID, Permission: dashboards.PERMISSION_ADMIN.String(), - }) - } - - if !isNested || !hs.Features.IsEnabled(featuremgmt.FlagNestedFolders) { - permissions = append(permissions, []accesscontrol.SetResourcePermissionCommand{ - {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_EDIT.String()}, - {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_VIEW.String()}, - }...) - } - - _, permissionErr = hs.folderPermissionsService.SetPermissions(ctx, orgID, folder.UID, permissions...) - return permissionErr - } else if hs.Cfg.EditorsCanAdmin && user.IsRealUser() && !user.IsAnonymous { - return hs.folderService.MakeUserAdmin(ctx, orgID, user.UserID, folder.ID, !isNested) + var permissions []accesscontrol.SetResourcePermissionCommand + if user.IsRealUser() && !user.IsAnonymous { + permissions = append(permissions, accesscontrol.SetResourcePermissionCommand{ + UserID: user.UserID, Permission: dashboards.PERMISSION_ADMIN.String(), + }) } - return nil + + isNested := folder.ParentUID != "" + if !isNested || !hs.Features.IsEnabled(featuremgmt.FlagNestedFolders) { + permissions = append(permissions, []accesscontrol.SetResourcePermissionCommand{ + {BuiltinRole: string(org.RoleEditor), Permission: dashboards.PERMISSION_EDIT.String()}, + {BuiltinRole: string(org.RoleViewer), Permission: dashboards.PERMISSION_VIEW.String()}, + }...) + } + + _, err := hs.folderPermissionsService.SetPermissions(ctx, orgID, folder.UID, permissions...) + return err } // swagger:route POST /folders/{folder_uid}/move folders moveFolder @@ -378,7 +370,7 @@ func (hs *HTTPServer) newToFolderDto(c *contextmodel.ReqContext, g guardian.Dash } func (hs *HTTPServer) getFolderACMetadata(c *contextmodel.ReqContext, f *folder.Folder) (accesscontrol.Metadata, error) { - if hs.AccessControl.IsDisabled() || !c.QueryBool("accesscontrol") { + if !c.QueryBool("accesscontrol") { return nil, nil } diff --git a/pkg/api/org_users.go b/pkg/api/org_users.go index 28aadd3a7e6..a91bb866749 100644 --- a/pkg/api/org_users.go +++ b/pkg/api/org_users.go @@ -412,12 +412,10 @@ func (hs *HTTPServer) updateOrgUserHelper(c *contextmodel.ReqContext, cmd org.Up return response.Error(http.StatusInternalServerError, "Failed update org user", err) } - if !hs.accesscontrolService.IsDisabled() { - hs.accesscontrolService.ClearUserPermissionCache(&user.SignedInUser{ - UserID: cmd.UserID, - OrgID: cmd.OrgID, - }) - } + hs.accesscontrolService.ClearUserPermissionCache(&user.SignedInUser{ + UserID: cmd.UserID, + OrgID: cmd.OrgID, + }) return response.Success("Organization user updated") } diff --git a/pkg/infra/db/sqlbuilder.go b/pkg/infra/db/sqlbuilder.go index 392c5e78a7e..35381ba0b22 100644 --- a/pkg/infra/db/sqlbuilder.go +++ b/pkg/infra/db/sqlbuilder.go @@ -3,7 +3,6 @@ package db import ( "bytes" - ac "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/sqlstore/migrator" @@ -67,19 +66,10 @@ func (sb *SQLBuilder) WriteDashboardPermissionFilter(user *user.SignedInUser, pe recQry string recQryParams []interface{} ) - if !ac.IsDisabled(sb.cfg) { - filterRBAC := permissions.NewAccessControlDashboardPermissionFilter(user, permission, queryType, sb.features, sb.recursiveQueriesAreSupported) - sql, params = filterRBAC.Where() - recQry, recQryParams = filterRBAC.With() - } else { - sql, params = permissions.DashboardPermissionFilter{ - OrgRole: user.OrgRole, - Dialect: sb.dialect, - UserId: user.UserID, - OrgId: user.OrgID, - PermissionLevel: permission, - }.Where() - } + + filterRBAC := permissions.NewAccessControlDashboardPermissionFilter(user, permission, queryType, sb.features, sb.recursiveQueriesAreSupported) + sql, params = filterRBAC.Where() + recQry, recQryParams = filterRBAC.With() sb.sql.WriteString(" AND " + sql) sb.params = append(sb.params, params...) diff --git a/pkg/infra/db/sqlbuilder_test.go b/pkg/infra/db/sqlbuilder_test.go deleted file mode 100644 index 2f959480dd3..00000000000 --- a/pkg/infra/db/sqlbuilder_test.go +++ /dev/null @@ -1,580 +0,0 @@ -package db - -import ( - "context" - "fmt" - "math/rand" - "strconv" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/grafana/grafana/pkg/components/simplejson" - "github.com/grafana/grafana/pkg/services/dashboards" - dashver "github.com/grafana/grafana/pkg/services/dashboardversion" - "github.com/grafana/grafana/pkg/services/featuremgmt" - "github.com/grafana/grafana/pkg/services/org" - "github.com/grafana/grafana/pkg/services/sqlstore" - "github.com/grafana/grafana/pkg/services/user" - "github.com/grafana/grafana/pkg/util" -) - -func TestIntegrationSQLBuilder(t *testing.T) { - if testing.Short() { - t.Skip("skipping integration test") - } - - t.Run("WriteDashboardPermissionFilter", func(t *testing.T) { - t.Run("user ACL", func(t *testing.T) { - test(t, - DashboardProps{}, - &DashboardPermission{User: true, Permission: dashboards.PERMISSION_VIEW}, - Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_VIEW}, - shouldFind, - featuremgmt.WithFeatures(), - ) - - test(t, - DashboardProps{}, - &DashboardPermission{User: true, Permission: dashboards.PERMISSION_VIEW}, - Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT}, - shouldNotFind, - featuremgmt.WithFeatures(), - ) - - test(t, - DashboardProps{}, - &DashboardPermission{User: true, Permission: dashboards.PERMISSION_EDIT}, - Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT}, - shouldFind, - featuremgmt.WithFeatures(), - ) - - test(t, - DashboardProps{}, - &DashboardPermission{User: true, Permission: dashboards.PERMISSION_VIEW}, - Search{RequiredPermission: dashboards.PERMISSION_VIEW}, - shouldNotFind, - featuremgmt.WithFeatures(), - ) - }) - - t.Run("user ACL with nested folders", func(t *testing.T) { - test(t, - DashboardProps{}, - &DashboardPermission{User: true, Permission: dashboards.PERMISSION_VIEW}, - Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_VIEW}, - shouldFind, - featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)), - ) - - test(t, - DashboardProps{}, - &DashboardPermission{User: true, Permission: dashboards.PERMISSION_VIEW}, - Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT}, - shouldNotFind, - featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)), - ) - - test(t, - DashboardProps{}, - &DashboardPermission{User: true, Permission: dashboards.PERMISSION_EDIT}, - Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT}, - shouldFind, - featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)), - ) - - test(t, - DashboardProps{}, - &DashboardPermission{User: true, Permission: dashboards.PERMISSION_VIEW}, - Search{RequiredPermission: dashboards.PERMISSION_VIEW}, - shouldNotFind, - featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)), - ) - }) - - t.Run("role ACL", func(t *testing.T) { - test(t, - DashboardProps{}, - &DashboardPermission{Role: org.RoleViewer, Permission: dashboards.PERMISSION_VIEW}, - Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW}, - shouldFind, - featuremgmt.WithFeatures(), - ) - - test(t, - DashboardProps{}, - &DashboardPermission{Role: org.RoleViewer, Permission: dashboards.PERMISSION_VIEW}, - Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_EDIT}, - shouldNotFind, - featuremgmt.WithFeatures(), - ) - - test(t, - DashboardProps{}, - &DashboardPermission{Role: org.RoleEditor, Permission: dashboards.PERMISSION_VIEW}, - Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW}, - shouldNotFind, - featuremgmt.WithFeatures(), - ) - - test(t, - DashboardProps{}, - &DashboardPermission{Role: org.RoleEditor, Permission: dashboards.PERMISSION_VIEW}, - Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW}, - shouldNotFind, - featuremgmt.WithFeatures(), - ) - }) - - t.Run("role ACL with nested folders", func(t *testing.T) { - test(t, - DashboardProps{}, - &DashboardPermission{Role: org.RoleViewer, Permission: dashboards.PERMISSION_VIEW}, - Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW}, - shouldFind, - featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)), - ) - - test(t, - DashboardProps{}, - &DashboardPermission{Role: org.RoleViewer, Permission: dashboards.PERMISSION_VIEW}, - Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_EDIT}, - shouldNotFind, - featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)), - ) - - test(t, - DashboardProps{}, - &DashboardPermission{Role: org.RoleEditor, Permission: dashboards.PERMISSION_VIEW}, - Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW}, - shouldNotFind, - featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)), - ) - - test(t, - DashboardProps{}, - &DashboardPermission{Role: org.RoleEditor, Permission: dashboards.PERMISSION_VIEW}, - Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW}, - shouldNotFind, - featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)), - ) - }) - - t.Run("team ACL", func(t *testing.T) { - test(t, - DashboardProps{}, - &DashboardPermission{Team: true, Permission: dashboards.PERMISSION_VIEW}, - Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_VIEW}, - shouldFind, - featuremgmt.WithFeatures(), - ) - - test(t, - DashboardProps{}, - &DashboardPermission{Team: true, Permission: dashboards.PERMISSION_VIEW}, - Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT}, - shouldNotFind, - featuremgmt.WithFeatures(), - ) - - test(t, - DashboardProps{}, - &DashboardPermission{Team: true, Permission: dashboards.PERMISSION_EDIT}, - Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT}, - shouldFind, - featuremgmt.WithFeatures(), - ) - - test(t, - DashboardProps{}, - &DashboardPermission{Team: true, Permission: dashboards.PERMISSION_EDIT}, - Search{UserFromACL: false, RequiredPermission: dashboards.PERMISSION_EDIT}, - shouldNotFind, - featuremgmt.WithFeatures(), - ) - }) - - t.Run("team ACL with nested folders", func(t *testing.T) { - test(t, - DashboardProps{}, - &DashboardPermission{Team: true, Permission: dashboards.PERMISSION_VIEW}, - Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_VIEW}, - shouldFind, - featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)), - ) - - test(t, - DashboardProps{}, - &DashboardPermission{Team: true, Permission: dashboards.PERMISSION_VIEW}, - Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT}, - shouldNotFind, - featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)), - ) - - test(t, - DashboardProps{}, - &DashboardPermission{Team: true, Permission: dashboards.PERMISSION_EDIT}, - Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT}, - shouldFind, - featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)), - ) - - test(t, - DashboardProps{}, - &DashboardPermission{Team: true, Permission: dashboards.PERMISSION_EDIT}, - Search{UserFromACL: false, RequiredPermission: dashboards.PERMISSION_EDIT}, - shouldNotFind, - featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)), - ) - }) - - t.Run("defaults for user ACL", func(t *testing.T) { - test(t, - DashboardProps{}, - nil, - Search{OrgId: -1, UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW}, - shouldNotFind, - featuremgmt.WithFeatures(), - ) - - test(t, - DashboardProps{OrgId: -1}, - nil, - Search{OrgId: -1, UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW}, - shouldFind, - featuremgmt.WithFeatures(), - ) - - test(t, - DashboardProps{OrgId: -1}, - nil, - Search{OrgId: -1, UsersOrgRole: org.RoleEditor, RequiredPermission: dashboards.PERMISSION_EDIT}, - shouldFind, - featuremgmt.WithFeatures(), - ) - - test(t, - DashboardProps{OrgId: -1}, - nil, - Search{OrgId: -1, UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_EDIT}, - shouldNotFind, - featuremgmt.WithFeatures(), - ) - }) - - t.Run("defaults for user ACL with nested folders", func(t *testing.T) { - test(t, - DashboardProps{}, - nil, - Search{OrgId: -1, UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW}, - shouldNotFind, - featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)), - ) - - test(t, - DashboardProps{OrgId: -1}, - nil, - Search{OrgId: -1, UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW}, - shouldFind, - featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)), - ) - - test(t, - DashboardProps{OrgId: -1}, - nil, - Search{OrgId: -1, UsersOrgRole: org.RoleEditor, RequiredPermission: dashboards.PERMISSION_EDIT}, - shouldFind, - featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)), - ) - - test(t, - DashboardProps{OrgId: -1}, - nil, - Search{OrgId: -1, UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_EDIT}, - shouldNotFind, - featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)), - ) - }) - }) -} - -const shouldFind = true -const shouldNotFind = false - -type DashboardProps struct { - OrgId int64 -} - -type DashboardPermission struct { - User bool - Team bool - Role org.RoleType - Permission dashboards.PermissionType -} - -type Search struct { - UsersOrgRole org.RoleType - UserFromACL bool - RequiredPermission dashboards.PermissionType - OrgId int64 -} - -type dashboardResponse struct { - Id int64 -} - -func test(t *testing.T, dashboardProps DashboardProps, dashboardPermission *DashboardPermission, search Search, shouldFind bool, features featuremgmt.FeatureToggles) { - t.Helper() - - t.Run("", func(t *testing.T) { - // Will also cleanup the db - sqlStore := InitTestDB(t) - - dashboard := createDummyDashboard(t, sqlStore, dashboardProps) - - var aclUserID int64 - if dashboardPermission != nil { - aclUserID = createDummyACL(t, sqlStore, dashboardPermission, search, dashboard.ID) - t.Logf("Created ACL with user ID %d\n", aclUserID) - } - dashboards := getDashboards(t, sqlStore, search, aclUserID, features) - - if shouldFind { - require.Len(t, dashboards, 1, "Should return one dashboard") - assert.Equal(t, dashboard.ID, dashboards[0].Id, "Should return created dashboard") - } else { - assert.Empty(t, dashboards, "Should not return any dashboard") - } - }) -} - -func createDummyUser(t *testing.T, sqlStore DB) *user.User { - t.Helper() - - uid := strconv.Itoa(rand.Intn(9999999)) - usr := &user.User{ - Email: uid + "@example.com", - Login: uid, - Name: uid, - Company: "", - Password: uid, - EmailVerified: true, - IsAdmin: false, - Created: time.Now(), - Updated: time.Now(), - } - - var id int64 - err := sqlStore.WithDbSession(context.Background(), func(sess *Session) error { - sess.UseBool("is_admin") - var err error - _, err = sess.Insert(usr) - id = usr.ID - return err - }) - require.NoError(t, err) - usr.ID = id - return usr -} - -func createDummyDashboard(t *testing.T, sqlStore *sqlstore.SQLStore, dashboardProps DashboardProps) *dashboards.Dashboard { - t.Helper() - - json, err := simplejson.NewJson([]byte(`{"schemaVersion":17,"title":"gdev dashboards","uid":"","version":1}`)) - require.NoError(t, err) - - saveDashboardCmd := dashboards.SaveDashboardCommand{ - Dashboard: json, - UserID: 0, - Overwrite: false, - Message: "", - RestoredFrom: 0, - PluginID: "", - FolderID: 0, - IsFolder: false, - UpdatedAt: time.Time{}, - } - if dashboardProps.OrgId != 0 { - saveDashboardCmd.OrgID = dashboardProps.OrgId - } else { - saveDashboardCmd.OrgID = 1 - } - - dash := insertTestDashboard(t, sqlStore, "", saveDashboardCmd.OrgID, 0, false, nil) - require.NoError(t, err) - - t.Logf("Created dashboard with ID %d and org ID %d\n", dash.ID, dash.OrgID) - return dash -} - -func createDummyACL(t *testing.T, sqlStore *sqlstore.SQLStore, dashboardPermission *DashboardPermission, search Search, dashboardID int64) int64 { - t.Helper() - - acl := &dashboards.DashboardACL{ - OrgID: 1, - Created: time.Now(), - Updated: time.Now(), - Permission: dashboardPermission.Permission, - DashboardID: dashboardID, - } - - var user *user.User - if dashboardPermission.User { - t.Logf("Creating user") - user = createDummyUser(t, sqlStore) - - acl.UserID = user.ID - } - - if dashboardPermission.Team { - // TODO: Restore/refactor sqlBuilder tests after user, org and team services are split - t.Skip("Creating team: skip, team service is moved") - } - - if len(string(dashboardPermission.Role)) > 0 { - acl.Role = &dashboardPermission.Role - } - - err := updateDashboardACL(t, sqlStore, dashboardID, acl) - require.NoError(t, err) - if user != nil { - return user.ID - } - return 0 -} - -func getDashboards(t *testing.T, sqlStore *sqlstore.SQLStore, search Search, aclUserID int64, features featuremgmt.FeatureToggles) []*dashboardResponse { - t.Helper() - - old := sqlStore.Cfg.RBACEnabled - sqlStore.Cfg.RBACEnabled = false - defer func() { - sqlStore.Cfg.RBACEnabled = old - }() - - recursiveQueriesAreSupported, err := sqlStore.RecursiveQueriesAreSupported() - require.NoError(t, err) - - builder := NewSqlBuilder(sqlStore.Cfg, features, sqlStore.GetDialect(), recursiveQueriesAreSupported) - signedInUser := &user.SignedInUser{ - UserID: 9999999999, - } - - if search.OrgId == 0 { - signedInUser.OrgID = 1 - } else { - signedInUser.OrgID = search.OrgId - } - - if len(string(search.UsersOrgRole)) > 0 { - signedInUser.OrgRole = search.UsersOrgRole - } else { - signedInUser.OrgRole = org.RoleViewer - } - if search.UserFromACL { - signedInUser.UserID = aclUserID - } - - var res []*dashboardResponse - builder.Write("SELECT * FROM dashboard WHERE true") - builder.WriteDashboardPermissionFilter(signedInUser, search.RequiredPermission, "") - t.Logf("Searching for dashboards, SQL: %q\n", builder.GetSQLString()) - err = sqlStore.GetEngine().SQL(builder.GetSQLString(), builder.params...).Find(&res) - require.NoError(t, err) - return res -} - -// TODO: Use FakeDashboardStore when org has its own service -func insertTestDashboard(t *testing.T, sqlStore *sqlstore.SQLStore, title string, orgId int64, - folderId int64, isFolder bool, tags ...interface{}) *dashboards.Dashboard { - t.Helper() - cmd := dashboards.SaveDashboardCommand{ - OrgID: orgId, - FolderID: folderId, - IsFolder: isFolder, - Dashboard: simplejson.NewFromAny(map[string]interface{}{ - "id": nil, - "title": title, - "tags": tags, - }), - } - - var dash *dashboards.Dashboard - err := sqlStore.WithDbSession(context.Background(), func(sess *Session) error { - dash = cmd.GetDashboardModel() - dash.SetVersion(1) - dash.Created = time.Now() - dash.Updated = time.Now() - dash.UID = util.GenerateShortUID() - _, err := sess.Insert(dash) - return err - }) - - require.NoError(t, err) - require.NotNil(t, dash) - dash.Data.Set("id", dash.ID) - dash.Data.Set("uid", dash.UID) - - err = sqlStore.WithDbSession(context.Background(), func(sess *Session) error { - dashVersion := &dashver.DashboardVersion{ - DashboardID: dash.ID, - ParentVersion: dash.Version, - RestoredFrom: cmd.RestoredFrom, - Version: dash.Version, - Created: time.Now(), - CreatedBy: dash.UpdatedBy, - Message: cmd.Message, - Data: dash.Data, - } - require.NoError(t, err) - - if affectedRows, err := sess.Insert(dashVersion); err != nil { - return err - } else if affectedRows == 0 { - return dashboards.ErrDashboardNotFound - } - - return nil - }) - require.NoError(t, err) - - return dash -} - -// TODO: Use FakeDashboardStore when org has its own service -func updateDashboardACL(t *testing.T, sqlStore *sqlstore.SQLStore, dashboardID int64, items ...*dashboards.DashboardACL) error { - t.Helper() - - err := sqlStore.WithDbSession(context.Background(), func(sess *Session) error { - _, err := sess.Exec("DELETE FROM dashboard_acl WHERE dashboard_id=?", dashboardID) - if err != nil { - return fmt.Errorf("deleting from dashboard_acl failed: %w", err) - } - - for _, item := range items { - item.Created = time.Now() - item.Updated = time.Now() - if item.UserID == 0 && item.TeamID == 0 && (item.Role == nil || !item.Role.IsValid()) { - return dashboards.ErrDashboardACLInfoMissing - } - - if item.DashboardID == 0 { - return dashboards.ErrDashboardPermissionDashboardEmpty - } - - sess.Nullable("user_id", "team_id") - if _, err := sess.Insert(item); err != nil { - return err - } - } - - // Update dashboard HasACL flag - dashboard := dashboards.Dashboard{HasACL: true} - _, err = sess.Cols("has_acl").Where("id=?", dashboardID).Update(&dashboard) - return err - }) - return err -} diff --git a/pkg/services/accesscontrol/acimpl/service.go b/pkg/services/accesscontrol/acimpl/service.go index 13f1fee9205..a3da99b7d1b 100644 --- a/pkg/services/accesscontrol/acimpl/service.go +++ b/pkg/services/accesscontrol/acimpl/service.go @@ -80,13 +80,8 @@ type Service struct { } func (s *Service) GetUsageStats(_ context.Context) map[string]interface{} { - enabled := 0 - if !accesscontrol.IsDisabled(s.cfg) { - enabled = 1 - } - return map[string]interface{}{ - "stats.oss.accesscontrol.enabled.count": enabled, + "stats.oss.accesscontrol.enabled.count": 1, } } @@ -165,11 +160,6 @@ func (s *Service) DeleteUserPermissions(ctx context.Context, orgID int64, userID // DeclareFixedRoles allow the caller to declare, to the service, fixed roles and their assignments // to organization roles ("Viewer", "Editor", "Admin") or "Grafana Admin" func (s *Service) DeclareFixedRoles(registrations ...accesscontrol.RoleRegistration) error { - // If accesscontrol is disabled no need to register roles - if accesscontrol.IsDisabled(s.cfg) { - return nil - } - for _, r := range registrations { err := accesscontrol.ValidateFixedRole(r.Role) if err != nil { diff --git a/pkg/services/accesscontrol/acimpl/service_test.go b/pkg/services/accesscontrol/acimpl/service_test.go index 3085fed5835..51a1debc7a1 100644 --- a/pkg/services/accesscontrol/acimpl/service_test.go +++ b/pkg/services/accesscontrol/acimpl/service_test.go @@ -45,11 +45,6 @@ func TestUsageMetrics(t *testing.T) { enabled bool expectedValue int }{ - { - name: "Expecting metric with value 0", - enabled: false, - expectedValue: 0, - }, { name: "Expecting metric with value 1", enabled: true, diff --git a/pkg/services/accesscontrol/middleware.go b/pkg/services/accesscontrol/middleware.go index aff2218c70c..dba479ce47b 100644 --- a/pkg/services/accesscontrol/middleware.go +++ b/pkg/services/accesscontrol/middleware.go @@ -239,10 +239,6 @@ func UseGlobalOrg(c *contextmodel.ReqContext) (int64, error) { func LoadPermissionsMiddleware(service Service) web.Handler { return func(c *contextmodel.ReqContext) { - if service.IsDisabled() { - return - } - permissions, err := service.GetUserPermissions(c.Req.Context(), c.SignedInUser, Options{ReloadCache: false}) if err != nil { diff --git a/pkg/services/apikey/apikeyimpl/sqlx_store.go b/pkg/services/apikey/apikeyimpl/sqlx_store.go index abb14484b27..530e6e1903b 100644 --- a/pkg/services/apikey/apikeyimpl/sqlx_store.go +++ b/pkg/services/apikey/apikeyimpl/sqlx_store.go @@ -34,19 +34,17 @@ func (ss *sqlxStore) GetAPIKeys(ctx context.Context, query *apikey.GetApiKeysQue where = append(where, "service_account_id IS NULL") - if !accesscontrol.IsDisabled(ss.cfg) { - filter, err := accesscontrol.Filter(query.User, "id", "apikeys:id:", accesscontrol.ActionAPIKeyRead) - if err != nil { - return nil, err - } - where = append(where, filter.Where) - args = append(args, filter.Args...) + filter, err := accesscontrol.Filter(query.User, "id", "apikeys:id:", accesscontrol.ActionAPIKeyRead) + if err != nil { + return nil, err } + where = append(where, filter.Where) + args = append(args, filter.Args...) ws := fmt.Sprint(strings.Join(where[:], " AND ")) qr := fmt.Sprintf(`SELECT * FROM api_key WHERE %s ORDER BY name ASC LIMIT 100`, ws) keys := make([]*apikey.APIKey, 0) - err := ss.sess.Select(ctx, &keys, qr, args...) + err = ss.sess.Select(ctx, &keys, qr, args...) return keys, err } diff --git a/pkg/services/apikey/apikeyimpl/xorm_store.go b/pkg/services/apikey/apikeyimpl/xorm_store.go index b94ea1c9fd7..11c9bd8468a 100644 --- a/pkg/services/apikey/apikeyimpl/xorm_store.go +++ b/pkg/services/apikey/apikeyimpl/xorm_store.go @@ -39,13 +39,11 @@ func (ss *sqlStore) GetAPIKeys(ctx context.Context, query *apikey.GetApiKeysQuer sess = sess.Where("service_account_id IS NULL") - if !accesscontrol.IsDisabled(ss.cfg) { - filter, err := accesscontrol.Filter(query.User, "id", "apikeys:id:", accesscontrol.ActionAPIKeyRead) - if err != nil { - return err - } - sess.And(filter.Where, filter.Args...) + filter, err := accesscontrol.Filter(query.User, "id", "apikeys:id:", accesscontrol.ActionAPIKeyRead) + if err != nil { + return err } + sess.And(filter.Where, filter.Args...) res = make([]*apikey.APIKey, 0) return sess.Find(&res) diff --git a/pkg/services/authn/authnimpl/sync/permission_sync.go b/pkg/services/authn/authnimpl/sync/permission_sync.go index 06b20270c52..ba297713de7 100644 --- a/pkg/services/authn/authnimpl/sync/permission_sync.go +++ b/pkg/services/authn/authnimpl/sync/permission_sync.go @@ -26,7 +26,7 @@ type PermissionsSync struct { } func (s *PermissionsSync) SyncPermissionsHook(ctx context.Context, identity *authn.Identity, _ *authn.Request) error { - if s.ac.IsDisabled() || !identity.ClientParams.SyncPermissions { + if !identity.ClientParams.SyncPermissions { return nil } diff --git a/pkg/services/authn/authnimpl/sync/permission_sync_test.go b/pkg/services/authn/authnimpl/sync/permission_sync_test.go index c9744ebd8ff..556138b28d4 100644 --- a/pkg/services/authn/authnimpl/sync/permission_sync_test.go +++ b/pkg/services/authn/authnimpl/sync/permission_sync_test.go @@ -17,56 +17,40 @@ func TestPermissionsSync_SyncPermission(t *testing.T) { type testCase struct { name string identity *authn.Identity - rbacDisabled bool expectedPermissions []accesscontrol.Permission } testCases := []testCase{ { - name: "enriches the identity successfully when SyncPermissions is true", - identity: &authn.Identity{ID: "user:2", OrgID: 1, ClientParams: authn.ClientParams{SyncPermissions: true}}, - rbacDisabled: false, + name: "enriches the identity successfully when SyncPermissions is true", + identity: &authn.Identity{ID: "user:2", OrgID: 1, ClientParams: authn.ClientParams{SyncPermissions: true}}, expectedPermissions: []accesscontrol.Permission{ {Action: accesscontrol.ActionUsersRead}, }, }, { - name: "does not load the permissions when SyncPermissions is false", - identity: &authn.Identity{ID: "user:2", OrgID: 1, ClientParams: authn.ClientParams{SyncPermissions: true}}, - rbacDisabled: false, + name: "does not load the permissions when SyncPermissions is false", + identity: &authn.Identity{ID: "user:2", OrgID: 1, ClientParams: authn.ClientParams{SyncPermissions: true}}, expectedPermissions: []accesscontrol.Permission{ {Action: accesscontrol.ActionUsersRead}, }, }, - { - name: "does not load the permissions when RBAC is disabled", - rbacDisabled: true, - identity: &authn.Identity{ID: "user:2", OrgID: 1, ClientParams: authn.ClientParams{SyncPermissions: true}}, - expectedPermissions: []accesscontrol.Permission{}, - }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { - s := setupTestEnv(tt.rbacDisabled) + s := setupTestEnv() err := s.SyncPermissionsHook(context.Background(), tt.identity, &authn.Request{}) require.NoError(t, err) - if !tt.rbacDisabled { - assert.Equal(t, 1, len(tt.identity.Permissions)) - assert.Equal(t, accesscontrol.GroupScopesByAction(tt.expectedPermissions), tt.identity.Permissions[tt.identity.OrgID]) - } else { - assert.Equal(t, 0, len(tt.identity.Permissions)) - } + assert.Equal(t, 1, len(tt.identity.Permissions)) + assert.Equal(t, accesscontrol.GroupScopesByAction(tt.expectedPermissions), tt.identity.Permissions[tt.identity.OrgID]) }) } } -func setupTestEnv(rbacDisabled bool) *PermissionsSync { +func setupTestEnv() *PermissionsSync { acMock := &acmock.Mock{ - IsDisabledFunc: func() bool { - return rbacDisabled - }, GetUserPermissionsFunc: func(ctx context.Context, siu *user.SignedInUser, o accesscontrol.Options) ([]accesscontrol.Permission, error) { return []accesscontrol.Permission{ {Action: accesscontrol.ActionUsersRead}, diff --git a/pkg/services/folder/folderimpl/folder.go b/pkg/services/folder/folderimpl/folder.go index 410c8604516..1b7a1c55a96 100644 --- a/pkg/services/folder/folderimpl/folder.go +++ b/pkg/services/folder/folderimpl/folder.go @@ -250,7 +250,7 @@ func (s *Service) Create(ctx context.Context, cmd *folder.CreateFolderCommand) ( return nil, folder.ErrBadRequest.Errorf("missing signed in user") } - if !s.accessControl.IsDisabled() && s.features.IsEnabled(featuremgmt.FlagNestedFolders) && cmd.ParentUID != "" { + if s.features.IsEnabled(featuremgmt.FlagNestedFolders) && cmd.ParentUID != "" { // Check that the user is allowed to create a subfolder in this folder evaluator := accesscontrol.EvalPermission(dashboards.ActionFoldersWrite, dashboards.ScopeFoldersProvider.GetResourceScopeUID(cmd.ParentUID)) hasAccess, evalErr := s.accessControl.Evaluate(ctx, cmd.SignedInUser, evaluator) @@ -549,32 +549,19 @@ func (s *Service) Move(ctx context.Context, cmd *folder.MoveFolderCommand) (*fol } // Check that the user is allowed to move the folder to the destination folder - if !s.accessControl.IsDisabled() { - var evaluator accesscontrol.Evaluator - if cmd.NewParentUID != "" { - evaluator = accesscontrol.EvalPermission(dashboards.ActionFoldersWrite, dashboards.ScopeFoldersProvider.GetResourceScopeUID(cmd.NewParentUID)) - } else { - // Evaluate folder creation permission when moving folder to the root level - evaluator = accesscontrol.EvalPermission(dashboards.ActionFoldersCreate) - } - hasAccess, evalErr := s.accessControl.Evaluate(ctx, cmd.SignedInUser, evaluator) - if evalErr != nil { - return nil, evalErr - } - if !hasAccess { - return nil, dashboards.ErrFolderAccessDenied - } + var evaluator accesscontrol.Evaluator + if cmd.NewParentUID != "" { + evaluator = accesscontrol.EvalPermission(dashboards.ActionFoldersWrite, dashboards.ScopeFoldersProvider.GetResourceScopeUID(cmd.NewParentUID)) } else { - g, err := guardian.NewByUID(ctx, cmd.UID, cmd.OrgID, cmd.SignedInUser) - if err != nil { - return nil, err - } - if canSave, err := g.CanSave(); err != nil || !canSave { - if err != nil { - return nil, toFolderError(err) - } - return nil, dashboards.ErrFolderAccessDenied - } + // Evaluate folder creation permission when moving folder to the root level + evaluator = accesscontrol.EvalPermission(dashboards.ActionFoldersCreate) + } + hasAccess, evalErr := s.accessControl.Evaluate(ctx, cmd.SignedInUser, evaluator) + if evalErr != nil { + return nil, evalErr + } + if !hasAccess { + return nil, dashboards.ErrFolderAccessDenied } // here we get the folder, we need to get the height of current folder diff --git a/pkg/services/publicdashboards/api/api_test.go b/pkg/services/publicdashboards/api/api_test.go index ab0c7ce9dbf..b1307edf99b 100644 --- a/pkg/services/publicdashboards/api/api_test.go +++ b/pkg/services/publicdashboards/api/api_test.go @@ -26,7 +26,7 @@ var userAdmin = &user.SignedInUser{UserID: 1, OrgID: 1, OrgRole: org.RoleAdmin, var userAdminRBAC = &user.SignedInUser{UserID: 2, OrgID: 1, OrgRole: org.RoleAdmin, Login: "testAdminUserRBAC", Permissions: map[int64]map[string][]string{1: {dashboards.ActionDashboardsPublicWrite: {dashboards.ScopeDashboardsAll}}}} var userViewer = &user.SignedInUser{UserID: 3, OrgID: 1, OrgRole: org.RoleViewer, Login: "testViewerUser"} var userViewerRBAC = &user.SignedInUser{UserID: 4, OrgID: 1, OrgRole: org.RoleViewer, Login: "testViewerUserRBAC", Permissions: map[int64]map[string][]string{1: {dashboards.ActionDashboardsRead: {dashboards.ScopeDashboardsAll}}}} -var anonymousUser *user.SignedInUser +var anonymousUser = &user.SignedInUser{IsAnonymous: true} type JsonErrResponse struct { Error string `json:"error"` diff --git a/pkg/services/publicdashboards/api/common_test.go b/pkg/services/publicdashboards/api/common_test.go index c486b670e98..9633a9cb5c9 100644 --- a/pkg/services/publicdashboards/api/common_test.go +++ b/pkg/services/publicdashboards/api/common_test.go @@ -84,7 +84,7 @@ type testContext struct { func contextProvider(tc *testContext) web.Handler { return func(c *web.Context) { - signedIn := tc.user != nil + signedIn := tc.user != nil && !tc.user.IsAnonymous reqCtx := &contextmodel.ReqContext{ Context: c, SignedInUser: tc.user, diff --git a/pkg/services/publicdashboards/api/query_test.go b/pkg/services/publicdashboards/api/query_test.go index 5d1d0e68413..fdf48a87705 100644 --- a/pkg/services/publicdashboards/api/query_test.go +++ b/pkg/services/publicdashboards/api/query_test.go @@ -189,7 +189,6 @@ func TestAPIQueryPublicDashboard(t *testing.T) { setup := func(enabled bool) (*web.Mux, *publicdashboards.FakePublicDashboardService) { service := publicdashboards.NewFakePublicDashboardService(t) cfg := setting.NewCfg() - cfg.RBACEnabled = false testServer := setupTestServer( t,