Skip to content

Commit

Permalink
feat: add ResourceAccessScopeStrategy
Browse files Browse the repository at this point in the history
  • Loading branch information
zoop-btc committed Mar 29, 2024
1 parent 1f27af4 commit 9cf1e65
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 0 deletions.
66 changes: 66 additions & 0 deletions scope_strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,69 @@ func WildcardScopeStrategy(matchers []string, needle string) bool {

return false
}

func ResourceAccessScopeStrategy(matchers []string, needle string) bool {
needleResources := strings.Split(needle, ":")

matcherloop:
for _, matcher := range matchers {
matcherResources := strings.Split(matcher, ":")

if len(matcherResources) != len(needleResources) {
continue matcherloop
}

var match bool

for index, matcherResource := range matcherResources {
isLastLoop := index+1 == len(matcherResources)
needleResource := needleResources[index]

// on the last resource we split off the verb
matcherVerb := ""
if strings.Contains(matcherResource, ".") && isLastLoop {
matcherVerb = matcherResource[strings.LastIndex(matcherResource, "."):]
matcherResource, _ = strings.CutSuffix(matcherResource, matcherVerb)
}

needleVerb := ""
if strings.Contains(needleResource, ".") && isLastLoop && matcherVerb != "" {
needleVerb = needleResource[strings.LastIndex(needleResource, "."):]
needleResource, _ = strings.CutSuffix(needleResource, needleVerb)
}

var exactmatch bool
var prefixmatch bool

if matcherResource == needleResource {
exactmatch = true
}
// if prefix we check only on the left side of `-`
if strings.HasSuffix(matcherResource, "-*") {
matcherPrefix, _, _ := strings.Cut(matcherResource, "-")
needlePrefix, _, hasPrefix := strings.Cut(needleResource, "-")
if hasPrefix && needlePrefix == matcherPrefix {
prefixmatch = true
}
}
match = prefixmatch || exactmatch

if !match {
continue matcherloop
}

// if matcher defines .* as verb then everything is permitted
// resource provider has responsibility to assume least privilege
if isLastLoop && matcherVerb != "" {
if matcherVerb == ".*" {
continue
}
match = matcherVerb == needleVerb
}
}
if match {
return true
}
}
return false
}
58 changes: 58 additions & 0 deletions scope_strategy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,61 @@ func TestExactScopeStrategy2ScopeStrategy(t *testing.T) {

assert.False(t, strategy([]string{}, "foo"))
}

func TestResourceAccessScopeStrategy(t *testing.T) {
var strategy ScopeStrategy = ResourceAccessScopeStrategy
var scopes = []string{}

assert.False(t, strategy(scopes, "foo:bar:baz"))
assert.False(t, strategy(scopes, "foo:bar"))

scopes = []string{"*"}
assert.False(t, strategy(scopes, ""))
assert.True(t, strategy(scopes, "*"))
assert.False(t, strategy(scopes, "asdf.asdf"))

scopes = []string{"foo"}
assert.False(t, strategy(scopes, "*"))
assert.False(t, strategy(scopes, "foo:*"))
assert.False(t, strategy(scopes, "fo*"))
assert.True(t, strategy(scopes, "foo"))

scopes = []string{"foo-*"}
assert.False(t, strategy(scopes, "foo"))
assert.True(t, strategy(scopes, "foo-a"))
assert.False(t, strategy(scopes, "fo-bar"))
assert.True(t, strategy(scopes, "foo-*"))

scopes = []string{"foo:bar"}
assert.True(t, strategy(scopes, "foo:bar"))
assert.False(t, strategy(scopes, "foo:baz"))
assert.False(t, strategy(scopes, "foo:bar:baz"))
assert.False(t, strategy(scopes, "foo"))

scopes = []string{"foo-*:bar.read"}
assert.True(t, strategy(scopes, "foo-bar:bar.read"))
assert.False(t, strategy(scopes, "foo-bar:bar"))
assert.False(t, strategy(scopes, "foo:bar"))
assert.True(t, strategy(scopes, "foo-*:bar.read"))
assert.False(t, strategy(scopes, "bar-foo:foo"))
assert.False(t, strategy(scopes, "foo-bar:bar:baz"))

scopes = []string{"foo-*:bar.*"}
assert.True(t, strategy(scopes, "foo-bar:bar.read"))
assert.True(t, strategy(scopes, "foo-bar:bar"))
assert.False(t, strategy(scopes, "foo:bar"))
assert.True(t, strategy(scopes, "foo-*:bar.write"))
assert.False(t, strategy(scopes, "bar-foo:foo"))
assert.False(t, strategy(scopes, "foo-bar:bar:baz"))

scopes = []string{"foo-*.read:bar"}
assert.True(t, strategy(scopes, "foo-*.read:bar"))
assert.False(t, strategy(scopes, "foo-bar:bar"))

scopes = strings.Fields("hydra:clients.* openid offline hydra")
assert.True(t, strategy(scopes, "hydra:clients"))
assert.True(t, strategy(scopes, "hydra:clients.get"))
assert.True(t, strategy(scopes, "hydra"))
assert.True(t, strategy(scopes, "offline"))
assert.True(t, strategy(scopes, "openid"))
}

0 comments on commit 9cf1e65

Please sign in to comment.