mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
AccessControl: Handle ':' in attribute resolution (#46742)
* AccessControl: Handle ':' in attribute resolution * Simplify based on assumption that prefixes will have maximum 2 parts
This commit is contained in:
parent
76c9ad2d9b
commit
ff3c1e3144
@ -14,8 +14,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ttl = 30 * time.Second
|
ttl = 30 * time.Second
|
||||||
cleanInterval = 2 * time.Minute
|
cleanInterval = 2 * time.Minute
|
||||||
|
maxPrefixParts = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetResourceScope(resource string, resourceID string) string {
|
func GetResourceScope(resource string, resourceID string) string {
|
||||||
@ -156,10 +157,15 @@ func (s *ScopeResolver) GetResolveAttributeScopeMutator(orgID int64) ScopeMutato
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// scopePrefix returns the prefix associated to a given scope
|
||||||
|
// we assume prefixes are all in the form <resource>:<attribute>:<value>
|
||||||
|
// ex: "datasources:name:test" returns "datasources:name:"
|
||||||
func scopePrefix(scope string) string {
|
func scopePrefix(scope string) string {
|
||||||
parts := strings.Split(scope, ":")
|
parts := strings.Split(scope, ":")
|
||||||
n := len(parts) - 1
|
// We assume prefixes don't have more than maxPrefixParts parts
|
||||||
parts[n] = ""
|
if len(parts) > maxPrefixParts {
|
||||||
|
parts = append(parts[:maxPrefixParts], "")
|
||||||
|
}
|
||||||
return strings.Join(parts, ":")
|
return strings.Join(parts, ":")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,6 +66,10 @@ func TestScopeResolver_ResolveAttribute(t *testing.T) {
|
|||||||
return Scope("datasources", "id", "1"), nil
|
return Scope("datasources", "id", "1"), nil
|
||||||
} else if initialScope == "datasources:name:testds2" {
|
} else if initialScope == "datasources:name:testds2" {
|
||||||
return Scope("datasources", "id", "2"), nil
|
return Scope("datasources", "id", "2"), nil
|
||||||
|
} else if initialScope == "datasources:name:test:ds4" {
|
||||||
|
return Scope("datasources", "id", "4"), nil
|
||||||
|
} else if initialScope == "datasources:name:testds5*" {
|
||||||
|
return Scope("datasources", "id", "5"), nil
|
||||||
} else {
|
} else {
|
||||||
return "", models.ErrDataSourceNotFound
|
return "", models.ErrDataSourceNotFound
|
||||||
}
|
}
|
||||||
@ -118,6 +122,20 @@ func TestScopeResolver_ResolveAttribute(t *testing.T) {
|
|||||||
),
|
),
|
||||||
wantCalls: 2,
|
wantCalls: 2,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "should resolve name with colon",
|
||||||
|
orgID: 1,
|
||||||
|
evaluator: EvalPermission("datasources:read", Scope("datasources", "name", "test:ds4")),
|
||||||
|
wantEvaluator: EvalPermission("datasources:read", Scope("datasources", "id", "4")),
|
||||||
|
wantCalls: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "should resolve names with '*'",
|
||||||
|
orgID: 1,
|
||||||
|
evaluator: EvalPermission("datasources:read", Scope("datasources", "name", "testds5*")),
|
||||||
|
wantEvaluator: EvalPermission("datasources:read", Scope("datasources", "id", "5")),
|
||||||
|
wantCalls: 1,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
resolver := NewScopeResolver()
|
resolver := NewScopeResolver()
|
||||||
@ -167,6 +185,16 @@ func Test_scopePrefix(t *testing.T) {
|
|||||||
scope: "datasources:name:testds",
|
scope: "datasources:name:testds",
|
||||||
want: "datasources:name:",
|
want: "datasources:name:",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "datasources with colons in name",
|
||||||
|
scope: "datasources:name:test:a::ds",
|
||||||
|
want: "datasources:name:",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "prefix",
|
||||||
|
scope: "datasources:name:",
|
||||||
|
want: "datasources:name:",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
Loading…
Reference in New Issue
Block a user