It allows filtering for specific rules and also the rules which are applied to the resource, and not to a specific resource. Introduces generic methods for RuleSet and FindRules method to access_control generation template.
131 lines
2.6 KiB
Go
131 lines
2.6 KiB
Go
package rbac
|
|
|
|
import (
|
|
"path"
|
|
"strings"
|
|
)
|
|
|
|
type (
|
|
resource string
|
|
Resource interface {
|
|
RbacResource() string
|
|
}
|
|
|
|
resourceDicter interface {
|
|
Dict() map[string]interface{}
|
|
}
|
|
)
|
|
|
|
const (
|
|
nsSep = "::"
|
|
cmpSep = ":"
|
|
pathSep = "/"
|
|
wildcard = "*"
|
|
)
|
|
|
|
// NewResource constructs untyped resource from the given string
|
|
//
|
|
// This is a utility method that should not be used for standard permission checking and granting
|
|
// it's intended to be used for testing end permission evaluation where we do not have access to the resource struct
|
|
func NewResource(s string) Resource {
|
|
return resource(s)
|
|
}
|
|
|
|
// RbacResource returns string of an untyped resource
|
|
func (t resource) RbacResource() string {
|
|
return string(t)
|
|
}
|
|
|
|
// ResourceType extracts 1st part of the resource
|
|
//
|
|
// ns::cmp:res/c returns ns::cmp:res
|
|
// ns::cmp:res/ returns ns::cmp:res
|
|
// ns::cmp:res returns ns::cmp:res
|
|
func ResourceType(r string) string {
|
|
if p := strings.Index(r, pathSep); p > 0 {
|
|
return r[:p]
|
|
} else {
|
|
return r
|
|
}
|
|
}
|
|
|
|
func ResourceComponent(r string) string {
|
|
var (
|
|
t = ResourceType(r)
|
|
ns = strings.Index(t, nsSep)
|
|
c = strings.LastIndex(t, cmpSep)
|
|
)
|
|
|
|
// make sure that we have both namespace + component separators
|
|
if c > ns+1 && ns > -1 {
|
|
return t[:c]
|
|
} else {
|
|
return t
|
|
}
|
|
}
|
|
|
|
// match returns true if the given resource matches the given pattern
|
|
func matchResource(matcher, resource string) (m bool) {
|
|
if matcher == resource {
|
|
return true
|
|
}
|
|
|
|
m, _ = path.Match(matcher, resource)
|
|
return
|
|
}
|
|
|
|
func hasWildcards(resource string) bool {
|
|
return strings.Index(resource, wildcard) != -1
|
|
}
|
|
|
|
// returns level for the given resource match
|
|
// In a nutshell, level indicates number of wildcard characters
|
|
//
|
|
// More defined resources use less wildcards and are on a lower level
|
|
func level(r string) (score int) {
|
|
var nl bool
|
|
for l := len(r) - 1; l > strings.Index(r, pathSep); l-- {
|
|
switch r[l] {
|
|
case wildcard[0]:
|
|
// nop
|
|
case pathSep[0]:
|
|
// found next resource reference level
|
|
score *= 10
|
|
nl = false
|
|
default:
|
|
if !nl {
|
|
score += 1
|
|
nl = true
|
|
}
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// isSpecific will return true if rule relates to a specific resource
|
|
//
|
|
// ns::cmp:res/xx/* returns true
|
|
// ns::cmp:res/xx/xx returns true
|
|
// ns::cmp:res/ returns false
|
|
// ns::cmp:res/*/* returns false
|
|
func isSpecific(r string) (out bool) {
|
|
out = false
|
|
parts := strings.Split(r, pathSep)
|
|
// remove resource name part
|
|
parts = parts[1:]
|
|
|
|
// check parts for wildcard if it's not empty otherwise return false
|
|
for _, p := range parts {
|
|
if len(p) == 0 {
|
|
continue
|
|
}
|
|
|
|
if p != wildcard && !out {
|
|
out = true
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|