PublicDashboards: Validate access token (#57298)

Adding validation for access token
This commit is contained in:
lean.dev
2022-10-20 16:43:33 -03:00
committed by GitHub
parent 5ee4744d62
commit 552d9d70eb
6 changed files with 118 additions and 59 deletions
+80 -38
View File
@@ -10,7 +10,6 @@ import (
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/google/uuid"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/stretchr/testify/assert"
@@ -53,28 +52,44 @@ type JsonErrResponse struct {
func TestAPIGetAnnotations(t *testing.T) {
testCases := []struct {
Name string
ExpectedHttpResponse int
Annotations []AnnotationEvent
ServiceError error
From string
To string
Name string
ExpectedHttpResponse int
Annotations []AnnotationEvent
ServiceError error
AccessToken string
From string
To string
ExpectedServiceCalled bool
}{
{
Name: "will return success when there is no error and to and from are provided",
ExpectedHttpResponse: http.StatusOK,
Annotations: []AnnotationEvent{{Id: 1}},
ServiceError: nil,
From: "123",
To: "123",
Name: "will return success when there is no error and to and from are provided",
ExpectedHttpResponse: http.StatusOK,
Annotations: []AnnotationEvent{{Id: 1}},
ServiceError: nil,
AccessToken: validAccessToken,
From: "123",
To: "123",
ExpectedServiceCalled: true,
},
{
Name: "will return 500 when service returns an error",
ExpectedHttpResponse: http.StatusInternalServerError,
Annotations: nil,
ServiceError: errors.New("an error happened"),
From: "123",
To: "123",
Name: "will return 500 when service returns an error",
ExpectedHttpResponse: http.StatusInternalServerError,
Annotations: nil,
ServiceError: errors.New("an error happened"),
AccessToken: validAccessToken,
From: "123",
To: "123",
ExpectedServiceCalled: true,
},
{
Name: "will return 400 when has an incorrect Access Token",
ExpectedHttpResponse: http.StatusBadRequest,
Annotations: nil,
ServiceError: errors.New("an error happened"),
AccessToken: "TooShortAccessToken",
From: "123",
To: "123",
ExpectedServiceCalled: false,
},
}
for _, test := range testCases {
@@ -82,11 +97,15 @@ func TestAPIGetAnnotations(t *testing.T) {
cfg := setting.NewCfg()
cfg.RBACEnabled = false
service := publicdashboards.NewFakePublicDashboardService(t)
service.On("GetAnnotations", mock.Anything, mock.Anything, mock.AnythingOfType("string")).
Return(test.Annotations, test.ServiceError).Once()
if test.ExpectedServiceCalled {
service.On("GetAnnotations", mock.Anything, mock.Anything, mock.AnythingOfType("string")).
Return(test.Annotations, test.ServiceError).Once()
}
testServer := setupTestServer(t, cfg, featuremgmt.WithFeatures(featuremgmt.FlagPublicDashboards), service, nil, anonymousUser)
path := fmt.Sprintf("/api/public/dashboards/abc123/annotations?from=%s&to=%s", test.From, test.To)
path := fmt.Sprintf("/api/public/dashboards/%s/annotations?from=%s&to=%s", test.AccessToken, test.From, test.To)
response := callAPI(testServer, http.MethodGet, path, nil, t)
assert.Equal(t, test.ExpectedHttpResponse, response.Code)
@@ -221,9 +240,6 @@ func TestAPIListPublicDashboard(t *testing.T) {
func TestAPIGetPublicDashboard(t *testing.T) {
DashboardUid := "dashboard-abcd1234"
token, err := uuid.NewRandom()
require.NoError(t, err)
accessToken := fmt.Sprintf("%x", token)
testCases := []struct {
Name string
@@ -231,24 +247,35 @@ func TestAPIGetPublicDashboard(t *testing.T) {
ExpectedHttpResponse int
DashboardResult *models.Dashboard
Err error
FixedErrorResponse string
}{
{
Name: "It gets a public dashboard",
AccessToken: accessToken,
AccessToken: validAccessToken,
ExpectedHttpResponse: http.StatusOK,
DashboardResult: &models.Dashboard{
Data: simplejson.NewFromAny(map[string]interface{}{
"Uid": DashboardUid,
}),
},
Err: nil,
Err: nil,
FixedErrorResponse: "",
},
{
Name: "It should return 404 if no public dashboard",
AccessToken: accessToken,
AccessToken: validAccessToken,
ExpectedHttpResponse: http.StatusNotFound,
DashboardResult: nil,
Err: ErrPublicDashboardNotFound,
FixedErrorResponse: "",
},
{
Name: "It should return 400 if it is an invalid access token",
AccessToken: "SomeInvalidAccessToken",
ExpectedHttpResponse: http.StatusBadRequest,
DashboardResult: nil,
Err: nil,
FixedErrorResponse: "{\"message\":\"Invalid Access Token\"}",
},
}
@@ -278,7 +305,7 @@ func TestAPIGetPublicDashboard(t *testing.T) {
assert.Equal(t, test.ExpectedHttpResponse, response.Code)
if test.Err == nil {
if test.Err == nil && test.FixedErrorResponse == "" {
var dashResp dtos.DashboardFullWithMeta
err := json.Unmarshal(response.Body.Bytes(), &dashResp)
require.NoError(t, err)
@@ -287,6 +314,9 @@ func TestAPIGetPublicDashboard(t *testing.T) {
assert.Equal(t, false, dashResp.Meta.CanEdit)
assert.Equal(t, false, dashResp.Meta.CanDelete)
assert.Equal(t, false, dashResp.Meta.CanSave)
} else if test.FixedErrorResponse != "" {
require.Equal(t, test.ExpectedHttpResponse, response.Code)
require.JSONEq(t, "{\"message\":\"Invalid Access Token\"}", response.Body.String())
} else {
var errResp JsonErrResponse
err := json.Unmarshal(response.Body.Bytes(), &errResp)
@@ -585,29 +615,37 @@ func TestAPIQueryPublicDashboard(t *testing.T) {
t.Run("Status code is 400 when the panel ID is invalid", func(t *testing.T) {
server, _ := setup(true)
resp := callAPI(server, http.MethodPost, "/api/public/dashboards/abc123/panels/notanumber/query", strings.NewReader("{}"), t)
path := fmt.Sprintf("/api/public/dashboards/%s/panels/notanumber/query", validAccessToken)
resp := callAPI(server, http.MethodPost, path, strings.NewReader("{}"), t)
require.Equal(t, http.StatusBadRequest, resp.Code)
})
t.Run("Status code is 400 when the access token is invalid", func(t *testing.T) {
server, _ := setup(true)
resp := callAPI(server, http.MethodPost, getValidQueryPath("SomeInvalidAccessToken"), strings.NewReader("{}"), t)
require.Equal(t, http.StatusBadRequest, resp.Code)
require.JSONEq(t, "{\"message\":\"Invalid Access Token\"}", resp.Body.String())
})
t.Run("Status code is 400 when the intervalMS is lesser than 0", func(t *testing.T) {
server, fakeDashboardService := setup(true)
fakeDashboardService.On("GetQueryDataResponse", mock.Anything, true, mock.Anything, int64(2), "abc123").Return(&backend.QueryDataResponse{}, ErrPublicDashboardBadRequest)
resp := callAPI(server, http.MethodPost, "/api/public/dashboards/abc123/panels/2/query", strings.NewReader(`{"intervalMs":-100,"maxDataPoints":1000}`), t)
fakeDashboardService.On("GetQueryDataResponse", mock.Anything, true, mock.Anything, int64(2), validAccessToken).Return(&backend.QueryDataResponse{}, ErrPublicDashboardBadRequest)
resp := callAPI(server, http.MethodPost, getValidQueryPath(validAccessToken), strings.NewReader(`{"intervalMs":-100,"maxDataPoints":1000}`), t)
require.Equal(t, http.StatusBadRequest, resp.Code)
})
t.Run("Status code is 400 when the maxDataPoints is lesser than 0", func(t *testing.T) {
server, fakeDashboardService := setup(true)
fakeDashboardService.On("GetQueryDataResponse", mock.Anything, true, mock.Anything, int64(2), "abc123").Return(&backend.QueryDataResponse{}, ErrPublicDashboardBadRequest)
resp := callAPI(server, http.MethodPost, "/api/public/dashboards/abc123/panels/2/query", strings.NewReader(`{"intervalMs":100,"maxDataPoints":-1000}`), t)
fakeDashboardService.On("GetQueryDataResponse", mock.Anything, true, mock.Anything, int64(2), validAccessToken).Return(&backend.QueryDataResponse{}, ErrPublicDashboardBadRequest)
resp := callAPI(server, http.MethodPost, getValidQueryPath(validAccessToken), strings.NewReader(`{"intervalMs":100,"maxDataPoints":-1000}`), t)
require.Equal(t, http.StatusBadRequest, resp.Code)
})
t.Run("Returns query data when feature toggle is enabled", func(t *testing.T) {
server, fakeDashboardService := setup(true)
fakeDashboardService.On("GetQueryDataResponse", mock.Anything, true, mock.Anything, int64(2), "abc123").Return(mockedResponse, nil)
fakeDashboardService.On("GetQueryDataResponse", mock.Anything, true, mock.Anything, int64(2), validAccessToken).Return(mockedResponse, nil)
resp := callAPI(server, http.MethodPost, "/api/public/dashboards/abc123/panels/2/query", strings.NewReader("{}"), t)
resp := callAPI(server, http.MethodPost, getValidQueryPath(validAccessToken), strings.NewReader("{}"), t)
require.JSONEq(
t,
@@ -619,13 +657,17 @@ func TestAPIQueryPublicDashboard(t *testing.T) {
t.Run("Status code is 500 when the query fails", func(t *testing.T) {
server, fakeDashboardService := setup(true)
fakeDashboardService.On("GetQueryDataResponse", mock.Anything, true, mock.Anything, int64(2), "abc123").Return(&backend.QueryDataResponse{}, fmt.Errorf("error"))
fakeDashboardService.On("GetQueryDataResponse", mock.Anything, true, mock.Anything, int64(2), validAccessToken).Return(&backend.QueryDataResponse{}, fmt.Errorf("error"))
resp := callAPI(server, http.MethodPost, "/api/public/dashboards/abc123/panels/2/query", strings.NewReader("{}"), t)
resp := callAPI(server, http.MethodPost, getValidQueryPath(validAccessToken), strings.NewReader("{}"), t)
require.Equal(t, http.StatusInternalServerError, resp.Code)
})
}
func getValidQueryPath(accessToken string) string {
return fmt.Sprintf("/api/public/dashboards/%s/panels/2/query", accessToken)
}
func TestIntegrationUnauthenticatedUserCanGetPubdashPanelQueryData(t *testing.T) {
db := db.InitTestDB(t)