diff --git a/pkg/services/ngalert/api/api_alertmanager.go b/pkg/services/ngalert/api/api_alertmanager.go index 780bfc84085..db30e7df622 100644 --- a/pkg/services/ngalert/api/api_alertmanager.go +++ b/pkg/services/ngalert/api/api_alertmanager.go @@ -64,6 +64,9 @@ func (srv AlertmanagerSrv) RouteDeleteSilence(c *models.ReqContext) response.Res } func (srv AlertmanagerSrv) RouteGetAlertingConfig(c *models.ReqContext) response.Response { + if !c.HasUserRole(models.ROLE_EDITOR) { + return ErrResp(http.StatusForbidden, errors.New("permission denied"), "") + } query := ngmodels.GetLatestAlertmanagerConfigurationQuery{} if err := srv.store.GetLatestAlertmanagerConfiguration(&query); err != nil { if errors.Is(err, store.ErrNoAlertmanagerConfiguration) { diff --git a/pkg/tests/api/alerting/api_alertmanager_test.go b/pkg/tests/api/alerting/api_alertmanager_test.go index 6d1a4491278..8cd8092da79 100644 --- a/pkg/tests/api/alerting/api_alertmanager_test.go +++ b/pkg/tests/api/alerting/api_alertmanager_test.go @@ -118,6 +118,77 @@ func TestAMConfigAccess(t *testing.T) { } }) + t.Run("when retrieve alertmanager configuration", func(t *testing.T) { + cfgBody := ` + { + "template_files": null, + "alertmanager_config": { + "route": { + "receiver": "grafana-default-email" + }, + "templates": null, + "receivers": [{ + "name": "grafana-default-email", + "grafana_managed_receiver_configs": [{ + "disableResolveMessage": false, + "uid": "", + "name": "email receiver", + "type": "email", + "secureFields": {}, + "settings": { + "addresses": "" + } + }] + }] + } + } + ` + testCases := []testCase{ + { + desc: "un-authenticated request should fail", + url: "http://%s/api/alertmanager/grafana/config/api/v1/alerts", + expStatus: http.StatusUnauthorized, + expBody: `{"message": "Unauthorized"}`, + }, + { + desc: "viewer request should fail", + url: "http://viewer:viewer@%s/api/alertmanager/grafana/config/api/v1/alerts", + expStatus: http.StatusForbidden, + expBody: `{"message": "permission denied"}`, + }, + { + desc: "editor request should succeed", + url: "http://editor:editor@%s/api/alertmanager/grafana/config/api/v1/alerts", + expStatus: http.StatusOK, + expBody: cfgBody, + }, + { + desc: "admin request should succeed", + url: "http://admin:admin@%s/api/alertmanager/grafana/config/api/v1/alerts", + expStatus: http.StatusOK, + expBody: cfgBody, + }, + } + + for _, tc := range testCases { + t.Run(tc.desc, func(t *testing.T) { + resp, err := http.Get(fmt.Sprintf(tc.url, grafanaListedAddr)) + t.Cleanup(func() { + require.NoError(t, resp.Body.Close()) + }) + require.NoError(t, err) + require.Equal(t, tc.expStatus, resp.StatusCode) + b, err := ioutil.ReadAll(resp.Body) + if tc.expStatus == http.StatusOK { + re := regexp.MustCompile(`"uid":"([\w|-]+)"`) + b = re.ReplaceAll(b, []byte(`"uid":""`)) + } + require.NoError(t, err) + require.JSONEq(t, tc.expBody, string(b)) + }) + } + }) + t.Run("when creating silence", func(t *testing.T) { body := ` {