mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
AccessControl: Grant data source reader to all users when running oss (#49514)
* grant data source reader to all users when running oss or enterprise without license * fix asserts in alerting tests * add oss licensing service for test setup * fix tests to pass in enterprise * lint * fix tests * set setting.IsEnterprise flag for tests Co-authored-by: Yuriy Tseretyan <yuriy.tseretyan@grafana.com>
This commit is contained in:
@@ -94,6 +94,11 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
|||||||
Grants: []string{string(models.ROLE_ADMIN)},
|
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{
|
datasourcesWriterRole := ac.RoleRegistration{
|
||||||
Role: ac.RoleDTO{
|
Role: ac.RoleDTO{
|
||||||
Version: 3,
|
Version: 3,
|
||||||
@@ -135,21 +140,6 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
|||||||
Grants: []string{string(models.ROLE_VIEWER)},
|
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{
|
apikeyReaderRole := ac.RoleRegistration{
|
||||||
Role: ac.RoleDTO{
|
Role: ac.RoleDTO{
|
||||||
Version: 1,
|
Version: 1,
|
||||||
@@ -419,8 +409,8 @@ func (hs *HTTPServer) declareFixedRoles() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return hs.AccessControl.DeclareFixedRoles(
|
return hs.AccessControl.DeclareFixedRoles(
|
||||||
provisioningWriterRole, datasourcesReaderRole, datasourcesWriterRole, datasourcesIdReaderRole,
|
provisioningWriterRole, datasourcesReaderRole, datasourcesWriterRole,
|
||||||
datasourcesCompatibilityReaderRole, orgReaderRole, orgWriterRole,
|
datasourcesIdReaderRole, orgReaderRole, orgWriterRole,
|
||||||
orgMaintainerRole, teamsCreatorRole, teamsWriterRole, datasourcesExplorerRole,
|
orgMaintainerRole, teamsCreatorRole, teamsWriterRole, datasourcesExplorerRole,
|
||||||
annotationsReaderRole, dashboardAnnotationsWriterRole, annotationsWriterRole,
|
annotationsReaderRole, dashboardAnnotationsWriterRole, annotationsWriterRole,
|
||||||
dashboardsCreatorRole, dashboardsReaderRole, dashboardsWriterRole,
|
dashboardsCreatorRole, dashboardsReaderRole, dashboardsWriterRole,
|
||||||
|
|||||||
@@ -34,6 +34,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/ldap"
|
"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/loginservice"
|
||||||
"github.com/grafana/grafana/pkg/services/login/logintest"
|
"github.com/grafana/grafana/pkg/services/login/logintest"
|
||||||
"github.com/grafana/grafana/pkg/services/preference/preftest"
|
"github.com/grafana/grafana/pkg/services/preference/preftest"
|
||||||
@@ -373,6 +374,7 @@ func setupHTTPServerWithCfgDb(t *testing.T, useFakeAccessControl, enableAccessCo
|
|||||||
QuotaService: "a.QuotaService{Cfg: cfg},
|
QuotaService: "a.QuotaService{Cfg: cfg},
|
||||||
RouteRegister: routeRegister,
|
RouteRegister: routeRegister,
|
||||||
SQLStore: store,
|
SQLStore: store,
|
||||||
|
License: &licensing.OSSLicensingService{},
|
||||||
searchUsersService: searchusers.ProvideUsersService(db, filters.ProvideOSSSearchUserFilter()),
|
searchUsersService: searchusers.ProvideUsersService(db, filters.ProvideOSSSearchUserFilter()),
|
||||||
dashboardService: dashboardservice.ProvideDashboardService(
|
dashboardService: dashboardservice.ProvideDashboardService(
|
||||||
cfg, dashboardsStore, nil, features,
|
cfg, dashboardsStore, nil, features,
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import (
|
|||||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||||
ngstore "github.com/grafana/grafana/pkg/services/ngalert/store"
|
ngstore "github.com/grafana/grafana/pkg/services/ngalert/store"
|
||||||
"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/tests/testinfra"
|
"github.com/grafana/grafana/pkg/tests/testinfra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2279,9 +2280,9 @@ func TestEval(t *testing.T) {
|
|||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
payload string
|
payload string
|
||||||
expectedStatusCode int
|
expectedStatusCode func() int
|
||||||
expectedResponse string
|
expectedResponse func() string
|
||||||
expectedMessage string
|
expectedMessage func() string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "alerting condition",
|
desc: "alerting condition",
|
||||||
@@ -2307,8 +2308,10 @@ func TestEval(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
expectedStatusCode: http.StatusOK,
|
expectedMessage: func() string { return "" },
|
||||||
expectedResponse: `{
|
expectedStatusCode: func() int { return http.StatusOK },
|
||||||
|
expectedResponse: func() string {
|
||||||
|
return `{
|
||||||
"instances": [
|
"instances": [
|
||||||
{
|
{
|
||||||
"schema": {
|
"schema": {
|
||||||
@@ -2342,7 +2345,8 @@ func TestEval(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}`,
|
}`
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "normal condition",
|
desc: "normal condition",
|
||||||
@@ -2368,8 +2372,10 @@ func TestEval(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
expectedStatusCode: http.StatusOK,
|
expectedMessage: func() string { return "" },
|
||||||
expectedResponse: `{
|
expectedStatusCode: func() int { return http.StatusOK },
|
||||||
|
expectedResponse: func() string {
|
||||||
|
return `{
|
||||||
"instances": [
|
"instances": [
|
||||||
{
|
{
|
||||||
"schema": {
|
"schema": {
|
||||||
@@ -2403,7 +2409,8 @@ func TestEval(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}`,
|
}`
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "condition not found in any query or expression",
|
desc: "condition not found in any query or expression",
|
||||||
@@ -2429,8 +2436,11 @@ func TestEval(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
expectedStatusCode: http.StatusBadRequest,
|
expectedStatusCode: func() int { return http.StatusBadRequest },
|
||||||
expectedMessage: "invalid condition: condition B not found in any query or expression: it should be one of: [A]",
|
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",
|
desc: "unknown query datasource",
|
||||||
@@ -2454,8 +2464,19 @@ func TestEval(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
expectedStatusCode: http.StatusUnauthorized,
|
expectedStatusCode: func() int {
|
||||||
expectedMessage: "user is not authorized to query one or many data sources used by the rule",
|
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)
|
err = json.Unmarshal(b, &res)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
|
assert.Equal(t, tc.expectedStatusCode(), resp.StatusCode)
|
||||||
if tc.expectedResponse != "" {
|
if tc.expectedResponse() != "" {
|
||||||
require.JSONEq(t, tc.expectedResponse, string(b))
|
require.JSONEq(t, tc.expectedResponse(), string(b))
|
||||||
}
|
}
|
||||||
if tc.expectedMessage != "" {
|
if tc.expectedMessage() != "" {
|
||||||
assert.Equal(t, tc.expectedMessage, res.Message)
|
assert.Equal(t, tc.expectedMessage(), res.Message)
|
||||||
assert.NotEmpty(t, res.TraceID)
|
assert.NotEmpty(t, res.TraceID)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -2491,9 +2512,9 @@ func TestEval(t *testing.T) {
|
|||||||
testCases = []struct {
|
testCases = []struct {
|
||||||
desc string
|
desc string
|
||||||
payload string
|
payload string
|
||||||
expectedStatusCode int
|
expectedStatusCode func() int
|
||||||
expectedResponse string
|
expectedResponse func() string
|
||||||
expectedMessage string
|
expectedMessage func() string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "alerting condition",
|
desc: "alerting condition",
|
||||||
@@ -2516,8 +2537,10 @@ func TestEval(t *testing.T) {
|
|||||||
"now": "2021-04-11T14:38:14Z"
|
"now": "2021-04-11T14:38:14Z"
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
expectedStatusCode: http.StatusOK,
|
expectedMessage: func() string { return "" },
|
||||||
expectedResponse: `{
|
expectedStatusCode: func() int { return http.StatusOK },
|
||||||
|
expectedResponse: func() string {
|
||||||
|
return `{
|
||||||
"results": {
|
"results": {
|
||||||
"A": {
|
"A": {
|
||||||
"frames": [
|
"frames": [
|
||||||
@@ -2546,7 +2569,8 @@ func TestEval(t *testing.T) {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}`,
|
}`
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "normal condition",
|
desc: "normal condition",
|
||||||
@@ -2569,8 +2593,10 @@ func TestEval(t *testing.T) {
|
|||||||
"now": "2021-04-11T14:38:14Z"
|
"now": "2021-04-11T14:38:14Z"
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
expectedStatusCode: http.StatusOK,
|
expectedMessage: func() string { return "" },
|
||||||
expectedResponse: `{
|
expectedStatusCode: func() int { return http.StatusOK },
|
||||||
|
expectedResponse: func() string {
|
||||||
|
return `{
|
||||||
"results": {
|
"results": {
|
||||||
"A": {
|
"A": {
|
||||||
"frames": [
|
"frames": [
|
||||||
@@ -2599,7 +2625,8 @@ func TestEval(t *testing.T) {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}`,
|
}`
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "unknown query datasource",
|
desc: "unknown query datasource",
|
||||||
@@ -2620,8 +2647,19 @@ func TestEval(t *testing.T) {
|
|||||||
"now": "2021-04-11T14:38:14Z"
|
"now": "2021-04-11T14:38:14Z"
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
expectedStatusCode: http.StatusUnauthorized,
|
expectedResponse: func() string { return "" },
|
||||||
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 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)
|
err = json.Unmarshal(b, &res)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
|
assert.Equal(t, tc.expectedStatusCode(), resp.StatusCode)
|
||||||
if tc.expectedResponse != "" {
|
if tc.expectedResponse() != "" {
|
||||||
require.JSONEq(t, tc.expectedResponse, string(b))
|
require.JSONEq(t, tc.expectedResponse(), string(b))
|
||||||
}
|
}
|
||||||
|
if tc.expectedMessage() != "" {
|
||||||
if tc.expectedMessage != "" {
|
require.Equal(t, tc.expectedMessage(), res.Message)
|
||||||
require.Equal(t, tc.expectedMessage, res.Message)
|
|
||||||
require.NotEmpty(t, res.TraceID)
|
require.NotEmpty(t, res.TraceID)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import (
|
|||||||
"gopkg.in/ini.v1"
|
"gopkg.in/ini.v1"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/api"
|
"github.com/grafana/grafana/pkg/api"
|
||||||
|
"github.com/grafana/grafana/pkg/extensions"
|
||||||
"github.com/grafana/grafana/pkg/infra/fs"
|
"github.com/grafana/grafana/pkg/infra/fs"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/server"
|
"github.com/grafana/grafana/pkg/server"
|
||||||
@@ -35,6 +36,7 @@ func StartGrafanaEnv(t *testing.T, grafDir, cfgPath string) (string, *server.Tes
|
|||||||
t.Helper()
|
t.Helper()
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
|
setting.IsEnterprise = extensions.IsEnterprise
|
||||||
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
cmdLineArgs := setting.CommandLineArgs{Config: cfgPath, HomePath: grafDir}
|
cmdLineArgs := setting.CommandLineArgs{Config: cfgPath, HomePath: grafDir}
|
||||||
|
|||||||
Reference in New Issue
Block a user