mirror of
https://github.com/grafana/grafana.git
synced 2025-02-10 15:45:43 -06:00
AccessControl: Extend scope parameters with extra params from context (#39722)
* AccessControl: Extend scope parameters with extra params from context Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com>
This commit is contained in:
parent
d1b2b10e6a
commit
458371c8eb
@ -17,17 +17,17 @@ const (
|
||||
)
|
||||
|
||||
// API related scopes
|
||||
const (
|
||||
ScopeProvisionersAll = "provisioners:*"
|
||||
ScopeProvisionersDashboards = "provisioners:dashboards"
|
||||
ScopeProvisionersPlugins = "provisioners:plugins"
|
||||
ScopeProvisionersDatasources = "provisioners:datasources"
|
||||
ScopeProvisionersNotifications = "provisioners:notifications"
|
||||
var (
|
||||
ScopeProvisionersAll = accesscontrol.Scope("provisioners", "*")
|
||||
ScopeProvisionersDashboards = accesscontrol.Scope("provisioners", "dashboards")
|
||||
ScopeProvisionersPlugins = accesscontrol.Scope("provisioners", "plugins")
|
||||
ScopeProvisionersDatasources = accesscontrol.Scope("provisioners", "datasources")
|
||||
ScopeProvisionersNotifications = accesscontrol.Scope("provisioners", "notifications")
|
||||
|
||||
ScopeDatasourcesAll = `datasources:*`
|
||||
ScopeDatasourceID = `datasources:id:{{ index . ":id" }}`
|
||||
ScopeDatasourceUID = `datasources:uid:{{ index . ":uid" }}`
|
||||
ScopeDatasourceName = `datasources:name:{{ index . ":name" }}`
|
||||
ScopeDatasourcesAll = accesscontrol.Scope("datasources", "*")
|
||||
ScopeDatasourceID = accesscontrol.Scope("datasources", "id", accesscontrol.Parameter(":id"))
|
||||
ScopeDatasourceUID = accesscontrol.Scope("datasources", "uid", accesscontrol.Parameter(":uid"))
|
||||
ScopeDatasourceName = accesscontrol.Scope("datasources", "name", accesscontrol.Parameter(":name"))
|
||||
)
|
||||
|
||||
// declareFixedRoles declares to the AccessControl service fixed roles and their
|
||||
|
@ -15,7 +15,7 @@ type Evaluator interface {
|
||||
// Evaluate permissions that are grouped by action
|
||||
Evaluate(permissions map[string]map[string]struct{}) (bool, error)
|
||||
// Inject params into the evaluator's templated scopes. e.g. "settings:" + eval.Parameters(":id") and returns a new Evaluator
|
||||
Inject(params map[string]string) (Evaluator, error)
|
||||
Inject(params ScopeParams) (Evaluator, error)
|
||||
// String returns a string representation of permission required by the evaluator
|
||||
String() string
|
||||
}
|
||||
@ -89,7 +89,7 @@ func match(scope, target string) (bool, error) {
|
||||
return scope == target, nil
|
||||
}
|
||||
|
||||
func (p permissionEvaluator) Inject(params map[string]string) (Evaluator, error) {
|
||||
func (p permissionEvaluator) Inject(params ScopeParams) (Evaluator, error) {
|
||||
scopes := make([]string, 0, len(p.Scopes))
|
||||
for _, scope := range p.Scopes {
|
||||
tmpl, err := template.New("scope").Parse(scope)
|
||||
@ -129,7 +129,7 @@ func (a allEvaluator) Evaluate(permissions map[string]map[string]struct{}) (bool
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (a allEvaluator) Inject(params map[string]string) (Evaluator, error) {
|
||||
func (a allEvaluator) Inject(params ScopeParams) (Evaluator, error) {
|
||||
var injected []Evaluator
|
||||
for _, e := range a.allOf {
|
||||
i, err := e.Inject(params)
|
||||
@ -173,7 +173,7 @@ func (a anyEvaluator) Evaluate(permissions map[string]map[string]struct{}) (bool
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (a anyEvaluator) Inject(params map[string]string) (Evaluator, error) {
|
||||
func (a anyEvaluator) Inject(params ScopeParams) (Evaluator, error) {
|
||||
var injected []Evaluator
|
||||
for _, e := range a.anyOf {
|
||||
i, err := e.Inject(params)
|
||||
|
@ -17,7 +17,7 @@ type injectTestCase struct {
|
||||
desc string
|
||||
expected bool
|
||||
evaluator Evaluator
|
||||
params map[string]string
|
||||
params ScopeParams
|
||||
permissions map[string]map[string]struct{}
|
||||
}
|
||||
|
||||
@ -77,13 +77,28 @@ func TestPermission_Evaluate(t *testing.T) {
|
||||
|
||||
func TestPermission_Inject(t *testing.T) {
|
||||
tests := []injectTestCase{
|
||||
{
|
||||
desc: "should inject field",
|
||||
expected: true,
|
||||
evaluator: EvalPermission("orgs:read", Scope("orgs", Field("OrgID"))),
|
||||
params: ScopeParams{
|
||||
OrgID: 3,
|
||||
},
|
||||
permissions: map[string]map[string]struct{}{
|
||||
"orgs:read": {
|
||||
"orgs:3": struct{}{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should inject correct param",
|
||||
expected: true,
|
||||
evaluator: EvalPermission("reports:read", Scope("reports", Parameter(":reportId"))),
|
||||
params: map[string]string{
|
||||
":id": "10",
|
||||
":reportId": "1",
|
||||
params: ScopeParams{
|
||||
URLParams: map[string]string{
|
||||
":id": "10",
|
||||
":reportId": "1",
|
||||
},
|
||||
},
|
||||
permissions: map[string]map[string]struct{}{
|
||||
"reports:read": {
|
||||
@ -95,7 +110,7 @@ func TestPermission_Inject(t *testing.T) {
|
||||
desc: "should fail for nil params",
|
||||
expected: false,
|
||||
evaluator: EvalPermission("reports:read", Scope("reports", Parameter(":reportId"))),
|
||||
params: nil,
|
||||
params: ScopeParams{},
|
||||
permissions: map[string]map[string]struct{}{
|
||||
"reports:read": {
|
||||
"reports:1": struct{}{},
|
||||
@ -106,9 +121,11 @@ func TestPermission_Inject(t *testing.T) {
|
||||
desc: "should inject several parameters to one permission",
|
||||
expected: true,
|
||||
evaluator: EvalPermission("reports:read", Scope("reports", Parameter(":reportId"), Parameter(":reportId2"))),
|
||||
params: map[string]string{
|
||||
":reportId": "report",
|
||||
":reportId2": "report2",
|
||||
params: ScopeParams{
|
||||
URLParams: map[string]string{
|
||||
":reportId": "report",
|
||||
":reportId2": "report2",
|
||||
},
|
||||
},
|
||||
permissions: map[string]map[string]struct{}{
|
||||
"reports:read": {
|
||||
@ -187,10 +204,12 @@ func TestAll_Inject(t *testing.T) {
|
||||
EvalPermission("reports:read", Scope("reports", Parameter(":reportId"))),
|
||||
EvalPermission("settings:read", Scope("settings", Parameter(":settingsId"))),
|
||||
),
|
||||
params: map[string]string{
|
||||
":id": "10",
|
||||
":settingsId": "3",
|
||||
":reportId": "1",
|
||||
params: ScopeParams{
|
||||
URLParams: map[string]string{
|
||||
":id": "10",
|
||||
":settingsId": "3",
|
||||
":reportId": "1",
|
||||
},
|
||||
},
|
||||
permissions: map[string]map[string]struct{}{
|
||||
"reports:read": {
|
||||
@ -201,6 +220,26 @@ func TestAll_Inject(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should inject field and URL param",
|
||||
expected: true,
|
||||
evaluator: EvalAll(
|
||||
EvalPermission("orgs:read", Scope("orgs", Field("OrgID"))),
|
||||
EvalPermission("orgs:read", Scope("orgs", Parameter(":orgId"))),
|
||||
),
|
||||
params: ScopeParams{
|
||||
OrgID: 3,
|
||||
URLParams: map[string]string{
|
||||
":orgId": "4",
|
||||
},
|
||||
},
|
||||
permissions: map[string]map[string]struct{}{
|
||||
"orgs:read": {
|
||||
"orgs:3": struct{}{},
|
||||
"orgs:4": struct{}{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should fail for nil params",
|
||||
expected: false,
|
||||
@ -208,7 +247,7 @@ func TestAll_Inject(t *testing.T) {
|
||||
EvalPermission("settings:read", Scope("reports", Parameter(":settingsId"))),
|
||||
EvalPermission("reports:read", Scope("reports", Parameter(":reportId"))),
|
||||
),
|
||||
params: nil,
|
||||
params: ScopeParams{},
|
||||
permissions: map[string]map[string]struct{}{
|
||||
"reports:read": {
|
||||
"reports:1": struct{}{},
|
||||
@ -287,10 +326,12 @@ func TestAny_Inject(t *testing.T) {
|
||||
EvalPermission("reports:read", Scope("reports", Parameter(":reportId"))),
|
||||
EvalPermission("settings:read", Scope("settings", Parameter(":settingsId"))),
|
||||
),
|
||||
params: map[string]string{
|
||||
":id": "10",
|
||||
":settingsId": "3",
|
||||
":reportId": "1",
|
||||
params: ScopeParams{
|
||||
URLParams: map[string]string{
|
||||
":id": "10",
|
||||
":settingsId": "3",
|
||||
":reportId": "1",
|
||||
},
|
||||
},
|
||||
permissions: map[string]map[string]struct{}{
|
||||
"reports:read": {
|
||||
@ -301,6 +342,26 @@ func TestAny_Inject(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should inject field and URL param",
|
||||
expected: true,
|
||||
evaluator: EvalAny(
|
||||
EvalPermission("orgs:read", Scope("orgs", Field("OrgID"))),
|
||||
EvalPermission("orgs:read", Scope("orgs", Parameter(":orgId"))),
|
||||
),
|
||||
params: ScopeParams{
|
||||
OrgID: 3,
|
||||
URLParams: map[string]string{
|
||||
":orgId": "4",
|
||||
},
|
||||
},
|
||||
permissions: map[string]map[string]struct{}{
|
||||
"orgs:read": {
|
||||
"orgs:3": struct{}{},
|
||||
"orgs:4": struct{}{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should fail for nil params",
|
||||
expected: false,
|
||||
@ -308,7 +369,7 @@ func TestAny_Inject(t *testing.T) {
|
||||
EvalPermission("settings:read", Scope("reports", Parameter(":settingsId"))),
|
||||
EvalPermission("reports:read", Scope("reports", Parameter(":reportId"))),
|
||||
),
|
||||
params: nil,
|
||||
params: ScopeParams{},
|
||||
permissions: map[string]map[string]struct{}{
|
||||
"reports:read": {
|
||||
"reports:1": struct{}{},
|
||||
|
@ -19,7 +19,7 @@ func Middleware(ac accesscontrol.AccessControl) func(macaron.Handler, accesscont
|
||||
}
|
||||
|
||||
return func(c *models.ReqContext) {
|
||||
injected, err := evaluator.Inject(macaron.Params(c.Req))
|
||||
injected, err := evaluator.Inject(buildScopeParams(c))
|
||||
if err != nil {
|
||||
c.JsonApiErr(http.StatusInternalServerError, "Internal server error", err)
|
||||
return
|
||||
@ -69,3 +69,10 @@ func newID() string {
|
||||
}
|
||||
return "ACE" + id
|
||||
}
|
||||
|
||||
func buildScopeParams(c *models.ReqContext) accesscontrol.ScopeParams {
|
||||
return accesscontrol.ScopeParams{
|
||||
OrgID: c.OrgId,
|
||||
URLParams: macaron.Params(c.Req),
|
||||
}
|
||||
}
|
||||
|
@ -140,6 +140,12 @@ func (p Permission) OSSPermission() Permission {
|
||||
}
|
||||
}
|
||||
|
||||
// ScopeParams holds the parameters used to fill in scope templates
|
||||
type ScopeParams struct {
|
||||
OrgID int64
|
||||
URLParams map[string]string
|
||||
}
|
||||
|
||||
const (
|
||||
GlobalOrgID = 0
|
||||
// Permission actions
|
||||
|
@ -18,8 +18,14 @@ func Scope(parts ...string) string {
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// Parameter returns injectable scope part
|
||||
// Parameter returns injectable scope part, based on URL parameters.
|
||||
// e.g. Scope("users", Parameter(":id")) or "users:" + Parameter(":id")
|
||||
func Parameter(key string) string {
|
||||
return fmt.Sprintf(`{{ index . "%s" }}`, key)
|
||||
return fmt.Sprintf(`{{ index .URLParams "%s" }}`, key)
|
||||
}
|
||||
|
||||
// Field returns an injectable scope part for selected fields from the request's context available in accesscontrol.ScopeParams.
|
||||
// e.g. Scope("orgs", Parameter("OrgID")) or "orgs:" + Parameter("OrgID")
|
||||
func Field(key string) string {
|
||||
return fmt.Sprintf(`{{ .%s }}`, key)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user