Move SignedInUser to user service and RoleType and Roles to org (#53445)

* Move SignedInUser to user service and RoleType and Roles to org

* Use go naming convention for roles

* Fix some imports and leftovers

* Fix ldap debug test

* Fix lint

* Fix lint 2

* Fix lint 3

* Fix type and not needed conversion

* Clean up messages in api tests

* Clean up api tests 2
This commit is contained in:
idafurjes
2022-08-10 11:56:48 +02:00
committed by GitHub
parent 46004037e2
commit 6afad51761
278 changed files with 1758 additions and 1543 deletions
+18 -17
View File
@@ -8,6 +8,7 @@ import (
ac "github.com/grafana/grafana/pkg/services/accesscontrol" ac "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/serviceaccounts" "github.com/grafana/grafana/pkg/services/serviceaccounts"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb/grafanads" "github.com/grafana/grafana/pkg/tsdb/grafanads"
@@ -74,11 +75,11 @@ func (hs *HTTPServer) declareFixedRoles() error {
}, },
}, },
}, },
Grants: []string{string(models.ROLE_EDITOR)}, Grants: []string{string(org.RoleEditor)},
} }
if setting.ViewersCanEdit { if setting.ViewersCanEdit {
datasourcesExplorerRole.Grants = append(datasourcesExplorerRole.Grants, string(models.ROLE_VIEWER)) datasourcesExplorerRole.Grants = append(datasourcesExplorerRole.Grants, string(org.RoleViewer))
} }
datasourcesReaderRole := ac.RoleRegistration{ datasourcesReaderRole := ac.RoleRegistration{
@@ -98,7 +99,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
}, },
}, },
}, },
Grants: []string{string(models.ROLE_ADMIN)}, Grants: []string{string(org.RoleAdmin)},
} }
builtInDatasourceReader := ac.RoleRegistration{ builtInDatasourceReader := ac.RoleRegistration{
@@ -119,12 +120,12 @@ func (hs *HTTPServer) declareFixedRoles() error {
}, },
Hidden: true, Hidden: true,
}, },
Grants: []string{string(models.ROLE_VIEWER)}, Grants: []string{string(org.RoleViewer)},
} }
// when running oss or enterprise without a license all users should be able to query data sources // when running oss or enterprise without a license all users should be able to query data sources
if !hs.License.FeatureEnabled("accesscontrol.enforcement") { if !hs.License.FeatureEnabled("accesscontrol.enforcement") {
datasourcesReaderRole.Grants = []string{string(models.ROLE_VIEWER)} datasourcesReaderRole.Grants = []string{string(org.RoleViewer)}
} }
datasourcesWriterRole := ac.RoleRegistration{ datasourcesWriterRole := ac.RoleRegistration{
@@ -147,7 +148,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
}, },
}), }),
}, },
Grants: []string{string(models.ROLE_ADMIN)}, Grants: []string{string(org.RoleAdmin)},
} }
datasourcesIdReaderRole := ac.RoleRegistration{ datasourcesIdReaderRole := ac.RoleRegistration{
@@ -163,7 +164,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
}, },
}, },
}, },
Grants: []string{string(models.ROLE_VIEWER)}, Grants: []string{string(org.RoleViewer)},
} }
apikeyReaderRole := ac.RoleRegistration{ apikeyReaderRole := ac.RoleRegistration{
@@ -179,7 +180,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
}, },
}, },
}, },
Grants: []string{string(models.ROLE_ADMIN)}, Grants: []string{string(org.RoleAdmin)},
} }
apikeyWriterRole := ac.RoleRegistration{ apikeyWriterRole := ac.RoleRegistration{
@@ -198,7 +199,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
}, },
}), }),
}, },
Grants: []string{string(models.ROLE_ADMIN)}, Grants: []string{string(org.RoleAdmin)},
} }
orgReaderRole := ac.RoleRegistration{ orgReaderRole := ac.RoleRegistration{
@@ -212,7 +213,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
{Action: ActionOrgsQuotasRead}, {Action: ActionOrgsQuotasRead},
}, },
}, },
Grants: []string{string(models.ROLE_VIEWER), ac.RoleGrafanaAdmin}, Grants: []string{string(org.RoleViewer), ac.RoleGrafanaAdmin},
} }
orgWriterRole := ac.RoleRegistration{ orgWriterRole := ac.RoleRegistration{
@@ -227,7 +228,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
{Action: ActionOrgsPreferencesWrite}, {Action: ActionOrgsPreferencesWrite},
}), }),
}, },
Grants: []string{string(models.ROLE_ADMIN)}, Grants: []string{string(org.RoleAdmin)},
} }
orgMaintainerRole := ac.RoleRegistration{ orgMaintainerRole := ac.RoleRegistration{
@@ -246,9 +247,9 @@ func (hs *HTTPServer) declareFixedRoles() error {
Grants: []string{string(ac.RoleGrafanaAdmin)}, Grants: []string{string(ac.RoleGrafanaAdmin)},
} }
teamCreatorGrants := []string{string(models.ROLE_ADMIN)} teamCreatorGrants := []string{string(org.RoleAdmin)}
if hs.Cfg.EditorsCanAdmin { if hs.Cfg.EditorsCanAdmin {
teamCreatorGrants = append(teamCreatorGrants, string(models.ROLE_EDITOR)) teamCreatorGrants = append(teamCreatorGrants, string(org.RoleEditor))
} }
teamsCreatorRole := ac.RoleRegistration{ teamsCreatorRole := ac.RoleRegistration{
Role: ac.RoleDTO{ Role: ac.RoleDTO{
@@ -279,7 +280,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
{Action: ac.ActionTeamsWrite, Scope: ac.ScopeTeamsAll}, {Action: ac.ActionTeamsWrite, Scope: ac.ScopeTeamsAll},
}, },
}, },
Grants: []string{string(models.ROLE_ADMIN)}, Grants: []string{string(org.RoleAdmin)},
} }
annotationsReaderRole := ac.RoleRegistration{ annotationsReaderRole := ac.RoleRegistration{
@@ -292,7 +293,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
{Action: ac.ActionAnnotationsRead, Scope: ac.ScopeAnnotationsAll}, {Action: ac.ActionAnnotationsRead, Scope: ac.ScopeAnnotationsAll},
}, },
}, },
Grants: []string{string(models.ROLE_VIEWER)}, Grants: []string{string(org.RoleViewer)},
} }
dashboardAnnotationsWriterRole := ac.RoleRegistration{ dashboardAnnotationsWriterRole := ac.RoleRegistration{
@@ -307,7 +308,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
{Action: ac.ActionAnnotationsWrite, Scope: ac.ScopeAnnotationsTypeDashboard}, {Action: ac.ActionAnnotationsWrite, Scope: ac.ScopeAnnotationsTypeDashboard},
}, },
}, },
Grants: []string{string(models.ROLE_VIEWER)}, Grants: []string{string(org.RoleViewer)},
} }
annotationsWriterRole := ac.RoleRegistration{ annotationsWriterRole := ac.RoleRegistration{
@@ -322,7 +323,7 @@ func (hs *HTTPServer) declareFixedRoles() error {
{Action: ac.ActionAnnotationsWrite, Scope: ac.ScopeAnnotationsAll}, {Action: ac.ActionAnnotationsWrite, Scope: ac.ScopeAnnotationsAll},
}, },
}, },
Grants: []string{string(models.ROLE_EDITOR)}, Grants: []string{string(org.RoleEditor)},
} }
dashboardsCreatorRole := ac.RoleRegistration{ dashboardsCreatorRole := ac.RoleRegistration{
+2 -1
View File
@@ -7,6 +7,7 @@ import (
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
ac "github.com/grafana/grafana/pkg/services/accesscontrol" ac "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
@@ -53,7 +54,7 @@ func (hs *HTTPServer) AdminGetStats(c *models.ReqContext) response.Response {
return response.JSON(http.StatusOK, statsQuery.Result) return response.JSON(http.StatusOK, statsQuery.Result)
} }
func (hs *HTTPServer) getAuthorizedSettings(ctx context.Context, user *models.SignedInUser, bag setting.SettingsBag) (setting.SettingsBag, error) { func (hs *HTTPServer) getAuthorizedSettings(ctx context.Context, user *user.SignedInUser, bag setting.SettingsBag) (setting.SettingsBag, error) {
if hs.AccessControl.IsDisabled() { if hs.AccessControl.IsDisabled() {
return bag, nil return bag, nil
} }
+6 -5
View File
@@ -15,6 +15,7 @@ import (
"github.com/grafana/grafana/pkg/services/auth" "github.com/grafana/grafana/pkg/services/auth"
"github.com/grafana/grafana/pkg/services/login/loginservice" "github.com/grafana/grafana/pkg/services/login/loginservice"
"github.com/grafana/grafana/pkg/services/login/logintest" "github.com/grafana/grafana/pkg/services/login/logintest"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/services/user"
@@ -30,7 +31,7 @@ const (
) )
func TestAdminAPIEndpoint(t *testing.T) { func TestAdminAPIEndpoint(t *testing.T) {
const role = models.ROLE_ADMIN const role = org.RoleAdmin
userService := usertest.NewUserServiceFake() userService := usertest.NewUserServiceFake()
t.Run("Given a server admin attempts to remove themselves as an admin", func(t *testing.T) { t.Run("Given a server admin attempts to remove themselves as an admin", func(t *testing.T) {
updateCmd := dtos.AdminUpdateUserPermissionsForm{ updateCmd := dtos.AdminUpdateUserPermissionsForm{
@@ -236,7 +237,7 @@ func TestAdminAPIEndpoint(t *testing.T) {
}) })
} }
func putAdminScenario(t *testing.T, desc string, url string, routePattern string, role models.RoleType, func putAdminScenario(t *testing.T, desc string, url string, routePattern string, role org.RoleType,
cmd dtos.AdminUpdateUserPermissionsForm, fn scenarioFunc, sqlStore sqlstore.Store) { cmd dtos.AdminUpdateUserPermissionsForm, fn scenarioFunc, sqlStore sqlstore.Store) {
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) { t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
hs := &HTTPServer{ hs := &HTTPServer{
@@ -277,7 +278,7 @@ func adminLogoutUserScenario(t *testing.T, desc string, url string, routePattern
sc.context = c sc.context = c
sc.context.UserId = testUserID sc.context.UserId = testUserID
sc.context.OrgId = testOrgID sc.context.OrgId = testOrgID
sc.context.OrgRole = models.ROLE_ADMIN sc.context.OrgRole = org.RoleAdmin
return hs.AdminLogoutUser(c) return hs.AdminLogoutUser(c)
}) })
@@ -305,7 +306,7 @@ func adminRevokeUserAuthTokenScenario(t *testing.T, desc string, url string, rou
sc.context = c sc.context = c
sc.context.UserId = testUserID sc.context.UserId = testUserID
sc.context.OrgId = testOrgID sc.context.OrgId = testOrgID
sc.context.OrgRole = models.ROLE_ADMIN sc.context.OrgRole = org.RoleAdmin
return hs.AdminRevokeUserAuthToken(c) return hs.AdminRevokeUserAuthToken(c)
}) })
@@ -331,7 +332,7 @@ func adminGetUserAuthTokensScenario(t *testing.T, desc string, url string, route
sc.context = c sc.context = c
sc.context.UserId = testUserID sc.context.UserId = testUserID
sc.context.OrgId = testOrgID sc.context.OrgId = testOrgID
sc.context.OrgRole = models.ROLE_ADMIN sc.context.OrgRole = org.RoleAdmin
return hs.AdminGetUserAuthTokens(c) return hs.AdminGetUserAuthTokens(c)
}) })
+6 -4
View File
@@ -14,6 +14,8 @@ import (
"github.com/grafana/grafana/pkg/services/annotations" "github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
) )
@@ -504,7 +506,7 @@ func (hs *HTTPServer) canSaveAnnotation(c *models.ReqContext, annotation *annota
return canEditDashboard(c, annotation.DashboardId) return canEditDashboard(c, annotation.DashboardId)
} else { } else {
if hs.AccessControl.IsDisabled() { if hs.AccessControl.IsDisabled() {
return c.SignedInUser.HasRole(models.ROLE_EDITOR), nil return c.SignedInUser.HasRole(org.RoleEditor), nil
} }
return true, nil return true, nil
} }
@@ -519,7 +521,7 @@ func canEditDashboard(c *models.ReqContext, dashboardID int64) (bool, error) {
return true, nil return true, nil
} }
func findAnnotationByID(ctx context.Context, repo annotations.Repository, annotationID int64, user *models.SignedInUser) (*annotations.ItemDTO, response.Response) { func findAnnotationByID(ctx context.Context, repo annotations.Repository, annotationID int64, user *user.SignedInUser) (*annotations.ItemDTO, response.Response) {
query := &annotations.ItemQuery{ query := &annotations.ItemQuery{
AnnotationId: annotationID, AnnotationId: annotationID,
OrgId: user.OrgId, OrgId: user.OrgId,
@@ -583,7 +585,7 @@ func AnnotationTypeScopeResolver() (string, accesscontrol.ScopeAttributeResolver
// tempUser is used to resolve annotation type. // tempUser is used to resolve annotation type.
// The annotation doesn't get returned to the real user, so real user's permissions don't matter here. // The annotation doesn't get returned to the real user, so real user's permissions don't matter here.
tempUser := &models.SignedInUser{ tempUser := &user.SignedInUser{
OrgId: orgID, OrgId: orgID,
Permissions: map[int64]map[string][]string{ Permissions: map[int64]map[string][]string{
orgID: { orgID: {
@@ -620,7 +622,7 @@ func (hs *HTTPServer) canCreateAnnotation(c *models.ReqContext, dashboardId int6
evaluator := accesscontrol.EvalPermission(accesscontrol.ActionAnnotationsCreate, accesscontrol.ScopeAnnotationsTypeOrganization) evaluator := accesscontrol.EvalPermission(accesscontrol.ActionAnnotationsCreate, accesscontrol.ScopeAnnotationsTypeOrganization)
return hs.AccessControl.Evaluate(c.Req.Context(), c.SignedInUser, evaluator) return hs.AccessControl.Evaluate(c.Req.Context(), c.SignedInUser, evaluator)
} else { } else {
return c.SignedInUser.HasRole(models.ROLE_EDITOR), nil return c.SignedInUser.HasRole(org.RoleEditor), nil
} }
} }
} }
+12 -11
View File
@@ -19,6 +19,7 @@ import (
"github.com/grafana/grafana/pkg/services/annotations" "github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
) )
@@ -49,7 +50,7 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
} }
t.Run("When user is an Org Viewer", func(t *testing.T) { t.Run("When user is an Org Viewer", func(t *testing.T) {
role := models.ROLE_VIEWER role := org.RoleViewer
t.Run("Should not be allowed to save an annotation", func(t *testing.T) { t.Run("Should not be allowed to save an annotation", func(t *testing.T) {
postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role, postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role,
cmd, store, nil, func(sc *scenarioContext) { cmd, store, nil, func(sc *scenarioContext) {
@@ -82,7 +83,7 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
}) })
t.Run("When user is an Org Editor", func(t *testing.T) { t.Run("When user is an Org Editor", func(t *testing.T) {
role := models.ROLE_EDITOR role := org.RoleEditor
t.Run("Should be able to save an annotation", func(t *testing.T) { t.Run("Should be able to save an annotation", func(t *testing.T) {
postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role, postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role,
cmd, store, nil, func(sc *scenarioContext) { cmd, store, nil, func(sc *scenarioContext) {
@@ -154,7 +155,7 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
} }
t.Run("When user is an Org Viewer", func(t *testing.T) { t.Run("When user is an Org Viewer", func(t *testing.T) {
role := models.ROLE_VIEWER role := org.RoleViewer
t.Run("Should not be allowed to save an annotation", func(t *testing.T) { t.Run("Should not be allowed to save an annotation", func(t *testing.T) {
postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role, cmd, store, nil, func(sc *scenarioContext) { postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role, cmd, store, nil, func(sc *scenarioContext) {
setUpACL() setUpACL()
@@ -187,7 +188,7 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
}) })
t.Run("When user is an Org Editor", func(t *testing.T) { t.Run("When user is an Org Editor", func(t *testing.T) {
role := models.ROLE_EDITOR role := org.RoleEditor
t.Run("Should be able to save an annotation", func(t *testing.T) { t.Run("Should be able to save an annotation", func(t *testing.T) {
postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role, cmd, store, nil, func(sc *scenarioContext) { postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role, cmd, store, nil, func(sc *scenarioContext) {
setUpACL() setUpACL()
@@ -220,7 +221,7 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
}) })
t.Run("When user is an Admin", func(t *testing.T) { t.Run("When user is an Admin", func(t *testing.T) {
role := models.ROLE_ADMIN role := org.RoleAdmin
mockStore := mockstore.NewSQLStoreMock() mockStore := mockstore.NewSQLStoreMock()
@@ -338,7 +339,7 @@ func (repo *fakeAnnotationsRepo) LoadItems() {
var fakeAnnoRepo *fakeAnnotationsRepo var fakeAnnoRepo *fakeAnnotationsRepo
func postAnnotationScenario(t *testing.T, desc string, url string, routePattern string, role models.RoleType, func postAnnotationScenario(t *testing.T, desc string, url string, routePattern string, role org.RoleType,
cmd dtos.PostAnnotationsCmd, store sqlstore.Store, dashSvc dashboards.DashboardService, fn scenarioFunc) { cmd dtos.PostAnnotationsCmd, store sqlstore.Store, dashSvc dashboards.DashboardService, fn scenarioFunc) {
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) { t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
hs := setupSimpleHTTPServer(nil) hs := setupSimpleHTTPServer(nil)
@@ -366,7 +367,7 @@ func postAnnotationScenario(t *testing.T, desc string, url string, routePattern
}) })
} }
func putAnnotationScenario(t *testing.T, desc string, url string, routePattern string, role models.RoleType, func putAnnotationScenario(t *testing.T, desc string, url string, routePattern string, role org.RoleType,
cmd dtos.UpdateAnnotationsCmd, fn scenarioFunc) { cmd dtos.UpdateAnnotationsCmd, fn scenarioFunc) {
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) { t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
hs := setupSimpleHTTPServer(nil) hs := setupSimpleHTTPServer(nil)
@@ -395,7 +396,7 @@ func putAnnotationScenario(t *testing.T, desc string, url string, routePattern s
}) })
} }
func patchAnnotationScenario(t *testing.T, desc string, url string, routePattern string, role models.RoleType, cmd dtos.PatchAnnotationsCmd, fn scenarioFunc) { func patchAnnotationScenario(t *testing.T, desc string, url string, routePattern string, role org.RoleType, cmd dtos.PatchAnnotationsCmd, fn scenarioFunc) {
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) { t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
hs := setupSimpleHTTPServer(nil) hs := setupSimpleHTTPServer(nil)
store := sqlstore.InitTestDB(t) store := sqlstore.InitTestDB(t)
@@ -423,7 +424,7 @@ func patchAnnotationScenario(t *testing.T, desc string, url string, routePattern
}) })
} }
func deleteAnnotationsScenario(t *testing.T, desc string, url string, routePattern string, role models.RoleType, func deleteAnnotationsScenario(t *testing.T, desc string, url string, routePattern string, role org.RoleType,
cmd dtos.MassDeleteAnnotationsCmd, store sqlstore.Store, dashSvc dashboards.DashboardService, fn scenarioFunc) { cmd dtos.MassDeleteAnnotationsCmd, store sqlstore.Store, dashSvc dashboards.DashboardService, fn scenarioFunc) {
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) { t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
hs := setupSimpleHTTPServer(nil) hs := setupSimpleHTTPServer(nil)
@@ -998,8 +999,8 @@ func TestAPI_MassDeleteAnnotations_AccessControl(t *testing.T) {
} }
func setUpACL() { func setUpACL() {
viewerRole := models.ROLE_VIEWER viewerRole := org.RoleViewer
editorRole := models.ROLE_EDITOR editorRole := org.RoleEditor
store := mockstore.NewSQLStoreMock() store := mockstore.NewSQLStoreMock()
store.ExpectedTeamsByUser = []*models.TeamDTO{} store.ExpectedTeamsByUser = []*models.TeamDTO{}
dashSvc := &dashboards.FakeDashboardService{} dashSvc := &dashboards.FakeDashboardService{}
+5 -4
View File
@@ -14,6 +14,7 @@ import (
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins"
ac "github.com/grafana/grafana/pkg/services/accesscontrol" ac "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
) )
@@ -49,10 +50,10 @@ func (hs *HTTPServer) initAppPluginRoutes(r *web.Mux) {
ac.EvalPermission(plugins.ActionAppAccess, plugins.ScopeProvider.GetResourceScope(plugin.ID)))) ac.EvalPermission(plugins.ActionAppAccess, plugins.ScopeProvider.GetResourceScope(plugin.ID))))
if route.ReqRole != "" { if route.ReqRole != "" {
if route.ReqRole == models.ROLE_ADMIN { if route.ReqRole == org.RoleAdmin {
handlers = append(handlers, middleware.RoleAuth(models.ROLE_ADMIN)) handlers = append(handlers, middleware.RoleAuth(org.RoleAdmin))
} else if route.ReqRole == models.ROLE_EDITOR { } else if route.ReqRole == org.RoleEditor {
handlers = append(handlers, middleware.RoleAuth(models.ROLE_EDITOR, models.ROLE_ADMIN)) handlers = append(handlers, middleware.RoleAuth(org.RoleEditor, org.RoleAdmin))
} }
} }
+2 -1
View File
@@ -7,6 +7,7 @@ import (
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/comments" "github.com/grafana/grafana/pkg/services/comments"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
) )
@@ -33,7 +34,7 @@ func (hs *HTTPServer) commentsCreate(c *models.ReqContext) response.Response {
if err := web.Bind(c.Req, &cmd); err != nil { if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err) return response.Error(http.StatusBadRequest, "bad request data", err)
} }
if c.SignedInUser.UserId == 0 && !c.SignedInUser.HasRole(models.ROLE_ADMIN) { if c.SignedInUser.UserId == 0 && !c.SignedInUser.HasRole(org.RoleAdmin) {
return response.Error(http.StatusForbidden, "admin role required", nil) return response.Error(http.StatusForbidden, "admin role required", nil)
} }
comment, err := hs.commentsService.Create(c.Req.Context(), c.OrgId, c.SignedInUser, cmd) comment, err := hs.commentsService.Create(c.Req.Context(), c.OrgId, c.SignedInUser, cmd)
+10 -9
View File
@@ -39,6 +39,7 @@ import (
"github.com/grafana/grafana/pkg/services/licensing" "github.com/grafana/grafana/pkg/services/licensing"
"github.com/grafana/grafana/pkg/services/login/loginservice" "github.com/grafana/grafana/pkg/services/login/loginservice"
"github.com/grafana/grafana/pkg/services/login/logintest" "github.com/grafana/grafana/pkg/services/login/logintest"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/preference/preftest" "github.com/grafana/grafana/pkg/services/preference/preftest"
"github.com/grafana/grafana/pkg/services/quota/quotaimpl" "github.com/grafana/grafana/pkg/services/quota/quotaimpl"
"github.com/grafana/grafana/pkg/services/rendering" "github.com/grafana/grafana/pkg/services/rendering"
@@ -55,10 +56,10 @@ import (
) )
func loggedInUserScenario(t *testing.T, desc string, url string, routePattern string, fn scenarioFunc, sqlStore sqlstore.Store) { func loggedInUserScenario(t *testing.T, desc string, url string, routePattern string, fn scenarioFunc, sqlStore sqlstore.Store) {
loggedInUserScenarioWithRole(t, desc, "GET", url, routePattern, models.ROLE_EDITOR, fn, sqlStore) loggedInUserScenarioWithRole(t, desc, "GET", url, routePattern, org.RoleEditor, fn, sqlStore)
} }
func loggedInUserScenarioWithRole(t *testing.T, desc string, method string, url string, routePattern string, role models.RoleType, fn scenarioFunc, sqlStore sqlstore.Store) { func loggedInUserScenarioWithRole(t *testing.T, desc string, method string, url string, routePattern string, role org.RoleType, fn scenarioFunc, sqlStore sqlstore.Store) {
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) { t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
sc := setupScenarioContext(t, url) sc := setupScenarioContext(t, url)
sc.sqlStore = sqlStore sc.sqlStore = sqlStore
@@ -295,7 +296,7 @@ type accessControlScenarioContext struct {
func setAccessControlPermissions(acmock *accesscontrolmock.Mock, perms []accesscontrol.Permission, org int64) { func setAccessControlPermissions(acmock *accesscontrolmock.Mock, perms []accesscontrol.Permission, org int64) {
acmock.GetUserPermissionsFunc = acmock.GetUserPermissionsFunc =
func(_ context.Context, u *models.SignedInUser, _ accesscontrol.Options) ([]accesscontrol.Permission, error) { func(_ context.Context, u *user.SignedInUser, _ accesscontrol.Options) ([]accesscontrol.Permission, error) {
if u.OrgId == org { if u.OrgId == org {
return perms, nil return perms, nil
} }
@@ -304,24 +305,24 @@ func setAccessControlPermissions(acmock *accesscontrolmock.Mock, perms []accessc
} }
// setInitCtxSignedInUser sets a copy of the user in initCtx // setInitCtxSignedInUser sets a copy of the user in initCtx
func setInitCtxSignedInUser(initCtx *models.ReqContext, user models.SignedInUser) { func setInitCtxSignedInUser(initCtx *models.ReqContext, user user.SignedInUser) {
initCtx.IsSignedIn = true initCtx.IsSignedIn = true
initCtx.SignedInUser = &user initCtx.SignedInUser = &user
} }
func setInitCtxSignedInViewer(initCtx *models.ReqContext) { func setInitCtxSignedInViewer(initCtx *models.ReqContext) {
initCtx.IsSignedIn = true initCtx.IsSignedIn = true
initCtx.SignedInUser = &models.SignedInUser{UserId: testUserID, OrgId: 1, OrgRole: models.ROLE_VIEWER, Login: testUserLogin} initCtx.SignedInUser = &user.SignedInUser{UserId: testUserID, OrgId: 1, OrgRole: org.RoleViewer, Login: testUserLogin}
} }
func setInitCtxSignedInEditor(initCtx *models.ReqContext) { func setInitCtxSignedInEditor(initCtx *models.ReqContext) {
initCtx.IsSignedIn = true initCtx.IsSignedIn = true
initCtx.SignedInUser = &models.SignedInUser{UserId: testUserID, OrgId: 1, OrgRole: models.ROLE_EDITOR, Login: testUserLogin} initCtx.SignedInUser = &user.SignedInUser{UserId: testUserID, OrgId: 1, OrgRole: org.RoleEditor, Login: testUserLogin}
} }
func setInitCtxSignedInOrgAdmin(initCtx *models.ReqContext) { func setInitCtxSignedInOrgAdmin(initCtx *models.ReqContext) {
initCtx.IsSignedIn = true initCtx.IsSignedIn = true
initCtx.SignedInUser = &models.SignedInUser{UserId: testUserID, OrgId: 1, OrgRole: models.ROLE_ADMIN, Login: testUserLogin} initCtx.SignedInUser = &user.SignedInUser{UserId: testUserID, OrgId: 1, OrgRole: org.RoleAdmin, Login: testUserLogin}
} }
func setupSimpleHTTPServer(features *featuremgmt.FeatureManager) *HTTPServer { func setupSimpleHTTPServer(features *featuremgmt.FeatureManager) *HTTPServer {
@@ -479,8 +480,8 @@ func SetupAPITestServer(t *testing.T, opts ...APITestServerOption) *webtest.Serv
} }
var ( var (
viewerRole = models.ROLE_VIEWER viewerRole = org.RoleViewer
editorRole = models.ROLE_EDITOR editorRole = org.RoleEditor
) )
type setUpConf struct { type setUpConf struct {
+4 -3
View File
@@ -26,6 +26,7 @@ import (
dashver "github.com/grafana/grafana/pkg/services/dashboardversion" dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/org"
pref "github.com/grafana/grafana/pkg/services/preference" pref "github.com/grafana/grafana/pkg/services/preference"
"github.com/grafana/grafana/pkg/services/star" "github.com/grafana/grafana/pkg/services/star"
"github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/services/user"
@@ -538,7 +539,7 @@ func (hs *HTTPServer) GetHomeDashboard(c *models.ReqContext) response.Response {
dash := dtos.DashboardFullWithMeta{} dash := dtos.DashboardFullWithMeta{}
dash.Meta.IsHome = true dash.Meta.IsHome = true
dash.Meta.CanEdit = c.SignedInUser.HasRole(models.ROLE_EDITOR) dash.Meta.CanEdit = c.SignedInUser.HasRole(org.RoleEditor)
dash.Meta.FolderTitle = "General" dash.Meta.FolderTitle = "General"
dash.Dashboard = simplejson.New() dash.Dashboard = simplejson.New()
@@ -555,8 +556,8 @@ func (hs *HTTPServer) GetHomeDashboard(c *models.ReqContext) response.Response {
func (hs *HTTPServer) addGettingStartedPanelToHomeDashboard(c *models.ReqContext, dash *simplejson.Json) { func (hs *HTTPServer) addGettingStartedPanelToHomeDashboard(c *models.ReqContext, dash *simplejson.Json) {
// We only add this getting started panel for Admins who have not dismissed it, // We only add this getting started panel for Admins who have not dismissed it,
// and if a custom default home dashboard hasn't been configured // and if a custom default home dashboard hasn't been configured
if !c.HasUserRole(models.ROLE_ADMIN) || if !c.HasUserRole(org.RoleAdmin) ||
c.HasHelpFlag(models.HelpFlagGettingStartedPanelDismissed) || c.HasHelpFlag(user.HelpFlagGettingStartedPanelDismissed) ||
hs.Cfg.DefaultHomeDashboardPath != "" { hs.Cfg.DefaultHomeDashboardPath != "" {
return return
} }
+5 -4
View File
@@ -18,6 +18,7 @@ import (
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service" dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
@@ -53,7 +54,7 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) {
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanAdminValue: false}) guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanAdminValue: false})
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/1/permissions", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/1/permissions",
"/api/dashboards/id/:dashboardId/permissions", models.ROLE_EDITOR, func(sc *scenarioContext) { "/api/dashboards/id/:dashboardId/permissions", org.RoleEditor, func(sc *scenarioContext) {
callGetDashboardPermissions(sc, hs) callGetDashboardPermissions(sc, hs)
assert.Equal(t, 403, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
@@ -96,7 +97,7 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) {
}) })
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/1/permissions", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/1/permissions",
"/api/dashboards/id/:dashboardId/permissions", models.ROLE_ADMIN, func(sc *scenarioContext) { "/api/dashboards/id/:dashboardId/permissions", org.RoleAdmin, func(sc *scenarioContext) {
callGetDashboardPermissions(sc, hs) callGetDashboardPermissions(sc, hs)
assert.Equal(t, 200, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
@@ -189,7 +190,7 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) {
}) })
t.Run("When trying to update team or user permissions with a role", func(t *testing.T) { t.Run("When trying to update team or user permissions with a role", func(t *testing.T) {
role := models.ROLE_EDITOR role := org.RoleEditor
cmds := []dtos.UpdateDashboardACLCommand{ cmds := []dtos.UpdateDashboardACLCommand{
{ {
Items: []dtos.DashboardACLUpdateItem{ Items: []dtos.DashboardACLUpdateItem{
@@ -264,7 +265,7 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) {
mockSQLStore := mockstore.NewSQLStoreMock() mockSQLStore := mockstore.NewSQLStoreMock()
var resp []*models.DashboardACLInfoDTO var resp []*models.DashboardACLInfoDTO
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/1/permissions", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/1/permissions",
"/api/dashboards/id/:dashboardId/permissions", models.ROLE_ADMIN, func(sc *scenarioContext) { "/api/dashboards/id/:dashboardId/permissions", org.RoleAdmin, func(sc *scenarioContext) {
setUp() setUp()
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{ guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{
CanAdminValue: true, CanAdminValue: true,
+14 -13
View File
@@ -18,6 +18,7 @@ import (
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/dashboardsnapshots" "github.com/grafana/grafana/pkg/services/dashboardsnapshots"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
) )
@@ -65,7 +66,7 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
t.Run("When user has editor role and is not in the ACL", func(t *testing.T) { t.Run("When user has editor role and is not in the ACL", func(t *testing.T) {
loggedInUserScenarioWithRole(t, "Should not be able to delete snapshot when calling DELETE on", loggedInUserScenarioWithRole(t, "Should not be able to delete snapshot when calling DELETE on",
"DELETE", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) { "DELETE", "/api/snapshots/12345", "/api/snapshots/:key", org.RoleEditor, func(sc *scenarioContext) {
hs := &HTTPServer{dashboardsnapshotsService: setUpSnapshotTest(t, 0, "")} hs := &HTTPServer{dashboardsnapshotsService: setUpSnapshotTest(t, 0, "")}
sc.handlerFunc = hs.DeleteDashboardSnapshot sc.handlerFunc = hs.DeleteDashboardSnapshot
@@ -116,7 +117,7 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
}).Return(nil) }).Return(nil)
loggedInUserScenarioWithRole(t, "Should be able to delete a snapshot when calling DELETE on", "DELETE", loggedInUserScenarioWithRole(t, "Should be able to delete a snapshot when calling DELETE on", "DELETE",
"/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) { "/api/snapshots/12345", "/api/snapshots/:key", org.RoleEditor, func(sc *scenarioContext) {
guardian.InitLegacyGuardian(sc.sqlStore, dashSvc) guardian.InitLegacyGuardian(sc.sqlStore, dashSvc)
var externalRequest *http.Request var externalRequest *http.Request
ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) { ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
@@ -140,7 +141,7 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
t.Run("When user is editor and creator of the snapshot", func(t *testing.T) { t.Run("When user is editor and creator of the snapshot", func(t *testing.T) {
loggedInUserScenarioWithRole(t, "Should be able to delete a snapshot when calling DELETE on", loggedInUserScenarioWithRole(t, "Should be able to delete a snapshot when calling DELETE on",
"DELETE", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) { "DELETE", "/api/snapshots/12345", "/api/snapshots/:key", org.RoleEditor, func(sc *scenarioContext) {
d := setUpSnapshotTest(t, testUserID, "") d := setUpSnapshotTest(t, testUserID, "")
hs := &HTTPServer{dashboardsnapshotsService: d} hs := &HTTPServer{dashboardsnapshotsService: d}
@@ -159,7 +160,7 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
t.Run("When deleting an external snapshot", func(t *testing.T) { t.Run("When deleting an external snapshot", func(t *testing.T) {
loggedInUserScenarioWithRole(t, loggedInUserScenarioWithRole(t,
"Should gracefully delete local snapshot when remote snapshot has already been removed when calling DELETE on", "Should gracefully delete local snapshot when remote snapshot has already been removed when calling DELETE on",
"DELETE", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) { "DELETE", "/api/snapshots/12345", "/api/snapshots/:key", org.RoleEditor, func(sc *scenarioContext) {
var writeErr error var writeErr error
ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) { ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(500) rw.WriteHeader(500)
@@ -180,7 +181,7 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
loggedInUserScenarioWithRole(t, loggedInUserScenarioWithRole(t,
"Should fail to delete local snapshot when an unexpected 500 error occurs when calling DELETE on", "DELETE", "Should fail to delete local snapshot when an unexpected 500 error occurs when calling DELETE on", "DELETE",
"/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) { "/api/snapshots/12345", "/api/snapshots/:key", org.RoleEditor, func(sc *scenarioContext) {
var writeErr error var writeErr error
ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) { ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(500) rw.WriteHeader(500)
@@ -196,7 +197,7 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
loggedInUserScenarioWithRole(t, loggedInUserScenarioWithRole(t,
"Should fail to delete local snapshot when an unexpected remote error occurs when calling DELETE on", "Should fail to delete local snapshot when an unexpected remote error occurs when calling DELETE on",
"DELETE", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) { "DELETE", "/api/snapshots/12345", "/api/snapshots/:key", org.RoleEditor, func(sc *scenarioContext) {
ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) { ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(404) rw.WriteHeader(404)
}) })
@@ -208,7 +209,7 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
}, sqlmock) }, sqlmock)
loggedInUserScenarioWithRole(t, "Should be able to read a snapshot's unencrypted data when calling GET on", loggedInUserScenarioWithRole(t, "Should be able to read a snapshot's unencrypted data when calling GET on",
"GET", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) { "GET", "/api/snapshots/12345", "/api/snapshots/:key", org.RoleEditor, func(sc *scenarioContext) {
hs := &HTTPServer{dashboardsnapshotsService: setUpSnapshotTest(t, 0, "")} hs := &HTTPServer{dashboardsnapshotsService: setUpSnapshotTest(t, 0, "")}
sc.handlerFunc = hs.GetDashboardSnapshot sc.handlerFunc = hs.GetDashboardSnapshot
sc.fakeReqWithParams("GET", sc.url, map[string]string{"key": "12345"}).exec() sc.fakeReqWithParams("GET", sc.url, map[string]string{"key": "12345"}).exec()
@@ -243,7 +244,7 @@ func TestGetDashboardSnapshotNotFound(t *testing.T) {
loggedInUserScenarioWithRole(t, loggedInUserScenarioWithRole(t,
"GET /snapshots/{key} should return 404 when the snapshot does not exist", "GET", "GET /snapshots/{key} should return 404 when the snapshot does not exist", "GET",
"/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) { "/api/snapshots/12345", "/api/snapshots/:key", org.RoleEditor, func(sc *scenarioContext) {
d := setUpSnapshotTest(t) d := setUpSnapshotTest(t)
hs := &HTTPServer{dashboardsnapshotsService: d} hs := &HTTPServer{dashboardsnapshotsService: d}
sc.handlerFunc = hs.GetDashboardSnapshot sc.handlerFunc = hs.GetDashboardSnapshot
@@ -254,7 +255,7 @@ func TestGetDashboardSnapshotNotFound(t *testing.T) {
loggedInUserScenarioWithRole(t, loggedInUserScenarioWithRole(t,
"DELETE /snapshots/{key} should return 404 when the snapshot does not exist", "DELETE", "DELETE /snapshots/{key} should return 404 when the snapshot does not exist", "DELETE",
"/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) { "/api/snapshots/12345", "/api/snapshots/:key", org.RoleEditor, func(sc *scenarioContext) {
d := setUpSnapshotTest(t) d := setUpSnapshotTest(t)
hs := &HTTPServer{dashboardsnapshotsService: d} hs := &HTTPServer{dashboardsnapshotsService: d}
sc.handlerFunc = hs.DeleteDashboardSnapshot sc.handlerFunc = hs.DeleteDashboardSnapshot
@@ -265,7 +266,7 @@ func TestGetDashboardSnapshotNotFound(t *testing.T) {
loggedInUserScenarioWithRole(t, loggedInUserScenarioWithRole(t,
"GET /snapshots-delete/{deleteKey} should return 404 when the snapshot does not exist", "DELETE", "GET /snapshots-delete/{deleteKey} should return 404 when the snapshot does not exist", "DELETE",
"/api/snapshots-delete/12345", "/api/snapshots-delete/:deleteKey", models.ROLE_EDITOR, func(sc *scenarioContext) { "/api/snapshots-delete/12345", "/api/snapshots-delete/:deleteKey", org.RoleEditor, func(sc *scenarioContext) {
d := setUpSnapshotTest(t) d := setUpSnapshotTest(t)
hs := &HTTPServer{dashboardsnapshotsService: d} hs := &HTTPServer{dashboardsnapshotsService: d}
sc.handlerFunc = hs.DeleteDashboardSnapshotByDeleteKey sc.handlerFunc = hs.DeleteDashboardSnapshotByDeleteKey
@@ -293,7 +294,7 @@ func TestGetDashboardSnapshotFailure(t *testing.T) {
loggedInUserScenarioWithRole(t, loggedInUserScenarioWithRole(t,
"GET /snapshots/{key} should return 404 when the snapshot does not exist", "GET", "GET /snapshots/{key} should return 404 when the snapshot does not exist", "GET",
"/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) { "/api/snapshots/12345", "/api/snapshots/:key", org.RoleEditor, func(sc *scenarioContext) {
d := setUpSnapshotTest(t) d := setUpSnapshotTest(t)
hs := &HTTPServer{dashboardsnapshotsService: d} hs := &HTTPServer{dashboardsnapshotsService: d}
sc.handlerFunc = hs.GetDashboardSnapshot sc.handlerFunc = hs.GetDashboardSnapshot
@@ -304,7 +305,7 @@ func TestGetDashboardSnapshotFailure(t *testing.T) {
loggedInUserScenarioWithRole(t, loggedInUserScenarioWithRole(t,
"DELETE /snapshots/{key} should return 404 when the snapshot does not exist", "DELETE", "DELETE /snapshots/{key} should return 404 when the snapshot does not exist", "DELETE",
"/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) { "/api/snapshots/12345", "/api/snapshots/:key", org.RoleEditor, func(sc *scenarioContext) {
d := setUpSnapshotTest(t) d := setUpSnapshotTest(t)
hs := &HTTPServer{dashboardsnapshotsService: d} hs := &HTTPServer{dashboardsnapshotsService: d}
sc.handlerFunc = hs.DeleteDashboardSnapshot sc.handlerFunc = hs.DeleteDashboardSnapshot
@@ -315,7 +316,7 @@ func TestGetDashboardSnapshotFailure(t *testing.T) {
loggedInUserScenarioWithRole(t, loggedInUserScenarioWithRole(t,
"GET /snapshots-delete/{deleteKey} should return 404 when the snapshot does not exist", "DELETE", "GET /snapshots-delete/{deleteKey} should return 404 when the snapshot does not exist", "DELETE",
"/api/snapshots-delete/12345", "/api/snapshots-delete/:deleteKey", models.ROLE_EDITOR, func(sc *scenarioContext) { "/api/snapshots-delete/12345", "/api/snapshots-delete/:deleteKey", org.RoleEditor, func(sc *scenarioContext) {
d := setUpSnapshotTest(t) d := setUpSnapshotTest(t)
hs := &HTTPServer{dashboardsnapshotsService: d} hs := &HTTPServer{dashboardsnapshotsService: d}
sc.handlerFunc = hs.DeleteDashboardSnapshotByDeleteKey sc.handlerFunc = hs.DeleteDashboardSnapshotByDeleteKey
+28 -26
View File
@@ -31,12 +31,14 @@ import (
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/libraryelements" "github.com/grafana/grafana/pkg/services/libraryelements"
"github.com/grafana/grafana/pkg/services/live" "github.com/grafana/grafana/pkg/services/live"
"github.com/grafana/grafana/pkg/services/org"
pref "github.com/grafana/grafana/pkg/services/preference" pref "github.com/grafana/grafana/pkg/services/preference"
"github.com/grafana/grafana/pkg/services/preference/preftest" "github.com/grafana/grafana/pkg/services/preference/preftest"
"github.com/grafana/grafana/pkg/services/provisioning" "github.com/grafana/grafana/pkg/services/provisioning"
"github.com/grafana/grafana/pkg/services/quota/quotaimpl" "github.com/grafana/grafana/pkg/services/quota/quotaimpl"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
) )
@@ -45,7 +47,7 @@ func TestGetHomeDashboard(t *testing.T) {
httpReq, err := http.NewRequest(http.MethodGet, "", nil) httpReq, err := http.NewRequest(http.MethodGet, "", nil)
require.NoError(t, err) require.NoError(t, err)
httpReq.Header.Add("Content-Type", "application/json") httpReq.Header.Add("Content-Type", "application/json")
req := &models.ReqContext{SignedInUser: &models.SignedInUser{}, Context: &web.Context{Req: httpReq}} req := &models.ReqContext{SignedInUser: &user.SignedInUser{}, Context: &web.Context{Req: httpReq}}
cfg := setting.NewCfg() cfg := setting.NewCfg()
cfg.StaticRootPath = "../../public/" cfg.StaticRootPath = "../../public/"
prefService := preftest.NewPreferenceServiceFake() prefService := preftest.NewPreferenceServiceFake()
@@ -145,8 +147,8 @@ func TestDashboardAPIEndpoint(t *testing.T) {
} }
setUp := func() { setUp := func() {
viewerRole := models.ROLE_VIEWER viewerRole := org.RoleViewer
editorRole := models.ROLE_EDITOR editorRole := org.RoleEditor
dashboardService.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*models.GetDashboardACLInfoListQuery")).Run(func(args mock.Arguments) { dashboardService.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*models.GetDashboardACLInfoListQuery")).Run(func(args mock.Arguments) {
q := args.Get(1).(*models.GetDashboardACLInfoListQuery) q := args.Get(1).(*models.GetDashboardACLInfoListQuery)
q.Result = []*models.DashboardACLInfoDTO{ q.Result = []*models.DashboardACLInfoDTO{
@@ -162,7 +164,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
// 2. user is an org editor // 2. user is an org editor
t.Run("When user is an Org Viewer", func(t *testing.T) { t.Run("When user is an Org Viewer", func(t *testing.T) {
role := models.ROLE_VIEWER role := org.RoleViewer
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUp() setUp()
@@ -194,7 +196,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
}) })
t.Run("When user is an Org Editor", func(t *testing.T) { t.Run("When user is an Org Editor", func(t *testing.T) {
role := models.ROLE_EDITOR role := org.RoleEditor
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUp() setUp()
@@ -283,7 +285,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
// 6. user is an org editor AND has been granted a view permission // 6. user is an org editor AND has been granted a view permission
t.Run("When user is an Org Viewer and has no permissions for this dashboard", func(t *testing.T) { t.Run("When user is an Org Viewer and has no permissions for this dashboard", func(t *testing.T) {
role := models.ROLE_VIEWER role := org.RoleViewer
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUp() setUp()
@@ -322,7 +324,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
}) })
t.Run("When user is an Org Editor and has no permissions for this dashboard", func(t *testing.T) { t.Run("When user is an Org Editor and has no permissions for this dashboard", func(t *testing.T) {
role := models.ROLE_EDITOR role := org.RoleEditor
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUp() setUp()
@@ -359,7 +361,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
}) })
t.Run("When user is an Org Viewer but has an edit permission", func(t *testing.T) { t.Run("When user is an Org Viewer but has an edit permission", func(t *testing.T) {
role := models.ROLE_VIEWER role := org.RoleViewer
setUpInner := func() { setUpInner := func() {
origCanEdit := setting.ViewersCanEdit origCanEdit := setting.ViewersCanEdit
@@ -421,7 +423,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
}) })
t.Run("When user is an Org Viewer and viewers can edit", func(t *testing.T) { t.Run("When user is an Org Viewer and viewers can edit", func(t *testing.T) {
role := models.ROLE_VIEWER role := org.RoleViewer
setUpInner := func() { setUpInner := func() {
origCanEdit := setting.ViewersCanEdit origCanEdit := setting.ViewersCanEdit
@@ -461,7 +463,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
}) })
t.Run("When user is an Org Viewer but has an admin permission", func(t *testing.T) { t.Run("When user is an Org Viewer but has an admin permission", func(t *testing.T) {
role := models.ROLE_VIEWER role := org.RoleViewer
setUpInner := func() { setUpInner := func() {
origCanEdit := setting.ViewersCanEdit origCanEdit := setting.ViewersCanEdit
@@ -520,7 +522,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
}) })
t.Run("When user is an Org Editor but has a view permission", func(t *testing.T) { t.Run("When user is an Org Editor but has a view permission", func(t *testing.T) {
role := models.ROLE_EDITOR role := org.RoleEditor
setUpInner := func() { setUpInner := func() {
dashboardService := dashboards.NewFakeDashboardService(t) dashboardService := dashboards.NewFakeDashboardService(t)
@@ -758,7 +760,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
} }
t.Run("when user does not have permission", func(t *testing.T) { t.Run("when user does not have permission", func(t *testing.T) {
role := models.ROLE_VIEWER role := org.RoleViewer
postDiffScenario(t, "When calling POST on", "/api/dashboards/calculate-diff", "/api/dashboards/calculate-diff", cmd, role, func(sc *scenarioContext) { postDiffScenario(t, "When calling POST on", "/api/dashboards/calculate-diff", "/api/dashboards/calculate-diff", cmd, role, func(sc *scenarioContext) {
setUp() setUp()
@@ -768,7 +770,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
}) })
t.Run("when user does have permission", func(t *testing.T) { t.Run("when user does have permission", func(t *testing.T) {
role := models.ROLE_ADMIN role := org.RoleAdmin
postDiffScenario(t, "When calling POST on", "/api/dashboards/calculate-diff", "/api/dashboards/calculate-diff", cmd, role, func(sc *scenarioContext) { postDiffScenario(t, "When calling POST on", "/api/dashboards/calculate-diff", "/api/dashboards/calculate-diff", cmd, role, func(sc *scenarioContext) {
// This test shouldn't hit GetDashboardACLInfoList, so no setup needed // This test shouldn't hit GetDashboardACLInfoList, so no setup needed
sc.dashboardVersionService = fakeDashboardVersionService sc.dashboardVersionService = fakeDashboardVersionService
@@ -872,7 +874,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
}).Return(nil) }).Return(nil)
guardian.InitLegacyGuardian(mockSQLStore, dashboardService) guardian.InitLegacyGuardian(mockSQLStore, dashboardService)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/dash", "/api/dashboards/uid/:uid", models.ROLE_EDITOR, func(sc *scenarioContext) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/dash", "/api/dashboards/uid/:uid", org.RoleEditor, func(sc *scenarioContext) {
fakeProvisioningService := provisioning.NewProvisioningServiceMock(context.Background()) fakeProvisioningService := provisioning.NewProvisioningServiceMock(context.Background())
fakeProvisioningService.GetDashboardProvisionerResolvedPathFunc = func(name string) string { fakeProvisioningService.GetDashboardProvisionerResolvedPathFunc = func(name string) string {
return "/tmp/grafana/dashboards" return "/tmp/grafana/dashboards"
@@ -883,7 +885,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.Equal(t, "../../../dashboard1.json", dash.Meta.ProvisionedExternalId, mockSQLStore) assert.Equal(t, "../../../dashboard1.json", dash.Meta.ProvisionedExternalId, mockSQLStore)
}, mockSQLStore) }, mockSQLStore)
loggedInUserScenarioWithRole(t, "When allowUiUpdates is true and calling GET on", "GET", "/api/dashboards/uid/dash", "/api/dashboards/uid/:uid", models.ROLE_EDITOR, func(sc *scenarioContext) { loggedInUserScenarioWithRole(t, "When allowUiUpdates is true and calling GET on", "GET", "/api/dashboards/uid/dash", "/api/dashboards/uid/:uid", org.RoleEditor, func(sc *scenarioContext) {
fakeProvisioningService := provisioning.NewProvisioningServiceMock(context.Background()) fakeProvisioningService := provisioning.NewProvisioningServiceMock(context.Background())
fakeProvisioningService.GetDashboardProvisionerResolvedPathFunc = func(name string) string { fakeProvisioningService.GetDashboardProvisionerResolvedPathFunc = func(name string) string {
return "/tmp/grafana/dashboards" return "/tmp/grafana/dashboards"
@@ -1032,7 +1034,7 @@ func postDashboardScenario(t *testing.T, desc string, url string, routePattern s
c.Req.Body = mockRequestBody(cmd) c.Req.Body = mockRequestBody(cmd)
c.Req.Header.Add("Content-Type", "application/json") c.Req.Header.Add("Content-Type", "application/json")
sc.context = c sc.context = c
sc.context.SignedInUser = &models.SignedInUser{OrgId: cmd.OrgId, UserId: cmd.UserId} sc.context.SignedInUser = &user.SignedInUser{OrgId: cmd.OrgId, UserId: cmd.UserId}
return hs.PostDashboard(c) return hs.PostDashboard(c)
}) })
@@ -1044,7 +1046,7 @@ func postDashboardScenario(t *testing.T, desc string, url string, routePattern s
} }
func postDiffScenario(t *testing.T, desc string, url string, routePattern string, cmd dtos.CalculateDiffOptions, func postDiffScenario(t *testing.T, desc string, url string, routePattern string, cmd dtos.CalculateDiffOptions,
role models.RoleType, fn scenarioFunc, sqlmock sqlstore.Store, fakeDashboardVersionService *dashvertest.FakeDashboardVersionService) { role org.RoleType, fn scenarioFunc, sqlmock sqlstore.Store, fakeDashboardVersionService *dashvertest.FakeDashboardVersionService) {
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) { t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
cfg := setting.NewCfg() cfg := setting.NewCfg()
hs := HTTPServer{ hs := HTTPServer{
@@ -1065,7 +1067,7 @@ func postDiffScenario(t *testing.T, desc string, url string, routePattern string
c.Req.Body = mockRequestBody(cmd) c.Req.Body = mockRequestBody(cmd)
c.Req.Header.Add("Content-Type", "application/json") c.Req.Header.Add("Content-Type", "application/json")
sc.context = c sc.context = c
sc.context.SignedInUser = &models.SignedInUser{ sc.context.SignedInUser = &user.SignedInUser{
OrgId: testOrgID, OrgId: testOrgID,
UserId: testUserID, UserId: testUserID,
} }
@@ -1106,11 +1108,11 @@ func restoreDashboardVersionScenario(t *testing.T, desc string, url string, rout
c.Req.Body = mockRequestBody(cmd) c.Req.Body = mockRequestBody(cmd)
c.Req.Header.Add("Content-Type", "application/json") c.Req.Header.Add("Content-Type", "application/json")
sc.context = c sc.context = c
sc.context.SignedInUser = &models.SignedInUser{ sc.context.SignedInUser = &user.SignedInUser{
OrgId: testOrgID, OrgId: testOrgID,
UserId: testUserID, UserId: testUserID,
} }
sc.context.OrgRole = models.ROLE_ADMIN sc.context.OrgRole = org.RoleAdmin
return hs.RestoreDashboardVersion(c) return hs.RestoreDashboardVersion(c)
}) })
@@ -1148,23 +1150,23 @@ func (m *mockLibraryPanelService) CleanLibraryPanelsForDashboard(dash *models.Da
return nil return nil
} }
func (m *mockLibraryPanelService) ConnectLibraryPanelsForDashboard(c context.Context, signedInUser *models.SignedInUser, dash *models.Dashboard) error { func (m *mockLibraryPanelService) ConnectLibraryPanelsForDashboard(c context.Context, signedInUser *user.SignedInUser, dash *models.Dashboard) error {
return nil return nil
} }
func (m *mockLibraryPanelService) ImportLibraryPanelsForDashboard(c context.Context, signedInUser *models.SignedInUser, libraryPanels *simplejson.Json, panels []interface{}, folderID int64) error { func (m *mockLibraryPanelService) ImportLibraryPanelsForDashboard(c context.Context, signedInUser *user.SignedInUser, libraryPanels *simplejson.Json, panels []interface{}, folderID int64) error {
return nil return nil
} }
type mockLibraryElementService struct { type mockLibraryElementService struct {
} }
func (l *mockLibraryElementService) CreateElement(c context.Context, signedInUser *models.SignedInUser, cmd libraryelements.CreateLibraryElementCommand) (libraryelements.LibraryElementDTO, error) { func (l *mockLibraryElementService) CreateElement(c context.Context, signedInUser *user.SignedInUser, cmd libraryelements.CreateLibraryElementCommand) (libraryelements.LibraryElementDTO, error) {
return libraryelements.LibraryElementDTO{}, nil return libraryelements.LibraryElementDTO{}, nil
} }
// GetElement gets an element from a UID. // GetElement gets an element from a UID.
func (l *mockLibraryElementService) GetElement(c context.Context, signedInUser *models.SignedInUser, UID string) (libraryelements.LibraryElementDTO, error) { func (l *mockLibraryElementService) GetElement(c context.Context, signedInUser *user.SignedInUser, UID string) (libraryelements.LibraryElementDTO, error) {
return libraryelements.LibraryElementDTO{}, nil return libraryelements.LibraryElementDTO{}, nil
} }
@@ -1174,7 +1176,7 @@ func (l *mockLibraryElementService) GetElementsForDashboard(c context.Context, d
} }
// ConnectElementsToDashboard connects elements to a specific dashboard. // ConnectElementsToDashboard connects elements to a specific dashboard.
func (l *mockLibraryElementService) ConnectElementsToDashboard(c context.Context, signedInUser *models.SignedInUser, elementUIDs []string, dashboardID int64) error { func (l *mockLibraryElementService) ConnectElementsToDashboard(c context.Context, signedInUser *user.SignedInUser, elementUIDs []string, dashboardID int64) error {
return nil return nil
} }
@@ -1184,6 +1186,6 @@ func (l *mockLibraryElementService) DisconnectElementsFromDashboard(c context.Co
} }
// DeleteLibraryElementsInFolder deletes all elements for a specific folder. // DeleteLibraryElementsInFolder deletes all elements for a specific folder.
func (l *mockLibraryElementService) DeleteLibraryElementsInFolder(c context.Context, signedInUser *models.SignedInUser, folderUID string) error { func (l *mockLibraryElementService) DeleteLibraryElementsInFolder(c context.Context, signedInUser *user.SignedInUser, folderUID string) error {
return nil return nil
} }
+2 -1
View File
@@ -19,6 +19,7 @@ import (
"github.com/grafana/grafana/pkg/plugins/adapters" "github.com/grafana/grafana/pkg/plugins/adapters"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/datasources/permissions" "github.com/grafana/grafana/pkg/services/datasources/permissions"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/util/proxyutil" "github.com/grafana/grafana/pkg/util/proxyutil"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
@@ -833,7 +834,7 @@ func (hs *HTTPServer) decryptSecureJsonDataFn(ctx context.Context) func(ds *data
} }
} }
func (hs *HTTPServer) filterDatasourcesByQueryPermission(ctx context.Context, user *models.SignedInUser, ds []*datasources.DataSource) ([]*datasources.DataSource, error) { func (hs *HTTPServer) filterDatasourcesByQueryPermission(ctx context.Context, user *user.SignedInUser, ds []*datasources.DataSource) ([]*datasources.DataSource, error) {
query := datasources.DatasourcesPermissionFilterQuery{ query := datasources.DatasourcesPermissionFilterQuery{
User: user, User: user,
Datasources: ds, Datasources: ds,
+2 -1
View File
@@ -19,6 +19,7 @@ import (
ac "github.com/grafana/grafana/pkg/services/accesscontrol" ac "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/datasources/permissions" "github.com/grafana/grafana/pkg/services/datasources/permissions"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
@@ -520,7 +521,7 @@ func TestAPI_Datasources_AccessControl(t *testing.T) {
sc.context.UserId = testUserID sc.context.UserId = testUserID
sc.context.OrgId = testOrgID sc.context.OrgId = testOrgID
sc.context.Login = testUserLogin sc.context.Login = testUserLogin
sc.context.OrgRole = models.ROLE_VIEWER sc.context.OrgRole = org.RoleViewer
sc.context.IsSignedIn = true sc.context.IsSignedIn = true
} }
sc.m.Use(pretendSignInMiddleware) sc.m.Use(pretendSignInMiddleware)
+7 -4
View File
@@ -1,6 +1,9 @@
package dtos package dtos
import "github.com/grafana/grafana/pkg/models" import (
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/org"
)
// swagger:model // swagger:model
type UpdateDashboardACLCommand struct { type UpdateDashboardACLCommand struct {
@@ -9,9 +12,9 @@ type UpdateDashboardACLCommand struct {
// swagger:model // swagger:model
type DashboardACLUpdateItem struct { type DashboardACLUpdateItem struct {
UserID int64 `json:"userId"` UserID int64 `json:"userId"`
TeamID int64 `json:"teamId"` TeamID int64 `json:"teamId"`
Role *models.RoleType `json:"role,omitempty"` Role *org.RoleType `json:"role,omitempty"`
// Permission level // Permission level
// Description: // Description:
// * `1` - View // * `1` - View
+2 -2
View File
@@ -3,8 +3,8 @@ package dtos
import ( import (
"time" "time"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/org"
) )
// swagger:model // swagger:model
@@ -20,7 +20,7 @@ type NewApiKeyResult struct {
type ApiKeyDTO struct { type ApiKeyDTO struct {
Id int64 `json:"id"` Id int64 `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Role models.RoleType `json:"role"` Role org.RoleType `json:"role"`
Expiration *time.Time `json:"expiration,omitempty"` Expiration *time.Time `json:"expiration,omitempty"`
AccessControl accesscontrol.Metadata `json:"accessControl,omitempty"` AccessControl accesscontrol.Metadata `json:"accessControl,omitempty"`
} }
+5 -5
View File
@@ -1,12 +1,12 @@
package dtos package dtos
import "github.com/grafana/grafana/pkg/models" import "github.com/grafana/grafana/pkg/services/org"
type AddInviteForm struct { type AddInviteForm struct {
LoginOrEmail string `json:"loginOrEmail" binding:"Required"` LoginOrEmail string `json:"loginOrEmail" binding:"Required"`
Name string `json:"name"` Name string `json:"name"`
Role models.RoleType `json:"role" binding:"Required"` Role org.RoleType `json:"role" binding:"Required"`
SendEmail bool `json:"sendEmail"` SendEmail bool `json:"sendEmail"`
} }
type InviteInfo struct { type InviteInfo struct {
+5 -4
View File
@@ -9,7 +9,8 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
@@ -37,13 +38,13 @@ type CurrentUser struct {
OrgCount int `json:"orgCount"` OrgCount int `json:"orgCount"`
OrgId int64 `json:"orgId"` OrgId int64 `json:"orgId"`
OrgName string `json:"orgName"` OrgName string `json:"orgName"`
OrgRole models.RoleType `json:"orgRole"` OrgRole org.RoleType `json:"orgRole"`
IsGrafanaAdmin bool `json:"isGrafanaAdmin"` IsGrafanaAdmin bool `json:"isGrafanaAdmin"`
GravatarUrl string `json:"gravatarUrl"` GravatarUrl string `json:"gravatarUrl"`
Timezone string `json:"timezone"` Timezone string `json:"timezone"`
WeekStart string `json:"weekStart"` WeekStart string `json:"weekStart"`
Locale string `json:"locale"` Locale string `json:"locale"`
HelpFlags1 models.HelpFlags1 `json:"helpFlags1"` HelpFlags1 user.HelpFlags1 `json:"helpFlags1"`
HasEditPermissionInFolders bool `json:"hasEditPermissionInFolders"` HasEditPermissionInFolders bool `json:"hasEditPermissionInFolders"`
Permissions UserPermissionsMap `json:"permissions,omitempty"` Permissions UserPermissionsMap `json:"permissions,omitempty"`
} }
@@ -120,7 +121,7 @@ func GetGravatarUrlWithDefault(text string, defaultText string) string {
return GetGravatarUrl(text) return GetGravatarUrl(text)
} }
func IsHiddenUser(userLogin string, signedInUser *models.SignedInUser, cfg *setting.Cfg) bool { func IsHiddenUser(userLogin string, signedInUser *user.SignedInUser, cfg *setting.Cfg) bool {
if userLogin == "" || signedInUser.IsGrafanaAdmin || userLogin == signedInUser.Login { if userLogin == "" || signedInUser.IsGrafanaAdmin || userLogin == signedInUser.Login {
return false return false
} }
+7 -7
View File
@@ -3,7 +3,7 @@ package dtos
import ( import (
"testing" "testing"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@@ -17,14 +17,14 @@ func TestIsHiddenUser(t *testing.T) {
testcases := []struct { testcases := []struct {
desc string desc string
userLogin string userLogin string
signedInUser *models.SignedInUser signedInUser *user.SignedInUser
hiddenUsers map[string]struct{} hiddenUsers map[string]struct{}
expected bool expected bool
}{ }{
{ {
desc: "non-server admin user should see non-hidden user", desc: "non-server admin user should see non-hidden user",
userLogin: "user", userLogin: "user",
signedInUser: &models.SignedInUser{ signedInUser: &user.SignedInUser{
IsGrafanaAdmin: false, IsGrafanaAdmin: false,
Login: "admin", Login: "admin",
}, },
@@ -34,7 +34,7 @@ func TestIsHiddenUser(t *testing.T) {
{ {
desc: "non-server admin user should not see hidden user", desc: "non-server admin user should not see hidden user",
userLogin: "user", userLogin: "user",
signedInUser: &models.SignedInUser{ signedInUser: &user.SignedInUser{
IsGrafanaAdmin: false, IsGrafanaAdmin: false,
Login: "admin", Login: "admin",
}, },
@@ -44,7 +44,7 @@ func TestIsHiddenUser(t *testing.T) {
{ {
desc: "non-server admin user should see himself, even if he's hidden", desc: "non-server admin user should see himself, even if he's hidden",
userLogin: "admin", userLogin: "admin",
signedInUser: &models.SignedInUser{ signedInUser: &user.SignedInUser{
IsGrafanaAdmin: false, IsGrafanaAdmin: false,
Login: "admin", Login: "admin",
}, },
@@ -56,7 +56,7 @@ func TestIsHiddenUser(t *testing.T) {
{ {
desc: "server admin user should see hidden user", desc: "server admin user should see hidden user",
userLogin: "user", userLogin: "user",
signedInUser: &models.SignedInUser{ signedInUser: &user.SignedInUser{
IsGrafanaAdmin: true, IsGrafanaAdmin: true,
Login: "admin", Login: "admin",
}, },
@@ -66,7 +66,7 @@ func TestIsHiddenUser(t *testing.T) {
{ {
desc: "server admin user should see non-hidden user", desc: "server admin user should see non-hidden user",
userLogin: "user", userLogin: "user",
signedInUser: &models.SignedInUser{ signedInUser: &user.SignedInUser{
IsGrafanaAdmin: true, IsGrafanaAdmin: true,
Login: "admin", Login: "admin",
}, },
+6 -5
View File
@@ -18,6 +18,7 @@ import (
service "github.com/grafana/grafana/pkg/services/dashboards/service" service "github.com/grafana/grafana/pkg/services/dashboards/service"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
@@ -51,7 +52,7 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
t.Run("Given folder not exists", func(t *testing.T) { t.Run("Given folder not exists", func(t *testing.T) {
folderService.On("GetFolderByUID", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, dashboards.ErrFolderNotFound).Twice() folderService.On("GetFolderByUID", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, dashboards.ErrFolderNotFound).Twice()
mockSQLStore := mockstore.NewSQLStoreMock() mockSQLStore := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", models.ROLE_EDITOR, func(sc *scenarioContext) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", org.RoleEditor, func(sc *scenarioContext) {
callGetFolderPermissions(sc, hs) callGetFolderPermissions(sc, hs)
assert.Equal(t, 404, sc.resp.Code) assert.Equal(t, 404, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
@@ -84,7 +85,7 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
folderService.On("GetFolderByUID", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, dashboards.ErrFolderAccessDenied).Twice() folderService.On("GetFolderByUID", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, dashboards.ErrFolderAccessDenied).Twice()
mockSQLStore := mockstore.NewSQLStoreMock() mockSQLStore := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", models.ROLE_EDITOR, func(sc *scenarioContext) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", org.RoleEditor, func(sc *scenarioContext) {
callGetFolderPermissions(sc, hs) callGetFolderPermissions(sc, hs)
assert.Equal(t, 403, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore) }, mockSQLStore)
@@ -130,7 +131,7 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
dashboardStore.On("UpdateDashboardACL", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() dashboardStore.On("UpdateDashboardACL", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
mockSQLStore := mockstore.NewSQLStoreMock() mockSQLStore := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", models.ROLE_ADMIN, func(sc *scenarioContext) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", org.RoleAdmin, func(sc *scenarioContext) {
callGetFolderPermissions(sc, hs) callGetFolderPermissions(sc, hs)
assert.Equal(t, 200, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
@@ -205,7 +206,7 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
}) })
t.Run("When trying to update team or user permissions with a role", func(t *testing.T) { t.Run("When trying to update team or user permissions with a role", func(t *testing.T) {
role := models.ROLE_ADMIN role := org.RoleAdmin
cmds := []dtos.UpdateDashboardACLCommand{ cmds := []dtos.UpdateDashboardACLCommand{
{ {
Items: []dtos.DashboardACLUpdateItem{ Items: []dtos.DashboardACLUpdateItem{
@@ -303,7 +304,7 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
var resp []*models.DashboardACLInfoDTO var resp []*models.DashboardACLInfoDTO
mockSQLStore := mockstore.NewSQLStoreMock() mockSQLStore := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", models.ROLE_ADMIN, func(sc *scenarioContext) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", org.RoleAdmin, func(sc *scenarioContext) {
callGetFolderPermissions(sc, hs) callGetFolderPermissions(sc, hs)
assert.Equal(t, 200, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
+12 -11
View File
@@ -22,6 +22,7 @@ import (
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/quota/quotatest" "github.com/grafana/grafana/pkg/services/quota/quotatest"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web/webtest" "github.com/grafana/grafana/pkg/web/webtest"
) )
@@ -155,7 +156,7 @@ func TestHTTPServer_FolderMetadata(t *testing.T) {
}, nil) }, nil)
req := server.NewGetRequest("/api/folders?accesscontrol=true") req := server.NewGetRequest("/api/folders?accesscontrol=true")
webtest.RequestWithSignedInUser(req, &models.SignedInUser{UserId: 1, OrgId: 1, Permissions: map[int64]map[string][]string{ webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserId: 1, OrgId: 1, Permissions: map[int64]map[string][]string{
1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{ 1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{
{Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersAll}, {Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersAll},
{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("2")}, {Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("2")},
@@ -184,7 +185,7 @@ func TestHTTPServer_FolderMetadata(t *testing.T) {
folderService.On("GetFolderByUID", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&models.Folder{Uid: "folderUid"}, nil) folderService.On("GetFolderByUID", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&models.Folder{Uid: "folderUid"}, nil)
req := server.NewGetRequest("/api/folders/folderUid?accesscontrol=true") req := server.NewGetRequest("/api/folders/folderUid?accesscontrol=true")
webtest.RequestWithSignedInUser(req, &models.SignedInUser{UserId: 1, OrgId: 1, Permissions: map[int64]map[string][]string{ webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserId: 1, OrgId: 1, Permissions: map[int64]map[string][]string{
1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{ 1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{
{Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersAll}, {Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersAll},
{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("folderUid")}, {Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("folderUid")},
@@ -207,7 +208,7 @@ func TestHTTPServer_FolderMetadata(t *testing.T) {
folderService.On("GetFolderByUID", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&models.Folder{Uid: "folderUid"}, nil) folderService.On("GetFolderByUID", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&models.Folder{Uid: "folderUid"}, nil)
req := server.NewGetRequest("/api/folders/folderUid") req := server.NewGetRequest("/api/folders/folderUid")
webtest.RequestWithSignedInUser(req, &models.SignedInUser{UserId: 1, OrgId: 1, Permissions: map[int64]map[string][]string{ webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserId: 1, OrgId: 1, Permissions: map[int64]map[string][]string{
1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{ 1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{
{Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersAll}, {Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersAll},
{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("folderUid")}, {Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("folderUid")},
@@ -255,7 +256,7 @@ func createFolderScenario(t *testing.T, desc string, url string, routePattern st
c.Req.Body = mockRequestBody(cmd) c.Req.Body = mockRequestBody(cmd)
c.Req.Header.Add("Content-Type", "application/json") c.Req.Header.Add("Content-Type", "application/json")
sc.context = c sc.context = c
sc.context.SignedInUser = &models.SignedInUser{OrgId: testOrgID, UserId: testUserID} sc.context.SignedInUser = &user.SignedInUser{OrgId: testOrgID, UserId: testUserID}
return hs.CreateFolder(c) return hs.CreateFolder(c)
}) })
@@ -285,7 +286,7 @@ func updateFolderScenario(t *testing.T, desc string, url string, routePattern st
c.Req.Body = mockRequestBody(cmd) c.Req.Body = mockRequestBody(cmd)
c.Req.Header.Add("Content-Type", "application/json") c.Req.Header.Add("Content-Type", "application/json")
sc.context = c sc.context = c
sc.context.SignedInUser = &models.SignedInUser{OrgId: testOrgID, UserId: testUserID} sc.context.SignedInUser = &user.SignedInUser{OrgId: testOrgID, UserId: testUserID}
return hs.UpdateFolder(c) return hs.UpdateFolder(c)
}) })
@@ -314,28 +315,28 @@ type fakeFolderService struct {
DeletedFolderUids []string DeletedFolderUids []string
} }
func (s *fakeFolderService) GetFolders(ctx context.Context, user *models.SignedInUser, orgID int64, limit int64, page int64) ([]*models.Folder, error) { func (s *fakeFolderService) GetFolders(ctx context.Context, user *user.SignedInUser, orgID int64, limit int64, page int64) ([]*models.Folder, error) {
return s.GetFoldersResult, s.GetFoldersError return s.GetFoldersResult, s.GetFoldersError
} }
func (s *fakeFolderService) GetFolderByID(ctx context.Context, user *models.SignedInUser, id int64, orgID int64) (*models.Folder, error) { func (s *fakeFolderService) GetFolderByID(ctx context.Context, user *user.SignedInUser, id int64, orgID int64) (*models.Folder, error) {
return s.GetFolderByIDResult, s.GetFolderByIDError return s.GetFolderByIDResult, s.GetFolderByIDError
} }
func (s *fakeFolderService) GetFolderByUID(ctx context.Context, user *models.SignedInUser, orgID int64, uid string) (*models.Folder, error) { func (s *fakeFolderService) GetFolderByUID(ctx context.Context, user *user.SignedInUser, orgID int64, uid string) (*models.Folder, error) {
return s.GetFolderByUIDResult, s.GetFolderByUIDError return s.GetFolderByUIDResult, s.GetFolderByUIDError
} }
func (s *fakeFolderService) CreateFolder(ctx context.Context, user *models.SignedInUser, orgID int64, title, uid string) (*models.Folder, error) { func (s *fakeFolderService) CreateFolder(ctx context.Context, user *user.SignedInUser, orgID int64, title, uid string) (*models.Folder, error) {
return s.CreateFolderResult, s.CreateFolderError return s.CreateFolderResult, s.CreateFolderError
} }
func (s *fakeFolderService) UpdateFolder(ctx context.Context, user *models.SignedInUser, orgID int64, existingUid string, cmd *models.UpdateFolderCommand) error { func (s *fakeFolderService) UpdateFolder(ctx context.Context, user *user.SignedInUser, orgID int64, existingUid string, cmd *models.UpdateFolderCommand) error {
cmd.Result = s.UpdateFolderResult cmd.Result = s.UpdateFolderResult
return s.UpdateFolderError return s.UpdateFolderError
} }
func (s *fakeFolderService) DeleteFolder(ctx context.Context, user *models.SignedInUser, orgID int64, uid string, forceDeleteRules bool) (*models.Folder, error) { func (s *fakeFolderService) DeleteFolder(ctx context.Context, user *user.SignedInUser, orgID int64, uid string, forceDeleteRules bool) (*models.Folder, error) {
s.DeletedFolderUids = append(s.DeletedFolderUids, uid) s.DeletedFolderUids = append(s.DeletedFolderUids, uid)
return s.DeleteFolderResult, s.DeleteFolderError return s.DeleteFolderResult, s.DeleteFolderError
} }
+6 -5
View File
@@ -15,6 +15,7 @@ import (
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/org"
pref "github.com/grafana/grafana/pkg/services/preference" pref "github.com/grafana/grafana/pkg/services/preference"
"github.com/grafana/grafana/pkg/services/star" "github.com/grafana/grafana/pkg/services/star"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
@@ -162,7 +163,7 @@ func enableServiceAccount(hs *HTTPServer, c *models.ReqContext) bool {
} }
func (hs *HTTPServer) ReqCanAdminTeams(c *models.ReqContext) bool { func (hs *HTTPServer) ReqCanAdminTeams(c *models.ReqContext) bool {
return c.OrgRole == models.ROLE_ADMIN || (hs.Cfg.EditorsCanAdmin && c.OrgRole == models.ROLE_EDITOR) return c.OrgRole == org.RoleAdmin || (hs.Cfg.EditorsCanAdmin && c.OrgRole == org.RoleEditor)
} }
func (hs *HTTPServer) getNavTree(c *models.ReqContext, hasEditPerm bool, prefs *pref.Preference) ([]*dtos.NavLink, error) { func (hs *HTTPServer) getNavTree(c *models.ReqContext, hasEditPerm bool, prefs *pref.Preference) ([]*dtos.NavLink, error) {
@@ -202,7 +203,7 @@ func (hs *HTTPServer) getNavTree(c *models.ReqContext, hasEditPerm bool, prefs *
} }
canExplore := func(context *models.ReqContext) bool { canExplore := func(context *models.ReqContext) bool {
return c.OrgRole == models.ROLE_ADMIN || c.OrgRole == models.ROLE_EDITOR || setting.ViewersCanEdit return c.OrgRole == org.RoleAdmin || c.OrgRole == org.RoleEditor || setting.ViewersCanEdit
} }
if setting.ExploreEnabled && hasAccess(canExplore, ac.EvalPermission(ac.ActionDatasourcesExplore)) { if setting.ExploreEnabled && hasAccess(canExplore, ac.EvalPermission(ac.ActionDatasourcesExplore)) {
@@ -284,7 +285,7 @@ func (hs *HTTPServer) getNavTree(c *models.ReqContext, hasEditPerm bool, prefs *
}) })
} }
if c.OrgRole == models.ROLE_ADMIN { if c.OrgRole == org.RoleAdmin {
configNodes = append(configNodes, &dtos.NavLink{ configNodes = append(configNodes, &dtos.NavLink{
Text: "Plugins", Text: "Plugins",
Id: "plugins", Id: "plugins",
@@ -537,7 +538,7 @@ func (hs *HTTPServer) buildLegacyAlertNavLinks(c *models.ReqContext) []*dtos.Nav
Text: "Alert rules", Id: "alert-list", Url: hs.Cfg.AppSubURL + "/alerting/list", Icon: "list-ul", Text: "Alert rules", Id: "alert-list", Url: hs.Cfg.AppSubURL + "/alerting/list", Icon: "list-ul",
}) })
if c.HasRole(models.ROLE_EDITOR) { if c.HasRole(org.RoleEditor) {
alertChildNavs = append(alertChildNavs, &dtos.NavLink{ alertChildNavs = append(alertChildNavs, &dtos.NavLink{
Text: "Notification channels", Id: "channels", Url: hs.Cfg.AppSubURL + "/alerting/notifications", Text: "Notification channels", Id: "channels", Url: hs.Cfg.AppSubURL + "/alerting/notifications",
Icon: "comment-alt-share", Icon: "comment-alt-share",
@@ -581,7 +582,7 @@ func (hs *HTTPServer) buildAlertNavLinks(c *models.ReqContext) []*dtos.NavLink {
alertChildNavs = append(alertChildNavs, &dtos.NavLink{Text: "Alert groups", Id: "groups", Url: hs.Cfg.AppSubURL + "/alerting/groups", Icon: "layer-group"}) alertChildNavs = append(alertChildNavs, &dtos.NavLink{Text: "Alert groups", Id: "groups", Url: hs.Cfg.AppSubURL + "/alerting/groups", Icon: "layer-group"})
} }
if c.OrgRole == models.ROLE_ADMIN { if c.OrgRole == org.RoleAdmin {
alertChildNavs = append(alertChildNavs, &dtos.NavLink{ alertChildNavs = append(alertChildNavs, &dtos.NavLink{
Text: "Admin", Id: "alerting-admin", Url: hs.Cfg.AppSubURL + "/alerting/admin", Text: "Admin", Id: "alerting-admin", Url: hs.Cfg.AppSubURL + "/alerting/admin",
Icon: "cog", Icon: "cog",
+6 -5
View File
@@ -14,6 +14,7 @@ import (
"github.com/grafana/grafana/pkg/services/ldap" "github.com/grafana/grafana/pkg/services/ldap"
"github.com/grafana/grafana/pkg/services/login" "github.com/grafana/grafana/pkg/services/login"
"github.com/grafana/grafana/pkg/services/multildap" "github.com/grafana/grafana/pkg/services/multildap"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
@@ -39,10 +40,10 @@ type LDAPAttribute struct {
// RoleDTO is a serializer for mapped roles from LDAP // RoleDTO is a serializer for mapped roles from LDAP
type LDAPRoleDTO struct { type LDAPRoleDTO struct {
OrgId int64 `json:"orgId"` OrgId int64 `json:"orgId"`
OrgName string `json:"orgName"` OrgName string `json:"orgName"`
OrgRole models.RoleType `json:"orgRole"` OrgRole org.RoleType `json:"orgRole"`
GroupDN string `json:"groupDN"` GroupDN string `json:"groupDN"`
} }
// LDAPUserDTO is a serializer for users mapped from LDAP // LDAPUserDTO is a serializer for users mapped from LDAP
@@ -333,7 +334,7 @@ func (hs *HTTPServer) GetUserFromLDAP(c *models.ReqContext) response.Response {
} }
orgIDs := []int64{} // IDs of the orgs the user is a member of orgIDs := []int64{} // IDs of the orgs the user is a member of
orgRolesMap := map[int64]models.RoleType{} orgRolesMap := map[int64]org.RoleType{}
for _, group := range serverConfig.Groups { for _, group := range serverConfig.Groups {
// only use the first match for each org // only use the first match for each org
if orgRolesMap[group.OrgId] != "" { if orgRolesMap[group.OrgId] != "" {
+9 -8
View File
@@ -20,6 +20,7 @@ import (
"github.com/grafana/grafana/pkg/services/login/loginservice" "github.com/grafana/grafana/pkg/services/login/loginservice"
"github.com/grafana/grafana/pkg/services/login/logintest" "github.com/grafana/grafana/pkg/services/login/logintest"
"github.com/grafana/grafana/pkg/services/multildap" "github.com/grafana/grafana/pkg/services/multildap"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/services/user/usertest" "github.com/grafana/grafana/pkg/services/user/usertest"
@@ -107,7 +108,7 @@ func TestGetUserFromLDAPAPIEndpoint_OrgNotfound(t *testing.T) {
Email: "john.doe@example.com", Email: "john.doe@example.com",
Login: "johndoe", Login: "johndoe",
Groups: []string{"cn=admins,ou=groups,dc=grafana,dc=org"}, Groups: []string{"cn=admins,ou=groups,dc=grafana,dc=org"},
OrgRoles: map[int64]models.RoleType{1: models.ROLE_ADMIN, 2: models.ROLE_VIEWER}, OrgRoles: map[int64]org.RoleType{1: org.RoleAdmin, 2: org.RoleViewer},
IsGrafanaAdmin: &isAdmin, IsGrafanaAdmin: &isAdmin,
} }
@@ -122,12 +123,12 @@ func TestGetUserFromLDAPAPIEndpoint_OrgNotfound(t *testing.T) {
{ {
GroupDN: "cn=admins,ou=groups,dc=grafana,dc=org", GroupDN: "cn=admins,ou=groups,dc=grafana,dc=org",
OrgId: 1, OrgId: 1,
OrgRole: models.ROLE_ADMIN, OrgRole: org.RoleAdmin,
}, },
{ {
GroupDN: "cn=admins,ou=groups,dc=grafana,dc=org", GroupDN: "cn=admins,ou=groups,dc=grafana,dc=org",
OrgId: 2, OrgId: 2,
OrgRole: models.ROLE_VIEWER, OrgRole: org.RoleViewer,
}, },
}, },
} }
@@ -162,7 +163,7 @@ func TestGetUserFromLDAPAPIEndpoint(t *testing.T) {
Email: "john.doe@example.com", Email: "john.doe@example.com",
Login: "johndoe", Login: "johndoe",
Groups: []string{"cn=admins,ou=groups,dc=grafana,dc=org", "another-group-not-matched"}, Groups: []string{"cn=admins,ou=groups,dc=grafana,dc=org", "another-group-not-matched"},
OrgRoles: map[int64]models.RoleType{1: models.ROLE_ADMIN}, OrgRoles: map[int64]org.RoleType{1: org.RoleAdmin},
IsGrafanaAdmin: &isAdmin, IsGrafanaAdmin: &isAdmin,
} }
@@ -177,12 +178,12 @@ func TestGetUserFromLDAPAPIEndpoint(t *testing.T) {
{ {
GroupDN: "cn=admins,ou=groups,dc=grafana,dc=org", GroupDN: "cn=admins,ou=groups,dc=grafana,dc=org",
OrgId: 1, OrgId: 1,
OrgRole: models.ROLE_ADMIN, OrgRole: org.RoleAdmin,
}, },
{ {
GroupDN: "cn=admins2,ou=groups,dc=grafana,dc=org", GroupDN: "cn=admins2,ou=groups,dc=grafana,dc=org",
OrgId: 1, OrgId: 1,
OrgRole: models.ROLE_ADMIN, OrgRole: org.RoleAdmin,
}, },
}, },
} }
@@ -237,7 +238,7 @@ func TestGetUserFromLDAPAPIEndpoint_WithTeamHandler(t *testing.T) {
Email: "john.doe@example.com", Email: "john.doe@example.com",
Login: "johndoe", Login: "johndoe",
Groups: []string{"cn=admins,ou=groups,dc=grafana,dc=org"}, Groups: []string{"cn=admins,ou=groups,dc=grafana,dc=org"},
OrgRoles: map[int64]models.RoleType{1: models.ROLE_ADMIN}, OrgRoles: map[int64]org.RoleType{1: org.RoleAdmin},
IsGrafanaAdmin: &isAdmin, IsGrafanaAdmin: &isAdmin,
} }
@@ -252,7 +253,7 @@ func TestGetUserFromLDAPAPIEndpoint_WithTeamHandler(t *testing.T) {
{ {
GroupDN: "cn=admins,ou=groups,dc=grafana,dc=org", GroupDN: "cn=admins,ou=groups,dc=grafana,dc=org",
OrgId: 1, OrgId: 1,
OrgRole: models.ROLE_ADMIN, OrgRole: org.RoleAdmin,
}, },
}, },
} }
+3 -2
View File
@@ -19,6 +19,7 @@ import (
"github.com/grafana/grafana/pkg/login/social" "github.com/grafana/grafana/pkg/login/social"
"github.com/grafana/grafana/pkg/middleware/cookies" "github.com/grafana/grafana/pkg/middleware/cookies"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
@@ -268,12 +269,12 @@ func (hs *HTTPServer) buildExternalUserInfo(token *oauth2.Token, userInfo *socia
Name: userInfo.Name, Name: userInfo.Name,
Login: userInfo.Login, Login: userInfo.Login,
Email: userInfo.Email, Email: userInfo.Email,
OrgRoles: map[int64]models.RoleType{}, OrgRoles: map[int64]org.RoleType{},
Groups: userInfo.Groups, Groups: userInfo.Groups,
} }
if userInfo.Role != "" && !hs.Cfg.OAuthSkipOrgRoleUpdateSync { if userInfo.Role != "" && !hs.Cfg.OAuthSkipOrgRoleUpdateSync {
rt := models.RoleType(userInfo.Role) rt := org.RoleType(userInfo.Role)
if rt.IsValid() { if rt.IsValid() {
// The user will be assigned a role in either the auto-assigned organization or in the default one // The user will be assigned a role in either the auto-assigned organization or in the default one
var orgID int64 var orgID int64
+2 -2
View File
@@ -154,7 +154,7 @@ func TestLoginViewRedirect(t *testing.T) {
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.IsSignedIn = true c.IsSignedIn = true
c.SignedInUser = &models.SignedInUser{ c.SignedInUser = &user.SignedInUser{
UserId: 10, UserId: 10,
} }
hs.LoginView(c) hs.LoginView(c)
@@ -571,7 +571,7 @@ func setupAuthProxyLoginTest(t *testing.T, enableLoginToken bool) *scenarioConte
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.IsSignedIn = true c.IsSignedIn = true
c.SignedInUser = &models.SignedInUser{ c.SignedInUser = &user.SignedInUser{
UserId: 10, UserId: 10,
} }
hs.LoginView(c) hs.LoginView(c)
+6 -5
View File
@@ -14,12 +14,13 @@ import (
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/quota/quotatest" "github.com/grafana/grafana/pkg/services/quota/quotatest"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/web/webtest" "github.com/grafana/grafana/pkg/web/webtest"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"github.com/grafana/grafana/pkg/models"
fakeDatasources "github.com/grafana/grafana/pkg/services/datasources/fakes" fakeDatasources "github.com/grafana/grafana/pkg/services/datasources/fakes"
"github.com/grafana/grafana/pkg/services/query" "github.com/grafana/grafana/pkg/services/query"
) )
@@ -57,7 +58,7 @@ type fakeOAuthTokenService struct {
token *oauth2.Token token *oauth2.Token
} }
func (ts *fakeOAuthTokenService) GetCurrentOAuthToken(context.Context, *models.SignedInUser) *oauth2.Token { func (ts *fakeOAuthTokenService) GetCurrentOAuthToken(context.Context, *user.SignedInUser) *oauth2.Token {
return ts.token return ts.token
} }
@@ -98,7 +99,7 @@ func TestAPIEndpoint_Metrics_QueryMetricsV2(t *testing.T) {
t.Run("Status code is 400 when data source response has an error and feature toggle is disabled", func(t *testing.T) { t.Run("Status code is 400 when data source response has an error and feature toggle is disabled", func(t *testing.T) {
req := serverFeatureDisabled.NewPostRequest("/api/ds/query", strings.NewReader(queryDatasourceInput)) req := serverFeatureDisabled.NewPostRequest("/api/ds/query", strings.NewReader(queryDatasourceInput))
webtest.RequestWithSignedInUser(req, &models.SignedInUser{UserId: 1, OrgId: 1, OrgRole: models.ROLE_VIEWER}) webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserId: 1, OrgId: 1, OrgRole: org.RoleViewer})
resp, err := serverFeatureDisabled.SendJSON(req) resp, err := serverFeatureDisabled.SendJSON(req)
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, resp.Body.Close()) require.NoError(t, resp.Body.Close())
@@ -107,7 +108,7 @@ func TestAPIEndpoint_Metrics_QueryMetricsV2(t *testing.T) {
t.Run("Status code is 207 when data source response has an error and feature toggle is enabled", func(t *testing.T) { t.Run("Status code is 207 when data source response has an error and feature toggle is enabled", func(t *testing.T) {
req := serverFeatureEnabled.NewPostRequest("/api/ds/query", strings.NewReader(queryDatasourceInput)) req := serverFeatureEnabled.NewPostRequest("/api/ds/query", strings.NewReader(queryDatasourceInput))
webtest.RequestWithSignedInUser(req, &models.SignedInUser{UserId: 1, OrgId: 1, OrgRole: models.ROLE_VIEWER}) webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserId: 1, OrgId: 1, OrgRole: org.RoleViewer})
resp, err := serverFeatureEnabled.SendJSON(req) resp, err := serverFeatureEnabled.SendJSON(req)
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, resp.Body.Close()) require.NoError(t, resp.Body.Close())
@@ -141,7 +142,7 @@ func TestAPIEndpoint_Metrics_PluginDecryptionFailure(t *testing.T) {
t.Run("Status code is 500 and a secrets plugin error is returned if there is a problem getting secrets from the remote plugin", func(t *testing.T) { t.Run("Status code is 500 and a secrets plugin error is returned if there is a problem getting secrets from the remote plugin", func(t *testing.T) {
req := httpServer.NewPostRequest("/api/ds/query", strings.NewReader(queryDatasourceInput)) req := httpServer.NewPostRequest("/api/ds/query", strings.NewReader(queryDatasourceInput))
webtest.RequestWithSignedInUser(req, &models.SignedInUser{UserId: 1, OrgId: 1, OrgRole: models.ROLE_VIEWER}) webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserId: 1, OrgId: 1, OrgRole: org.RoleViewer})
resp, err := httpServer.SendJSON(req) resp, err := httpServer.SendJSON(req)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, http.StatusInternalServerError, resp.StatusCode) require.Equal(t, http.StatusInternalServerError, resp.StatusCode)
+6 -6
View File
@@ -7,8 +7,8 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/services/user/usertest" "github.com/grafana/grafana/pkg/services/user/usertest"
) )
@@ -29,7 +29,7 @@ func TestOrgInvitesAPIEndpointAccess(t *testing.T) {
url: "/api/org/invites", url: "/api/org/invites",
method: http.MethodPost, method: http.MethodPost,
permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersAdd, Scope: accesscontrol.ScopeUsersAll}}, permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersAdd, Scope: accesscontrol.ScopeUsersAll}},
input: `{"loginOrEmail": "` + testAdminOrg2.Login + `", "role": "` + string(models.ROLE_VIEWER) + `"}`, input: `{"loginOrEmail": "` + testAdminOrg2.Login + `", "role": "` + string(org.RoleViewer) + `"}`,
}, },
{ {
expectedCode: http.StatusForbidden, expectedCode: http.StatusForbidden,
@@ -37,7 +37,7 @@ func TestOrgInvitesAPIEndpointAccess(t *testing.T) {
url: "/api/org/invites", url: "/api/org/invites",
method: http.MethodPost, method: http.MethodPost,
permissions: []accesscontrol.Permission{}, permissions: []accesscontrol.Permission{},
input: `{"loginOrEmail": "` + testAdminOrg2.Login + `", "role": "` + string(models.ROLE_VIEWER) + `"}`, input: `{"loginOrEmail": "` + testAdminOrg2.Login + `", "role": "` + string(org.RoleViewer) + `"}`,
}, },
{ {
expectedCode: http.StatusForbidden, expectedCode: http.StatusForbidden,
@@ -45,7 +45,7 @@ func TestOrgInvitesAPIEndpointAccess(t *testing.T) {
url: "/api/org/invites", url: "/api/org/invites",
method: http.MethodPost, method: http.MethodPost,
permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersAdd, Scope: "users:id:100"}}, permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersAdd, Scope: "users:id:100"}},
input: `{"loginOrEmail": "` + testAdminOrg2.Login + `", "role": "` + string(models.ROLE_VIEWER) + `"}`, input: `{"loginOrEmail": "` + testAdminOrg2.Login + `", "role": "` + string(org.RoleViewer) + `"}`,
}, },
{ {
expectedCode: http.StatusOK, expectedCode: http.StatusOK,
@@ -53,7 +53,7 @@ func TestOrgInvitesAPIEndpointAccess(t *testing.T) {
url: "/api/org/invites", url: "/api/org/invites",
method: http.MethodPost, method: http.MethodPost,
permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersAdd, Scope: accesscontrol.ScopeUsersAll}}, permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersAdd, Scope: accesscontrol.ScopeUsersAll}},
input: `{"loginOrEmail": "new user", "role": "` + string(models.ROLE_VIEWER) + `"}`, input: `{"loginOrEmail": "new user", "role": "` + string(org.RoleViewer) + `"}`,
}, },
{ {
expectedCode: http.StatusForbidden, expectedCode: http.StatusForbidden,
@@ -61,7 +61,7 @@ func TestOrgInvitesAPIEndpointAccess(t *testing.T) {
url: "/api/org/invites", url: "/api/org/invites",
method: http.MethodPost, method: http.MethodPost,
permissions: []accesscontrol.Permission{}, permissions: []accesscontrol.Permission{},
input: `{"loginOrEmail": "new user", "role": "` + string(models.ROLE_VIEWER) + `"}`, input: `{"loginOrEmail": "new user", "role": "` + string(org.RoleViewer) + `"}`,
}, },
} }
+1 -1
View File
@@ -186,7 +186,7 @@ func TestAPIEndpoint_PutCurrentOrgAddress_AccessControl(t *testing.T) {
// `/api/orgs/` endpoints test // `/api/orgs/` endpoints test
// setupOrgsDBForAccessControlTests stores users and create specified number of orgs // setupOrgsDBForAccessControlTests stores users and create specified number of orgs
func setupOrgsDBForAccessControlTests(t *testing.T, db sqlstore.Store, usr models.SignedInUser, orgsCount int) { func setupOrgsDBForAccessControlTests(t *testing.T, db sqlstore.Store, usr user.SignedInUser, orgsCount int) {
t.Helper() t.Helper()
_, err := db.CreateUser(context.Background(), user.CreateUserCommand{Email: usr.Email, SkipOrgSetup: true, Login: usr.Login}) _, err := db.CreateUser(context.Background(), user.CreateUserCommand{Email: usr.Email, SkipOrgSetup: true, Login: usr.Login})
+1 -1
View File
@@ -201,7 +201,7 @@ func (hs *HTTPServer) GetOrgUsers(c *models.ReqContext) response.Response {
return response.JSON(http.StatusOK, result) return response.JSON(http.StatusOK, result)
} }
func (hs *HTTPServer) getOrgUsersHelper(c *models.ReqContext, query *models.GetOrgUsersQuery, signedInUser *models.SignedInUser) ([]*models.OrgUserDTO, error) { func (hs *HTTPServer) getOrgUsersHelper(c *models.ReqContext, query *models.GetOrgUsersQuery, signedInUser *user.SignedInUser) ([]*models.OrgUserDTO, error) {
if err := hs.SQLStore.GetOrgUsers(c.Req.Context(), query); err != nil { if err := hs.SQLStore.GetOrgUsers(c.Req.Context(), query); err != nil {
return nil, err return nil, err
} }
+31 -30
View File
@@ -17,6 +17,7 @@ import (
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/featuremgmt" "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/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/services/user"
@@ -118,7 +119,7 @@ func TestOrgUsersAPIEndpoint_userLoggedIn(t *testing.T) {
}, mock) }, mock)
loggedInUserScenarioWithRole(t, "When calling GET as an admin on", "GET", "api/org/users/lookup", loggedInUserScenarioWithRole(t, "When calling GET as an admin on", "GET", "api/org/users/lookup",
"api/org/users/lookup", models.ROLE_ADMIN, func(sc *scenarioContext) { "api/org/users/lookup", org.RoleAdmin, func(sc *scenarioContext) {
setUpGetOrgUsersDB(t, sqlStore) setUpGetOrgUsersDB(t, sqlStore)
sc.handlerFunc = hs.GetOrgUsersForCurrentOrgLookup sc.handlerFunc = hs.GetOrgUsersForCurrentOrgLookup
@@ -234,11 +235,11 @@ func TestOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
} }
var ( var (
testServerAdminViewer = models.SignedInUser{ testServerAdminViewer = user.SignedInUser{
UserId: 1, UserId: 1,
OrgId: 1, OrgId: 1,
OrgName: "TestOrg1", OrgName: "TestOrg1",
OrgRole: models.ROLE_VIEWER, OrgRole: org.RoleViewer,
Login: "testServerAdmin", Login: "testServerAdmin",
Name: "testServerAdmin", Name: "testServerAdmin",
Email: "testServerAdmin@example.org", Email: "testServerAdmin@example.org",
@@ -247,11 +248,11 @@ var (
IsAnonymous: false, IsAnonymous: false,
} }
testAdminOrg2 = models.SignedInUser{ testAdminOrg2 = user.SignedInUser{
UserId: 2, UserId: 2,
OrgId: 2, OrgId: 2,
OrgName: "TestOrg2", OrgName: "TestOrg2",
OrgRole: models.ROLE_ADMIN, OrgRole: org.RoleAdmin,
Login: "testAdmin", Login: "testAdmin",
Name: "testAdmin", Name: "testAdmin",
Email: "testAdmin@example.org", Email: "testAdmin@example.org",
@@ -260,11 +261,11 @@ var (
IsAnonymous: false, IsAnonymous: false,
} }
testEditorOrg1 = models.SignedInUser{ testEditorOrg1 = user.SignedInUser{
UserId: 3, UserId: 3,
OrgId: 1, OrgId: 1,
OrgName: "TestOrg1", OrgName: "TestOrg1",
OrgRole: models.ROLE_EDITOR, OrgRole: org.RoleEditor,
Login: "testEditor", Login: "testEditor",
Name: "testEditor", Name: "testEditor",
Email: "testEditor@example.org", Email: "testEditor@example.org",
@@ -308,7 +309,7 @@ func TestGetOrgUsersAPIEndpoint_AccessControlMetadata(t *testing.T) {
enableAccessControl bool enableAccessControl bool
expectedCode int expectedCode int
expectedMetadata map[string]bool expectedMetadata map[string]bool
user models.SignedInUser user user.SignedInUser
targetOrg int64 targetOrg int64
} }
@@ -365,7 +366,7 @@ func TestGetOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
enableAccessControl bool enableAccessControl bool
expectedCode int expectedCode int
expectedUserCount int expectedUserCount int
user models.SignedInUser user user.SignedInUser
targetOrg int64 targetOrg int64
} }
@@ -458,7 +459,7 @@ func TestPostOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
type testCase struct { type testCase struct {
name string name string
enableAccessControl bool enableAccessControl bool
user models.SignedInUser user user.SignedInUser
targetOrg int64 targetOrg int64
input string input string
expectedCode int expectedCode int
@@ -553,7 +554,7 @@ func TestPostOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
err := json.NewDecoder(response.Body).Decode(&message) err := json.NewDecoder(response.Body).Decode(&message)
require.NoError(t, err) require.NoError(t, err)
getUsersQuery := models.GetOrgUsersQuery{OrgId: tc.targetOrg, User: &models.SignedInUser{ getUsersQuery := models.GetOrgUsersQuery{OrgId: tc.targetOrg, User: &user.SignedInUser{
OrgId: tc.targetOrg, OrgId: tc.targetOrg,
Permissions: map[int64]map[string][]string{tc.targetOrg: {"org.users:read": {"users:*"}}}, Permissions: map[int64]map[string][]string{tc.targetOrg: {"org.users:read": {"users:*"}}},
}} }}
@@ -580,7 +581,7 @@ func TestOrgUsersAPIEndpointWithSetPerms_AccessControl(t *testing.T) {
url: "/api/org/users", url: "/api/org/users",
method: http.MethodPost, method: http.MethodPost,
permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersAdd, Scope: accesscontrol.ScopeUsersAll}}, permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersAdd, Scope: accesscontrol.ScopeUsersAll}},
input: `{"loginOrEmail": "` + testAdminOrg2.Login + `", "role": "` + string(models.ROLE_VIEWER) + `"}`, input: `{"loginOrEmail": "` + testAdminOrg2.Login + `", "role": "` + string(org.RoleViewer) + `"}`,
}, },
{ {
expectedCode: http.StatusForbidden, expectedCode: http.StatusForbidden,
@@ -588,7 +589,7 @@ func TestOrgUsersAPIEndpointWithSetPerms_AccessControl(t *testing.T) {
url: "/api/org/users", url: "/api/org/users",
method: http.MethodPost, method: http.MethodPost,
permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersAdd, Scope: accesscontrol.ScopeUsersAll}}, permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersAdd, Scope: accesscontrol.ScopeUsersAll}},
input: `{"loginOrEmail": "` + testAdminOrg2.Login + `", "role": "` + string(models.ROLE_EDITOR) + `"}`, input: `{"loginOrEmail": "` + testAdminOrg2.Login + `", "role": "` + string(org.RoleEditor) + `"}`,
}, },
{ {
expectedCode: http.StatusOK, expectedCode: http.StatusOK,
@@ -596,7 +597,7 @@ func TestOrgUsersAPIEndpointWithSetPerms_AccessControl(t *testing.T) {
url: "/api/orgs/1/users", url: "/api/orgs/1/users",
method: http.MethodPost, method: http.MethodPost,
permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersAdd, Scope: accesscontrol.ScopeUsersAll}}, permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersAdd, Scope: accesscontrol.ScopeUsersAll}},
input: `{"loginOrEmail": "` + testAdminOrg2.Login + `", "role": "` + string(models.ROLE_VIEWER) + `"}`, input: `{"loginOrEmail": "` + testAdminOrg2.Login + `", "role": "` + string(org.RoleViewer) + `"}`,
}, },
{ {
expectedCode: http.StatusForbidden, expectedCode: http.StatusForbidden,
@@ -604,7 +605,7 @@ func TestOrgUsersAPIEndpointWithSetPerms_AccessControl(t *testing.T) {
url: "/api/orgs/1/users", url: "/api/orgs/1/users",
method: http.MethodPost, method: http.MethodPost,
permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersAdd, Scope: accesscontrol.ScopeUsersAll}}, permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersAdd, Scope: accesscontrol.ScopeUsersAll}},
input: `{"loginOrEmail": "` + testAdminOrg2.Login + `", "role": "` + string(models.ROLE_EDITOR) + `"}`, input: `{"loginOrEmail": "` + testAdminOrg2.Login + `", "role": "` + string(org.RoleEditor) + `"}`,
}, },
{ {
expectedCode: http.StatusOK, expectedCode: http.StatusOK,
@@ -612,7 +613,7 @@ func TestOrgUsersAPIEndpointWithSetPerms_AccessControl(t *testing.T) {
url: fmt.Sprintf("/api/org/users/%d", testEditorOrg1.UserId), url: fmt.Sprintf("/api/org/users/%d", testEditorOrg1.UserId),
method: http.MethodPatch, method: http.MethodPatch,
permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersWrite, Scope: accesscontrol.ScopeUsersAll}}, permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersWrite, Scope: accesscontrol.ScopeUsersAll}},
input: `{"role": "` + string(models.ROLE_VIEWER) + `"}`, input: `{"role": "` + string(org.RoleViewer) + `"}`,
}, },
{ {
expectedCode: http.StatusForbidden, expectedCode: http.StatusForbidden,
@@ -620,7 +621,7 @@ func TestOrgUsersAPIEndpointWithSetPerms_AccessControl(t *testing.T) {
url: fmt.Sprintf("/api/org/users/%d", testEditorOrg1.UserId), url: fmt.Sprintf("/api/org/users/%d", testEditorOrg1.UserId),
method: http.MethodPatch, method: http.MethodPatch,
permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersWrite, Scope: accesscontrol.ScopeUsersAll}}, permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersWrite, Scope: accesscontrol.ScopeUsersAll}},
input: `{"role": "` + string(models.ROLE_EDITOR) + `"}`, input: `{"role": "` + string(org.RoleEditor) + `"}`,
}, },
{ {
expectedCode: http.StatusOK, expectedCode: http.StatusOK,
@@ -628,7 +629,7 @@ func TestOrgUsersAPIEndpointWithSetPerms_AccessControl(t *testing.T) {
url: fmt.Sprintf("/api/orgs/1/users/%d", testEditorOrg1.UserId), url: fmt.Sprintf("/api/orgs/1/users/%d", testEditorOrg1.UserId),
method: http.MethodPatch, method: http.MethodPatch,
permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersWrite, Scope: accesscontrol.ScopeUsersAll}}, permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersWrite, Scope: accesscontrol.ScopeUsersAll}},
input: `{"role": "` + string(models.ROLE_VIEWER) + `"}`, input: `{"role": "` + string(org.RoleViewer) + `"}`,
}, },
{ {
expectedCode: http.StatusForbidden, expectedCode: http.StatusForbidden,
@@ -636,7 +637,7 @@ func TestOrgUsersAPIEndpointWithSetPerms_AccessControl(t *testing.T) {
url: fmt.Sprintf("/api/orgs/1/users/%d", testEditorOrg1.UserId), url: fmt.Sprintf("/api/orgs/1/users/%d", testEditorOrg1.UserId),
method: http.MethodPatch, method: http.MethodPatch,
permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersWrite, Scope: accesscontrol.ScopeUsersAll}}, permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersWrite, Scope: accesscontrol.ScopeUsersAll}},
input: `{"role": "` + string(models.ROLE_EDITOR) + `"}`, input: `{"role": "` + string(org.RoleEditor) + `"}`,
}, },
{ {
expectedCode: http.StatusOK, expectedCode: http.StatusOK,
@@ -644,7 +645,7 @@ func TestOrgUsersAPIEndpointWithSetPerms_AccessControl(t *testing.T) {
url: "/api/org/invites", url: "/api/org/invites",
method: http.MethodPost, method: http.MethodPost,
permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersAdd, Scope: accesscontrol.ScopeUsersAll}}, permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionOrgUsersAdd, Scope: accesscontrol.ScopeUsersAll}},
input: `{"loginOrEmail": "newUserEmail@test.com", "sendEmail": false, "role": "` + string(models.ROLE_VIEWER) + `"}`, input: `{"loginOrEmail": "newUserEmail@test.com", "sendEmail": false, "role": "` + string(org.RoleViewer) + `"}`,
}, },
{ {
expectedCode: http.StatusForbidden, expectedCode: http.StatusForbidden,
@@ -652,7 +653,7 @@ func TestOrgUsersAPIEndpointWithSetPerms_AccessControl(t *testing.T) {
url: "/api/org/invites", url: "/api/org/invites",
method: http.MethodPost, method: http.MethodPost,
permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionUsersCreate}}, permissions: []accesscontrol.Permission{{Action: accesscontrol.ActionUsersCreate}},
input: `{"loginOrEmail": "newUserEmail@test.com", "sendEmail": false, "role": "` + string(models.ROLE_EDITOR) + `"}`, input: `{"loginOrEmail": "newUserEmail@test.com", "sendEmail": false, "role": "` + string(org.RoleEditor) + `"}`,
}, },
} }
@@ -678,13 +679,13 @@ func TestPatchOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
type testCase struct { type testCase struct {
name string name string
enableAccessControl bool enableAccessControl bool
user models.SignedInUser user user.SignedInUser
targetUserId int64 targetUserId int64
targetOrg int64 targetOrg int64
input string input string
expectedCode int expectedCode int
expectedMessage util.DynMap expectedMessage util.DynMap
expectedUserRole models.RoleType expectedUserRole org.RoleType
} }
tests := []testCase{ tests := []testCase{
@@ -697,7 +698,7 @@ func TestPatchOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
input: `{"role": "Viewer"}`, input: `{"role": "Viewer"}`,
expectedCode: http.StatusOK, expectedCode: http.StatusOK,
expectedMessage: util.DynMap{"message": "Organization user updated"}, expectedMessage: util.DynMap{"message": "Organization user updated"},
expectedUserRole: models.ROLE_VIEWER, expectedUserRole: org.RoleViewer,
}, },
{ {
name: "server admin can update users in another org (legacy)", name: "server admin can update users in another org (legacy)",
@@ -708,7 +709,7 @@ func TestPatchOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
input: `{"role": "Editor"}`, input: `{"role": "Editor"}`,
expectedCode: http.StatusOK, expectedCode: http.StatusOK,
expectedMessage: util.DynMap{"message": "Organization user updated"}, expectedMessage: util.DynMap{"message": "Organization user updated"},
expectedUserRole: models.ROLE_EDITOR, expectedUserRole: org.RoleEditor,
}, },
{ {
name: "org admin cannot update users in his org (legacy)", name: "org admin cannot update users in his org (legacy)",
@@ -737,7 +738,7 @@ func TestPatchOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
input: `{"role": "Viewer"}`, input: `{"role": "Viewer"}`,
expectedCode: http.StatusOK, expectedCode: http.StatusOK,
expectedMessage: util.DynMap{"message": "Organization user updated"}, expectedMessage: util.DynMap{"message": "Organization user updated"},
expectedUserRole: models.ROLE_VIEWER, expectedUserRole: org.RoleViewer,
}, },
{ {
name: "server admin can update users in another org", name: "server admin can update users in another org",
@@ -748,7 +749,7 @@ func TestPatchOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
input: `{"role": "Editor"}`, input: `{"role": "Editor"}`,
expectedCode: http.StatusOK, expectedCode: http.StatusOK,
expectedMessage: util.DynMap{"message": "Organization user updated"}, expectedMessage: util.DynMap{"message": "Organization user updated"},
expectedUserRole: models.ROLE_EDITOR, expectedUserRole: org.RoleEditor,
}, },
{ {
name: "org admin can update users in his org", name: "org admin can update users in his org",
@@ -759,7 +760,7 @@ func TestPatchOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
input: `{"role": "Editor"}`, input: `{"role": "Editor"}`,
expectedCode: http.StatusOK, expectedCode: http.StatusOK,
expectedMessage: util.DynMap{"message": "Organization user updated"}, expectedMessage: util.DynMap{"message": "Organization user updated"},
expectedUserRole: models.ROLE_EDITOR, expectedUserRole: org.RoleEditor,
}, },
{ {
name: "org admin cannot update users in another org", name: "org admin cannot update users in another org",
@@ -807,7 +808,7 @@ func TestDeleteOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
type testCase struct { type testCase struct {
name string name string
enableAccessControl bool enableAccessControl bool
user models.SignedInUser user user.SignedInUser
targetUserId int64 targetUserId int64
targetOrg int64 targetOrg int64
expectedCode int expectedCode int
@@ -909,7 +910,7 @@ func TestDeleteOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
getUsersQuery := models.GetOrgUsersQuery{ getUsersQuery := models.GetOrgUsersQuery{
OrgId: tc.targetOrg, OrgId: tc.targetOrg,
User: &models.SignedInUser{ User: &user.SignedInUser{
OrgId: tc.targetOrg, OrgId: tc.targetOrg,
Permissions: map[int64]map[string][]string{tc.targetOrg: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}}}, Permissions: map[int64]map[string][]string{tc.targetOrg: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}}},
}, },
+3 -2
View File
@@ -9,6 +9,7 @@ import (
_ "github.com/grafana/grafana/pkg/infra/log" _ "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/search" "github.com/grafana/grafana/pkg/services/search"
"github.com/grafana/grafana/pkg/services/user"
) )
func (hs *HTTPServer) populateDashboardsByID(ctx context.Context, dashboardByIDs []int64, dashboardIDOrder map[int64]int) (dtos.PlaylistDashboardsSlice, error) { func (hs *HTTPServer) populateDashboardsByID(ctx context.Context, dashboardByIDs []int64, dashboardIDOrder map[int64]int) (dtos.PlaylistDashboardsSlice, error) {
@@ -35,7 +36,7 @@ func (hs *HTTPServer) populateDashboardsByID(ctx context.Context, dashboardByIDs
return result, nil return result, nil
} }
func (hs *HTTPServer) populateDashboardsByTag(ctx context.Context, orgID int64, signedInUser *models.SignedInUser, dashboardByTag []string, dashboardTagOrder map[string]int) dtos.PlaylistDashboardsSlice { func (hs *HTTPServer) populateDashboardsByTag(ctx context.Context, orgID int64, signedInUser *user.SignedInUser, dashboardByTag []string, dashboardTagOrder map[string]int) dtos.PlaylistDashboardsSlice {
result := make(dtos.PlaylistDashboardsSlice, 0) result := make(dtos.PlaylistDashboardsSlice, 0)
for _, tag := range dashboardByTag { for _, tag := range dashboardByTag {
@@ -65,7 +66,7 @@ func (hs *HTTPServer) populateDashboardsByTag(ctx context.Context, orgID int64,
return result return result
} }
func (hs *HTTPServer) LoadPlaylistDashboards(ctx context.Context, orgID int64, signedInUser *models.SignedInUser, playlistUID string) (dtos.PlaylistDashboardsSlice, error) { func (hs *HTTPServer) LoadPlaylistDashboards(ctx context.Context, orgID int64, signedInUser *user.SignedInUser, playlistUID string) (dtos.PlaylistDashboardsSlice, error) {
playlistItems, _ := hs.LoadPlaylistItems(ctx, playlistUID, orgID) playlistItems, _ := hs.LoadPlaylistItems(ctx, playlistUID, orgID)
dashboardByIDs := make([]int64, 0) dashboardByIDs := make([]int64, 0)
+7 -6
View File
@@ -8,10 +8,11 @@ import (
"net/http" "net/http"
"testing" "testing"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/plugindashboards" "github.com/grafana/grafana/pkg/services/plugindashboards"
"github.com/grafana/grafana/pkg/services/quota/quotatest" "github.com/grafana/grafana/pkg/services/quota/quotatest"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/web/webtest" "github.com/grafana/grafana/pkg/web/webtest"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -52,9 +53,9 @@ func TestGetPluginDashboards(t *testing.T) {
}) })
t.Run("Signed in and not org admin should return 403 Forbidden", func(t *testing.T) { t.Run("Signed in and not org admin should return 403 Forbidden", func(t *testing.T) {
user := &models.SignedInUser{ user := &user.SignedInUser{
UserId: 1, UserId: 1,
OrgRole: models.ROLE_EDITOR, OrgRole: org.RoleEditor,
} }
resp, err := sendGetPluginDashboardsRequestForSignedInUser(t, s, existingPluginID, user) resp, err := sendGetPluginDashboardsRequestForSignedInUser(t, s, existingPluginID, user)
@@ -64,10 +65,10 @@ func TestGetPluginDashboards(t *testing.T) {
}) })
t.Run("Signed in and org admin", func(t *testing.T) { t.Run("Signed in and org admin", func(t *testing.T) {
user := &models.SignedInUser{ user := &user.SignedInUser{
UserId: 1, UserId: 1,
OrgId: 1, OrgId: 1,
OrgRole: models.ROLE_ADMIN, OrgRole: org.RoleAdmin,
} }
t.Run("When plugin doesn't exist should return 404 Not Found", func(t *testing.T) { t.Run("When plugin doesn't exist should return 404 Not Found", func(t *testing.T) {
@@ -101,7 +102,7 @@ func TestGetPluginDashboards(t *testing.T) {
}) })
} }
func sendGetPluginDashboardsRequestForSignedInUser(t *testing.T, s *webtest.Server, pluginID string, user *models.SignedInUser) (*http.Response, error) { func sendGetPluginDashboardsRequestForSignedInUser(t *testing.T, s *webtest.Server, pluginID string, user *user.SignedInUser) (*http.Response, error) {
t.Helper() t.Helper()
req := s.NewGetRequest(fmt.Sprintf("/api/plugins/%s/dashboards", pluginID)) req := s.NewGetRequest(fmt.Sprintf("/api/plugins/%s/dashboards", pluginID))
+20 -18
View File
@@ -28,10 +28,12 @@ import (
datasourceservice "github.com/grafana/grafana/pkg/services/datasources/service" datasourceservice "github.com/grafana/grafana/pkg/services/datasources/service"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/oauthtoken" "github.com/grafana/grafana/pkg/services/oauthtoken"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/secrets" "github.com/grafana/grafana/pkg/services/secrets"
"github.com/grafana/grafana/pkg/services/secrets/fakes" "github.com/grafana/grafana/pkg/services/secrets/fakes"
"github.com/grafana/grafana/pkg/services/secrets/kvstore" "github.com/grafana/grafana/pkg/services/secrets/kvstore"
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
) )
@@ -46,7 +48,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
{ {
Path: "api/v4/", Path: "api/v4/",
URL: "https://www.google.com", URL: "https://www.google.com",
ReqRole: models.ROLE_EDITOR, ReqRole: org.RoleEditor,
Headers: []plugins.Header{ Headers: []plugins.Header{
{Name: "x-header", Content: "my secret {{.SecureJsonData.key}}"}, {Name: "x-header", Content: "my secret {{.SecureJsonData.key}}"},
}, },
@@ -54,7 +56,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
{ {
Path: "api/admin", Path: "api/admin",
URL: "https://www.google.com", URL: "https://www.google.com",
ReqRole: models.ROLE_ADMIN, ReqRole: org.RoleAdmin,
Headers: []plugins.Header{ Headers: []plugins.Header{
{Name: "x-header", Content: "my secret {{.SecureJsonData.key}}"}, {Name: "x-header", Content: "my secret {{.SecureJsonData.key}}"},
}, },
@@ -78,7 +80,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
}, },
{ {
Path: "api/restricted", Path: "api/restricted",
ReqRole: models.ROLE_ADMIN, ReqRole: org.RoleAdmin,
}, },
{ {
Path: "api/body", Path: "api/body",
@@ -125,7 +127,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
ctx := &models.ReqContext{ ctx := &models.ReqContext{
Context: &web.Context{Req: req}, Context: &web.Context{Req: req},
SignedInUser: &models.SignedInUser{OrgRole: models.ROLE_EDITOR}, SignedInUser: &user.SignedInUser{OrgRole: org.RoleEditor},
} }
return ctx, req return ctx, req
} }
@@ -200,7 +202,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
t.Run("plugin route with admin role and user is admin", func(t *testing.T) { t.Run("plugin route with admin role and user is admin", func(t *testing.T) {
ctx, _ := setUp() ctx, _ := setUp()
ctx.SignedInUser.OrgRole = models.ROLE_ADMIN ctx.SignedInUser.OrgRole = org.RoleAdmin
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService()) dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/admin", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer) proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/admin", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
require.NoError(t, err) require.NoError(t, err)
@@ -265,7 +267,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
ctx := &models.ReqContext{ ctx := &models.ReqContext{
Context: &web.Context{Req: req}, Context: &web.Context{Req: req},
SignedInUser: &models.SignedInUser{OrgRole: models.ROLE_EDITOR}, SignedInUser: &user.SignedInUser{OrgRole: org.RoleEditor},
} }
t.Run("When creating and caching access tokens", func(t *testing.T) { t.Run("When creating and caching access tokens", func(t *testing.T) {
@@ -479,7 +481,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
req, err := http.NewRequest("GET", "http://localhost/asd", nil) req, err := http.NewRequest("GET", "http://localhost/asd", nil)
require.NoError(t, err) require.NoError(t, err)
ctx := &models.ReqContext{ ctx := &models.ReqContext{
SignedInUser: &models.SignedInUser{UserId: 1}, SignedInUser: &user.SignedInUser{UserId: 1},
Context: &web.Context{Req: req}, Context: &web.Context{Req: req},
} }
@@ -517,7 +519,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
req := getDatasourceProxiedRequest( req := getDatasourceProxiedRequest(
t, t,
&models.ReqContext{ &models.ReqContext{
SignedInUser: &models.SignedInUser{ SignedInUser: &user.SignedInUser{
Login: "test_user", Login: "test_user",
}, },
}, },
@@ -530,7 +532,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
req := getDatasourceProxiedRequest( req := getDatasourceProxiedRequest(
t, t,
&models.ReqContext{ &models.ReqContext{
SignedInUser: &models.SignedInUser{ SignedInUser: &user.SignedInUser{
Login: "test_user", Login: "test_user",
}, },
}, },
@@ -544,7 +546,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
req := getDatasourceProxiedRequest( req := getDatasourceProxiedRequest(
t, t,
&models.ReqContext{ &models.ReqContext{
SignedInUser: &models.SignedInUser{IsAnonymous: true}, SignedInUser: &user.SignedInUser{IsAnonymous: true},
}, },
&setting.Cfg{SendUserHeader: true}, &setting.Cfg{SendUserHeader: true},
) )
@@ -621,7 +623,7 @@ func TestDataSourceProxy_requestHandling(t *testing.T) {
} }
return &models.ReqContext{ return &models.ReqContext{
SignedInUser: &models.SignedInUser{}, SignedInUser: &user.SignedInUser{},
Context: &web.Context{ Context: &web.Context{
Req: httptest.NewRequest("GET", "/render", nil), Req: httptest.NewRequest("GET", "/render", nil),
Resp: responseWriter, Resp: responseWriter,
@@ -758,7 +760,7 @@ func TestDataSourceProxy_requestHandling(t *testing.T) {
func TestNewDataSourceProxy_InvalidURL(t *testing.T) { func TestNewDataSourceProxy_InvalidURL(t *testing.T) {
ctx := models.ReqContext{ ctx := models.ReqContext{
Context: &web.Context{}, Context: &web.Context{},
SignedInUser: &models.SignedInUser{OrgRole: models.ROLE_EDITOR}, SignedInUser: &user.SignedInUser{OrgRole: org.RoleEditor},
} }
ds := datasources.DataSource{ ds := datasources.DataSource{
Type: "test", Type: "test",
@@ -778,7 +780,7 @@ func TestNewDataSourceProxy_InvalidURL(t *testing.T) {
func TestNewDataSourceProxy_ProtocolLessURL(t *testing.T) { func TestNewDataSourceProxy_ProtocolLessURL(t *testing.T) {
ctx := models.ReqContext{ ctx := models.ReqContext{
Context: &web.Context{}, Context: &web.Context{},
SignedInUser: &models.SignedInUser{OrgRole: models.ROLE_EDITOR}, SignedInUser: &user.SignedInUser{OrgRole: org.RoleEditor},
} }
ds := datasources.DataSource{ ds := datasources.DataSource{
Type: "test", Type: "test",
@@ -800,7 +802,7 @@ func TestNewDataSourceProxy_ProtocolLessURL(t *testing.T) {
func TestNewDataSourceProxy_MSSQL(t *testing.T) { func TestNewDataSourceProxy_MSSQL(t *testing.T) {
ctx := models.ReqContext{ ctx := models.ReqContext{
Context: &web.Context{}, Context: &web.Context{},
SignedInUser: &models.SignedInUser{OrgRole: models.ROLE_EDITOR}, SignedInUser: &user.SignedInUser{OrgRole: org.RoleEditor},
} }
tracer := tracing.InitializeTracerForTest() tracer := tracing.InitializeTracerForTest()
@@ -996,13 +998,13 @@ func Test_PathCheck(t *testing.T) {
{ {
Path: "a", Path: "a",
URL: "https://www.google.com", URL: "https://www.google.com",
ReqRole: models.ROLE_EDITOR, ReqRole: org.RoleEditor,
Method: http.MethodGet, Method: http.MethodGet,
}, },
{ {
Path: "b", Path: "b",
URL: "https://www.google.com", URL: "https://www.google.com",
ReqRole: models.ROLE_VIEWER, ReqRole: org.RoleViewer,
Method: http.MethodGet, Method: http.MethodGet,
}, },
} }
@@ -1013,7 +1015,7 @@ func Test_PathCheck(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
ctx := &models.ReqContext{ ctx := &models.ReqContext{
Context: &web.Context{Req: req}, Context: &web.Context{Req: req},
SignedInUser: &models.SignedInUser{OrgRole: models.ROLE_VIEWER}, SignedInUser: &user.SignedInUser{OrgRole: org.RoleViewer},
} }
return ctx, req return ctx, req
} }
@@ -1033,7 +1035,7 @@ type mockOAuthTokenService struct {
oAuthEnabled bool oAuthEnabled bool
} }
func (m *mockOAuthTokenService) GetCurrentOAuthToken(ctx context.Context, user *models.SignedInUser) *oauth2.Token { func (m *mockOAuthTokenService) GetCurrentOAuthToken(ctx context.Context, user *user.SignedInUser) *oauth2.Token {
return m.token return m.token
} }
+11 -9
View File
@@ -9,10 +9,12 @@ import (
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/pluginsettings" "github.com/grafana/grafana/pkg/services/pluginsettings"
"github.com/grafana/grafana/pkg/services/secrets" "github.com/grafana/grafana/pkg/services/secrets"
"github.com/grafana/grafana/pkg/services/secrets/fakes" "github.com/grafana/grafana/pkg/services/secrets/fakes"
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -45,7 +47,7 @@ func TestPluginProxy(t *testing.T) {
t, t,
secretsService, secretsService,
&models.ReqContext{ &models.ReqContext{
SignedInUser: &models.SignedInUser{ SignedInUser: &user.SignedInUser{
Login: "test_user", Login: "test_user",
}, },
Context: &web.Context{ Context: &web.Context{
@@ -71,7 +73,7 @@ func TestPluginProxy(t *testing.T) {
t, t,
secretsService, secretsService,
&models.ReqContext{ &models.ReqContext{
SignedInUser: &models.SignedInUser{ SignedInUser: &user.SignedInUser{
Login: "test_user", Login: "test_user",
}, },
Context: &web.Context{ Context: &web.Context{
@@ -98,7 +100,7 @@ func TestPluginProxy(t *testing.T) {
t, t,
secretsService, secretsService,
&models.ReqContext{ &models.ReqContext{
SignedInUser: &models.SignedInUser{ SignedInUser: &user.SignedInUser{
Login: "test_user", Login: "test_user",
}, },
Context: &web.Context{ Context: &web.Context{
@@ -124,7 +126,7 @@ func TestPluginProxy(t *testing.T) {
t, t,
secretsService, secretsService,
&models.ReqContext{ &models.ReqContext{
SignedInUser: &models.SignedInUser{IsAnonymous: true}, SignedInUser: &user.SignedInUser{IsAnonymous: true},
Context: &web.Context{ Context: &web.Context{
Req: httpReq, Req: httpReq,
}, },
@@ -158,7 +160,7 @@ func TestPluginProxy(t *testing.T) {
t, t,
secretsService, secretsService,
&models.ReqContext{ &models.ReqContext{
SignedInUser: &models.SignedInUser{ SignedInUser: &user.SignedInUser{
Login: "test_user", Login: "test_user",
}, },
Context: &web.Context{ Context: &web.Context{
@@ -189,7 +191,7 @@ func TestPluginProxy(t *testing.T) {
t, t,
secretsService, secretsService,
&models.ReqContext{ &models.ReqContext{
SignedInUser: &models.SignedInUser{ SignedInUser: &user.SignedInUser{
Login: "test_user", Login: "test_user",
}, },
Context: &web.Context{ Context: &web.Context{
@@ -228,7 +230,7 @@ func TestPluginProxy(t *testing.T) {
t, t,
secretsService, secretsService,
&models.ReqContext{ &models.ReqContext{
SignedInUser: &models.SignedInUser{ SignedInUser: &user.SignedInUser{
Login: "test_user", Login: "test_user",
}, },
Context: &web.Context{ Context: &web.Context{
@@ -261,7 +263,7 @@ func TestPluginProxy(t *testing.T) {
} }
ctx := &models.ReqContext{ ctx := &models.ReqContext{
SignedInUser: &models.SignedInUser{}, SignedInUser: &user.SignedInUser{},
Context: &web.Context{ Context: &web.Context{
Req: httptest.NewRequest("GET", "/", nil), Req: httptest.NewRequest("GET", "/", nil),
Resp: responseWriter, Resp: responseWriter,
@@ -292,7 +294,7 @@ func getPluginProxiedRequest(t *testing.T, secretsService secrets.Service, ctx *
route = &plugins.Route{ route = &plugins.Route{
Path: "api/v4/", Path: "api/v4/",
URL: "https://www.google.com", URL: "https://www.google.com",
ReqRole: models.ROLE_EDITOR, ReqRole: org.RoleEditor,
} }
} }
proxy := NewApiPluginProxy(ctx, "", route, "", cfg, pluginSettingsService, secretsService) proxy := NewApiPluginProxy(ctx, "", route, "", cfg, pluginSettingsService, secretsService)
+2 -2
View File
@@ -8,8 +8,8 @@ import (
"strings" "strings"
"text/template" "text/template"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/user"
) )
// interpolateString accepts template data and return a string with substitutions // interpolateString accepts template data and return a string with substitutions
@@ -86,7 +86,7 @@ func setBodyContent(req *http.Request, route *plugins.Route, data templateData)
} }
// Set the X-Grafana-User header if needed (and remove if not) // Set the X-Grafana-User header if needed (and remove if not)
func applyUserHeader(sendUserHeader bool, req *http.Request, user *models.SignedInUser) { func applyUserHeader(sendUserHeader bool, req *http.Request, user *user.SignedInUser) {
req.Header.Del("X-Grafana-User") req.Header.Del("X-Grafana-User")
if sendUserHeader && !user.IsAnonymous { if sendUserHeader && !user.IsAnonymous {
req.Header.Set("X-Grafana-User", user.Login) req.Header.Set("X-Grafana-User", user.Login)
+2 -1
View File
@@ -15,6 +15,7 @@ import (
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
@@ -38,7 +39,7 @@ func (hs *HTTPServer) GetPluginList(c *models.ReqContext) response.Response {
// When using access control anyone that can create a data source should be able to list all data sources installed // When using access control anyone that can create a data source should be able to list all data sources installed
// Fallback to only letting admins list non-core plugins // Fallback to only letting admins list non-core plugins
hasAccess := accesscontrol.HasAccess(hs.AccessControl, c) hasAccess := accesscontrol.HasAccess(hs.AccessControl, c)
if !hasAccess(accesscontrol.ReqOrgAdmin, accesscontrol.EvalPermission(datasources.ActionCreate)) && !c.HasRole(models.ROLE_ADMIN) { if !hasAccess(accesscontrol.ReqOrgAdmin, accesscontrol.EvalPermission(datasources.ActionCreate)) && !c.HasRole(org.RoleAdmin) {
coreFilter = "1" coreFilter = "1"
} }
+4 -2
View File
@@ -21,7 +21,9 @@ import (
"github.com/grafana/grafana/pkg/infra/log/logtest" "github.com/grafana/grafana/pkg/infra/log/logtest"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/quota/quotatest" "github.com/grafana/grafana/pkg/services/quota/quotatest"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web/webtest" "github.com/grafana/grafana/pkg/web/webtest"
) )
@@ -60,7 +62,7 @@ func Test_PluginsInstallAndUninstall(t *testing.T) {
t.Run(testName("Install", tc), func(t *testing.T) { t.Run(testName("Install", tc), func(t *testing.T) {
req := srv.NewPostRequest("/api/plugins/test/install", strings.NewReader("{ \"version\": \"1.0.2\" }")) req := srv.NewPostRequest("/api/plugins/test/install", strings.NewReader("{ \"version\": \"1.0.2\" }"))
webtest.RequestWithSignedInUser(req, &models.SignedInUser{UserId: 1, OrgId: 1, OrgRole: models.ROLE_EDITOR, IsGrafanaAdmin: true}) webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserId: 1, OrgId: 1, OrgRole: org.RoleEditor, IsGrafanaAdmin: true})
resp, err := srv.SendJSON(req) resp, err := srv.SendJSON(req)
require.NoError(t, err) require.NoError(t, err)
@@ -78,7 +80,7 @@ func Test_PluginsInstallAndUninstall(t *testing.T) {
t.Run(testName("Uninstall", tc), func(t *testing.T) { t.Run(testName("Uninstall", tc), func(t *testing.T) {
req := srv.NewPostRequest("/api/plugins/test/uninstall", strings.NewReader("{}")) req := srv.NewPostRequest("/api/plugins/test/uninstall", strings.NewReader("{}"))
webtest.RequestWithSignedInUser(req, &models.SignedInUser{UserId: 1, OrgId: 1, OrgRole: models.ROLE_VIEWER, IsGrafanaAdmin: true}) webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserId: 1, OrgId: 1, OrgRole: org.RoleViewer, IsGrafanaAdmin: true})
resp, err := srv.SendJSON(req) resp, err := srv.SendJSON(req)
require.NoError(t, err) require.NoError(t, err)
+3 -2
View File
@@ -12,12 +12,13 @@ import (
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/user"
) )
func TestHTTPServer_Search(t *testing.T) { func TestHTTPServer_Search(t *testing.T) {
sc := setupHTTPServer(t, true, true) sc := setupHTTPServer(t, true, true)
sc.initCtx.IsSignedIn = true sc.initCtx.IsSignedIn = true
sc.initCtx.SignedInUser = &models.SignedInUser{} sc.initCtx.SignedInUser = &user.SignedInUser{}
sc.hs.SearchService = &mockSearchService{ sc.hs.SearchService = &mockSearchService{
ExpectedResult: models.HitList{ ExpectedResult: models.HitList{
@@ -27,7 +28,7 @@ func TestHTTPServer_Search(t *testing.T) {
}, },
} }
sc.acmock.GetUserPermissionsFunc = func(ctx context.Context, user *models.SignedInUser, options accesscontrol.Options) ([]accesscontrol.Permission, error) { sc.acmock.GetUserPermissionsFunc = func(ctx context.Context, user *user.SignedInUser, options accesscontrol.Options) ([]accesscontrol.Permission, error) {
return []accesscontrol.Permission{ return []accesscontrol.Permission{
{Action: "folders:read", Scope: "folders:*"}, {Action: "folders:read", Scope: "folders:*"},
{Action: "folders:write", Scope: "folders:uid:folder2"}, {Action: "folders:write", Scope: "folders:uid:folder2"},
+6 -5
View File
@@ -12,6 +12,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/shorturls" "github.com/grafana/grafana/pkg/services/shorturls"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -29,7 +30,7 @@ func TestShortURLAPIEndpoint(t *testing.T) {
Path: cmd.Path, Path: cmd.Path,
} }
service := &fakeShortURLService{ service := &fakeShortURLService{
createShortURLFunc: func(ctx context.Context, user *models.SignedInUser, path string) (*models.ShortUrl, error) { createShortURLFunc: func(ctx context.Context, user *user.SignedInUser, path string) (*models.ShortUrl, error) {
return createResp, nil return createResp, nil
}, },
} }
@@ -64,7 +65,7 @@ func createShortURLScenario(t *testing.T, desc string, url string, routePattern
c.Req.Body = mockRequestBody(cmd) c.Req.Body = mockRequestBody(cmd)
c.Req.Header.Add("Content-Type", "application/json") c.Req.Header.Add("Content-Type", "application/json")
sc.context = c sc.context = c
sc.context.SignedInUser = &models.SignedInUser{OrgId: testOrgID, UserId: testUserID} sc.context.SignedInUser = &user.SignedInUser{OrgId: testOrgID, UserId: testUserID}
return hs.createShortURL(c) return hs.createShortURL(c)
}) })
@@ -76,14 +77,14 @@ func createShortURLScenario(t *testing.T, desc string, url string, routePattern
} }
type fakeShortURLService struct { type fakeShortURLService struct {
createShortURLFunc func(ctx context.Context, user *models.SignedInUser, path string) (*models.ShortUrl, error) createShortURLFunc func(ctx context.Context, user *user.SignedInUser, path string) (*models.ShortUrl, error)
} }
func (s *fakeShortURLService) GetShortURLByUID(ctx context.Context, user *models.SignedInUser, uid string) (*models.ShortUrl, error) { func (s *fakeShortURLService) GetShortURLByUID(ctx context.Context, user *user.SignedInUser, uid string) (*models.ShortUrl, error) {
return nil, nil return nil, nil
} }
func (s *fakeShortURLService) CreateShortURL(ctx context.Context, user *models.SignedInUser, path string) (*models.ShortUrl, error) { func (s *fakeShortURLService) CreateShortURL(ctx context.Context, user *user.SignedInUser, path string) (*models.ShortUrl, error) {
if s.createShortURLFunc != nil { if s.createShortURLFunc != nil {
return s.createShortURLFunc(ctx, user, path) return s.createShortURLFunc(ctx, user, path)
} }
+4 -3
View File
@@ -8,6 +8,7 @@ import (
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
) )
@@ -28,7 +29,7 @@ func (hs *HTTPServer) CreateTeam(c *models.ReqContext) response.Response {
return response.Error(http.StatusBadRequest, "bad request data", err) return response.Error(http.StatusBadRequest, "bad request data", err)
} }
accessControlEnabled := !hs.AccessControl.IsDisabled() accessControlEnabled := !hs.AccessControl.IsDisabled()
if !accessControlEnabled && c.OrgRole == models.ROLE_VIEWER { if !accessControlEnabled && c.OrgRole == org.RoleViewer {
return response.Error(403, "Not allowed to create team.", nil) return response.Error(403, "Not allowed to create team.", nil)
} }
@@ -40,7 +41,7 @@ func (hs *HTTPServer) CreateTeam(c *models.ReqContext) response.Response {
return response.Error(500, "Failed to create Team", err) return response.Error(500, "Failed to create Team", err)
} }
if accessControlEnabled || (c.OrgRole == models.ROLE_EDITOR && hs.Cfg.EditorsCanAdmin) { if accessControlEnabled || (c.OrgRole == org.RoleEditor && hs.Cfg.EditorsCanAdmin) {
// if the request is authenticated using API tokens // if the request is authenticated using API tokens
// the SignedInUser is an empty struct therefore // the SignedInUser is an empty struct therefore
// an additional check whether it is an actual user is required // an additional check whether it is an actual user is required
@@ -194,7 +195,7 @@ func (hs *HTTPServer) SearchTeams(c *models.ReqContext) response.Response {
// 2. If the user is an admin, this will return models.FilterIgnoreUser (0) // 2. If the user is an admin, this will return models.FilterIgnoreUser (0)
func userFilter(c *models.ReqContext) int64 { func userFilter(c *models.ReqContext) int64 {
userIdFilter := c.SignedInUser.UserId userIdFilter := c.SignedInUser.UserId
if c.OrgRole == models.ROLE_ADMIN { if c.OrgRole == org.RoleAdmin {
userIdFilter = models.FilterIgnoreUser userIdFilter = models.FilterIgnoreUser
} }
return userIdFilter return userIdFilter
+4 -3
View File
@@ -15,6 +15,7 @@ import (
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
ac "github.com/grafana/grafana/pkg/services/accesscontrol" ac "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/licensing" "github.com/grafana/grafana/pkg/services/licensing"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/services/teamguardian/database" "github.com/grafana/grafana/pkg/services/teamguardian/database"
@@ -27,7 +28,7 @@ type TeamGuardianMock struct {
result error result error
} }
func (t *TeamGuardianMock) CanAdmin(ctx context.Context, orgId int64, teamId int64, user *models.SignedInUser) error { func (t *TeamGuardianMock) CanAdmin(ctx context.Context, orgId int64, teamId int64, user *user.SignedInUser) error {
return t.result return t.result
} }
@@ -66,7 +67,7 @@ func TestTeamMembersAPIEndpoint_userLoggedIn(t *testing.T) {
mock := mockstore.NewSQLStoreMock() mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "api/teams/1/members", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "api/teams/1/members",
"api/teams/:teamId/members", models.ROLE_ADMIN, func(sc *scenarioContext) { "api/teams/:teamId/members", org.RoleAdmin, func(sc *scenarioContext) {
setUpGetTeamMembersHandler(t, sqlStore) setUpGetTeamMembersHandler(t, sqlStore)
sc.handlerFunc = hs.GetTeamMembers sc.handlerFunc = hs.GetTeamMembers
@@ -88,7 +89,7 @@ func TestTeamMembersAPIEndpoint_userLoggedIn(t *testing.T) {
t.Cleanup(func() { settings.HiddenUsers = make(map[string]struct{}) }) t.Cleanup(func() { settings.HiddenUsers = make(map[string]struct{}) })
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "api/teams/1/members", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "api/teams/1/members",
"api/teams/:teamId/members", models.ROLE_ADMIN, func(sc *scenarioContext) { "api/teams/:teamId/members", org.RoleAdmin, func(sc *scenarioContext) {
setUpGetTeamMembersHandler(t, sqlStore) setUpGetTeamMembersHandler(t, sqlStore)
sc.handlerFunc = hs.GetTeamMembers sc.handlerFunc = hs.GetTeamMembers
+7 -5
View File
@@ -15,10 +15,12 @@ import (
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/org"
pref "github.com/grafana/grafana/pkg/services/preference" pref "github.com/grafana/grafana/pkg/services/preference"
"github.com/grafana/grafana/pkg/services/preference/preftest" "github.com/grafana/grafana/pkg/services/preference/preftest"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
) )
@@ -33,7 +35,7 @@ func TestTeamAPIEndpoint(t *testing.T) {
mock := &mockstore.SQLStoreMock{} mock := &mockstore.SQLStoreMock{}
loggedInUserScenarioWithRole(t, "When admin is calling GET on", "GET", "/api/teams/search", "/api/teams/search", loggedInUserScenarioWithRole(t, "When admin is calling GET on", "GET", "/api/teams/search", "/api/teams/search",
models.ROLE_ADMIN, func(sc *scenarioContext) { org.RoleAdmin, func(sc *scenarioContext) {
_, err := hs.SQLStore.CreateTeam("team1", "", 1) _, err := hs.SQLStore.CreateTeam("team1", "", 1)
require.NoError(t, err) require.NoError(t, err)
_, err = hs.SQLStore.CreateTeam("team2", "", 1) _, err = hs.SQLStore.CreateTeam("team2", "", 1)
@@ -117,10 +119,10 @@ func TestTeamAPIEndpoint(t *testing.T) {
logger := &logtest.Fake{} logger := &logtest.Fake{}
c := &models.ReqContext{ c := &models.ReqContext{
Context: &web.Context{Req: req}, Context: &web.Context{Req: req},
SignedInUser: &models.SignedInUser{}, SignedInUser: &user.SignedInUser{},
Logger: logger, Logger: logger,
} }
c.OrgRole = models.ROLE_EDITOR c.OrgRole = org.RoleEditor
c.Req.Body = mockRequestBody(models.CreateTeamCommand{Name: teamName}) c.Req.Body = mockRequestBody(models.CreateTeamCommand{Name: teamName})
c.Req.Header.Add("Content-Type", "application/json") c.Req.Header.Add("Content-Type", "application/json")
r := hs.CreateTeam(c) r := hs.CreateTeam(c)
@@ -134,10 +136,10 @@ func TestTeamAPIEndpoint(t *testing.T) {
logger := &logtest.Fake{} logger := &logtest.Fake{}
c := &models.ReqContext{ c := &models.ReqContext{
Context: &web.Context{Req: req}, Context: &web.Context{Req: req},
SignedInUser: &models.SignedInUser{UserId: 42}, SignedInUser: &user.SignedInUser{UserId: 42},
Logger: logger, Logger: logger,
} }
c.OrgRole = models.ROLE_EDITOR c.OrgRole = org.RoleEditor
c.Req.Body = mockRequestBody(models.CreateTeamCommand{Name: teamName}) c.Req.Body = mockRequestBody(models.CreateTeamCommand{Name: teamName})
c.Req.Header.Add("Content-Type", "application/json") c.Req.Header.Add("Content-Type", "application/json")
r := hs.CreateTeam(c) r := hs.CreateTeam(c)
+2 -2
View File
@@ -447,7 +447,7 @@ func (hs *HTTPServer) SetHelpFlag(c *models.ReqContext) response.Response {
} }
bitmask := &c.HelpFlags1 bitmask := &c.HelpFlags1
bitmask.AddFlag(models.HelpFlags1(flag)) bitmask.AddFlag(user.HelpFlags1(flag))
cmd := models.SetUserHelpFlagCommand{ cmd := models.SetUserHelpFlagCommand{
UserId: c.UserId, UserId: c.UserId,
@@ -473,7 +473,7 @@ func (hs *HTTPServer) SetHelpFlag(c *models.ReqContext) response.Response {
func (hs *HTTPServer) ClearHelpFlags(c *models.ReqContext) response.Response { func (hs *HTTPServer) ClearHelpFlags(c *models.ReqContext) response.Response {
cmd := models.SetUserHelpFlagCommand{ cmd := models.SetUserHelpFlagCommand{
UserId: c.UserId, UserId: c.UserId,
HelpFlags1: models.HelpFlags1(0), HelpFlags1: user.HelpFlags1(0),
} }
if err := hs.SQLStore.SetUserHelpFlag(c.Req.Context(), &cmd); err != nil { if err := hs.SQLStore.SetUserHelpFlag(c.Req.Context(), &cmd); err != nil {
+6 -5
View File
@@ -12,6 +12,7 @@ import (
"github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/auth" "github.com/grafana/grafana/pkg/services/auth"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/services/user/usertest" "github.com/grafana/grafana/pkg/services/user/usertest"
) )
@@ -161,7 +162,7 @@ func revokeUserAuthTokenScenario(t *testing.T, desc string, url string, routePat
sc.context = c sc.context = c
sc.context.UserId = userId sc.context.UserId = userId
sc.context.OrgId = testOrgID sc.context.OrgId = testOrgID
sc.context.OrgRole = models.ROLE_ADMIN sc.context.OrgRole = org.RoleAdmin
return hs.RevokeUserAuthToken(c) return hs.RevokeUserAuthToken(c)
}) })
@@ -187,7 +188,7 @@ func getUserAuthTokensScenario(t *testing.T, desc string, url string, routePatte
sc.context = c sc.context = c
sc.context.UserId = userId sc.context.UserId = userId
sc.context.OrgId = testOrgID sc.context.OrgId = testOrgID
sc.context.OrgRole = models.ROLE_ADMIN sc.context.OrgRole = org.RoleAdmin
return hs.GetUserAuthTokens(c) return hs.GetUserAuthTokens(c)
}) })
@@ -210,7 +211,7 @@ func logoutUserFromAllDevicesInternalScenario(t *testing.T, desc string, userId
sc.context = c sc.context = c
sc.context.UserId = testUserID sc.context.UserId = testUserID
sc.context.OrgId = testOrgID sc.context.OrgId = testOrgID
sc.context.OrgRole = models.ROLE_ADMIN sc.context.OrgRole = org.RoleAdmin
return hs.logoutUserFromAllDevicesInternal(context.Background(), userId) return hs.logoutUserFromAllDevicesInternal(context.Background(), userId)
}) })
@@ -237,7 +238,7 @@ func revokeUserAuthTokenInternalScenario(t *testing.T, desc string, cmd models.R
sc.context = c sc.context = c
sc.context.UserId = testUserID sc.context.UserId = testUserID
sc.context.OrgId = testOrgID sc.context.OrgId = testOrgID
sc.context.OrgRole = models.ROLE_ADMIN sc.context.OrgRole = org.RoleAdmin
sc.context.UserToken = token sc.context.UserToken = token
return hs.revokeUserAuthTokenInternal(c, userId, cmd) return hs.revokeUserAuthTokenInternal(c, userId, cmd)
@@ -262,7 +263,7 @@ func getUserAuthTokensInternalScenario(t *testing.T, desc string, token *models.
sc.context = c sc.context = c
sc.context.UserId = testUserID sc.context.UserId = testUserID
sc.context.OrgId = testOrgID sc.context.OrgId = testOrgID
sc.context.OrgRole = models.ROLE_ADMIN sc.context.OrgRole = org.RoleAdmin
sc.context.UserToken = token sc.context.UserToken = token
return hs.getUserAuthTokensInternal(c, testUserID) return hs.getUserAuthTokensInternal(c, testUserID)
+4 -3
View File
@@ -14,6 +14,7 @@ import (
"github.com/grafana/grafana/pkg/services/contexthandler/ctxkey" "github.com/grafana/grafana/pkg/services/contexthandler/ctxkey"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
) )
@@ -58,7 +59,7 @@ func TestApi_getUsageStats(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) { t.Run(tt.desc, func(t *testing.T) {
uss.Cfg.ReportingEnabled = tt.enabled uss.Cfg.ReportingEnabled = tt.enabled
server := setupTestServer(t, &models.SignedInUser{OrgId: 1, IsGrafanaAdmin: tt.IsGrafanaAdmin}, uss) server := setupTestServer(t, &user.SignedInUser{OrgId: 1, IsGrafanaAdmin: tt.IsGrafanaAdmin}, uss)
usageStats, recorder := getUsageStats(t, server) usageStats, recorder := getUsageStats(t, server)
require.Equal(t, tt.expectedStatus, recorder.Code) require.Equal(t, tt.expectedStatus, recorder.Code)
@@ -83,7 +84,7 @@ func getUsageStats(t *testing.T, server *web.Mux) (*models.SystemStats, *httptes
return &usageStats, recorder return &usageStats, recorder
} }
func setupTestServer(t *testing.T, user *models.SignedInUser, service *UsageStats) *web.Mux { func setupTestServer(t *testing.T, user *user.SignedInUser, service *UsageStats) *web.Mux {
server := web.New() server := web.New()
server.UseMiddleware(web.Renderer(path.Join(setting.StaticRootPath, "views"), "[[", "]]")) server.UseMiddleware(web.Renderer(path.Join(setting.StaticRootPath, "views"), "[[", "]]"))
server.Use(contextProvider(&testContext{user})) server.Use(contextProvider(&testContext{user}))
@@ -92,7 +93,7 @@ func setupTestServer(t *testing.T, user *models.SignedInUser, service *UsageStat
} }
type testContext struct { type testContext struct {
user *models.SignedInUser user *user.SignedInUser
} }
func contextProvider(tc *testContext) web.Handler { func contextProvider(tc *testContext) web.Handler {
+11 -10
View File
@@ -10,6 +10,7 @@ import (
"strings" "strings"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/org"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"gopkg.in/square/go-jose.v2/jwt" "gopkg.in/square/go-jose.v2/jwt"
@@ -122,19 +123,19 @@ func (claims *azureClaims) extractEmail() string {
return claims.Email return claims.Email
} }
func (claims *azureClaims) extractRole(autoAssignRole string, strictMode bool) models.RoleType { func (claims *azureClaims) extractRole(autoAssignRole string, strictMode bool) org.RoleType {
if len(claims.Roles) == 0 { if len(claims.Roles) == 0 {
if strictMode { if strictMode {
return models.RoleType("") return org.RoleType("")
} }
return models.RoleType(autoAssignRole) return org.RoleType(autoAssignRole)
} }
roleOrder := []models.RoleType{ roleOrder := []org.RoleType{
models.ROLE_ADMIN, org.RoleAdmin,
models.ROLE_EDITOR, org.RoleEditor,
models.ROLE_VIEWER, org.RoleViewer,
} }
for _, role := range roleOrder { for _, role := range roleOrder {
@@ -144,13 +145,13 @@ func (claims *azureClaims) extractRole(autoAssignRole string, strictMode bool) m
} }
if strictMode { if strictMode {
return models.RoleType("") return org.RoleType("")
} }
return models.ROLE_VIEWER return org.RoleViewer
} }
func hasRole(roles []string, role models.RoleType) bool { func hasRole(roles []string, role org.RoleType) bool {
for _, item := range roles { for _, item := range roles {
if strings.EqualFold(item, string(role)) { if strings.EqualFold(item, string(role)) {
return true return true
+2 -1
View File
@@ -14,6 +14,7 @@ import (
"strconv" "strconv"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/org"
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )
@@ -180,7 +181,7 @@ func (s *SocialGenericOAuth) UserInfo(client *http.Client, token *oauth2.Token)
userInfo.Login = userInfo.Email userInfo.Login = userInfo.Email
} }
if s.roleAttributeStrict && !models.RoleType(userInfo.Role).IsValid() { if s.roleAttributeStrict && !org.RoleType(userInfo.Role).IsValid() {
return nil, errors.New("invalid role") return nil, errors.New("invalid role")
} }
+2 -1
View File
@@ -7,6 +7,7 @@ import (
"net/http" "net/http"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/org"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"gopkg.in/square/go-jose.v2/jwt" "gopkg.in/square/go-jose.v2/jwt"
) )
@@ -81,7 +82,7 @@ func (s *SocialOkta) UserInfo(client *http.Client, token *oauth2.Token) (*BasicU
if err != nil { if err != nil {
s.log.Error("Failed to extract role", "error", err) s.log.Error("Failed to extract role", "error", err)
} }
if s.roleAttributeStrict && !models.RoleType(role).IsValid() { if s.roleAttributeStrict && !org.RoleType(role).IsValid() {
return nil, errors.New("invalid role") return nil, errors.New("invalid role")
} }
+5 -5
View File
@@ -14,7 +14,7 @@ import (
"golang.org/x/oauth2" "golang.org/x/oauth2"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
) )
@@ -311,10 +311,10 @@ type groupStruct struct {
Groups []string `json:"groups"` Groups []string `json:"groups"`
} }
func (s *SocialBase) extractRole(rawJSON []byte, groups []string) (models.RoleType, error) { func (s *SocialBase) extractRole(rawJSON []byte, groups []string) (org.RoleType, error) {
if s.roleAttributePath == "" { if s.roleAttributePath == "" {
if s.autoAssignOrgRole != "" { if s.autoAssignOrgRole != "" {
return models.RoleType(s.autoAssignOrgRole), nil return org.RoleType(s.autoAssignOrgRole), nil
} }
return "", nil return "", nil
@@ -322,13 +322,13 @@ func (s *SocialBase) extractRole(rawJSON []byte, groups []string) (models.RoleTy
role, err := s.searchJSONForStringAttr(s.roleAttributePath, rawJSON) role, err := s.searchJSONForStringAttr(s.roleAttributePath, rawJSON)
if err == nil && role != "" { if err == nil && role != "" {
return models.RoleType(role), nil return org.RoleType(role), nil
} }
if groupBytes, err := json.Marshal(groupStruct{groups}); err == nil { if groupBytes, err := json.Marshal(groupStruct{groups}); err == nil {
if role, err := s.searchJSONForStringAttr( if role, err := s.searchJSONForStringAttr(
s.roleAttributePath, groupBytes); err == nil && role != "" { s.roleAttributePath, groupBytes); err == nil && role != "" {
return models.RoleType(role), nil return org.RoleType(role), nil
} }
} }
+6 -5
View File
@@ -10,6 +10,7 @@ import (
"github.com/grafana/grafana/pkg/middleware/cookies" "github.com/grafana/grafana/pkg/middleware/cookies"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/org"
"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"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
@@ -75,12 +76,12 @@ func removeForceLoginParams(str string) string {
} }
func EnsureEditorOrViewerCanEdit(c *models.ReqContext) { func EnsureEditorOrViewerCanEdit(c *models.ReqContext) {
if !c.SignedInUser.HasRole(models.ROLE_EDITOR) && !setting.ViewersCanEdit { if !c.SignedInUser.HasRole(org.RoleEditor) && !setting.ViewersCanEdit {
accessForbidden(c) accessForbidden(c)
} }
} }
func RoleAuth(roles ...models.RoleType) web.Handler { func RoleAuth(roles ...org.RoleType) web.Handler {
return func(c *models.ReqContext) { return func(c *models.ReqContext) {
ok := false ok := false
for _, role := range roles { for _, role := range roles {
@@ -136,11 +137,11 @@ func Auth(options *AuthOptions) web.Handler {
// are otherwise only available to admins. // are otherwise only available to admins.
func AdminOrEditorAndFeatureEnabled(enabled bool) web.Handler { func AdminOrEditorAndFeatureEnabled(enabled bool) web.Handler {
return func(c *models.ReqContext) { return func(c *models.ReqContext) {
if c.OrgRole == models.ROLE_ADMIN { if c.OrgRole == org.RoleAdmin {
return return
} }
if c.OrgRole == models.ROLE_EDITOR && enabled { if c.OrgRole == org.RoleEditor && enabled {
return return
} }
@@ -194,7 +195,7 @@ func shouldForceLogin(c *models.ReqContext) bool {
func OrgAdminDashOrFolderAdminOrTeamAdmin(ss sqlstore.Store, ds dashboards.DashboardService) func(c *models.ReqContext) { func OrgAdminDashOrFolderAdminOrTeamAdmin(ss sqlstore.Store, ds dashboards.DashboardService) func(c *models.ReqContext) {
return func(c *models.ReqContext) { return func(c *models.ReqContext) {
if c.OrgRole == models.ROLE_ADMIN { if c.OrgRole == org.RoleAdmin {
return return
} }
+3 -2
View File
@@ -5,6 +5,7 @@ import (
"strings" "strings"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
) )
@@ -16,8 +17,8 @@ var (
}) })
ReqSignedIn = Auth(&AuthOptions{ReqSignedIn: true}) ReqSignedIn = Auth(&AuthOptions{ReqSignedIn: true})
ReqSignedInNoAnonymous = Auth(&AuthOptions{ReqSignedIn: true, ReqNoAnonynmous: true}) ReqSignedInNoAnonymous = Auth(&AuthOptions{ReqSignedIn: true, ReqNoAnonynmous: true})
ReqEditorRole = RoleAuth(models.ROLE_EDITOR, models.ROLE_ADMIN) ReqEditorRole = RoleAuth(org.RoleEditor, org.RoleAdmin)
ReqOrgAdmin = RoleAuth(models.ROLE_ADMIN) ReqOrgAdmin = RoleAuth(org.RoleAdmin)
) )
func HandleNoCacheHeader(ctx *models.ReqContext) { func HandleNoCacheHeader(ctx *models.ReqContext) {
+5 -5
View File
@@ -5,10 +5,10 @@ import (
"testing" "testing"
"github.com/grafana/grafana/pkg/login" "github.com/grafana/grafana/pkg/login"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/apikey" "github.com/grafana/grafana/pkg/services/apikey"
"github.com/grafana/grafana/pkg/services/contexthandler" "github.com/grafana/grafana/pkg/services/contexthandler"
"github.com/grafana/grafana/pkg/services/login/logintest" "github.com/grafana/grafana/pkg/services/login/logintest"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/services/user/usertest" "github.com/grafana/grafana/pkg/services/user/usertest"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
@@ -30,7 +30,7 @@ func TestMiddlewareBasicAuth(t *testing.T) {
keyhash, err := util.EncodePassword("v5nAwpMafFP6znaS4urhdWDLS5511M42", "asd") keyhash, err := util.EncodePassword("v5nAwpMafFP6znaS4urhdWDLS5511M42", "asd")
require.NoError(t, err) require.NoError(t, err)
sc.apiKeyService.ExpectedAPIKey = &apikey.APIKey{OrgId: orgID, Role: models.ROLE_EDITOR, Key: keyhash} sc.apiKeyService.ExpectedAPIKey = &apikey.APIKey{OrgId: orgID, Role: org.RoleEditor, Key: keyhash}
authHeader := util.GetBasicAuthHeader("api_key", "eyJrIjoidjVuQXdwTWFmRlA2em5hUzR1cmhkV0RMUzU1MTFNNDIiLCJuIjoiYXNkIiwiaWQiOjF9") authHeader := util.GetBasicAuthHeader("api_key", "eyJrIjoidjVuQXdwTWFmRlA2em5hUzR1cmhkV0RMUzU1MTFNNDIiLCJuIjoiYXNkIiwiaWQiOjF9")
sc.fakeReq("GET", "/").withAuthorizationHeader(authHeader).exec() sc.fakeReq("GET", "/").withAuthorizationHeader(authHeader).exec()
@@ -38,14 +38,14 @@ func TestMiddlewareBasicAuth(t *testing.T) {
assert.Equal(t, 200, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
assert.True(t, sc.context.IsSignedIn) assert.True(t, sc.context.IsSignedIn)
assert.Equal(t, orgID, sc.context.OrgId) assert.Equal(t, orgID, sc.context.OrgId)
assert.Equal(t, models.ROLE_EDITOR, sc.context.OrgRole) assert.Equal(t, org.RoleEditor, sc.context.OrgRole)
}, configure) }, configure)
middlewareScenario(t, "Handle auth", func(t *testing.T, sc *scenarioContext) { middlewareScenario(t, "Handle auth", func(t *testing.T, sc *scenarioContext) {
const password = "MyPass" const password = "MyPass"
const orgID int64 = 2 const orgID int64 = 2
sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{OrgId: orgID, UserId: id} sc.mockSQLStore.ExpectedSignedInUser = &user.SignedInUser{OrgId: orgID, UserId: id}
authHeader := util.GetBasicAuthHeader("myUser", password) authHeader := util.GetBasicAuthHeader("myUser", password)
sc.fakeReq("GET", "/").withAuthorizationHeader(authHeader).exec() sc.fakeReq("GET", "/").withAuthorizationHeader(authHeader).exec()
@@ -63,7 +63,7 @@ func TestMiddlewareBasicAuth(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
sc.mockSQLStore.ExpectedUser = &user.User{Password: encoded, ID: id, Salt: salt} sc.mockSQLStore.ExpectedUser = &user.User{Password: encoded, ID: id, Salt: salt}
sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{UserId: id} sc.mockSQLStore.ExpectedSignedInUser = &user.SignedInUser{UserId: id}
login.ProvideService(sc.mockSQLStore, &logintest.LoginServiceFake{}, usertest.NewUserServiceFake()) login.ProvideService(sc.mockSQLStore, &logintest.LoginServiceFake{}, usertest.NewUserServiceFake())
authHeader := util.GetBasicAuthHeader("myUser", password) authHeader := util.GetBasicAuthHeader("myUser", password)
+3 -3
View File
@@ -46,7 +46,7 @@ func TestMiddlewareJWTAuth(t *testing.T) {
"foo-username": myUsername, "foo-username": myUsername,
}, nil }, nil
} }
sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{UserId: id, OrgId: orgID, Login: myUsername} sc.mockSQLStore.ExpectedSignedInUser = &user.SignedInUser{UserId: id, OrgId: orgID, Login: myUsername}
sc.fakeReq("GET", "/").withJWTAuthHeader(token).exec() sc.fakeReq("GET", "/").withJWTAuthHeader(token).exec()
assert.Equal(t, verifiedToken, token) assert.Equal(t, verifiedToken, token)
@@ -67,7 +67,7 @@ func TestMiddlewareJWTAuth(t *testing.T) {
"foo-email": myEmail, "foo-email": myEmail,
}, nil }, nil
} }
sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{UserId: id, OrgId: orgID, Email: myEmail} sc.mockSQLStore.ExpectedSignedInUser = &user.SignedInUser{UserId: id, OrgId: orgID, Email: myEmail}
sc.fakeReq("GET", "/").withJWTAuthHeader(token).exec() sc.fakeReq("GET", "/").withJWTAuthHeader(token).exec()
assert.Equal(t, verifiedToken, token) assert.Equal(t, verifiedToken, token)
@@ -108,7 +108,7 @@ func TestMiddlewareJWTAuth(t *testing.T) {
"foo-email": myEmail, "foo-email": myEmail,
}, nil }, nil
} }
sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{UserId: id, OrgId: orgID, Email: myEmail} sc.mockSQLStore.ExpectedSignedInUser = &user.SignedInUser{UserId: id, OrgId: orgID, Email: myEmail}
sc.fakeReq("GET", "/").withJWTAuthHeader(token).exec() sc.fakeReq("GET", "/").withJWTAuthHeader(token).exec()
assert.Equal(t, verifiedToken, token) assert.Equal(t, verifiedToken, token)
+20 -19
View File
@@ -27,6 +27,7 @@ import (
"github.com/grafana/grafana/pkg/services/contexthandler/authproxy" "github.com/grafana/grafana/pkg/services/contexthandler/authproxy"
"github.com/grafana/grafana/pkg/services/login/loginservice" "github.com/grafana/grafana/pkg/services/login/loginservice"
"github.com/grafana/grafana/pkg/services/login/logintest" "github.com/grafana/grafana/pkg/services/login/logintest"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/rendering" "github.com/grafana/grafana/pkg/services/rendering"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/services/user"
@@ -153,7 +154,7 @@ func TestMiddlewareContext(t *testing.T) {
keyhash, err := util.EncodePassword("v5nAwpMafFP6znaS4urhdWDLS5511M42", "asd") keyhash, err := util.EncodePassword("v5nAwpMafFP6znaS4urhdWDLS5511M42", "asd")
require.NoError(t, err) require.NoError(t, err)
sc.apiKeyService.ExpectedAPIKey = &apikey.APIKey{OrgId: orgID, Role: models.ROLE_EDITOR, Key: keyhash} sc.apiKeyService.ExpectedAPIKey = &apikey.APIKey{OrgId: orgID, Role: org.RoleEditor, Key: keyhash}
sc.fakeReq("GET", "/").withValidApiKey().exec() sc.fakeReq("GET", "/").withValidApiKey().exec()
@@ -161,12 +162,12 @@ func TestMiddlewareContext(t *testing.T) {
assert.True(t, sc.context.IsSignedIn) assert.True(t, sc.context.IsSignedIn)
assert.Equal(t, orgID, sc.context.OrgId) assert.Equal(t, orgID, sc.context.OrgId)
assert.Equal(t, models.ROLE_EDITOR, sc.context.OrgRole) assert.Equal(t, org.RoleEditor, sc.context.OrgRole)
}) })
middlewareScenario(t, "Valid API key, but does not match DB hash", func(t *testing.T, sc *scenarioContext) { middlewareScenario(t, "Valid API key, but does not match DB hash", func(t *testing.T, sc *scenarioContext) {
const keyhash = "Something_not_matching" const keyhash = "Something_not_matching"
sc.apiKeyService.ExpectedAPIKey = &apikey.APIKey{OrgId: 12, Role: models.ROLE_EDITOR, Key: keyhash} sc.apiKeyService.ExpectedAPIKey = &apikey.APIKey{OrgId: 12, Role: org.RoleEditor, Key: keyhash}
sc.fakeReq("GET", "/").withValidApiKey().exec() sc.fakeReq("GET", "/").withValidApiKey().exec()
@@ -181,7 +182,7 @@ func TestMiddlewareContext(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
expires := sc.contextHandler.GetTime().Add(-1 * time.Second).Unix() expires := sc.contextHandler.GetTime().Add(-1 * time.Second).Unix()
sc.apiKeyService.ExpectedAPIKey = &apikey.APIKey{OrgId: 12, Role: models.ROLE_EDITOR, Key: keyhash, Expires: &expires} sc.apiKeyService.ExpectedAPIKey = &apikey.APIKey{OrgId: 12, Role: org.RoleEditor, Key: keyhash, Expires: &expires}
sc.fakeReq("GET", "/").withValidApiKey().exec() sc.fakeReq("GET", "/").withValidApiKey().exec()
@@ -194,7 +195,7 @@ func TestMiddlewareContext(t *testing.T) {
const userID int64 = 12 const userID int64 = 12
sc.withTokenSessionCookie("token") sc.withTokenSessionCookie("token")
sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{OrgId: 2, UserId: userID} sc.mockSQLStore.ExpectedSignedInUser = &user.SignedInUser{OrgId: 2, UserId: userID}
sc.userAuthTokenService.LookupTokenProvider = func(ctx context.Context, unhashedToken string) (*models.UserToken, error) { sc.userAuthTokenService.LookupTokenProvider = func(ctx context.Context, unhashedToken string) (*models.UserToken, error) {
return &models.UserToken{ return &models.UserToken{
@@ -218,7 +219,7 @@ func TestMiddlewareContext(t *testing.T) {
const userID int64 = 12 const userID int64 = 12
sc.withTokenSessionCookie("token") sc.withTokenSessionCookie("token")
sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{OrgId: 2, UserId: userID} sc.mockSQLStore.ExpectedSignedInUser = &user.SignedInUser{OrgId: 2, UserId: userID}
sc.userAuthTokenService.LookupTokenProvider = func(ctx context.Context, unhashedToken string) (*models.UserToken, error) { sc.userAuthTokenService.LookupTokenProvider = func(ctx context.Context, unhashedToken string) (*models.UserToken, error) {
return &models.UserToken{ return &models.UserToken{
@@ -316,18 +317,18 @@ func TestMiddlewareContext(t *testing.T) {
middlewareScenario(t, "When anonymous access is enabled", func(t *testing.T, sc *scenarioContext) { middlewareScenario(t, "When anonymous access is enabled", func(t *testing.T, sc *scenarioContext) {
sc.mockSQLStore.ExpectedOrg = &models.Org{Id: 1, Name: sc.cfg.AnonymousOrgName} sc.mockSQLStore.ExpectedOrg = &models.Org{Id: 1, Name: sc.cfg.AnonymousOrgName}
org, err := sc.mockSQLStore.CreateOrgWithMember(sc.cfg.AnonymousOrgName, 1) orga, err := sc.mockSQLStore.CreateOrgWithMember(sc.cfg.AnonymousOrgName, 1)
require.NoError(t, err) require.NoError(t, err)
sc.fakeReq("GET", "/").exec() sc.fakeReq("GET", "/").exec()
assert.Equal(t, int64(0), sc.context.UserId) assert.Equal(t, int64(0), sc.context.UserId)
assert.Equal(t, org.Id, sc.context.OrgId) assert.Equal(t, orga.Id, sc.context.OrgId)
assert.Equal(t, models.ROLE_EDITOR, sc.context.OrgRole) assert.Equal(t, org.RoleEditor, sc.context.OrgRole)
assert.False(t, sc.context.IsSignedIn) assert.False(t, sc.context.IsSignedIn)
}, func(cfg *setting.Cfg) { }, func(cfg *setting.Cfg) {
cfg.AnonymousEnabled = true cfg.AnonymousEnabled = true
cfg.AnonymousOrgName = "test" cfg.AnonymousOrgName = "test"
cfg.AnonymousOrgRole = string(models.ROLE_EDITOR) cfg.AnonymousOrgRole = string(org.RoleEditor)
}) })
t.Run("auth_proxy", func(t *testing.T) { t.Run("auth_proxy", func(t *testing.T) {
@@ -349,7 +350,7 @@ func TestMiddlewareContext(t *testing.T) {
const group = "grafana-core-team" const group = "grafana-core-team"
middlewareScenario(t, "Should not sync the user if it's in the cache", func(t *testing.T, sc *scenarioContext) { middlewareScenario(t, "Should not sync the user if it's in the cache", func(t *testing.T, sc *scenarioContext) {
sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{OrgId: orgID, UserId: userID} sc.mockSQLStore.ExpectedSignedInUser = &user.SignedInUser{OrgId: orgID, UserId: userID}
h, err := authproxy.HashCacheKey(hdrName + "-" + group) h, err := authproxy.HashCacheKey(hdrName + "-" + group)
require.NoError(t, err) require.NoError(t, err)
@@ -389,7 +390,7 @@ func TestMiddlewareContext(t *testing.T) {
}) })
middlewareScenario(t, "Should create an user from a header", func(t *testing.T, sc *scenarioContext) { middlewareScenario(t, "Should create an user from a header", func(t *testing.T, sc *scenarioContext) {
sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{OrgId: orgID, UserId: userID} sc.mockSQLStore.ExpectedSignedInUser = &user.SignedInUser{OrgId: orgID, UserId: userID}
sc.loginService.ExpectedUser = &user.User{ID: userID} sc.loginService.ExpectedUser = &user.User{ID: userID}
sc.fakeReq("GET", "/") sc.fakeReq("GET", "/")
@@ -406,10 +407,10 @@ func TestMiddlewareContext(t *testing.T) {
}) })
middlewareScenario(t, "Should assign role from header to default org", func(t *testing.T, sc *scenarioContext) { middlewareScenario(t, "Should assign role from header to default org", func(t *testing.T, sc *scenarioContext) {
var storedRoleInfo map[int64]models.RoleType = nil var storedRoleInfo map[int64]org.RoleType = nil
sc.loginService.ExpectedUserFunc = func(cmd *models.UpsertUserCommand) *user.User { sc.loginService.ExpectedUserFunc = func(cmd *models.UpsertUserCommand) *user.User {
storedRoleInfo = cmd.ExternalUser.OrgRoles storedRoleInfo = cmd.ExternalUser.OrgRoles
sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{OrgId: defaultOrgId, UserId: userID, OrgRole: storedRoleInfo[defaultOrgId]} sc.mockSQLStore.ExpectedSignedInUser = &user.SignedInUser{OrgId: defaultOrgId, UserId: userID, OrgRole: storedRoleInfo[defaultOrgId]}
return &user.User{ID: userID} return &user.User{ID: userID}
} }
@@ -429,10 +430,10 @@ func TestMiddlewareContext(t *testing.T) {
}) })
middlewareScenario(t, "Should NOT assign role from header to non-default org", func(t *testing.T, sc *scenarioContext) { middlewareScenario(t, "Should NOT assign role from header to non-default org", func(t *testing.T, sc *scenarioContext) {
var storedRoleInfo map[int64]models.RoleType = nil var storedRoleInfo map[int64]org.RoleType = nil
sc.loginService.ExpectedUserFunc = func(cmd *models.UpsertUserCommand) *user.User { sc.loginService.ExpectedUserFunc = func(cmd *models.UpsertUserCommand) *user.User {
storedRoleInfo = cmd.ExternalUser.OrgRoles storedRoleInfo = cmd.ExternalUser.OrgRoles
sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{OrgId: orgID, UserId: userID, OrgRole: storedRoleInfo[orgID]} sc.mockSQLStore.ExpectedSignedInUser = &user.SignedInUser{OrgId: orgID, UserId: userID, OrgRole: storedRoleInfo[orgID]}
return &user.User{ID: userID} return &user.User{ID: userID}
} }
@@ -456,7 +457,7 @@ func TestMiddlewareContext(t *testing.T) {
middlewareScenario(t, "Should use organisation specified by targetOrgId parameter", func(t *testing.T, sc *scenarioContext) { middlewareScenario(t, "Should use organisation specified by targetOrgId parameter", func(t *testing.T, sc *scenarioContext) {
var targetOrgID int64 = 123 var targetOrgID int64 = 123
sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{OrgId: targetOrgID, UserId: userID} sc.mockSQLStore.ExpectedSignedInUser = &user.SignedInUser{OrgId: targetOrgID, UserId: userID}
sc.loginService.ExpectedUser = &user.User{ID: userID} sc.loginService.ExpectedUser = &user.User{ID: userID}
sc.fakeReq("GET", fmt.Sprintf("/?targetOrgId=%d", targetOrgID)) sc.fakeReq("GET", fmt.Sprintf("/?targetOrgId=%d", targetOrgID))
@@ -530,7 +531,7 @@ func TestMiddlewareContext(t *testing.T) {
const userID int64 = 12 const userID int64 = 12
const orgID int64 = 2 const orgID int64 = 2
sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{OrgId: orgID, UserId: userID} sc.mockSQLStore.ExpectedSignedInUser = &user.SignedInUser{OrgId: orgID, UserId: userID}
sc.loginService.ExpectedUser = &user.User{ID: userID} sc.loginService.ExpectedUser = &user.User{ID: userID}
sc.fakeReq("GET", "/") sc.fakeReq("GET", "/")
@@ -546,7 +547,7 @@ func TestMiddlewareContext(t *testing.T) {
}) })
middlewareScenario(t, "Should allow the request from whitelist IP", func(t *testing.T, sc *scenarioContext) { middlewareScenario(t, "Should allow the request from whitelist IP", func(t *testing.T, sc *scenarioContext) {
sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{OrgId: orgID, UserId: userID} sc.mockSQLStore.ExpectedSignedInUser = &user.SignedInUser{OrgId: orgID, UserId: userID}
sc.loginService.ExpectedUser = &user.User{ID: userID} sc.loginService.ExpectedUser = &user.User{ID: userID}
sc.fakeReq("GET", "/") sc.fakeReq("GET", "/")
+3 -2
View File
@@ -6,6 +6,7 @@ import (
"testing" "testing"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/user"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -45,7 +46,7 @@ func TestOrgRedirectMiddleware(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
middlewareScenario(t, tc.desc, func(t *testing.T, sc *scenarioContext) { middlewareScenario(t, tc.desc, func(t *testing.T, sc *scenarioContext) {
sc.withTokenSessionCookie("token") sc.withTokenSessionCookie("token")
sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{OrgId: 1, UserId: 12} sc.mockSQLStore.ExpectedSignedInUser = &user.SignedInUser{OrgId: 1, UserId: 12}
sc.userAuthTokenService.LookupTokenProvider = func(ctx context.Context, unhashedToken string) (*models.UserToken, error) { sc.userAuthTokenService.LookupTokenProvider = func(ctx context.Context, unhashedToken string) (*models.UserToken, error) {
return &models.UserToken{ return &models.UserToken{
UserId: 0, UserId: 0,
@@ -64,7 +65,7 @@ func TestOrgRedirectMiddleware(t *testing.T) {
middlewareScenario(t, "when setting an invalid org for user", func(t *testing.T, sc *scenarioContext) { middlewareScenario(t, "when setting an invalid org for user", func(t *testing.T, sc *scenarioContext) {
sc.withTokenSessionCookie("token") sc.withTokenSessionCookie("token")
sc.mockSQLStore.ExpectedSetUsingOrgError = fmt.Errorf("") sc.mockSQLStore.ExpectedSetUsingOrgError = fmt.Errorf("")
sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{OrgId: 1, UserId: 12} sc.mockSQLStore.ExpectedSignedInUser = &user.SignedInUser{OrgId: 1, UserId: 12}
sc.userAuthTokenService.LookupTokenProvider = func(ctx context.Context, unhashedToken string) (*models.UserToken, error) { sc.userAuthTokenService.LookupTokenProvider = func(ctx context.Context, unhashedToken string) (*models.UserToken, error) {
return &models.UserToken{ return &models.UserToken{
+2 -1
View File
@@ -8,6 +8,7 @@ import (
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/quota" "github.com/grafana/grafana/pkg/services/quota"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
) )
@@ -60,7 +61,7 @@ func TestMiddlewareQuota(t *testing.T) {
const quotaUsed = 4 const quotaUsed = 4
setUp := func(sc *scenarioContext) { setUp := func(sc *scenarioContext) {
sc.withTokenSessionCookie("token") sc.withTokenSessionCookie("token")
sc.mockSQLStore.ExpectedSignedInUser = &models.SignedInUser{UserId: 12} sc.mockSQLStore.ExpectedSignedInUser = &user.SignedInUser{UserId: 12}
sc.userAuthTokenService.LookupTokenProvider = func(ctx context.Context, unhashedToken string) (*models.UserToken, error) { sc.userAuthTokenService.LookupTokenProvider = func(ctx context.Context, unhashedToken string) (*models.UserToken, error) {
return &models.UserToken{ return &models.UserToken{
UserId: 12, UserId: 12,
+2 -1
View File
@@ -5,6 +5,7 @@ import (
"time" "time"
"github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/services/user"
) )
type AlertStateType string type AlertStateType string
@@ -159,7 +160,7 @@ type GetAlertsQuery struct {
PanelId int64 PanelId int64
Limit int64 Limit int64
Query string Query string
User *SignedInUser User *user.SignedInUser
Result []*AlertListItemDTO Result []*AlertListItemDTO
} }
+5 -3
View File
@@ -5,6 +5,8 @@ import (
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
@@ -12,7 +14,7 @@ import (
type ReqContext struct { type ReqContext struct {
*web.Context *web.Context
*SignedInUser *user.SignedInUser
UserToken *UserToken UserToken *UserToken
IsSignedIn bool IsSignedIn bool
@@ -77,11 +79,11 @@ func (ctx *ReqContext) JsonApiErr(status int, message string, err error) {
ctx.JSON(status, resp) ctx.JSON(status, resp)
} }
func (ctx *ReqContext) HasUserRole(role RoleType) bool { func (ctx *ReqContext) HasUserRole(role org.RoleType) bool {
return ctx.OrgRole.Includes(role) return ctx.OrgRole.Includes(role)
} }
func (ctx *ReqContext) HasHelpFlag(flag HelpFlags1) bool { func (ctx *ReqContext) HasHelpFlag(flag user.HelpFlags1) bool {
return ctx.HelpFlags1.HasFlag(flag) return ctx.HelpFlags1.HasFlag(flag)
} }
+6 -4
View File
@@ -3,6 +3,8 @@ package models
import ( import (
"errors" "errors"
"time" "time"
"github.com/grafana/grafana/pkg/services/org"
) )
type PermissionType int type PermissionType int
@@ -39,9 +41,9 @@ type DashboardACL struct {
OrgID int64 `xorm:"org_id"` OrgID int64 `xorm:"org_id"`
DashboardID int64 `xorm:"dashboard_id"` DashboardID int64 `xorm:"dashboard_id"`
UserID int64 `xorm:"user_id"` UserID int64 `xorm:"user_id"`
TeamID int64 `xorm:"team_id"` TeamID int64 `xorm:"team_id"`
Role *RoleType // pointer to be nullable Role *org.RoleType // pointer to be nullable
Permission PermissionType Permission PermissionType
Created time.Time Created time.Time
@@ -64,7 +66,7 @@ type DashboardACLInfoDTO struct {
TeamEmail string `json:"teamEmail"` TeamEmail string `json:"teamEmail"`
TeamAvatarUrl string `json:"teamAvatarUrl"` TeamAvatarUrl string `json:"teamAvatarUrl"`
Team string `json:"team"` Team string `json:"team"`
Role *RoleType `json:"role,omitempty"` Role *org.RoleType `json:"role,omitempty"`
Permission PermissionType `json:"permission"` Permission PermissionType `json:"permission"`
PermissionName string `json:"permissionName"` PermissionName string `json:"permissionName"`
Uid string `json:"uid"` Uid string `json:"uid"`
+4 -2
View File
@@ -3,6 +3,8 @@ package models
import ( import (
"strings" "strings"
"time" "time"
"github.com/grafana/grafana/pkg/services/user"
) )
type Folder struct { type Folder struct {
@@ -91,11 +93,11 @@ type UpdateFolderCommand struct {
// //
type HasEditPermissionInFoldersQuery struct { type HasEditPermissionInFoldersQuery struct {
SignedInUser *SignedInUser SignedInUser *user.SignedInUser
Result bool Result bool
} }
type HasAdminPermissionInDashboardsOrFoldersQuery struct { type HasAdminPermissionInDashboardsOrFoldersQuery struct {
SignedInUser *SignedInUser SignedInUser *user.SignedInUser
Result bool Result bool
} }
+2 -10
View File
@@ -1,16 +1,8 @@
package models package models
type HelpFlags1 uint64 import "github.com/grafana/grafana/pkg/services/user"
const (
HelpFlagGettingStartedPanelDismissed HelpFlags1 = 1 << iota
HelpFlagDashboardHelp1
)
func (f HelpFlags1) HasFlag(flag HelpFlags1) bool { return f&flag != 0 }
func (f *HelpFlags1) AddFlag(flag HelpFlags1) { *f |= flag }
type SetUserHelpFlagCommand struct { type SetUserHelpFlagCommand struct {
HelpFlags1 HelpFlags1 HelpFlags1 user.HelpFlags1
UserId int64 UserId int64
} }
+5 -4
View File
@@ -6,6 +6,7 @@ import (
"time" "time"
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/services/user"
) )
// ChannelPublisher writes data into a channel. Note that permissions are not checked. // ChannelPublisher writes data into a channel. Note that permissions are not checked.
@@ -52,10 +53,10 @@ type PublishReply struct {
// ChannelHandler defines the core channel behavior // ChannelHandler defines the core channel behavior
type ChannelHandler interface { type ChannelHandler interface {
// OnSubscribe is called when a client wants to subscribe to a channel // OnSubscribe is called when a client wants to subscribe to a channel
OnSubscribe(ctx context.Context, user *SignedInUser, e SubscribeEvent) (SubscribeReply, backend.SubscribeStreamStatus, error) OnSubscribe(ctx context.Context, user *user.SignedInUser, e SubscribeEvent) (SubscribeReply, backend.SubscribeStreamStatus, error)
// OnPublish is called when a client writes a message to the channel websocket. // OnPublish is called when a client writes a message to the channel websocket.
OnPublish(ctx context.Context, user *SignedInUser, e PublishEvent) (PublishReply, backend.PublishStreamStatus, error) OnPublish(ctx context.Context, user *user.SignedInUser, e PublishEvent) (PublishReply, backend.PublishStreamStatus, error)
} }
// ChannelHandlerFactory should be implemented by all core features. // ChannelHandlerFactory should be implemented by all core features.
@@ -71,10 +72,10 @@ type DashboardActivityChannel interface {
// gitops workflow that knows if the value was saved to the local database or not // gitops workflow that knows if the value was saved to the local database or not
// in many cases all direct save requests will fail, but the request should be forwarded // in many cases all direct save requests will fail, but the request should be forwarded
// to any gitops observers // to any gitops observers
DashboardSaved(orgID int64, user *UserDisplayDTO, message string, dashboard *Dashboard, err error) error DashboardSaved(orgID int64, user *user.UserDisplayDTO, message string, dashboard *Dashboard, err error) error
// Called when a dashboard is deleted // Called when a dashboard is deleted
DashboardDeleted(orgID int64, user *UserDisplayDTO, uid string) error DashboardDeleted(orgID int64, user *user.UserDisplayDTO, uid string) error
// Experimental! Indicate is GitOps is active. This really means // Experimental! Indicate is GitOps is active. This really means
// someone is subscribed to the `grafana/dashboards/gitops` channel // someone is subscribed to the `grafana/dashboards/gitops` channel
+5 -3
View File
@@ -3,6 +3,8 @@ package models
import ( import (
"errors" "errors"
"time" "time"
"github.com/grafana/grafana/pkg/services/org"
) )
// Typed errors // Typed errors
@@ -84,7 +86,7 @@ type OrgDetailsDTO struct {
} }
type UserOrgDTO struct { type UserOrgDTO struct {
OrgId int64 `json:"orgId"` OrgId int64 `json:"orgId"`
Name string `json:"name"` Name string `json:"name"`
Role RoleType `json:"role"` Role org.RoleType `json:"role"`
} }
+9 -71
View File
@@ -2,9 +2,10 @@ package models
import ( import (
"errors" "errors"
"fmt"
"strings"
"time" "time"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/user"
) )
// Typed errors // Typed errors
@@ -14,74 +15,11 @@ var (
ErrOrgUserAlreadyAdded = errors.New("user is already added to organization") ErrOrgUserAlreadyAdded = errors.New("user is already added to organization")
) )
// swagger:enum RoleType
type RoleType string
const (
ROLE_VIEWER RoleType = "Viewer"
ROLE_EDITOR RoleType = "Editor"
ROLE_ADMIN RoleType = "Admin"
)
func (r RoleType) IsValid() bool {
return r == ROLE_VIEWER || r == ROLE_ADMIN || r == ROLE_EDITOR
}
func (r RoleType) Includes(other RoleType) bool {
if r == ROLE_ADMIN {
return true
}
if r == ROLE_EDITOR {
return other != ROLE_ADMIN
}
return r == other
}
func (r RoleType) Children() []RoleType {
switch r {
case ROLE_ADMIN:
return []RoleType{ROLE_EDITOR, ROLE_VIEWER}
case ROLE_EDITOR:
return []RoleType{ROLE_VIEWER}
default:
return nil
}
}
func (r RoleType) Parents() []RoleType {
switch r {
case ROLE_EDITOR:
return []RoleType{ROLE_ADMIN}
case ROLE_VIEWER:
return []RoleType{ROLE_EDITOR, ROLE_ADMIN}
default:
return nil
}
}
func (r *RoleType) UnmarshalText(data []byte) error {
// make sure "viewer" and "Viewer" are both correct
str := strings.Title(string(data))
*r = RoleType(str)
if !r.IsValid() {
if (*r) != "" {
return fmt.Errorf("invalid role value: %s", *r)
}
*r = ROLE_VIEWER
}
return nil
}
type OrgUser struct { type OrgUser struct {
Id int64 Id int64
OrgId int64 OrgId int64
UserId int64 UserId int64
Role RoleType Role org.RoleType
Created time.Time Created time.Time
Updated time.Time Updated time.Time
} }
@@ -97,8 +35,8 @@ type RemoveOrgUserCommand struct {
} }
type AddOrgUserCommand struct { type AddOrgUserCommand struct {
LoginOrEmail string `json:"loginOrEmail" binding:"Required"` LoginOrEmail string `json:"loginOrEmail" binding:"Required"`
Role RoleType `json:"role" binding:"Required"` Role org.RoleType `json:"role" binding:"Required"`
OrgId int64 `json:"-"` OrgId int64 `json:"-"`
UserId int64 `json:"-"` UserId int64 `json:"-"`
@@ -108,7 +46,7 @@ type AddOrgUserCommand struct {
} }
type UpdateOrgUserCommand struct { type UpdateOrgUserCommand struct {
Role RoleType `json:"role" binding:"Required"` Role org.RoleType `json:"role" binding:"Required"`
OrgId int64 `json:"-"` OrgId int64 `json:"-"`
UserId int64 `json:"-"` UserId int64 `json:"-"`
@@ -125,7 +63,7 @@ type GetOrgUsersQuery struct {
// Flag used to allow oss edition to query users without access control // Flag used to allow oss edition to query users without access control
DontEnforceAccessControl bool DontEnforceAccessControl bool
User *SignedInUser User *user.SignedInUser
Result []*OrgUserDTO Result []*OrgUserDTO
} }
@@ -135,7 +73,7 @@ type SearchOrgUsersQuery struct {
Page int Page int
Limit int Limit int
User *SignedInUser User *user.SignedInUser
Result SearchOrgUsersQueryResult Result SearchOrgUsersQueryResult
} }
+2 -1
View File
@@ -4,6 +4,7 @@ import (
"strings" "strings"
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore" "github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
"github.com/grafana/grafana/pkg/services/user"
) )
type SortOption struct { type SortOption struct {
@@ -22,7 +23,7 @@ type SortOptionFilter interface {
type FindPersistedDashboardsQuery struct { type FindPersistedDashboardsQuery struct {
Title string Title string
OrgId int64 OrgId int64
SignedInUser *SignedInUser SignedInUser *user.SignedInUser
IsStarred bool IsStarred bool
DashboardIds []int64 DashboardIds []int64
DashboardUIDs []string DashboardUIDs []string
+6 -4
View File
@@ -3,6 +3,8 @@ package models
import ( import (
"errors" "errors"
"time" "time"
"github.com/grafana/grafana/pkg/services/user"
) )
// Typed errors // Typed errors
@@ -52,7 +54,7 @@ type DeleteTeamCommand struct {
type GetTeamByIdQuery struct { type GetTeamByIdQuery struct {
OrgId int64 OrgId int64
Id int64 Id int64
SignedInUser *SignedInUser SignedInUser *user.SignedInUser
HiddenUsers map[string]struct{} HiddenUsers map[string]struct{}
Result *TeamDTO Result *TeamDTO
UserIdFilter int64 UserIdFilter int64
@@ -65,7 +67,7 @@ type GetTeamsByUserQuery struct {
OrgId int64 OrgId int64
UserId int64 `json:"userId"` UserId int64 `json:"userId"`
Result []*TeamDTO `json:"teams"` Result []*TeamDTO `json:"teams"`
SignedInUser *SignedInUser SignedInUser *user.SignedInUser
} }
type SearchTeamsQuery struct { type SearchTeamsQuery struct {
@@ -75,7 +77,7 @@ type SearchTeamsQuery struct {
Page int Page int
OrgId int64 OrgId int64
UserIdFilter int64 UserIdFilter int64
SignedInUser *SignedInUser SignedInUser *user.SignedInUser
HiddenUsers map[string]struct{} HiddenUsers map[string]struct{}
Result SearchTeamQueryResult Result SearchTeamQueryResult
@@ -100,6 +102,6 @@ type SearchTeamQueryResult struct {
} }
type IsAdminOfTeamsQuery struct { type IsAdminOfTeamsQuery struct {
SignedInUser *SignedInUser SignedInUser *user.SignedInUser
Result bool Result bool
} }
+3 -1
View File
@@ -3,6 +3,8 @@ package models
import ( import (
"errors" "errors"
"time" "time"
"github.com/grafana/grafana/pkg/services/user"
) )
// Typed errors // Typed errors
@@ -55,7 +57,7 @@ type GetTeamMembersQuery struct {
TeamId int64 TeamId int64
UserId int64 UserId int64
External bool External bool
SignedInUser *SignedInUser SignedInUser *user.SignedInUser
Result []*TeamMemberDTO Result []*TeamMemberDTO
} }
+5 -3
View File
@@ -3,6 +3,8 @@ package models
import ( import (
"errors" "errors"
"time" "time"
"github.com/grafana/grafana/pkg/services/org"
) )
// Typed errors // Typed errors
@@ -27,7 +29,7 @@ type TempUser struct {
Version int Version int
Email string Email string
Name string Name string
Role RoleType Role org.RoleType
InvitedByUserId int64 InvitedByUserId int64
Status TempUserStatus Status TempUserStatus
@@ -50,7 +52,7 @@ type CreateTempUserCommand struct {
InvitedByUserId int64 InvitedByUserId int64
Status TempUserStatus Status TempUserStatus
Code string Code string
Role RoleType Role org.RoleType
RemoteAddr string RemoteAddr string
Result *TempUser Result *TempUser
@@ -90,7 +92,7 @@ type TempUserDTO struct {
OrgId int64 `json:"orgId"` OrgId int64 `json:"orgId"`
Name string `json:"name"` Name string `json:"name"`
Email string `json:"email"` Email string `json:"email"`
Role RoleType `json:"role"` Role org.RoleType `json:"role"`
InvitedByLogin string `json:"invitedByLogin"` InvitedByLogin string `json:"invitedByLogin"`
InvitedByEmail string `json:"invitedByEmail"` InvitedByEmail string `json:"invitedByEmail"`
InvitedByName string `json:"invitedByName"` InvitedByName string `json:"invitedByName"`
+2 -68
View File
@@ -70,7 +70,7 @@ type GetSignedInUserQuery struct {
Login string Login string
Email string Email string
OrgId int64 OrgId int64
Result *SignedInUser Result *user.SignedInUser
} }
type GetUserProfileQuery struct { type GetUserProfileQuery struct {
@@ -79,7 +79,7 @@ type GetUserProfileQuery struct {
} }
type SearchUsersQuery struct { type SearchUsersQuery struct {
SignedInUser *SignedInUser SignedInUser *user.SignedInUser
OrgId int64 OrgId int64
Query string Query string
Page int Page int
@@ -104,69 +104,10 @@ type GetUserOrgListQuery struct {
Result []*UserOrgDTO Result []*UserOrgDTO
} }
// ------------------------
// DTO & Projections
type SignedInUser struct {
UserId int64
OrgId int64
OrgName string
OrgRole RoleType
ExternalAuthModule string
ExternalAuthId string
Login string
Name string
Email string
ApiKeyId int64
OrgCount int
IsGrafanaAdmin bool
IsAnonymous bool
IsDisabled bool
HelpFlags1 HelpFlags1
LastSeenAt time.Time
Teams []int64
// Permissions grouped by orgID and actions
Permissions map[int64]map[string][]string `json:"-"`
}
func (u *SignedInUser) ShouldUpdateLastSeenAt() bool {
return u.UserId > 0 && time.Since(u.LastSeenAt) > time.Minute*5
}
func (u *SignedInUser) NameOrFallback() string {
if u.Name != "" {
return u.Name
}
if u.Login != "" {
return u.Login
}
return u.Email
}
func (u *SignedInUser) ToUserDisplayDTO() *UserDisplayDTO {
return &UserDisplayDTO{
Id: u.UserId,
Login: u.Login,
Name: u.Name,
}
}
type UpdateUserLastSeenAtCommand struct { type UpdateUserLastSeenAtCommand struct {
UserId int64 UserId int64
} }
func (u *SignedInUser) HasRole(role RoleType) bool {
if u.IsGrafanaAdmin {
return true
}
return u.OrgRole.Includes(role)
}
func (u *SignedInUser) IsRealUser() bool {
return u.UserId != 0
}
type UserProfileDTO struct { type UserProfileDTO struct {
Id int64 `json:"id"` Id int64 `json:"id"`
Email string `json:"email"` Email string `json:"email"`
@@ -198,13 +139,6 @@ type UserSearchHitDTO struct {
AuthModule AuthModuleConversion `json:"-"` AuthModule AuthModuleConversion `json:"-"`
} }
type UserDisplayDTO struct {
Id int64 `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Login string `json:"login,omitempty"`
AvatarUrl string `json:"avatarUrl"`
}
type UserIdDTO struct { type UserIdDTO struct {
Id int64 `json:"id"` Id int64 `json:"id"`
Message string `json:"message"` Message string `json:"message"`
+2 -1
View File
@@ -3,6 +3,7 @@ package models
import ( import (
"time" "time"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
@@ -31,7 +32,7 @@ type ExternalUserInfo struct {
Login string Login string
Name string Name string
Groups []string Groups []string
OrgRoles map[int64]RoleType OrgRoles map[int64]org.RoleType
IsGrafanaAdmin *bool // This is a pointer to know if we should sync this or not (nil = ignore sync) IsGrafanaAdmin *bool // This is a pointer to know if we should sync this or not (nil = ignore sync)
IsDisabled bool IsDisabled bool
} }
+2 -2
View File
@@ -1,8 +1,8 @@
package plugins package plugins
import ( import (
"github.com/grafana/grafana/pkg/models"
ac "github.com/grafana/grafana/pkg/services/accesscontrol" ac "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/org"
) )
const ( const (
@@ -24,7 +24,7 @@ func DeclareRBACRoles(acService ac.AccessControl) error {
{Action: ActionAppAccess, Scope: ScopeProvider.GetResourceAllScope()}, {Action: ActionAppAccess, Scope: ScopeProvider.GetResourceAllScope()},
}, },
}, },
Grants: []string{string(models.ROLE_VIEWER)}, Grants: []string{string(org.RoleViewer)},
} }
return acService.DeclareFixedRoles(AppPluginsReader) return acService.DeclareFixedRoles(AppPluginsReader)
} }
+2 -2
View File
@@ -7,8 +7,8 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/user"
) )
// ModelToInstanceSettings converts a datasources.DataSource to a backend.DataSourceInstanceSettings. // ModelToInstanceSettings converts a datasources.DataSource to a backend.DataSourceInstanceSettings.
@@ -45,7 +45,7 @@ func ModelToInstanceSettings(ds *datasources.DataSource, decryptFn func(ds *data
// BackendUserFromSignedInUser converts Grafana's SignedInUser model // BackendUserFromSignedInUser converts Grafana's SignedInUser model
// to the backend plugin's model. // to the backend plugin's model.
func BackendUserFromSignedInUser(su *models.SignedInUser) *backend.User { func BackendUserFromSignedInUser(su *user.SignedInUser) *backend.User {
if su == nil { if su == nil {
return nil return nil
} }
+2 -1
View File
@@ -22,6 +22,7 @@ import (
"github.com/grafana/grafana/pkg/plugins/manager/loader/finder" "github.com/grafana/grafana/pkg/plugins/manager/loader/finder"
"github.com/grafana/grafana/pkg/plugins/manager/loader/initializer" "github.com/grafana/grafana/pkg/plugins/manager/loader/initializer"
"github.com/grafana/grafana/pkg/plugins/manager/signature" "github.com/grafana/grafana/pkg/plugins/manager/signature"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
) )
@@ -225,7 +226,7 @@ func (l *Loader) readPluginJSON(pluginJSONPath string) (plugins.JSONData, error)
for _, include := range plugin.Includes { for _, include := range plugin.Includes {
if include.Role == "" { if include.Role == "" {
include.Role = models.ROLE_VIEWER include.Role = org.RoleViewer
} }
} }
+5 -5
View File
@@ -8,13 +8,13 @@ import (
"testing" "testing"
"github.com/grafana/grafana/pkg/infra/log/logtest" "github.com/grafana/grafana/pkg/infra/log/logtest"
"github.com/grafana/grafana/pkg/services/org"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts" "github.com/google/go-cmp/cmp/cmpopts"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/backendplugin" "github.com/grafana/grafana/pkg/plugins/backendplugin"
"github.com/grafana/grafana/pkg/plugins/backendplugin/coreplugin" "github.com/grafana/grafana/pkg/plugins/backendplugin/coreplugin"
@@ -1064,10 +1064,10 @@ func TestLoader_readPluginJSON(t *testing.T) {
}, },
}, },
Includes: []*plugins.Includes{ Includes: []*plugins.Includes{
{Name: "Nginx Connections", Path: "dashboards/connections.json", Type: "dashboard", Role: models.ROLE_VIEWER}, {Name: "Nginx Connections", Path: "dashboards/connections.json", Type: "dashboard", Role: org.RoleViewer},
{Name: "Nginx Memory", Path: "dashboards/memory.json", Type: "dashboard", Role: models.ROLE_VIEWER}, {Name: "Nginx Memory", Path: "dashboards/memory.json", Type: "dashboard", Role: org.RoleViewer},
{Name: "Nginx Panel", Type: "panel", Role: models.ROLE_VIEWER}, {Name: "Nginx Panel", Type: "panel", Role: org.RoleViewer},
{Name: "Nginx Datasource", Type: "datasource", Role: models.ROLE_VIEWER}, {Name: "Nginx Datasource", Type: "datasource", Role: org.RoleViewer},
}, },
Backend: false, Backend: false,
}, },
+11 -11
View File
@@ -4,7 +4,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/org"
) )
const ( const (
@@ -83,16 +83,16 @@ type Dependencies struct {
} }
type Includes struct { type Includes struct {
Name string `json:"name"` Name string `json:"name"`
Path string `json:"path"` Path string `json:"path"`
Type string `json:"type"` Type string `json:"type"`
Component string `json:"component"` Component string `json:"component"`
Role models.RoleType `json:"role"` Role org.RoleType `json:"role"`
AddToNav bool `json:"addToNav"` AddToNav bool `json:"addToNav"`
DefaultNav bool `json:"defaultNav"` DefaultNav bool `json:"defaultNav"`
Slug string `json:"slug"` Slug string `json:"slug"`
Icon string `json:"icon"` Icon string `json:"icon"`
UID string `json:"uid"` UID string `json:"uid"`
ID string `json:"-"` ID string `json:"-"`
} }
+5 -4
View File
@@ -16,6 +16,7 @@ import (
"github.com/grafana/grafana/pkg/plugins/adapters" "github.com/grafana/grafana/pkg/plugins/adapters"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/pluginsettings" "github.com/grafana/grafana/pkg/services/pluginsettings"
"github.com/grafana/grafana/pkg/services/user"
) )
func ProvideService(cacheService *localcache.CacheService, pluginStore plugins.Store, func ProvideService(cacheService *localcache.CacheService, pluginStore plugins.Store,
@@ -43,13 +44,13 @@ type Provider struct {
// Get allows getting plugin context by its ID. If datasourceUID is not empty string // Get allows getting plugin context by its ID. If datasourceUID is not empty string
// then PluginContext.DataSourceInstanceSettings will be resolved and appended to // then PluginContext.DataSourceInstanceSettings will be resolved and appended to
// returned context. // returned context.
func (p *Provider) Get(ctx context.Context, pluginID string, user *models.SignedInUser) (backend.PluginContext, bool, error) { func (p *Provider) Get(ctx context.Context, pluginID string, user *user.SignedInUser) (backend.PluginContext, bool, error) {
return p.pluginContext(ctx, pluginID, user) return p.pluginContext(ctx, pluginID, user)
} }
// GetWithDataSource allows getting plugin context by its ID and PluginContext.DataSourceInstanceSettings will be // GetWithDataSource allows getting plugin context by its ID and PluginContext.DataSourceInstanceSettings will be
// resolved and appended to the returned context. // resolved and appended to the returned context.
func (p *Provider) GetWithDataSource(ctx context.Context, pluginID string, user *models.SignedInUser, ds *datasources.DataSource) (backend.PluginContext, bool, error) { func (p *Provider) GetWithDataSource(ctx context.Context, pluginID string, user *user.SignedInUser, ds *datasources.DataSource) (backend.PluginContext, bool, error) {
pCtx, exists, err := p.pluginContext(ctx, pluginID, user) pCtx, exists, err := p.pluginContext(ctx, pluginID, user)
if err != nil { if err != nil {
return pCtx, exists, err return pCtx, exists, err
@@ -67,7 +68,7 @@ func (p *Provider) GetWithDataSource(ctx context.Context, pluginID string, user
const pluginSettingsCacheTTL = 5 * time.Second const pluginSettingsCacheTTL = 5 * time.Second
const pluginSettingsCachePrefix = "plugin-setting-" const pluginSettingsCachePrefix = "plugin-setting-"
func (p *Provider) pluginContext(ctx context.Context, pluginID string, user *models.SignedInUser) (backend.PluginContext, bool, error) { func (p *Provider) pluginContext(ctx context.Context, pluginID string, user *user.SignedInUser) (backend.PluginContext, bool, error) {
plugin, exists := p.pluginStore.Plugin(ctx, pluginID) plugin, exists := p.pluginStore.Plugin(ctx, pluginID)
if !exists { if !exists {
return backend.PluginContext{}, false, nil return backend.PluginContext{}, false, nil
@@ -105,7 +106,7 @@ func (p *Provider) pluginContext(ctx context.Context, pluginID string, user *mod
}, true, nil }, true, nil
} }
func (p *Provider) getCachedPluginSettings(ctx context.Context, pluginID string, user *models.SignedInUser) (*pluginsettings.DTO, error) { func (p *Provider) getCachedPluginSettings(ctx context.Context, pluginID string, user *user.SignedInUser) (*pluginsettings.DTO, error) {
cacheKey := pluginSettingsCachePrefix + pluginID cacheKey := pluginSettingsCachePrefix + pluginID
if cached, found := p.cacheService.Get(cacheKey); found { if cached, found := p.cacheService.Get(cacheKey); found {
+2 -2
View File
@@ -7,10 +7,10 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins/backendplugin" "github.com/grafana/grafana/pkg/plugins/backendplugin"
"github.com/grafana/grafana/pkg/plugins/backendplugin/pluginextensionv2" "github.com/grafana/grafana/pkg/plugins/backendplugin/pluginextensionv2"
"github.com/grafana/grafana/pkg/plugins/backendplugin/secretsmanagerplugin" "github.com/grafana/grafana/pkg/plugins/backendplugin/secretsmanagerplugin"
"github.com/grafana/grafana/pkg/services/org"
) )
type Plugin struct { type Plugin struct {
@@ -158,7 +158,7 @@ func (d JSONData) DashboardIncludes() []*Includes {
type Route struct { type Route struct {
Path string `json:"path"` Path string `json:"path"`
Method string `json:"method"` Method string `json:"method"`
ReqRole models.RoleType `json:"reqRole"` ReqRole org.RoleType `json:"reqRole"`
URL string `json:"url"` URL string `json:"url"`
URLParams []URLParam `json:"urlParams"` URLParams []URLParam `json:"urlParams"`
Headers []Header `json:"headers"` Headers []Header `json:"headers"`
+11 -9
View File
@@ -7,6 +7,8 @@ import (
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/registry" "github.com/grafana/grafana/pkg/registry"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
@@ -18,10 +20,10 @@ type AccessControl interface {
registry.ProvidesUsageStats registry.ProvidesUsageStats
// Evaluate evaluates access to the given resources. // Evaluate evaluates access to the given resources.
Evaluate(ctx context.Context, user *models.SignedInUser, evaluator Evaluator) (bool, error) Evaluate(ctx context.Context, user *user.SignedInUser, evaluator Evaluator) (bool, error)
// GetUserPermissions returns user permissions with only action and scope fields set. // GetUserPermissions returns user permissions with only action and scope fields set.
GetUserPermissions(ctx context.Context, user *models.SignedInUser, options Options) ([]Permission, error) GetUserPermissions(ctx context.Context, user *user.SignedInUser, options Options) ([]Permission, error)
//IsDisabled returns if access control is enabled or not //IsDisabled returns if access control is enabled or not
IsDisabled() bool IsDisabled() bool
@@ -49,7 +51,7 @@ type PermissionsStore interface {
} }
type TeamPermissionsService interface { type TeamPermissionsService interface {
GetPermissions(ctx context.Context, user *models.SignedInUser, resourceID string) ([]ResourcePermission, error) GetPermissions(ctx context.Context, user *user.SignedInUser, resourceID string) ([]ResourcePermission, error)
SetUserPermission(ctx context.Context, orgID int64, user User, resourceID, permission string) (*ResourcePermission, error) SetUserPermission(ctx context.Context, orgID int64, user User, resourceID, permission string) (*ResourcePermission, error)
} }
@@ -71,7 +73,7 @@ type ServiceAccountPermissionsService interface {
type PermissionsService interface { type PermissionsService interface {
// GetPermissions returns all permissions for given resourceID // GetPermissions returns all permissions for given resourceID
GetPermissions(ctx context.Context, user *models.SignedInUser, resourceID string) ([]ResourcePermission, error) GetPermissions(ctx context.Context, user *user.SignedInUser, resourceID string) ([]ResourcePermission, error)
// SetUserPermission sets permission on resource for a user // SetUserPermission sets permission on resource for a user
SetUserPermission(ctx context.Context, orgID int64, user User, resourceID, permission string) (*ResourcePermission, error) SetUserPermission(ctx context.Context, orgID int64, user User, resourceID, permission string) (*ResourcePermission, error)
// SetTeamPermission sets permission on resource for a team // SetTeamPermission sets permission on resource for a team
@@ -138,17 +140,17 @@ var ReqGrafanaAdmin = func(c *models.ReqContext) bool {
return c.IsGrafanaAdmin return c.IsGrafanaAdmin
} }
// ReqViewer returns true if the current user has models.ROLE_VIEWER. Note: this can be anonymous user as well // ReqViewer returns true if the current user has org.RoleViewer. Note: this can be anonymous user as well
var ReqViewer = func(c *models.ReqContext) bool { var ReqViewer = func(c *models.ReqContext) bool {
return c.OrgRole.Includes(models.ROLE_VIEWER) return c.OrgRole.Includes(org.RoleViewer)
} }
var ReqOrgAdmin = func(c *models.ReqContext) bool { var ReqOrgAdmin = func(c *models.ReqContext) bool {
return c.OrgRole == models.ROLE_ADMIN return c.OrgRole == org.RoleAdmin
} }
var ReqOrgAdminOrEditor = func(c *models.ReqContext) bool { var ReqOrgAdminOrEditor = func(c *models.ReqContext) bool {
return c.OrgRole == models.ROLE_ADMIN || c.OrgRole == models.ROLE_EDITOR return c.OrgRole == org.RoleAdmin || c.OrgRole == org.RoleEditor
} }
func BuildPermissionsMap(permissions []Permission) map[string]bool { func BuildPermissionsMap(permissions []Permission) map[string]bool {
@@ -268,7 +270,7 @@ func IsDisabled(cfg *setting.Cfg) bool {
} }
// GetOrgRoles returns legacy org roles for a user // GetOrgRoles returns legacy org roles for a user
func GetOrgRoles(cfg *setting.Cfg, user *models.SignedInUser) []string { func GetOrgRoles(cfg *setting.Cfg, user *user.SignedInUser) []string {
roles := []string{string(user.OrgRole)} roles := []string{string(user.OrgRole)}
// With built-in role simplifying, inheritance is performed upon role registration. // With built-in role simplifying, inheritance is performed upon role registration.
@@ -10,6 +10,7 @@ import (
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions/types" "github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions/types"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/services/user"
) )
@@ -120,7 +121,7 @@ func TestAccessControlStore_GetUserPermissions(t *testing.T) {
} }
var roles []string var roles []string
role := models.RoleType(tt.role) role := org.RoleType(tt.role)
if role.IsValid() { if role.IsValid() {
roles = append(roles, string(role)) roles = append(roles, string(role))
@@ -9,6 +9,7 @@ import (
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions/types" "github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions/types"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/services/user"
) )
@@ -118,7 +119,7 @@ func (s *AccessControlStore) SetBuiltInResourcePermission(
cmd types.SetResourcePermissionCommand, cmd types.SetResourcePermissionCommand,
hook types.BuiltinResourceHookFunc, hook types.BuiltinResourceHookFunc,
) (*accesscontrol.ResourcePermission, error) { ) (*accesscontrol.ResourcePermission, error) {
if !models.RoleType(builtInRole).IsValid() || builtInRole == accesscontrol.RoleGrafanaAdmin { if !org.RoleType(builtInRole).IsValid() || builtInRole == accesscontrol.RoleGrafanaAdmin {
return nil, fmt.Errorf("invalid role: %s", builtInRole) return nil, fmt.Errorf("invalid role: %s", builtInRole)
} }
@@ -171,7 +172,7 @@ func (s *AccessControlStore) SetResourcePermissions(
p, err = s.setUserResourcePermission(sess, orgID, cmd.User, cmd.SetResourcePermissionCommand, hooks.User) p, err = s.setUserResourcePermission(sess, orgID, cmd.User, cmd.SetResourcePermissionCommand, hooks.User)
} else if cmd.TeamID != 0 { } else if cmd.TeamID != 0 {
p, err = s.setTeamResourcePermission(sess, orgID, cmd.TeamID, cmd.SetResourcePermissionCommand, hooks.Team) p, err = s.setTeamResourcePermission(sess, orgID, cmd.TeamID, cmd.SetResourcePermissionCommand, hooks.Team)
} else if models.RoleType(cmd.BuiltinRole).IsValid() || cmd.BuiltinRole == accesscontrol.RoleGrafanaAdmin { } else if org.RoleType(cmd.BuiltinRole).IsValid() || cmd.BuiltinRole == accesscontrol.RoleGrafanaAdmin {
p, err = s.setBuiltInResourcePermission(sess, orgID, cmd.BuiltinRole, cmd.SetResourcePermissionCommand, hooks.BuiltInRole) p, err = s.setBuiltInResourcePermission(sess, orgID, cmd.BuiltinRole, cmd.SetResourcePermissionCommand, hooks.BuiltInRole)
} }
if err != nil { if err != nil {
@@ -10,7 +10,6 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions/types" "github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions/types"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
@@ -58,7 +57,7 @@ func getDSPermissions(b *testing.B, store *AccessControlStore, dataSources []int
dsId := dataSources[0] dsId := dataSources[0]
permissions, err := store.GetResourcePermissions(context.Background(), accesscontrol.GlobalOrgID, types.GetResourcePermissionsQuery{ permissions, err := store.GetResourcePermissions(context.Background(), accesscontrol.GlobalOrgID, types.GetResourcePermissionsQuery{
User: &models.SignedInUser{OrgId: 1, Permissions: map[int64]map[string][]string{1: {"org.users:read": {"users:*"}, "teams:read": {"teams:*"}}}}, User: &user.SignedInUser{OrgId: 1, Permissions: map[int64]map[string][]string{1: {"org.users:read": {"users:*"}, "teams:read": {"teams:*"}}}},
Actions: []string{dsAction}, Actions: []string{dsAction},
Resource: dsResource, Resource: dsResource,
ResourceID: strconv.Itoa(int(dsId)), ResourceID: strconv.Itoa(int(dsId)),
@@ -9,7 +9,6 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions/types" "github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions/types"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
@@ -338,7 +337,7 @@ func TestAccessControlStore_SetResourcePermissions(t *testing.T) {
type getResourcePermissionsTest struct { type getResourcePermissionsTest struct {
desc string desc string
user *models.SignedInUser user *user.SignedInUser
numUsers int numUsers int
actions []string actions []string
resource string resource string
@@ -351,7 +350,7 @@ func TestAccessControlStore_GetResourcePermissions(t *testing.T) {
tests := []getResourcePermissionsTest{ tests := []getResourcePermissionsTest{
{ {
desc: "should return permissions for resource id", desc: "should return permissions for resource id",
user: &models.SignedInUser{ user: &user.SignedInUser{
OrgId: 1, OrgId: 1,
Permissions: map[int64]map[string][]string{ Permissions: map[int64]map[string][]string{
1: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}}, 1: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}},
@@ -364,7 +363,7 @@ func TestAccessControlStore_GetResourcePermissions(t *testing.T) {
}, },
{ {
desc: "should return manage permissions for all resource ids", desc: "should return manage permissions for all resource ids",
user: &models.SignedInUser{ user: &user.SignedInUser{
OrgId: 1, OrgId: 1,
Permissions: map[int64]map[string][]string{ Permissions: map[int64]map[string][]string{
1: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}}, 1: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}},
+2 -2
View File
@@ -5,7 +5,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/user"
) )
var sqlIDAcceptList = map[string]struct{}{ var sqlIDAcceptList = map[string]struct{}{
@@ -33,7 +33,7 @@ type SQLFilter struct {
// Filter creates a where clause to restrict the view of a query based on a users permissions // Filter creates a where clause to restrict the view of a query based on a users permissions
// Scopes that exists for all actions will be parsed and compared against the supplied sqlID // Scopes that exists for all actions will be parsed and compared against the supplied sqlID
// Prefix parameter is the prefix of the scope that we support (e.g. "users:id:") // Prefix parameter is the prefix of the scope that we support (e.g. "users:id:")
func Filter(user *models.SignedInUser, sqlID, prefix string, actions ...string) (SQLFilter, error) { func Filter(user *user.SignedInUser, sqlID, prefix string, actions ...string) (SQLFilter, error) {
if _, ok := sqlIDAcceptList[sqlID]; !ok { if _, ok := sqlIDAcceptList[sqlID]; !ok {
return denyQuery, errors.New("sqlID is not in the accept list") return denyQuery, errors.New("sqlID is not in the accept list")
} }
@@ -8,10 +8,10 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/user"
) )
func BenchmarkFilter10_10(b *testing.B) { benchmarkFilter(b, 10, 10) } func BenchmarkFilter10_10(b *testing.B) { benchmarkFilter(b, 10, 10) }
@@ -33,7 +33,7 @@ func benchmarkFilter(b *testing.B, numDs, numPermissions int) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
baseSql := `SELECT data_source.* FROM data_source WHERE` baseSql := `SELECT data_source.* FROM data_source WHERE`
acFilter, err := accesscontrol.Filter( acFilter, err := accesscontrol.Filter(
&models.SignedInUser{OrgId: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(permissions)}}, &user.SignedInUser{OrgId: 1, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByAction(permissions)}},
"data_source.id", "data_source.id",
"datasources:id:", "datasources:id:",
"datasources:read", "datasources:read",
+2 -2
View File
@@ -8,10 +8,10 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/user"
) )
type filterDatasourcesTestCase struct { type filterDatasourcesTestCase struct {
@@ -177,7 +177,7 @@ func TestFilter_Datasources(t *testing.T) {
baseSql := `SELECT data_source.* FROM data_source WHERE` baseSql := `SELECT data_source.* FROM data_source WHERE`
acFilter, err := accesscontrol.Filter( acFilter, err := accesscontrol.Filter(
&models.SignedInUser{ &user.SignedInUser{
OrgId: 1, OrgId: 1,
Permissions: map[int64]map[string][]string{1: tt.permissions}, Permissions: map[int64]map[string][]string{1: tt.permissions},
}, },
+2 -1
View File
@@ -8,6 +8,7 @@ import (
"time" "time"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
@@ -25,7 +26,7 @@ func Middleware(ac AccessControl) func(web.Handler, Evaluator) web.Handler {
} }
} }
func authorize(c *models.ReqContext, ac AccessControl, user *models.SignedInUser, evaluator Evaluator) { func authorize(c *models.ReqContext, ac AccessControl, user *user.SignedInUser, evaluator Evaluator) {
injected, err := evaluator.MutateScopes(c.Req.Context(), ScopeInjector(ScopeParams{ injected, err := evaluator.MutateScopes(c.Req.Context(), ScopeInjector(ScopeParams{
OrgID: c.OrgId, OrgID: c.OrgId,
URLParams: web.Params(c.Req), URLParams: web.Params(c.Req),
@@ -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/mock" "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
"github.com/grafana/grafana/pkg/services/contexthandler/ctxkey" "github.com/grafana/grafana/pkg/services/contexthandler/ctxkey"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
) )
@@ -87,7 +88,7 @@ func contextProvider() web.Handler {
reqCtx := &models.ReqContext{ reqCtx := &models.ReqContext{
Context: c, Context: c,
Logger: log.New(""), Logger: log.New(""),
SignedInUser: &models.SignedInUser{}, SignedInUser: &user.SignedInUser{},
IsSignedIn: true, IsSignedIn: true,
SkipCache: true, SkipCache: true,
} }
+8 -8
View File
@@ -3,13 +3,13 @@ package mock
import ( import (
"context" "context"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/user"
) )
type fullAccessControl interface { type fullAccessControl interface {
accesscontrol.AccessControl accesscontrol.AccessControl
GetUserBuiltInRoles(user *models.SignedInUser) []string GetUserBuiltInRoles(user *user.SignedInUser) []string
RegisterFixedRoles(context.Context) error RegisterFixedRoles(context.Context) error
} }
@@ -36,11 +36,11 @@ type Mock struct {
Calls Calls Calls Calls
// Override functions // Override functions
EvaluateFunc func(context.Context, *models.SignedInUser, accesscontrol.Evaluator) (bool, error) EvaluateFunc func(context.Context, *user.SignedInUser, accesscontrol.Evaluator) (bool, error)
GetUserPermissionsFunc func(context.Context, *models.SignedInUser, accesscontrol.Options) ([]accesscontrol.Permission, error) GetUserPermissionsFunc func(context.Context, *user.SignedInUser, accesscontrol.Options) ([]accesscontrol.Permission, error)
IsDisabledFunc func() bool IsDisabledFunc func() bool
DeclareFixedRolesFunc func(...accesscontrol.RoleRegistration) error DeclareFixedRolesFunc func(...accesscontrol.RoleRegistration) error
GetUserBuiltInRolesFunc func(user *models.SignedInUser) []string GetUserBuiltInRolesFunc func(user *user.SignedInUser) []string
RegisterFixedRolesFunc func() error RegisterFixedRolesFunc func() error
RegisterScopeAttributeResolverFunc func(string, accesscontrol.ScopeAttributeResolver) RegisterScopeAttributeResolverFunc func(string, accesscontrol.ScopeAttributeResolver)
DeleteUserPermissionsFunc func(context.Context, int64) error DeleteUserPermissionsFunc func(context.Context, int64) error
@@ -84,7 +84,7 @@ func (m Mock) WithBuiltInRoles(builtInRoles []string) *Mock {
// Evaluate evaluates access to the given resource. // Evaluate evaluates access to the given resource.
// This mock uses GetUserPermissions to then call the evaluator Evaluate function. // This mock uses GetUserPermissions to then call the evaluator Evaluate function.
func (m *Mock) Evaluate(ctx context.Context, user *models.SignedInUser, evaluator accesscontrol.Evaluator) (bool, error) { func (m *Mock) Evaluate(ctx context.Context, user *user.SignedInUser, evaluator accesscontrol.Evaluator) (bool, error) {
m.Calls.Evaluate = append(m.Calls.Evaluate, []interface{}{ctx, user, evaluator}) m.Calls.Evaluate = append(m.Calls.Evaluate, []interface{}{ctx, user, evaluator})
// Use override if provided // Use override if provided
if m.EvaluateFunc != nil { if m.EvaluateFunc != nil {
@@ -114,7 +114,7 @@ func (m *Mock) Evaluate(ctx context.Context, user *models.SignedInUser, evaluato
// GetUserPermissions returns user permissions. // GetUserPermissions returns user permissions.
// This mock return m.permissions unless an override is provided. // This mock return m.permissions unless an override is provided.
func (m *Mock) GetUserPermissions(ctx context.Context, user *models.SignedInUser, opts accesscontrol.Options) ([]accesscontrol.Permission, error) { func (m *Mock) GetUserPermissions(ctx context.Context, user *user.SignedInUser, opts accesscontrol.Options) ([]accesscontrol.Permission, error) {
m.Calls.GetUserPermissions = append(m.Calls.GetUserPermissions, []interface{}{ctx, user, opts}) m.Calls.GetUserPermissions = append(m.Calls.GetUserPermissions, []interface{}{ctx, user, opts})
// Use override if provided // Use override if provided
if m.GetUserPermissionsFunc != nil { if m.GetUserPermissionsFunc != nil {
@@ -151,7 +151,7 @@ func (m *Mock) DeclareFixedRoles(registrations ...accesscontrol.RoleRegistration
// GetUserBuiltInRoles returns the list of organizational roles ("Viewer", "Editor", "Admin") // GetUserBuiltInRoles returns the list of organizational roles ("Viewer", "Editor", "Admin")
// or "Grafana Admin" associated to a user // or "Grafana Admin" associated to a user
// This mock returns m.builtInRoles unless an override is provided. // This mock returns m.builtInRoles unless an override is provided.
func (m *Mock) GetUserBuiltInRoles(user *models.SignedInUser) []string { func (m *Mock) GetUserBuiltInRoles(user *user.SignedInUser) []string {
m.Calls.GetUserBuiltInRoles = append(m.Calls.GetUserBuiltInRoles, []interface{}{user}) m.Calls.GetUserBuiltInRoles = append(m.Calls.GetUserBuiltInRoles, []interface{}{user})
// Use override if provided // Use override if provided
@@ -5,8 +5,8 @@ import (
"github.com/stretchr/testify/mock" "github.com/stretchr/testify/mock"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/user"
) )
var _ accesscontrol.PermissionsService = new(MockPermissionsService) var _ accesscontrol.PermissionsService = new(MockPermissionsService)
@@ -19,7 +19,7 @@ type MockPermissionsService struct {
mock.Mock mock.Mock
} }
func (m *MockPermissionsService) GetPermissions(ctx context.Context, user *models.SignedInUser, resourceID string) ([]accesscontrol.ResourcePermission, error) { func (m *MockPermissionsService) GetPermissions(ctx context.Context, user *user.SignedInUser, resourceID string) ([]accesscontrol.ResourcePermission, error) {
mockedArgs := m.Called(ctx, user, resourceID) mockedArgs := m.Called(ctx, user, resourceID)
return mockedArgs.Get(0).([]accesscontrol.ResourcePermission), mockedArgs.Error(1) return mockedArgs.Get(0).([]accesscontrol.ResourcePermission), mockedArgs.Error(1)
} }
+2 -2
View File
@@ -6,8 +6,8 @@ import (
"strings" "strings"
"time" "time"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/annotations" "github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/org"
) )
// RoleRegistration stores a role and its assignments to built-in roles // RoleRegistration stores a role and its assignments to built-in roles
@@ -410,7 +410,7 @@ func BuiltInRolesWithParents(builtInRoles []string) map[string]struct{} {
for _, br := range builtInRoles { for _, br := range builtInRoles {
res[br] = struct{}{} res[br] = struct{}{}
if br != RoleGrafanaAdmin { if br != RoleGrafanaAdmin {
for _, parent := range models.RoleType(br).Parents() { for _, parent := range org.RoleType(br).Parents() {
res[string(parent)] = struct{}{} res[string(parent)] = struct{}{}
} }
} }
@@ -6,10 +6,10 @@ import (
"github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/metrics" "github.com/grafana/grafana/pkg/infra/metrics"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/api" "github.com/grafana/grafana/pkg/services/accesscontrol/api"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@@ -77,7 +77,7 @@ func (ac *OSSAccessControlService) getUsageMetrics() interface{} {
} }
// Evaluate evaluates access to the given resources // Evaluate evaluates access to the given resources
func (ac *OSSAccessControlService) Evaluate(ctx context.Context, user *models.SignedInUser, evaluator accesscontrol.Evaluator) (bool, error) { func (ac *OSSAccessControlService) Evaluate(ctx context.Context, user *user.SignedInUser, evaluator accesscontrol.Evaluator) (bool, error) {
timer := prometheus.NewTimer(metrics.MAccessEvaluationsSummary) timer := prometheus.NewTimer(metrics.MAccessEvaluationsSummary)
defer timer.ObserveDuration() defer timer.ObserveDuration()
metrics.MAccessEvaluationCount.Inc() metrics.MAccessEvaluationCount.Inc()
@@ -103,7 +103,7 @@ func (ac *OSSAccessControlService) Evaluate(ctx context.Context, user *models.Si
} }
// GetUserPermissions returns user permissions based on built-in roles // GetUserPermissions returns user permissions based on built-in roles
func (ac *OSSAccessControlService) GetUserPermissions(ctx context.Context, user *models.SignedInUser, _ accesscontrol.Options) ([]accesscontrol.Permission, error) { func (ac *OSSAccessControlService) GetUserPermissions(ctx context.Context, user *user.SignedInUser, _ accesscontrol.Options) ([]accesscontrol.Permission, error) {
timer := prometheus.NewTimer(metrics.MAccessPermissionsSummary) timer := prometheus.NewTimer(metrics.MAccessPermissionsSummary)
defer timer.ObserveDuration() defer timer.ObserveDuration()
@@ -132,7 +132,7 @@ func (ac *OSSAccessControlService) GetUserPermissions(ctx context.Context, user
return permissions, nil return permissions, nil
} }
func (ac *OSSAccessControlService) getFixedPermissions(ctx context.Context, user *models.SignedInUser) []accesscontrol.Permission { func (ac *OSSAccessControlService) getFixedPermissions(ctx context.Context, user *user.SignedInUser) []accesscontrol.Permission {
permissions := make([]accesscontrol.Permission, 0) permissions := make([]accesscontrol.Permission, 0)
for _, builtin := range accesscontrol.GetOrgRoles(ac.cfg, user) { for _, builtin := range accesscontrol.GetOrgRoles(ac.cfg, user) {
@@ -13,7 +13,9 @@ 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"
"github.com/grafana/grafana/pkg/services/featuremgmt" "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/sqlstore"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
@@ -52,7 +54,7 @@ type evaluatingPermissionsTestCase struct {
type userTestCase struct { type userTestCase struct {
name string name string
orgRole models.RoleType orgRole org.RoleType
isGrafanaAdmin bool isGrafanaAdmin bool
} }
@@ -66,7 +68,7 @@ func TestEvaluatingPermissions(t *testing.T) {
desc: "should successfully evaluate access to the endpoint", desc: "should successfully evaluate access to the endpoint",
user: userTestCase{ user: userTestCase{
name: "testuser", name: "testuser",
orgRole: models.ROLE_VIEWER, orgRole: org.RoleViewer,
isGrafanaAdmin: true, isGrafanaAdmin: true,
}, },
endpoints: []endpointTestCase{ endpoints: []endpointTestCase{
@@ -79,7 +81,7 @@ func TestEvaluatingPermissions(t *testing.T) {
desc: "should restrict access to the unauthorized endpoints", desc: "should restrict access to the unauthorized endpoints",
user: userTestCase{ user: userTestCase{
name: "testuser", name: "testuser",
orgRole: models.ROLE_VIEWER, orgRole: org.RoleViewer,
isGrafanaAdmin: false, isGrafanaAdmin: false,
}, },
endpoints: []endpointTestCase{ endpoints: []endpointTestCase{
@@ -99,7 +101,7 @@ func TestEvaluatingPermissions(t *testing.T) {
errRegisterRoles := ac.RegisterFixedRoles(context.Background()) errRegisterRoles := ac.RegisterFixedRoles(context.Background())
require.NoError(t, errRegisterRoles) require.NoError(t, errRegisterRoles)
user := &models.SignedInUser{ user := &user.SignedInUser{
UserId: 1, UserId: 1,
OrgId: 1, OrgId: 1,
Name: tc.user.name, Name: tc.user.name,
@@ -357,11 +359,11 @@ func TestOSSAccessControlService_RegisterFixedRoles(t *testing.T) {
} }
func TestOSSAccessControlService_GetUserPermissions(t *testing.T) { func TestOSSAccessControlService_GetUserPermissions(t *testing.T) {
testUser := models.SignedInUser{ testUser := user.SignedInUser{
UserId: 2, UserId: 2,
OrgId: 3, OrgId: 3,
OrgName: "TestOrg", OrgName: "TestOrg",
OrgRole: models.ROLE_VIEWER, OrgRole: org.RoleViewer,
Login: "testUser", Login: "testUser",
Name: "Test User", Name: "Test User",
Email: "testuser@example.org", Email: "testuser@example.org",
@@ -377,7 +379,7 @@ func TestOSSAccessControlService_GetUserPermissions(t *testing.T) {
} }
tests := []struct { tests := []struct {
name string name string
user models.SignedInUser user user.SignedInUser
rawPerm accesscontrol.Permission rawPerm accesscontrol.Permission
wantPerm accesscontrol.Permission wantPerm accesscontrol.Permission
wantErr bool wantErr bool
@@ -419,11 +421,11 @@ func TestOSSAccessControlService_GetUserPermissions(t *testing.T) {
} }
func TestOSSAccessControlService_Evaluate(t *testing.T) { func TestOSSAccessControlService_Evaluate(t *testing.T) {
testUser := models.SignedInUser{ testUser := user.SignedInUser{
UserId: 2, UserId: 2,
OrgId: 3, OrgId: 3,
OrgName: "TestOrg", OrgName: "TestOrg",
OrgRole: models.ROLE_VIEWER, OrgRole: org.RoleViewer,
Login: "testUser", Login: "testUser",
Name: "Test User", Name: "Test User",
Email: "testuser@example.org", Email: "testuser@example.org",
@@ -446,7 +448,7 @@ func TestOSSAccessControlService_Evaluate(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
user models.SignedInUser user user.SignedInUser
rawPerm accesscontrol.Permission rawPerm accesscontrol.Permission
evaluator accesscontrol.Evaluator evaluator accesscontrol.Evaluator
wantAccess bool wantAccess bool
@@ -13,6 +13,7 @@ import (
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/serviceaccounts" "github.com/grafana/grafana/pkg/services/serviceaccounts"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
@@ -235,7 +236,7 @@ var _ accesscontrol.DatasourcePermissionsService = new(DatasourcePermissionsServ
type DatasourcePermissionsService struct{} type DatasourcePermissionsService struct{}
func (e DatasourcePermissionsService) GetPermissions(ctx context.Context, user *models.SignedInUser, resourceID string) ([]accesscontrol.ResourcePermission, error) { func (e DatasourcePermissionsService) GetPermissions(ctx context.Context, user *user.SignedInUser, resourceID string) ([]accesscontrol.ResourcePermission, error) {
return nil, nil return nil, nil
} }
+6 -6
View File
@@ -9,7 +9,7 @@ import (
"github.com/grafana/grafana/pkg/infra/localcache" "github.com/grafana/grafana/pkg/infra/localcache"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/user"
) )
const ( const (
@@ -60,7 +60,7 @@ func (s *ScopeResolvers) GetScopeAttributeMutator(orgID int64) ScopeAttributeMut
} }
} }
func (s *ScopeResolvers) GetScopeKeywordMutator(user *models.SignedInUser) ScopeKeywordMutator { func (s *ScopeResolvers) GetScopeKeywordMutator(user *user.SignedInUser) ScopeKeywordMutator {
return func(ctx context.Context, scope string) (string, error) { return func(ctx context.Context, scope string) (string, error) {
if resolver, ok := s.keywordResolvers[scope]; ok { if resolver, ok := s.keywordResolvers[scope]; ok {
scopes, err := resolver.Resolve(ctx, user) scopes, err := resolver.Resolve(ctx, user)
@@ -103,13 +103,13 @@ type ScopeAttributeMutator func(context.Context, string) ([]string, error)
// ScopeKeywordResolver is used to resolve keywords in scopes e.g. "users:self" -> "user:id:1". // ScopeKeywordResolver is used to resolve keywords in scopes e.g. "users:self" -> "user:id:1".
// These type of resolvers is used when fetching stored permissions // These type of resolvers is used when fetching stored permissions
type ScopeKeywordResolver interface { type ScopeKeywordResolver interface {
Resolve(ctx context.Context, user *models.SignedInUser) (string, error) Resolve(ctx context.Context, user *user.SignedInUser) (string, error)
} }
// ScopeKeywordResolverFunc is an adapter to allow functions to implement ScopeKeywordResolver interface // ScopeKeywordResolverFunc is an adapter to allow functions to implement ScopeKeywordResolver interface
type ScopeKeywordResolverFunc func(ctx context.Context, user *models.SignedInUser) (string, error) type ScopeKeywordResolverFunc func(ctx context.Context, user *user.SignedInUser) (string, error)
func (f ScopeKeywordResolverFunc) Resolve(ctx context.Context, user *models.SignedInUser) (string, error) { func (f ScopeKeywordResolverFunc) Resolve(ctx context.Context, user *user.SignedInUser) (string, error) {
return f(ctx, user) return f(ctx, user)
} }
@@ -135,6 +135,6 @@ func ScopeInjector(params ScopeParams) ScopeAttributeMutator {
} }
} }
var userSelfResolver = ScopeKeywordResolverFunc(func(ctx context.Context, user *models.SignedInUser) (string, error) { var userSelfResolver = ScopeKeywordResolverFunc(func(ctx context.Context, user *user.SignedInUser) (string, error) {
return Scope("users", "id", fmt.Sprintf("%v", user.UserId)), nil return Scope("users", "id", fmt.Sprintf("%v", user.UserId)), nil
}) })
+5 -4
View File
@@ -6,15 +6,16 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/user"
) )
func TestResolveKeywordScope(t *testing.T) { func TestResolveKeywordScope(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
user *models.SignedInUser user *user.SignedInUser
permission accesscontrol.Permission permission accesscontrol.Permission
want accesscontrol.Permission want accesscontrol.Permission
wantErr bool wantErr bool
@@ -50,11 +51,11 @@ func TestResolveKeywordScope(t *testing.T) {
} }
} }
var testUser = &models.SignedInUser{ var testUser = &user.SignedInUser{
UserId: 2, UserId: 2,
OrgId: 3, OrgId: 3,
OrgName: "TestOrg", OrgName: "TestOrg",
OrgRole: models.ROLE_VIEWER, OrgRole: org.RoleViewer,
Login: "testUser", Login: "testUser",
Name: "Test User", Name: "Test User",
Email: "testuser@example.org", Email: "testuser@example.org",
@@ -10,6 +10,7 @@ import (
"github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
) )
@@ -97,7 +98,7 @@ func (a *api) getPermissions(c *models.ReqContext) response.Response {
permissions = append(permissions, accesscontrol.ResourcePermission{ permissions = append(permissions, accesscontrol.ResourcePermission{
Actions: a.service.actions, Actions: a.service.actions,
Scope: "*", Scope: "*",
BuiltInRole: string(models.ROLE_ADMIN), BuiltInRole: string(org.RoleAdmin),
}) })
} }
@@ -113,7 +113,7 @@ func TestApi_getDescription(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) { t.Run(tt.desc, func(t *testing.T) {
service, _ := setupTestEnvironment(t, tt.permissions, tt.options) service, _ := setupTestEnvironment(t, tt.permissions, tt.options)
server := setupTestServer(t, &models.SignedInUser{OrgId: 1}, service) server := setupTestServer(t, &user.SignedInUser{OrgId: 1}, service)
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/api/access-control/%s/description", tt.options.Resource), nil) req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/api/access-control/%s/description", tt.options.Resource), nil)
require.NoError(t, err) require.NoError(t, err)
@@ -160,7 +160,7 @@ func TestApi_getPermissions(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) { t.Run(tt.desc, func(t *testing.T) {
service, sql := setupTestEnvironment(t, tt.permissions, testOptions) service, sql := setupTestEnvironment(t, tt.permissions, testOptions)
server := setupTestServer(t, &models.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.GroupScopesByAction(tt.permissions)}}, service)
seedPermissions(t, tt.resourceID, sql, service) seedPermissions(t, tt.resourceID, sql, service)
@@ -237,7 +237,7 @@ func TestApi_setBuiltinRolePermission(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) { t.Run(tt.desc, func(t *testing.T) {
service, _ := setupTestEnvironment(t, tt.permissions, testOptions) service, _ := setupTestEnvironment(t, tt.permissions, testOptions)
server := setupTestServer(t, &models.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.GroupScopesByAction(tt.permissions)}}, service)
recorder := setPermission(t, server, testOptions.Resource, tt.resourceID, tt.permission, "builtInRoles", tt.builtInRole) recorder := setPermission(t, server, testOptions.Resource, tt.resourceID, tt.permission, "builtInRoles", tt.builtInRole)
assert.Equal(t, tt.expectedStatus, recorder.Code) assert.Equal(t, tt.expectedStatus, recorder.Code)
@@ -315,7 +315,7 @@ func TestApi_setTeamPermission(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) { t.Run(tt.desc, func(t *testing.T) {
service, sql := setupTestEnvironment(t, tt.permissions, testOptions) service, sql := setupTestEnvironment(t, tt.permissions, testOptions)
server := setupTestServer(t, &models.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.GroupScopesByAction(tt.permissions)}}, service)
// seed team // seed team
_, err := sql.CreateTeam("test", "test@test.com", 1) _, err := sql.CreateTeam("test", "test@test.com", 1)
@@ -398,7 +398,7 @@ func TestApi_setUserPermission(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) { t.Run(tt.desc, func(t *testing.T) {
service, sql := setupTestEnvironment(t, tt.permissions, testOptions) service, sql := setupTestEnvironment(t, tt.permissions, testOptions)
server := setupTestServer(t, &models.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.GroupScopesByAction(tt.permissions)}}, service)
// seed user // seed user
_, err := sql.CreateUser(context.Background(), user.CreateUserCommand{Login: "test", OrgID: 1}) _, err := sql.CreateUser(context.Background(), user.CreateUserCommand{Login: "test", OrgID: 1})
@@ -418,7 +418,7 @@ func TestApi_setUserPermission(t *testing.T) {
} }
} }
func setupTestServer(t *testing.T, user *models.SignedInUser, service *Service) *web.Mux { func setupTestServer(t *testing.T, user *user.SignedInUser, service *Service) *web.Mux {
server := web.New() server := web.New()
server.UseMiddleware(web.Renderer(path.Join(setting.StaticRootPath, "views"), "[[", "]]")) server.UseMiddleware(web.Renderer(path.Join(setting.StaticRootPath, "views"), "[[", "]]"))
server.Use(contextProvider(&testContext{user})) server.Use(contextProvider(&testContext{user}))
@@ -427,7 +427,7 @@ func setupTestServer(t *testing.T, user *models.SignedInUser, service *Service)
} }
type testContext struct { type testContext struct {
user *models.SignedInUser user *user.SignedInUser
} }
func contextProvider(tc *testContext) web.Handler { func contextProvider(tc *testContext) web.Handler {
@@ -9,7 +9,9 @@ import (
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions/types" "github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions/types"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
@@ -105,7 +107,7 @@ type Service struct {
sqlStore *sqlstore.SQLStore sqlStore *sqlstore.SQLStore
} }
func (s *Service) GetPermissions(ctx context.Context, user *models.SignedInUser, resourceID string) ([]accesscontrol.ResourcePermission, error) { func (s *Service) GetPermissions(ctx context.Context, user *user.SignedInUser, resourceID string) ([]accesscontrol.ResourcePermission, error) {
var inheritedScopes []string var inheritedScopes []string
if s.options.InheritedScopesSolver != nil { if s.options.InheritedScopesSolver != nil {
var err error var err error
@@ -318,7 +320,7 @@ func (s *Service) declareFixedRoles() error {
{Action: fmt.Sprintf("%s.permissions:read", s.options.Resource), Scope: scopeAll}, {Action: fmt.Sprintf("%s.permissions:read", s.options.Resource), Scope: scopeAll},
}, },
}, },
Grants: []string{string(models.ROLE_ADMIN)}, Grants: []string{string(org.RoleAdmin)},
} }
writerRole := accesscontrol.RoleRegistration{ writerRole := accesscontrol.RoleRegistration{
@@ -330,7 +332,7 @@ func (s *Service) declareFixedRoles() error {
{Action: fmt.Sprintf("%s.permissions:write", s.options.Resource), Scope: scopeAll}, {Action: fmt.Sprintf("%s.permissions:write", s.options.Resource), Scope: scopeAll},
}), }),
}, },
Grants: []string{string(models.ROLE_ADMIN)}, Grants: []string{string(org.RoleAdmin)},
} }
return s.ac.DeclareFixedRoles(readerRole, writerRole) return s.ac.DeclareFixedRoles(readerRole, writerRole)
@@ -1,8 +1,8 @@
package types package types
import ( import (
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/user"
) )
type SetResourcePermissionCommand struct { type SetResourcePermissionCommand struct {
@@ -28,5 +28,5 @@ type GetResourcePermissionsQuery struct {
ResourceAttribute string ResourceAttribute string
OnlyManaged bool OnlyManaged bool
InheritedScopes []string InheritedScopes []string
User *models.SignedInUser User *user.SignedInUser
} }

Some files were not shown because too many files have changed in this diff Show More