310 lines
7.2 KiB
Go
310 lines
7.2 KiB
Go
package graphvent
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
)
|
|
|
|
const (
|
|
UserOfPolicyType = PolicyType("USER_OF")
|
|
RequirementOfPolicyType = PolicyType("REQUIREMENT_OF")
|
|
PerNodePolicyType = PolicyType("PER_NODE")
|
|
AllNodesPolicyType = PolicyType("ALL_NODES")
|
|
)
|
|
|
|
type Policy interface {
|
|
Serializable[PolicyType]
|
|
Allows(principal_id NodeID, action Action, node *Node)(Messages, error)
|
|
// Merge with another policy of the same underlying type
|
|
Merge(Policy) Policy
|
|
// Make a copy of this policy
|
|
Copy() Policy
|
|
}
|
|
|
|
func (policy AllNodesPolicy) Allows(principal_id NodeID, action Action, node *Node)(Messages, error) {
|
|
return nil, policy.Actions.Allows(action)
|
|
}
|
|
|
|
func (policy PerNodePolicy) Allows(principal_id NodeID, action Action, node *Node)(Messages, error) {
|
|
for id, actions := range(policy.NodeActions) {
|
|
if id != principal_id {
|
|
continue
|
|
}
|
|
return nil, actions.Allows(action)
|
|
}
|
|
return nil, fmt.Errorf("%s is not in per node policy of %s", principal_id, node.ID)
|
|
}
|
|
|
|
func (policy *RequirementOfPolicy) Allows(principal_id NodeID, action Action, node *Node)(Messages, error) {
|
|
lockable_ext, err := GetExt[*LockableExt](node)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for id, _ := range(lockable_ext.Requirements) {
|
|
if id == principal_id {
|
|
return nil, policy.Actions.Allows(action)
|
|
}
|
|
}
|
|
|
|
return nil, fmt.Errorf("%s is not a requirement of %s", principal_id, node.ID)
|
|
}
|
|
|
|
type UserOfPolicy struct {
|
|
PerNodePolicy
|
|
}
|
|
|
|
func (policy *UserOfPolicy) Type() PolicyType {
|
|
return UserOfPolicyType
|
|
}
|
|
|
|
func NewUserOfPolicy(group_actions NodeActions) UserOfPolicy {
|
|
return UserOfPolicy{
|
|
PerNodePolicy: NewPerNodePolicy(group_actions),
|
|
}
|
|
}
|
|
|
|
// Send a read signal to Group to check if principal_id is a member of it
|
|
func (policy *UserOfPolicy) Allows(principal_id NodeID, action Action, node *Node) (Messages, error) {
|
|
// Send a read signal to each of the groups in the map
|
|
// Check for principal_id in any of the returned member lists(skipping errors)
|
|
// Return an error in the default case
|
|
return nil, fmt.Errorf("NOT_IMPLEMENTED")
|
|
}
|
|
|
|
func (policy *UserOfPolicy) Merge(p Policy) Policy {
|
|
other := p.(*UserOfPolicy)
|
|
policy.NodeActions = MergeNodeActions(policy.NodeActions, other.NodeActions)
|
|
return policy
|
|
}
|
|
|
|
func (policy *UserOfPolicy) Copy() Policy {
|
|
new_actions := CopyNodeActions(policy.NodeActions)
|
|
return &UserOfPolicy{
|
|
PerNodePolicy: NewPerNodePolicy(new_actions),
|
|
}
|
|
}
|
|
|
|
type RequirementOfPolicy struct {
|
|
AllNodesPolicy
|
|
}
|
|
func (policy *RequirementOfPolicy) Type() PolicyType {
|
|
return RequirementOfPolicyType
|
|
}
|
|
|
|
func NewRequirementOfPolicy(actions Actions) RequirementOfPolicy {
|
|
return RequirementOfPolicy{
|
|
AllNodesPolicy: NewAllNodesPolicy(actions),
|
|
}
|
|
}
|
|
|
|
func MergeActions(first Actions, second Actions) Actions {
|
|
ret := second
|
|
for _, action := range(first) {
|
|
ret = append(ret, action)
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func CopyNodeActions(actions NodeActions) NodeActions {
|
|
ret := NodeActions{}
|
|
for id, a := range(actions) {
|
|
ret[id] = a
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func MergeNodeActions(first NodeActions, second NodeActions) NodeActions {
|
|
merged := NodeActions{}
|
|
for id, actions := range(first) {
|
|
merged[id] = actions
|
|
}
|
|
for id, actions := range(second) {
|
|
existing, exists := merged[id]
|
|
if exists {
|
|
merged[id] = MergeActions(existing, actions)
|
|
} else {
|
|
merged[id] = actions
|
|
}
|
|
}
|
|
return merged
|
|
}
|
|
|
|
func (policy *PerNodePolicy) Merge(p Policy) Policy {
|
|
other := p.(*PerNodePolicy)
|
|
policy.NodeActions = MergeNodeActions(policy.NodeActions, other.NodeActions)
|
|
return policy
|
|
}
|
|
|
|
func (policy *PerNodePolicy) Copy() Policy {
|
|
new_actions := CopyNodeActions(policy.NodeActions)
|
|
return &PerNodePolicy{
|
|
NodeActions: new_actions,
|
|
}
|
|
}
|
|
|
|
func (policy *AllNodesPolicy) Merge(p Policy) Policy {
|
|
other := p.(*AllNodesPolicy)
|
|
policy.Actions = MergeActions(policy.Actions, other.Actions)
|
|
return policy
|
|
}
|
|
|
|
func (policy *AllNodesPolicy) Copy() Policy {
|
|
new_actions := policy.Actions
|
|
return &AllNodesPolicy {
|
|
Actions: new_actions,
|
|
}
|
|
}
|
|
|
|
func (policy *RequirementOfPolicy) Merge(p Policy) Policy {
|
|
other := p.(*RequirementOfPolicy)
|
|
policy.Actions = MergeActions(policy.Actions, other.Actions)
|
|
return policy
|
|
}
|
|
|
|
func (policy *RequirementOfPolicy) Copy() Policy {
|
|
new_actions := policy.Actions
|
|
return &RequirementOfPolicy{
|
|
AllNodesPolicy {
|
|
Actions: new_actions,
|
|
},
|
|
}
|
|
}
|
|
|
|
type Action []string
|
|
|
|
func MakeAction(parts ...interface{}) Action {
|
|
action := make(Action, len(parts))
|
|
for i, part := range(parts) {
|
|
stringer, ok := part.(fmt.Stringer)
|
|
if ok == false {
|
|
switch p := part.(type) {
|
|
case string:
|
|
action[i] = p
|
|
default:
|
|
panic("%s can not be part of an action")
|
|
}
|
|
} else {
|
|
action[i] = stringer.String()
|
|
}
|
|
}
|
|
return action
|
|
}
|
|
|
|
func (action Action) Allows(test Action) bool {
|
|
action_len := len(action)
|
|
for i, part := range(test) {
|
|
if i >= action_len {
|
|
return false
|
|
} else if action[i] == part || action[i] == "*" {
|
|
continue
|
|
} else if action[i] == "+" {
|
|
break
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
type Actions []Action
|
|
|
|
func (actions Actions) Allows(action Action) error {
|
|
for _, a := range(actions) {
|
|
if a.Allows(action) == true {
|
|
return nil
|
|
}
|
|
}
|
|
return fmt.Errorf("%s not in allows list", action)
|
|
}
|
|
|
|
type NodeActions map[NodeID]Actions
|
|
|
|
func (actions NodeActions) MarshalJSON() ([]byte, error) {
|
|
tmp := map[string]Actions{}
|
|
for id, a := range(actions) {
|
|
tmp[id.String()] = a
|
|
}
|
|
return json.Marshal(tmp)
|
|
}
|
|
|
|
func (actions *NodeActions) UnmarshalJSON(data []byte) error {
|
|
tmp := map[string]Actions{}
|
|
err := json.Unmarshal(data, &tmp)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for id_str, a := range(tmp) {
|
|
id, err := ParseID(id_str)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ac := *actions
|
|
ac[id] = a
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func NewPerNodePolicy(node_actions NodeActions) PerNodePolicy {
|
|
if node_actions == nil {
|
|
node_actions = NodeActions{}
|
|
}
|
|
|
|
return PerNodePolicy{
|
|
NodeActions: node_actions,
|
|
}
|
|
}
|
|
|
|
type PerNodePolicy struct {
|
|
NodeActions NodeActions `json:"node_actions"`
|
|
}
|
|
|
|
func (policy *PerNodePolicy) Type() PolicyType {
|
|
return PerNodePolicyType
|
|
}
|
|
|
|
func (policy *PerNodePolicy) Serialize() ([]byte, error) {
|
|
return json.MarshalIndent(policy, "", " ")
|
|
}
|
|
|
|
func (policy *PerNodePolicy) Deserialize(ctx *Context, data []byte) error {
|
|
return json.Unmarshal(data, policy)
|
|
}
|
|
|
|
func NewAllNodesPolicy(actions Actions) AllNodesPolicy {
|
|
if actions == nil {
|
|
actions = Actions{}
|
|
}
|
|
|
|
return AllNodesPolicy{
|
|
Actions: actions,
|
|
}
|
|
}
|
|
|
|
type AllNodesPolicy struct {
|
|
Actions Actions
|
|
}
|
|
|
|
func (policy *AllNodesPolicy) Type() PolicyType {
|
|
return AllNodesPolicyType
|
|
}
|
|
|
|
func (policy *AllNodesPolicy) Serialize() ([]byte, error) {
|
|
return json.MarshalIndent(policy, "", " ")
|
|
}
|
|
|
|
func (policy *AllNodesPolicy) Deserialize(ctx *Context, data []byte) error {
|
|
return json.Unmarshal(data, policy)
|
|
}
|
|
|
|
var ErrorSignalAction = Action{"ERROR_RESP"}
|
|
var ReadResultSignalAction = Action{"READ_RESULT"}
|
|
var AuthorizedSignalAction = Action{"AUTHORIZED_READ"}
|
|
var defaultPolicy = NewAllNodesPolicy(Actions{ErrorSignalAction, ReadResultSignalAction, AuthorizedSignalAction})
|
|
var DefaultACLPolicies = []Policy{
|
|
&defaultPolicy,
|
|
}
|