PublicDashboards: Validate access token (#57298)
Adding validation for access token
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user