mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Editor role can access all provisioning API (#85022)
This commit is contained in:
parent
87548968e9
commit
48de8657c9
@ -469,6 +469,8 @@ const (
|
||||
ActionAlertingProvisioningRead = "alert.provisioning:read"
|
||||
ActionAlertingProvisioningReadSecrets = "alert.provisioning.secrets:read"
|
||||
ActionAlertingProvisioningWrite = "alert.provisioning:write"
|
||||
// ActionAlertingProvisioningSetStatus Gives access to set provisioning status to alerting resources. Cannot be used alone. Only in conjunction with other permissions.
|
||||
ActionAlertingProvisioningSetStatus = "alert.provisioning.provenance:write"
|
||||
|
||||
// Feature Management actions
|
||||
ActionFeatureManagementRead = "featuremgmt.read"
|
||||
|
@ -205,6 +205,21 @@ var (
|
||||
},
|
||||
Grants: []string{string(org.RoleAdmin)},
|
||||
}
|
||||
|
||||
alertingProvisioningStatus = accesscontrol.RoleRegistration{
|
||||
Role: accesscontrol.RoleDTO{
|
||||
Name: accesscontrol.FixedRolePrefix + "alerting.provisioning.provenance:writer",
|
||||
DisplayName: "Set provisioning status",
|
||||
Description: "Set provisioning status for alerting resources. Should be used together with other regular roles (Notifications Writer and/or Rules Writer)",
|
||||
Group: AlertRolesGroup,
|
||||
Permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: accesscontrol.ActionAlertingProvisioningSetStatus, // organization scope
|
||||
},
|
||||
},
|
||||
},
|
||||
Grants: []string{string(org.RoleAdmin), string(org.RoleEditor)},
|
||||
}
|
||||
)
|
||||
|
||||
func DeclareFixedRoles(service accesscontrol.Service) error {
|
||||
@ -212,6 +227,6 @@ func DeclareFixedRoles(service accesscontrol.Service) error {
|
||||
rulesReaderRole, rulesWriterRole,
|
||||
instancesReaderRole, instancesWriterRole,
|
||||
notificationsReaderRole, notificationsWriterRole,
|
||||
alertingReaderRole, alertingWriterRole, alertingProvisionerRole, alertingProvisioningReaderWithSecretsRole,
|
||||
alertingReaderRole, alertingWriterRole, alertingProvisionerRole, alertingProvisioningReaderWithSecretsRole, alertingProvisioningStatus,
|
||||
)
|
||||
}
|
||||
|
@ -265,23 +265,33 @@ func (api *API) authorize(method, path string) web.Handler {
|
||||
eval = ac.EvalAny(
|
||||
ac.EvalPermission(ac.ActionAlertingProvisioningRead),
|
||||
ac.EvalPermission(ac.ActionAlertingProvisioningReadSecrets),
|
||||
ac.EvalPermission(ac.ActionAlertingNotificationsRead),
|
||||
)
|
||||
|
||||
// Grafana-only Provisioning Write Paths
|
||||
case http.MethodPost + "/api/v1/provisioning/alert-rules":
|
||||
eval = ac.EvalAny(
|
||||
ac.EvalPermission(ac.ActionAlertingProvisioningWrite),
|
||||
ac.EvalPermission(ac.ActionAlertingRuleCreate), // more granular permissions are enforced by the handler via "authorizeRuleChanges"
|
||||
ac.EvalAll(
|
||||
ac.EvalPermission(ac.ActionAlertingRuleCreate), // more granular permissions are enforced by the handler via "authorizeRuleChanges"
|
||||
ac.EvalPermission(ac.ActionAlertingProvisioningSetStatus),
|
||||
),
|
||||
)
|
||||
case http.MethodPut + "/api/v1/provisioning/alert-rules/{UID}":
|
||||
eval = ac.EvalAny(
|
||||
ac.EvalPermission(ac.ActionAlertingProvisioningWrite),
|
||||
ac.EvalPermission(ac.ActionAlertingRuleUpdate), // more granular permissions are enforced by the handler via "authorizeRuleChanges"
|
||||
ac.EvalAll(
|
||||
ac.EvalPermission(ac.ActionAlertingRuleUpdate), // more granular permissions are enforced by the handler via "authorizeRuleChanges"
|
||||
ac.EvalPermission(ac.ActionAlertingProvisioningSetStatus),
|
||||
),
|
||||
)
|
||||
case http.MethodDelete + "/api/v1/provisioning/alert-rules/{UID}":
|
||||
eval = ac.EvalAny(
|
||||
ac.EvalPermission(ac.ActionAlertingProvisioningWrite),
|
||||
ac.EvalPermission(ac.ActionAlertingRuleDelete), // more granular permissions are enforced by the handler via "authorizeRuleChanges"
|
||||
ac.EvalAll(
|
||||
ac.EvalPermission(ac.ActionAlertingRuleDelete), // more granular permissions are enforced by the handler via "authorizeRuleChanges"
|
||||
ac.EvalPermission(ac.ActionAlertingProvisioningSetStatus),
|
||||
),
|
||||
)
|
||||
case http.MethodDelete + "/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}":
|
||||
scope := dashboards.ScopeFoldersProvider.GetResourceScopeUID(ac.Parameter(":FolderUID"))
|
||||
@ -291,6 +301,7 @@ func (api *API) authorize(method, path string) web.Handler {
|
||||
ac.EvalPermission(ac.ActionAlertingRuleDelete, scope),
|
||||
ac.EvalPermission(ac.ActionAlertingRuleRead, scope),
|
||||
ac.EvalPermission(dashboards.ActionFoldersRead, scope),
|
||||
ac.EvalPermission(ac.ActionAlertingProvisioningSetStatus),
|
||||
),
|
||||
)
|
||||
case http.MethodPut + "/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}":
|
||||
@ -300,6 +311,7 @@ func (api *API) authorize(method, path string) web.Handler {
|
||||
ac.EvalAll(
|
||||
ac.EvalPermission(ac.ActionAlertingRuleRead, scope),
|
||||
ac.EvalPermission(dashboards.ActionFoldersRead, scope),
|
||||
ac.EvalPermission(ac.ActionAlertingProvisioningSetStatus),
|
||||
ac.EvalAny( // the exact permissions will be checked after the operations are determined
|
||||
ac.EvalPermission(ac.ActionAlertingRuleUpdate, scope),
|
||||
ac.EvalPermission(ac.ActionAlertingRuleCreate, scope),
|
||||
@ -318,7 +330,13 @@ func (api *API) authorize(method, path string) web.Handler {
|
||||
http.MethodPost + "/api/v1/provisioning/mute-timings",
|
||||
http.MethodPut + "/api/v1/provisioning/mute-timings/{name}",
|
||||
http.MethodDelete + "/api/v1/provisioning/mute-timings/{name}":
|
||||
eval = ac.EvalPermission(ac.ActionAlertingProvisioningWrite) // organization scope
|
||||
eval = ac.EvalAny(
|
||||
ac.EvalPermission(ac.ActionAlertingProvisioningWrite), // organization scope,
|
||||
ac.EvalAll(
|
||||
ac.EvalPermission(ac.ActionAlertingNotificationsWrite),
|
||||
ac.EvalPermission(ac.ActionAlertingProvisioningSetStatus),
|
||||
),
|
||||
)
|
||||
case http.MethodGet + "/api/v1/notifications/time-intervals/{name}",
|
||||
http.MethodGet + "/api/v1/notifications/time-intervals":
|
||||
eval = ac.EvalAny(ac.EvalPermission(ac.ActionAlertingNotificationsRead), ac.EvalPermission(ac.ActionAlertingNotificationsTimeIntervalsRead), ac.EvalPermission(ac.ActionAlertingProvisioningRead))
|
||||
|
@ -98,24 +98,24 @@ func TestIntegrationProvisioning(t *testing.T) {
|
||||
require.Equal(t, 401, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("viewer GET should 403", func(t *testing.T) {
|
||||
t.Run("viewer GET should succeed", func(t *testing.T) {
|
||||
req := createTestRequest("GET", url, "viewer", "")
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, resp.Body.Close())
|
||||
|
||||
require.Equal(t, 403, resp.StatusCode)
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("editor GET should 403", func(t *testing.T) {
|
||||
t.Run("editor GET should succeed", func(t *testing.T) {
|
||||
req := createTestRequest("GET", url, "editor", "")
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, resp.Body.Close())
|
||||
|
||||
require.Equal(t, 403, resp.StatusCode)
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("admin GET should succeed", func(t *testing.T) {
|
||||
@ -148,14 +148,13 @@ func TestIntegrationProvisioning(t *testing.T) {
|
||||
require.Equal(t, 403, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("editor PUT should 403", func(t *testing.T) {
|
||||
t.Run("editor PUT should succeed", func(t *testing.T) {
|
||||
req := createTestRequest("PUT", url, "editor", body)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, resp.Body.Close())
|
||||
|
||||
require.Equal(t, 403, resp.StatusCode)
|
||||
require.Equal(t, 202, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("admin PUT should succeed", func(t *testing.T) {
|
||||
@ -190,24 +189,24 @@ func TestIntegrationProvisioning(t *testing.T) {
|
||||
require.Equal(t, 401, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("viewer GET should 403", func(t *testing.T) {
|
||||
t.Run("viewer GET should succeed", func(t *testing.T) {
|
||||
req := createTestRequest("GET", url, "viewer", "")
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, resp.Body.Close())
|
||||
|
||||
require.Equal(t, 403, resp.StatusCode)
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("editor GET should 403", func(t *testing.T) {
|
||||
t.Run("editor GET should succeed", func(t *testing.T) {
|
||||
req := createTestRequest("GET", url, "editor", "")
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, resp.Body.Close())
|
||||
|
||||
require.Equal(t, 403, resp.StatusCode)
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("admin GET should succeed", func(t *testing.T) {
|
||||
@ -240,14 +239,14 @@ func TestIntegrationProvisioning(t *testing.T) {
|
||||
require.Equal(t, 403, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("editor POST should 403", func(t *testing.T) {
|
||||
t.Run("editor POST should succeed", func(t *testing.T) {
|
||||
req := createTestRequest("POST", url, "editor", body)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, resp.Body.Close())
|
||||
|
||||
require.Equal(t, 403, resp.StatusCode)
|
||||
require.Equal(t, 202, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("admin POST should succeed", func(t *testing.T) {
|
||||
@ -274,24 +273,24 @@ func TestIntegrationProvisioning(t *testing.T) {
|
||||
require.Equal(t, 401, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("viewer GET should 403", func(t *testing.T) {
|
||||
t.Run("viewer GET should succeed", func(t *testing.T) {
|
||||
req := createTestRequest("GET", url, "viewer", "")
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, resp.Body.Close())
|
||||
|
||||
require.Equal(t, 403, resp.StatusCode)
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("editor GET should 403", func(t *testing.T) {
|
||||
t.Run("editor GET should succeed", func(t *testing.T) {
|
||||
req := createTestRequest("GET", url, "editor", "")
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, resp.Body.Close())
|
||||
|
||||
require.Equal(t, 403, resp.StatusCode)
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("admin GET should succeed", func(t *testing.T) {
|
||||
@ -318,24 +317,24 @@ func TestIntegrationProvisioning(t *testing.T) {
|
||||
require.Equal(t, 401, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("viewer GET should 403", func(t *testing.T) {
|
||||
t.Run("viewer GET should succeed", func(t *testing.T) {
|
||||
req := createTestRequest("GET", url, "viewer", "")
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, resp.Body.Close())
|
||||
|
||||
require.Equal(t, 403, resp.StatusCode)
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("editor GET should 403", func(t *testing.T) {
|
||||
t.Run("editor GET should succeed", func(t *testing.T) {
|
||||
req := createTestRequest("GET", url, "editor", "")
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, resp.Body.Close())
|
||||
|
||||
require.Equal(t, 403, resp.StatusCode)
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("admin GET should succeed", func(t *testing.T) {
|
||||
|
Loading…
Reference in New Issue
Block a user