Plugins: Add backend check for app page role access (#78269)

* add backend check for roles

* tidy

* fix tests

* incorporate rbac

* fix linter

* apply PR feedback

* add tests

* fix logic

* add comment

* apply PR feedback
This commit is contained in:
Will Browne
2023-12-18 16:12:46 +01:00
committed by GitHub
parent 68189cdaeb
commit 0b511aaace
4 changed files with 245 additions and 2 deletions
+52
View File
@@ -4,17 +4,21 @@ import (
"errors"
"net/http"
"net/url"
"path/filepath"
"regexp"
"strconv"
"strings"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/middleware/cookies"
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/auth"
"github.com/grafana/grafana/pkg/services/authn"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginaccesscontrol"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web"
)
@@ -97,6 +101,54 @@ func CanAdminPlugins(cfg *setting.Cfg, accessControl ac.AccessControl) func(c *c
}
}
func RoleAppPluginAuth(accessControl ac.AccessControl, ps pluginstore.Store, features featuremgmt.FeatureToggles,
logger log.Logger) func(c *contextmodel.ReqContext) {
return func(c *contextmodel.ReqContext) {
pluginID := web.Params(c.Req)[":id"]
p, exists := ps.Plugin(c.Req.Context(), pluginID)
if !exists {
// The frontend will handle app not found appropriately
return
}
permitted := true
path := normalizeIncludePath(c.Req.URL.Path)
hasAccess := ac.HasAccess(accessControl, c)
for _, i := range p.Includes {
if i.Type != "page" {
continue
}
u, err := url.Parse(i.Path)
if err != nil {
logger.Error("failed to parse include path", "pluginId", pluginID, "include", i.Name, "err", err)
continue
}
if normalizeIncludePath(u.Path) == path {
useRBAC := features.IsEnabledGlobally(featuremgmt.FlagAccessControlOnCall) && i.RequiresRBACAction()
if useRBAC && !hasAccess(ac.EvalPermission(i.Action)) {
logger.Debug("Plugin include is covered by RBAC, user doesn't have access", "plugin", pluginID, "include", i.Name)
permitted = false
break
} else if !useRBAC && !c.HasUserRole(i.Role) {
permitted = false
break
}
}
}
if !permitted {
accessForbidden(c)
return
}
}
}
func normalizeIncludePath(p string) string {
return strings.TrimPrefix(filepath.Clean(p), "/")
}
func RoleAuth(roles ...org.RoleType) web.Handler {
return func(c *contextmodel.ReqContext) {
ok := false