77e69b9cf3
Signed-off-by: Olivier Gambier <olivier@docker.com>
133 lines
3.1 KiB
Go
133 lines
3.1 KiB
Go
package trustgraph
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/docker/libtrust"
|
|
)
|
|
|
|
type grantNode struct {
|
|
grants []*Grant
|
|
children map[string]*grantNode
|
|
}
|
|
|
|
type memoryGraph struct {
|
|
roots map[string]*grantNode
|
|
}
|
|
|
|
func newGrantNode() *grantNode {
|
|
return &grantNode{
|
|
grants: []*Grant{},
|
|
children: map[string]*grantNode{},
|
|
}
|
|
}
|
|
|
|
// NewMemoryGraph returns a new in memory trust graph created from
|
|
// a static list of grants. This graph is immutable after creation
|
|
// and any alterations should create a new instance.
|
|
func NewMemoryGraph(grants []*Grant) TrustGraph {
|
|
roots := map[string]*grantNode{}
|
|
for _, grant := range grants {
|
|
parts := strings.Split(grant.Grantee, "/")
|
|
nodes := roots
|
|
var node *grantNode
|
|
var nodeOk bool
|
|
for _, part := range parts {
|
|
node, nodeOk = nodes[part]
|
|
if !nodeOk {
|
|
node = newGrantNode()
|
|
nodes[part] = node
|
|
}
|
|
if part != "" {
|
|
node.grants = append(node.grants, grant)
|
|
}
|
|
nodes = node.children
|
|
}
|
|
}
|
|
return &memoryGraph{roots}
|
|
}
|
|
|
|
func (g *memoryGraph) getGrants(name string) []*Grant {
|
|
nameParts := strings.Split(name, "/")
|
|
nodes := g.roots
|
|
var node *grantNode
|
|
var nodeOk bool
|
|
for _, part := range nameParts {
|
|
node, nodeOk = nodes[part]
|
|
if !nodeOk {
|
|
return nil
|
|
}
|
|
nodes = node.children
|
|
}
|
|
return node.grants
|
|
}
|
|
|
|
func isSubName(name, sub string) bool {
|
|
if strings.HasPrefix(name, sub) {
|
|
if len(name) == len(sub) || name[len(sub)] == '/' {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
type walkFunc func(*Grant, []*Grant) bool
|
|
|
|
func foundWalkFunc(*Grant, []*Grant) bool {
|
|
return true
|
|
}
|
|
|
|
func (g *memoryGraph) walkGrants(start, target string, permission uint16, f walkFunc, chain []*Grant, visited map[*Grant]bool, collect bool) bool {
|
|
if visited == nil {
|
|
visited = map[*Grant]bool{}
|
|
}
|
|
grants := g.getGrants(start)
|
|
subGrants := make([]*Grant, 0, len(grants))
|
|
for _, grant := range grants {
|
|
if visited[grant] {
|
|
continue
|
|
}
|
|
visited[grant] = true
|
|
if grant.Permission&permission == permission {
|
|
if isSubName(target, grant.Subject) {
|
|
if f(grant, chain) {
|
|
return true
|
|
}
|
|
} else {
|
|
subGrants = append(subGrants, grant)
|
|
}
|
|
}
|
|
}
|
|
for _, grant := range subGrants {
|
|
var chainCopy []*Grant
|
|
if collect {
|
|
chainCopy = make([]*Grant, len(chain)+1)
|
|
copy(chainCopy, chain)
|
|
chainCopy[len(chainCopy)-1] = grant
|
|
} else {
|
|
chainCopy = nil
|
|
}
|
|
|
|
if g.walkGrants(grant.Subject, target, permission, f, chainCopy, visited, collect) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (g *memoryGraph) Verify(key libtrust.PublicKey, node string, permission uint16) (bool, error) {
|
|
return g.walkGrants(key.KeyID(), node, permission, foundWalkFunc, nil, nil, false), nil
|
|
}
|
|
|
|
func (g *memoryGraph) GetGrants(key libtrust.PublicKey, node string, permission uint16) ([][]*Grant, error) {
|
|
grants := [][]*Grant{}
|
|
collect := func(grant *Grant, chain []*Grant) bool {
|
|
grantChain := make([]*Grant, len(chain)+1)
|
|
copy(grantChain, chain)
|
|
grantChain[len(grantChain)-1] = grant
|
|
grants = append(grants, grantChain)
|
|
return false
|
|
}
|
|
g.walkGrants(key.KeyID(), node, permission, collect, nil, nil, true)
|
|
return grants, nil
|
|
}
|