diff --git a/pkg/api/accesscontrol.go b/pkg/api/accesscontrol.go index 4d2f33a9516..82c82670bfc 100644 --- a/pkg/api/accesscontrol.go +++ b/pkg/api/accesscontrol.go @@ -94,6 +94,11 @@ func (hs *HTTPServer) declareFixedRoles() error { Grants: []string{string(models.ROLE_ADMIN)}, } + // when running oss or enterprise without a license all users should be able to query data sources + if !hs.License.FeatureEnabled("accesscontrol.enforcement") { + datasourcesReaderRole.Grants = []string{string(models.ROLE_VIEWER)} + } + datasourcesWriterRole := ac.RoleRegistration{ Role: ac.RoleDTO{ Version: 3, @@ -135,21 +140,6 @@ func (hs *HTTPServer) declareFixedRoles() error { Grants: []string{string(models.ROLE_VIEWER)}, } - datasourcesCompatibilityReaderRole := ac.RoleRegistration{ - Role: ac.RoleDTO{ - Version: 3, - Name: "fixed:datasources:compatibility:querier", - DisplayName: "Data source compatibility querier", - Description: "Only used for open source compatibility. Query data sources.", - Group: "Infrequently used", - Permissions: []ac.Permission{ - {Action: datasources.ActionQuery}, - {Action: datasources.ActionRead}, - }, - }, - Grants: []string{string(models.ROLE_VIEWER)}, - } - apikeyReaderRole := ac.RoleRegistration{ Role: ac.RoleDTO{ Version: 1, @@ -419,8 +409,8 @@ func (hs *HTTPServer) declareFixedRoles() error { } return hs.AccessControl.DeclareFixedRoles( - provisioningWriterRole, datasourcesReaderRole, datasourcesWriterRole, datasourcesIdReaderRole, - datasourcesCompatibilityReaderRole, orgReaderRole, orgWriterRole, + provisioningWriterRole, datasourcesReaderRole, datasourcesWriterRole, + datasourcesIdReaderRole, orgReaderRole, orgWriterRole, orgMaintainerRole, teamsCreatorRole, teamsWriterRole, datasourcesExplorerRole, annotationsReaderRole, dashboardAnnotationsWriterRole, annotationsWriterRole, dashboardsCreatorRole, dashboardsReaderRole, dashboardsWriterRole, diff --git a/pkg/api/common_test.go b/pkg/api/common_test.go index 012380ef0bf..6e0f28266a7 100644 --- a/pkg/api/common_test.go +++ b/pkg/api/common_test.go @@ -33,6 +33,7 @@ import ( dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/ldap" + "github.com/grafana/grafana/pkg/services/licensing" "github.com/grafana/grafana/pkg/services/login/loginservice" "github.com/grafana/grafana/pkg/services/login/logintest" "github.com/grafana/grafana/pkg/services/preference/preftest" @@ -371,6 +372,7 @@ func setupHTTPServerWithCfgDb(t *testing.T, useFakeAccessControl, enableAccessCo QuotaService: "a.QuotaService{Cfg: cfg}, RouteRegister: routeRegister, SQLStore: store, + License: &licensing.OSSLicensingService{}, searchUsersService: searchusers.ProvideUsersService(db, filters.ProvideOSSSearchUserFilter()), dashboardService: dashboardservice.ProvideDashboardService( cfg, dashboardsStore, nil, features, diff --git a/pkg/tests/api/alerting/api_alertmanager_test.go b/pkg/tests/api/alerting/api_alertmanager_test.go index 52d2b5db713..d7ff048ab13 100644 --- a/pkg/tests/api/alerting/api_alertmanager_test.go +++ b/pkg/tests/api/alerting/api_alertmanager_test.go @@ -22,6 +22,7 @@ import ( ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models" ngstore "github.com/grafana/grafana/pkg/services/ngalert/store" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/tests/testinfra" ) @@ -2279,9 +2280,9 @@ func TestEval(t *testing.T) { testCases := []struct { desc string payload string - expectedStatusCode int - expectedResponse string - expectedMessage string + expectedStatusCode func() int + expectedResponse func() string + expectedMessage func() string }{ { desc: "alerting condition", @@ -2307,8 +2308,10 @@ func TestEval(t *testing.T) { } } `, - expectedStatusCode: http.StatusOK, - expectedResponse: `{ + expectedMessage: func() string { return "" }, + expectedStatusCode: func() int { return http.StatusOK }, + expectedResponse: func() string { + return `{ "instances": [ { "schema": { @@ -2342,7 +2345,8 @@ func TestEval(t *testing.T) { } } ] - }`, + }` + }, }, { desc: "normal condition", @@ -2368,8 +2372,10 @@ func TestEval(t *testing.T) { } } `, - expectedStatusCode: http.StatusOK, - expectedResponse: `{ + expectedMessage: func() string { return "" }, + expectedStatusCode: func() int { return http.StatusOK }, + expectedResponse: func() string { + return `{ "instances": [ { "schema": { @@ -2403,7 +2409,8 @@ func TestEval(t *testing.T) { } } ] - }`, + }` + }, }, { desc: "condition not found in any query or expression", @@ -2429,8 +2436,11 @@ func TestEval(t *testing.T) { } } `, - expectedStatusCode: http.StatusBadRequest, - expectedMessage: "invalid condition: condition B not found in any query or expression: it should be one of: [A]", + expectedStatusCode: func() int { return http.StatusBadRequest }, + expectedMessage: func() string { + return "invalid condition: condition B not found in any query or expression: it should be one of: [A]" + }, + expectedResponse: func() string { return "" }, }, { desc: "unknown query datasource", @@ -2454,8 +2464,19 @@ func TestEval(t *testing.T) { } } `, - expectedStatusCode: http.StatusUnauthorized, - expectedMessage: "user is not authorized to query one or many data sources used by the rule", + expectedStatusCode: func() int { + if setting.IsEnterprise { + return http.StatusUnauthorized + } + return http.StatusBadRequest + }, + expectedMessage: func() string { + if setting.IsEnterprise { + return "user is not authorized to query one or many data sources used by the rule" + } + return "invalid condition: invalid query A: data source not found: unknown" + }, + expectedResponse: func() string { return "" }, }, } @@ -2476,12 +2497,12 @@ func TestEval(t *testing.T) { err = json.Unmarshal(b, &res) require.NoError(t, err) - assert.Equal(t, tc.expectedStatusCode, resp.StatusCode) - if tc.expectedResponse != "" { - require.JSONEq(t, tc.expectedResponse, string(b)) + assert.Equal(t, tc.expectedStatusCode(), resp.StatusCode) + if tc.expectedResponse() != "" { + require.JSONEq(t, tc.expectedResponse(), string(b)) } - if tc.expectedMessage != "" { - assert.Equal(t, tc.expectedMessage, res.Message) + if tc.expectedMessage() != "" { + assert.Equal(t, tc.expectedMessage(), res.Message) assert.NotEmpty(t, res.TraceID) } }) @@ -2491,9 +2512,9 @@ func TestEval(t *testing.T) { testCases = []struct { desc string payload string - expectedStatusCode int - expectedResponse string - expectedMessage string + expectedStatusCode func() int + expectedResponse func() string + expectedMessage func() string }{ { desc: "alerting condition", @@ -2516,8 +2537,10 @@ func TestEval(t *testing.T) { "now": "2021-04-11T14:38:14Z" } `, - expectedStatusCode: http.StatusOK, - expectedResponse: `{ + expectedMessage: func() string { return "" }, + expectedStatusCode: func() int { return http.StatusOK }, + expectedResponse: func() string { + return `{ "results": { "A": { "frames": [ @@ -2546,7 +2569,8 @@ func TestEval(t *testing.T) { ] } } - }`, + }` + }, }, { desc: "normal condition", @@ -2569,8 +2593,10 @@ func TestEval(t *testing.T) { "now": "2021-04-11T14:38:14Z" } `, - expectedStatusCode: http.StatusOK, - expectedResponse: `{ + expectedMessage: func() string { return "" }, + expectedStatusCode: func() int { return http.StatusOK }, + expectedResponse: func() string { + return `{ "results": { "A": { "frames": [ @@ -2599,7 +2625,8 @@ func TestEval(t *testing.T) { ] } } - }`, + }` + }, }, { desc: "unknown query datasource", @@ -2620,8 +2647,19 @@ func TestEval(t *testing.T) { "now": "2021-04-11T14:38:14Z" } `, - expectedStatusCode: http.StatusUnauthorized, - expectedMessage: "user is not authorized to query one or many data sources used by the rule", + expectedResponse: func() string { return "" }, + expectedStatusCode: func() int { + if setting.IsEnterprise { + return http.StatusUnauthorized + } + return http.StatusBadRequest + }, + expectedMessage: func() string { + if setting.IsEnterprise { + return "user is not authorized to query one or many data sources used by the rule" + } + return "invalid queries or expressions: invalid query A: data source not found: unknown" + }, }, } @@ -2642,13 +2680,12 @@ func TestEval(t *testing.T) { err = json.Unmarshal(b, &res) require.NoError(t, err) - assert.Equal(t, tc.expectedStatusCode, resp.StatusCode) - if tc.expectedResponse != "" { - require.JSONEq(t, tc.expectedResponse, string(b)) + assert.Equal(t, tc.expectedStatusCode(), resp.StatusCode) + if tc.expectedResponse() != "" { + require.JSONEq(t, tc.expectedResponse(), string(b)) } - - if tc.expectedMessage != "" { - require.Equal(t, tc.expectedMessage, res.Message) + if tc.expectedMessage() != "" { + require.Equal(t, tc.expectedMessage(), res.Message) require.NotEmpty(t, res.TraceID) } }) diff --git a/pkg/tests/testinfra/testinfra.go b/pkg/tests/testinfra/testinfra.go index 5ebd80e79ba..1213bf8bba5 100644 --- a/pkg/tests/testinfra/testinfra.go +++ b/pkg/tests/testinfra/testinfra.go @@ -17,6 +17,7 @@ import ( "gopkg.in/ini.v1" "github.com/grafana/grafana/pkg/api" + "github.com/grafana/grafana/pkg/extensions" "github.com/grafana/grafana/pkg/infra/fs" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/server" @@ -35,6 +36,7 @@ func StartGrafanaEnv(t *testing.T, grafDir, cfgPath string) (string, *server.Tes t.Helper() ctx := context.Background() + setting.IsEnterprise = extensions.IsEnterprise listener, err := net.Listen("tcp", "127.0.0.1:0") require.NoError(t, err) cmdLineArgs := setting.CommandLineArgs{Config: cfgPath, HomePath: grafDir}