mirror of
https://github.com/grafana/grafana.git
synced 2025-08-01 05:41:49 +08:00
Query History: Prevent viewers from accessing (#88735)
* Add permissions check for viewer without viewers_can_edit * Add test * fix lint * Add role checks on other handlers * Linter and fix Go issue * Fix conflict * Remove invalid way of testing for error
This commit is contained in:
@ -8,6 +8,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/middleware"
|
||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
)
|
||||
@ -35,6 +36,10 @@ func (s *QueryHistoryService) registerAPIEndpoints() {
|
||||
// 401: unauthorisedError
|
||||
// 500: internalServerError
|
||||
func (s *QueryHistoryService) createHandler(c *contextmodel.ReqContext) response.Response {
|
||||
if c.GetOrgRole() == org.RoleViewer && !s.Cfg.ViewersCanEdit {
|
||||
return response.Error(http.StatusUnauthorized, "Failed to create query history", nil)
|
||||
}
|
||||
|
||||
cmd := CreateQueryInQueryHistoryCommand{}
|
||||
if err := web.Bind(c.Req, &cmd); err != nil {
|
||||
return response.Error(http.StatusBadRequest, "bad request data", err)
|
||||
@ -61,6 +66,10 @@ func (s *QueryHistoryService) createHandler(c *contextmodel.ReqContext) response
|
||||
// 401: unauthorisedError
|
||||
// 500: internalServerError
|
||||
func (s *QueryHistoryService) searchHandler(c *contextmodel.ReqContext) response.Response {
|
||||
if c.GetOrgRole() == org.RoleViewer && !s.Cfg.ViewersCanEdit {
|
||||
return response.Error(http.StatusUnauthorized, "Failed to get query history", nil)
|
||||
}
|
||||
|
||||
timeRange := gtime.NewTimeRange(c.Query("from"), c.Query("to"))
|
||||
|
||||
query := SearchInQueryHistoryQuery{
|
||||
@ -93,6 +102,10 @@ func (s *QueryHistoryService) searchHandler(c *contextmodel.ReqContext) response
|
||||
// 401: unauthorisedError
|
||||
// 500: internalServerError
|
||||
func (s *QueryHistoryService) deleteHandler(c *contextmodel.ReqContext) response.Response {
|
||||
if c.GetOrgRole() == org.RoleViewer && !s.Cfg.ViewersCanEdit {
|
||||
return response.Error(http.StatusUnauthorized, "Failed to delete query history", nil)
|
||||
}
|
||||
|
||||
queryUID := web.Params(c.Req)[":uid"]
|
||||
if len(queryUID) > 0 && !util.IsValidShortUID(queryUID) {
|
||||
return response.Error(http.StatusNotFound, "Query in query history not found", nil)
|
||||
@ -150,6 +163,9 @@ func (s *QueryHistoryService) patchCommentHandler(c *contextmodel.ReqContext) re
|
||||
// 401: unauthorisedError
|
||||
// 500: internalServerError
|
||||
func (s *QueryHistoryService) starHandler(c *contextmodel.ReqContext) response.Response {
|
||||
if c.GetOrgRole() == org.RoleViewer && !s.Cfg.ViewersCanEdit {
|
||||
return response.Error(http.StatusUnauthorized, "Failed to star query history", nil)
|
||||
}
|
||||
queryUID := web.Params(c.Req)[":uid"]
|
||||
if len(queryUID) > 0 && !util.IsValidShortUID(queryUID) {
|
||||
return response.Error(http.StatusNotFound, "Query in query history not found", nil)
|
||||
@ -174,6 +190,9 @@ func (s *QueryHistoryService) starHandler(c *contextmodel.ReqContext) response.R
|
||||
// 401: unauthorisedError
|
||||
// 500: internalServerError
|
||||
func (s *QueryHistoryService) unstarHandler(c *contextmodel.ReqContext) response.Response {
|
||||
if c.GetOrgRole() == org.RoleViewer && !s.Cfg.ViewersCanEdit {
|
||||
return response.Error(http.StatusUnauthorized, "Failed to unstar query history", nil)
|
||||
}
|
||||
queryUID := web.Params(c.Req)[":uid"]
|
||||
if len(queryUID) > 0 && !util.IsValidShortUID(queryUID) {
|
||||
return response.Error(http.StatusNotFound, "Query in query history not found", nil)
|
||||
|
@ -12,7 +12,7 @@ func TestIntegrationCreateQueryInQueryHistory(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping integration test")
|
||||
}
|
||||
testScenario(t, "When users tries to create query in query history it should succeed",
|
||||
testScenario(t, "When users tries to create query in query history it should succeed", false,
|
||||
func(t *testing.T, sc scenarioContext) {
|
||||
command := CreateQueryInQueryHistoryCommand{
|
||||
DatasourceUID: "NCzh67i",
|
||||
|
@ -12,7 +12,7 @@ func TestIntegrationGetQueriesFromQueryHistory(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping integration test")
|
||||
}
|
||||
testScenario(t, "When users tries to get query in empty query history, it should return empty result",
|
||||
testScenario(t, "When users tries to get query in empty query history, it should return empty result", false,
|
||||
func(t *testing.T, sc scenarioContext) {
|
||||
sc.reqContext.Req.Form.Add("datasourceUid", "test")
|
||||
resp := sc.service.searchHandler(sc.reqContext)
|
||||
@ -262,6 +262,13 @@ func TestIntegrationGetQueriesFromQueryHistory(t *testing.T) {
|
||||
require.Equal(t, 0, response.Result.TotalCount)
|
||||
})
|
||||
|
||||
testScenario(t, "When user is viewer, return 401", true,
|
||||
func(t *testing.T, sc scenarioContext) {
|
||||
sc.reqContext.Req.Form.Add("datasourceUid", "test")
|
||||
resp := sc.service.searchHandler(sc.reqContext)
|
||||
require.Equal(t, 401, resp.Status())
|
||||
})
|
||||
|
||||
testScenarioWithMixedQueriesInQueryHistory(t, "When users tries to get queries with mixed data source it should return correct queries",
|
||||
func(t *testing.T, sc scenarioContext) {
|
||||
t.Skip() // This test fails a lot at the moment
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
@ -47,7 +48,7 @@ type scenarioContext struct {
|
||||
initialResult QueryHistoryResponse
|
||||
}
|
||||
|
||||
func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioContext)) {
|
||||
func testScenario(t *testing.T, desc string, isViewer bool, fn func(t *testing.T, sc scenarioContext)) {
|
||||
t.Helper()
|
||||
|
||||
t.Run(desc, func(t *testing.T) {
|
||||
@ -72,13 +73,20 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
var role identity.RoleType
|
||||
if isViewer {
|
||||
role = org.RoleViewer
|
||||
} else {
|
||||
role = org.RoleEditor
|
||||
}
|
||||
|
||||
usr := user.SignedInUser{
|
||||
UserID: testUserID,
|
||||
Name: "Signed In User",
|
||||
Login: "signed_in_user",
|
||||
Email: "signed.in.user@test.com",
|
||||
OrgID: testOrgID,
|
||||
OrgRole: org.RoleViewer,
|
||||
OrgRole: role,
|
||||
LastSeenAt: service.now(),
|
||||
}
|
||||
|
||||
@ -105,7 +113,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
|
||||
func testScenarioWithQueryInQueryHistory(t *testing.T, desc string, fn func(t *testing.T, sc scenarioContext)) {
|
||||
t.Helper()
|
||||
|
||||
testScenario(t, desc, func(t *testing.T, sc scenarioContext) {
|
||||
testScenario(t, desc, false, func(t *testing.T, sc scenarioContext) {
|
||||
command := CreateQueryInQueryHistoryCommand{
|
||||
DatasourceUID: testDsUID1,
|
||||
Queries: simplejson.NewFromAny([]interface{}{
|
||||
@ -124,7 +132,7 @@ func testScenarioWithQueryInQueryHistory(t *testing.T, desc string, fn func(t *t
|
||||
func testScenarioWithMultipleQueriesInQueryHistory(t *testing.T, desc string, fn func(t *testing.T, sc scenarioContext)) {
|
||||
t.Helper()
|
||||
|
||||
testScenario(t, desc, func(t *testing.T, sc scenarioContext) {
|
||||
testScenario(t, desc, false, func(t *testing.T, sc scenarioContext) {
|
||||
start := time.Now().Add(-3 * time.Second)
|
||||
sc.service.now = func() time.Time { return start }
|
||||
command1 := CreateQueryInQueryHistoryCommand{
|
||||
@ -185,7 +193,7 @@ func testScenarioWithMultipleQueriesInQueryHistory(t *testing.T, desc string, fn
|
||||
func testScenarioWithMixedQueriesInQueryHistory(t *testing.T, desc string, fn func(t *testing.T, sc scenarioContext)) {
|
||||
t.Helper()
|
||||
|
||||
testScenario(t, desc, func(t *testing.T, sc scenarioContext) {
|
||||
testScenario(t, desc, false, func(t *testing.T, sc scenarioContext) {
|
||||
start := time.Now()
|
||||
sc.service.now = func() time.Time { return start }
|
||||
command1 := CreateQueryInQueryHistoryCommand{
|
||||
|
Reference in New Issue
Block a user