mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Fix anonymous access to alerting (#49203)
* introduce a fallback handler that checks that role is Viewer. * update UI nav links to allow alerting tabs for anonymous user * update rule api to check for Viewer role instead of SignedIn when RBAC is disabled
This commit is contained in:
parent
31ca628262
commit
f7f2253072
@ -513,7 +513,7 @@ func (hs *HTTPServer) buildAlertNavLinks(c *models.ReqContext) []*dtos.NavLink {
|
||||
hasAccess := ac.HasAccess(hs.AccessControl, c)
|
||||
var alertChildNavs []*dtos.NavLink
|
||||
|
||||
if hasAccess(ac.ReqSignedIn, ac.EvalAny(ac.EvalPermission(ac.ActionAlertingRuleRead), ac.EvalPermission(ac.ActionAlertingRuleExternalRead))) {
|
||||
if hasAccess(ac.ReqViewer, ac.EvalAny(ac.EvalPermission(ac.ActionAlertingRuleRead), ac.EvalPermission(ac.ActionAlertingRuleExternalRead))) {
|
||||
alertChildNavs = append(alertChildNavs, &dtos.NavLink{
|
||||
Text: "Alert rules", Id: "alert-list", Url: hs.Cfg.AppSubURL + "/alerting/list", Icon: "list-ul",
|
||||
})
|
||||
@ -527,7 +527,7 @@ func (hs *HTTPServer) buildAlertNavLinks(c *models.ReqContext) []*dtos.NavLink {
|
||||
alertChildNavs = append(alertChildNavs, &dtos.NavLink{Text: "Notification policies", Id: "am-routes", Url: hs.Cfg.AppSubURL + "/alerting/routes", Icon: "sitemap"})
|
||||
}
|
||||
|
||||
if hasAccess(ac.ReqSignedIn, ac.EvalAny(ac.EvalPermission(ac.ActionAlertingInstanceRead), ac.EvalPermission(ac.ActionAlertingInstancesExternalRead))) {
|
||||
if hasAccess(ac.ReqViewer, ac.EvalAny(ac.EvalPermission(ac.ActionAlertingInstanceRead), ac.EvalPermission(ac.ActionAlertingInstancesExternalRead))) {
|
||||
alertChildNavs = append(alertChildNavs, &dtos.NavLink{Text: "Silences", Id: "silences", Url: hs.Cfg.AppSubURL + "/alerting/silences", Icon: "bell-slash"})
|
||||
alertChildNavs = append(alertChildNavs, &dtos.NavLink{Text: "Alert groups", Id: "groups", Url: hs.Cfg.AppSubURL + "/alerting/groups", Icon: "layer-group"})
|
||||
}
|
||||
|
@ -129,6 +129,11 @@ var ReqGrafanaAdmin = func(c *models.ReqContext) bool {
|
||||
return c.IsGrafanaAdmin
|
||||
}
|
||||
|
||||
// ReqViewer returns true if the current user has models.ROLE_VIEWER. Note: this can be anonymous user as well
|
||||
var ReqViewer = func(c *models.ReqContext) bool {
|
||||
return c.OrgRole.Includes(models.ROLE_VIEWER)
|
||||
}
|
||||
|
||||
var ReqOrgAdmin = func(c *models.ReqContext) bool {
|
||||
return c.OrgRole == models.ROLE_ADMIN
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ Scopes must have an order to ensure consistency and ease of search, this helps u
|
||||
- [FEATURE] Indicate whether contact point is provisioned when GETting Alertmanager configuration #48323
|
||||
- [FEATURE] Indicate whether alert rule is provisioned when GETting the rule #48458
|
||||
- [BUGFIX] Migration: ignore alerts that do not belong to any existing organization\dashboard #49192
|
||||
- [BUGFIX] Allow anonymous access to alerts #49203
|
||||
|
||||
## 8.5.3
|
||||
|
||||
|
@ -154,7 +154,7 @@ func (srv PrometheusSrv) RouteGetRuleStatuses(c *models.ReqContext) response.Res
|
||||
return response.JSON(http.StatusInternalServerError, ruleResponse)
|
||||
}
|
||||
hasAccess := func(evaluator accesscontrol.Evaluator) bool {
|
||||
return accesscontrol.HasAccess(srv.ac, c)(accesscontrol.ReqSignedIn, evaluator)
|
||||
return accesscontrol.HasAccess(srv.ac, c)(accesscontrol.ReqViewer, evaluator)
|
||||
}
|
||||
|
||||
groupedRules := make(map[ngmodels.AlertRuleGroupKey][]*ngmodels.AlertRule)
|
||||
|
@ -255,7 +255,7 @@ func TestRouteGetRuleStatuses(t *testing.T) {
|
||||
|
||||
req, err := http.NewRequest("GET", "/api/v1/rules", nil)
|
||||
require.NoError(t, err)
|
||||
c := &models.ReqContext{Context: &web.Context{Req: req}, SignedInUser: &models.SignedInUser{OrgId: orgID}, IsSignedIn: true}
|
||||
c := &models.ReqContext{Context: &web.Context{Req: req}, SignedInUser: &models.SignedInUser{OrgId: orgID, OrgRole: models.ROLE_VIEWER}}
|
||||
|
||||
t.Run("with no rules", func(t *testing.T) {
|
||||
_, _, _, api := setupAPI(t)
|
||||
@ -325,7 +325,7 @@ func TestRouteGetRuleStatuses(t *testing.T) {
|
||||
|
||||
req, err := http.NewRequest("GET", "/api/v1/rules?includeInternalLabels=true", nil)
|
||||
require.NoError(t, err)
|
||||
c := &models.ReqContext{Context: &web.Context{Req: req}, SignedInUser: &models.SignedInUser{OrgId: orgID}, IsSignedIn: true}
|
||||
c := &models.ReqContext{Context: &web.Context{Req: req}, SignedInUser: &models.SignedInUser{OrgId: orgID, OrgRole: models.ROLE_VIEWER}}
|
||||
|
||||
r := api.RouteGetRuleStatuses(c)
|
||||
require.Equal(t, http.StatusOK, r.Status())
|
||||
|
@ -174,7 +174,7 @@ func (srv RulerSrv) RouteGetNamespaceRulesConfig(c *models.ReqContext) response.
|
||||
ruleGroupConfigs := make(map[string]apimodels.GettableRuleGroupConfig)
|
||||
|
||||
hasAccess := func(evaluator accesscontrol.Evaluator) bool {
|
||||
return accesscontrol.HasAccess(srv.ac, c)(accesscontrol.ReqSignedIn, evaluator)
|
||||
return accesscontrol.HasAccess(srv.ac, c)(accesscontrol.ReqViewer, evaluator)
|
||||
}
|
||||
|
||||
provenanceRecords, err := srv.provenanceStore.GetProvenances(c.Req.Context(), c.SignedInUser.OrgId, (&ngmodels.AlertRule{}).ResourceType())
|
||||
@ -227,7 +227,7 @@ func (srv RulerSrv) RouteGetRulesGroupConfig(c *models.ReqContext) response.Resp
|
||||
}
|
||||
|
||||
hasAccess := func(evaluator accesscontrol.Evaluator) bool {
|
||||
return accesscontrol.HasAccess(srv.ac, c)(accesscontrol.ReqSignedIn, evaluator)
|
||||
return accesscontrol.HasAccess(srv.ac, c)(accesscontrol.ReqViewer, evaluator)
|
||||
}
|
||||
|
||||
provenanceRecords, err := srv.provenanceStore.GetProvenances(c.Req.Context(), c.SignedInUser.OrgId, (&ngmodels.AlertRule{}).ResourceType())
|
||||
@ -287,7 +287,7 @@ func (srv RulerSrv) RouteGetRulesConfig(c *models.ReqContext) response.Response
|
||||
}
|
||||
|
||||
hasAccess := func(evaluator accesscontrol.Evaluator) bool {
|
||||
return accesscontrol.HasAccess(srv.ac, c)(accesscontrol.ReqSignedIn, evaluator)
|
||||
return accesscontrol.HasAccess(srv.ac, c)(accesscontrol.ReqViewer, evaluator)
|
||||
}
|
||||
|
||||
provenanceRecords, err := srv.provenanceStore.GetProvenances(c.Req.Context(), c.SignedInUser.OrgId, (&ngmodels.AlertRule{}).ResourceType())
|
||||
|
@ -575,7 +575,7 @@ func TestRouteGetNamespaceRulesConfig(t *testing.T) {
|
||||
ruleStore.PutRule(context.Background(), expectedRules...)
|
||||
ac := acMock.New().WithDisabled()
|
||||
|
||||
response := createService(ac, ruleStore, nil).RouteGetNamespaceRulesConfig(createRequestContext(orgID, "", map[string]string{
|
||||
response := createService(ac, ruleStore, nil).RouteGetNamespaceRulesConfig(createRequestContext(orgID, models2.ROLE_VIEWER, map[string]string{
|
||||
":Namespace": folder.Title,
|
||||
}))
|
||||
|
||||
@ -619,7 +619,7 @@ func TestRouteGetNamespaceRulesConfig(t *testing.T) {
|
||||
err := svc.provenanceStore.SetProvenance(context.Background(), rule, orgID, models.ProvenanceAPI)
|
||||
require.NoError(t, err)
|
||||
|
||||
response := svc.RouteGetNamespaceRulesConfig(createRequestContext(orgID, "", map[string]string{
|
||||
response := svc.RouteGetNamespaceRulesConfig(createRequestContext(orgID, models2.ROLE_VIEWER, map[string]string{
|
||||
":Namespace": folder.Title,
|
||||
}))
|
||||
|
||||
|
@ -134,7 +134,7 @@ const unifiedRoutes: RouteDescriptor[] = [
|
||||
path: '/alerting/silences',
|
||||
roles: evaluateAccess(
|
||||
[AccessControlAction.AlertingInstanceRead, AccessControlAction.AlertingInstancesExternalRead],
|
||||
['Editor', 'Admin']
|
||||
['Viewer', 'Editor', 'Admin']
|
||||
),
|
||||
component: SafeDynamicImport(
|
||||
() => import(/* webpackChunkName: "AlertSilences" */ 'app/features/alerting/unified/Silences')
|
||||
|
Loading…
Reference in New Issue
Block a user