RBAC: Cover plugin routes (#80578)
* RBAC: Cover plugin routes * Action instead of ReqAction * Fix test initializations * Fix NewPluginProxy call * Duplicate test to add RBAC checks * Cover legacy access control as well * Fix typo * action -> reqAction * Add example Co-authored-by: Andres Martinez Gotor <andres.martinez@grafana.com> --------- Co-authored-by: Andres Martinez Gotor <andres.martinez@grafana.com>
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings"
|
||||
@@ -22,6 +23,7 @@ import (
|
||||
)
|
||||
|
||||
type PluginProxy struct {
|
||||
accessControl ac.AccessControl
|
||||
ps *pluginsettings.DTO
|
||||
pluginRoutes []*plugins.Route
|
||||
ctx *contextmodel.ReqContext
|
||||
@@ -37,8 +39,9 @@ type PluginProxy struct {
|
||||
// NewPluginProxy creates a plugin proxy.
|
||||
func NewPluginProxy(ps *pluginsettings.DTO, routes []*plugins.Route, ctx *contextmodel.ReqContext,
|
||||
proxyPath string, cfg *setting.Cfg, secretsService secrets.Service, tracer tracing.Tracer,
|
||||
transport *http.Transport, features featuremgmt.FeatureToggles) (*PluginProxy, error) {
|
||||
transport *http.Transport, accessControl ac.AccessControl, features featuremgmt.FeatureToggles) (*PluginProxy, error) {
|
||||
return &PluginProxy{
|
||||
accessControl: accessControl,
|
||||
ps: ps,
|
||||
pluginRoutes: routes,
|
||||
ctx: ctx,
|
||||
@@ -67,11 +70,9 @@ func (proxy *PluginProxy) HandleRequest() {
|
||||
continue
|
||||
}
|
||||
|
||||
if route.ReqRole.IsValid() {
|
||||
if !proxy.ctx.HasUserRole(route.ReqRole) {
|
||||
proxy.ctx.JsonApiErr(http.StatusForbidden, "plugin proxy route access denied", nil)
|
||||
return
|
||||
}
|
||||
if !proxy.hasAccessToRoute(route) {
|
||||
proxy.ctx.JsonApiErr(http.StatusForbidden, "plugin proxy route access denied", nil)
|
||||
return
|
||||
}
|
||||
|
||||
if path, exists := params["*"]; exists {
|
||||
@@ -120,6 +121,21 @@ func (proxy *PluginProxy) HandleRequest() {
|
||||
reverseProxy.ServeHTTP(proxy.ctx.Resp, proxy.ctx.Req)
|
||||
}
|
||||
|
||||
func (proxy *PluginProxy) hasAccessToRoute(route *plugins.Route) bool {
|
||||
useRBAC := proxy.features.IsEnabled(proxy.ctx.Req.Context(), featuremgmt.FlagAccessControlOnCall) && route.RequiresRBACAction()
|
||||
if useRBAC {
|
||||
hasAccess := ac.HasAccess(proxy.accessControl, proxy.ctx)(ac.EvalPermission(route.ReqAction))
|
||||
if !hasAccess {
|
||||
proxy.ctx.Logger.Debug("plugin route is covered by RBAC, user doesn't have access", "route", proxy.ctx.Req.URL.Path)
|
||||
}
|
||||
return hasAccess
|
||||
}
|
||||
if route.ReqRole.IsValid() {
|
||||
return proxy.ctx.HasUserRole(route.ReqRole)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (proxy PluginProxy) director(req *http.Request) {
|
||||
secureJsonData, err := proxy.secretsService.DecryptJsonData(proxy.ctx.Req.Context(), proxy.ps.SecureJSONData)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user