graphvent/policy.go

254 lines
5.7 KiB
Go

2023-07-20 23:19:10 -06:00
package graphvent
import (
"github.com/google/uuid"
)
2023-07-20 23:19:10 -06:00
type Policy interface {
Allows(ctx *Context, principal_id NodeID, action Tree, node *Node)(Messages, RuleResult)
ContinueAllows(ctx *Context, current PendingACL, signal Signal)RuleResult
ID() uuid.UUID
}
type PolicyHeader struct {
UUID uuid.UUID `gv:"uuid"`
}
func (header PolicyHeader) ID() uuid.UUID {
return header.UUID
}
func (policy AllNodesPolicy) Allows(ctx *Context, principal_id NodeID, action Tree, node *Node)(Messages, RuleResult) {
2023-08-10 23:43:10 -06:00
return nil, policy.Rules.Allows(action)
}
func (policy AllNodesPolicy) ContinueAllows(ctx *Context, current PendingACL, signal Signal) RuleResult {
2023-08-10 23:43:10 -06:00
return Deny
}
func (policy PerNodePolicy) Allows(ctx *Context, principal_id NodeID, action Tree, node *Node)(Messages, RuleResult) {
2023-08-10 23:43:10 -06:00
for id, actions := range(policy.NodeRules) {
if id != principal_id {
continue
}
return nil, actions.Allows(action)
}
2023-08-10 23:43:10 -06:00
return nil, Deny
}
func (policy PerNodePolicy) ContinueAllows(ctx *Context, current PendingACL, signal Signal) RuleResult {
2023-08-10 23:43:10 -06:00
return Deny
}
2023-08-11 16:00:36 -06:00
type RequirementOfPolicy struct {
PerNodePolicy
}
func NewRequirementOfPolicy(dep_rules map[NodeID]Tree) RequirementOfPolicy {
return RequirementOfPolicy {
PerNodePolicy: NewPerNodePolicy(dep_rules),
}
}
func (policy RequirementOfPolicy) ContinueAllows(ctx *Context, current PendingACL, signal Signal) RuleResult {
2023-08-11 16:00:36 -06:00
sig, ok := signal.(*ReadResultSignal)
if ok == false {
return Deny
}
ext, ok := sig.Extensions[LockableExtType]
if ok == false {
return Deny
}
reqs_ser, ok := ext["requirements"]
if ok == false {
return Deny
}
_, reqs_if, _, err := DeserializeValue(ctx, reqs_ser)
if err != nil {
return Deny
}
requirements, ok := reqs_if.Interface().(map[NodeID]ReqState)
2023-08-11 16:00:36 -06:00
if ok == false {
return Deny
}
for req, _ := range(requirements) {
if req == current.Principal {
return policy.NodeRules[sig.NodeID].Allows(current.Action)
}
}
return Deny
}
2023-08-10 23:43:10 -06:00
type MemberOfPolicy struct {
PerNodePolicy
}
2023-08-11 16:00:36 -06:00
func NewMemberOfPolicy(group_rules map[NodeID]Tree) MemberOfPolicy {
2023-08-10 23:43:10 -06:00
return MemberOfPolicy{
PerNodePolicy: NewPerNodePolicy(group_rules),
}
}
func (policy MemberOfPolicy) ContinueAllows(ctx *Context, current PendingACL, signal Signal) RuleResult {
2023-08-10 23:43:10 -06:00
sig, ok := signal.(*ReadResultSignal)
if ok == false {
return Deny
}
group_ext_data, ok := sig.Extensions[GroupExtType]
if ok == false {
return Deny
}
members_ser, ok := group_ext_data["members"]
if ok == false {
return Deny
}
_, members_if, _, err := DeserializeValue(ctx, members_ser)
if err != nil {
return Deny
}
members, ok := members_if.Interface().(map[NodeID]string)
2023-08-10 23:43:10 -06:00
if ok == false {
return Deny
}
for member := range(members) {
2023-08-10 23:43:10 -06:00
if member == current.Principal {
return policy.NodeRules[sig.NodeID].Allows(current.Action)
}
}
2023-08-10 23:43:10 -06:00
return Deny
}
// Send a read signal to Group to check if principal_id is a member of it
func (policy MemberOfPolicy) Allows(ctx *Context, principal_id NodeID, action Tree, node *Node) (Messages, RuleResult) {
2023-08-10 23:43:10 -06:00
msgs := Messages{}
for id, rule := range(policy.NodeRules) {
if id == node.ID {
ext, err := GetExt[*GroupExt](node, GroupExtType)
2023-08-10 23:43:10 -06:00
if err == nil {
for member := range(ext.Members) {
2023-08-10 23:43:10 -06:00
if member == principal_id {
if rule.Allows(action) == Allow {
return nil, Allow
}
}
}
}
} else {
msgs = msgs.Add(ctx, node.ID, node.Key, NewReadSignal(map[ExtType][]string{
2023-08-10 23:43:10 -06:00
GroupExtType: []string{"members"},
}), id)
}
}
return msgs, Pending
}
2023-08-10 23:43:10 -06:00
func CopyTree(tree Tree) Tree {
if tree == nil {
return nil
}
2023-08-10 23:43:10 -06:00
ret := Tree{}
for name, sub := range(tree) {
ret[name] = CopyTree(sub)
}
2023-08-10 23:43:10 -06:00
return ret
}
2023-08-10 23:43:10 -06:00
func MergeTrees(first Tree, second Tree) Tree {
if first == nil || second == nil {
return nil
}
ret := CopyTree(first)
for name, sub := range(second) {
current, exists := ret[name]
if exists == true {
ret[name] = MergeTrees(current, sub)
} else {
ret[name] = CopyTree(sub)
}
}
return ret
}
type Tree map[SerializedType]Tree
2023-08-10 23:43:10 -06:00
func (rule Tree) Allows(action Tree) RuleResult {
// If the current rule is nil, it's a wildcard and any action being processed is allowed
if rule == nil {
return Allow
// If the rule isn't "allow all" but the action is "request all", deny
2023-08-10 23:43:10 -06:00
} else if action == nil {
return Deny
// If the current action has no children, it's allowed
2023-08-10 23:43:10 -06:00
} else if len(action) == 0 {
return Allow
// If the current rule has no children but the action goes further, it's not allowed
2023-08-10 23:43:10 -06:00
} else if len(rule) == 0 {
return Deny
// If the current rule and action have children, all the children of action must be allowed by rule
2023-08-10 23:43:10 -06:00
} else {
for sub, subtree := range(action) {
subrule, exists := rule[sub]
if exists == false {
return Deny
} else if subrule.Allows(subtree) == Deny {
return Deny
}
}
2023-08-10 23:43:10 -06:00
return Allow
}
}
func NewPolicyHeader() PolicyHeader {
return PolicyHeader{
UUID: uuid.New(),
}
}
2023-08-11 16:00:36 -06:00
func NewPerNodePolicy(node_actions map[NodeID]Tree) PerNodePolicy {
2023-07-26 13:28:03 -06:00
if node_actions == nil {
2023-08-11 16:00:36 -06:00
node_actions = map[NodeID]Tree{}
2023-07-26 13:28:03 -06:00
}
return PerNodePolicy{
PolicyHeader: NewPolicyHeader(),
2023-08-10 23:43:10 -06:00
NodeRules: node_actions,
2023-07-26 13:28:03 -06:00
}
}
type PerNodePolicy struct {
PolicyHeader
NodeRules map[NodeID]Tree `gv:"node_rules"`
2023-07-26 13:28:03 -06:00
}
2023-08-10 23:43:10 -06:00
func NewAllNodesPolicy(rules Tree) AllNodesPolicy {
2023-07-27 00:30:24 -06:00
return AllNodesPolicy{
PolicyHeader: NewPolicyHeader(),
2023-08-10 23:43:10 -06:00
Rules: rules,
2023-07-27 00:30:24 -06:00
}
}
type AllNodesPolicy struct {
PolicyHeader
Rules Tree `gv:"rules"`
2023-07-27 00:30:24 -06:00
}
2023-08-10 23:43:10 -06:00
var DefaultPolicy = NewAllNodesPolicy(Tree{
ResponseType: nil,
2023-09-27 18:28:56 -06:00
StatusType: nil,
2023-08-10 23:43:10 -06:00
})