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:
+18
-17
@@ -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
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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
@@ -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{}
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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",
|
||||||
|
|||||||
@@ -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] != "" {
|
||||||
|
|||||||
@@ -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,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
@@ -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})
|
||||||
|
|||||||
@@ -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
@@ -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}}},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
@@ -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"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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"},
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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", "/")
|
||||||
|
|||||||
@@ -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{
|
||||||
|
|||||||
@@ -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
@@ -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,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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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"`
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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,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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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"`
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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:"-"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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"`
|
||||||
|
|||||||
@@ -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}},
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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
Reference in New Issue
Block a user