-
Notifications
You must be signed in to change notification settings - Fork 1
/
conditions.go
143 lines (116 loc) · 4 KB
/
conditions.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package conditions
import (
"fmt"
"strings"
"github.com/hexa-org/policy-mapper/hexaIdql/pkg/hexapolicy/conditions/parser"
)
const (
AAllow string = "allow"
ADeny string = "deny"
AAudit string = "audit"
)
type ConditionInfo struct {
Rule string `json:"Rule,omitempty" validate:"required"` // in RFC7644 idqlCondition form
Action string `json:"Action,omitempty"` // allow/deny/audit default is allow
}
type AttributeMap struct {
forward map[string]string
reverse map[string]string
}
type NameMapper interface {
// GetProviderAttributeName returns a simple string representation of the mapped attribute name (usually in name[.sub-attribute] form).
GetProviderAttributeName(hexaName string) string
// GetHexaFilterAttributePath returns a filterAttributePath which is used to build a SCIM Filter AST
GetHexaFilterAttributePath(provName string) string
}
type ConditionMapper interface {
/*
MapConditionToProvider takes an IDQL Condition expression and converts it to a string
usable the target provider. For example from RFC7644, Section-3.4.2.2 to Google Common Expression Language
*/
MapConditionToProvider(condition ConditionInfo) interface{}
/*
MapProviderToCondition take a string expression from a platform policy and converts it to RFC7644: Section-3.4.2.2.
*/
MapProviderToCondition(expression string) (ConditionInfo, error)
}
// NewNameMapper is called by a condition mapTool provider to instantiate an attribute name translator using interface NameMapper
func NewNameMapper(attributeMap map[string]string) *AttributeMap {
reverse := make(map[string]string, len(attributeMap))
forward := make(map[string]string, len(attributeMap))
for k, v := range attributeMap {
reverse[strings.ToLower(v)] = k
forward[strings.ToLower(k)] = v
}
return &AttributeMap{
forward: forward,
reverse: reverse,
}
}
func (n *AttributeMap) GetProviderAttributeName(hexaName string) string {
val, exists := n.forward[strings.ToLower(hexaName)]
if exists {
return val
}
return hexaName
}
func (n *AttributeMap) GetHexaFilterAttributePath(provName string) string {
val, exists := n.reverse[provName]
if !exists {
val = provName
}
return val
}
// ParseConditionRuleAst is used by mapping providers to get the IDQL condition rule AST tree
func ParseConditionRuleAst(condition ConditionInfo) (*parser.Expression, error) {
return parser.ParseFilter(condition.Rule)
}
func ParseExpressionAst(expression string) (*parser.Expression, error) {
return parser.ParseFilter(expression)
}
// SerializeExpression walks the AST and emits the condition in string form. It preserves precedence over the normal idqlCondition.String() method
func SerializeExpression(ast *parser.Expression) string {
return walk(*ast, false)
}
func checkNestedLogic(e parser.Expression, op parser.LogicalOperator) string {
// if the child is a repeat of the parent eliminate brackets (e.g. a or b or c)
switch v := e.(type) {
case parser.PrecedenceExpression:
e = v.Expression
}
switch v := e.(type) {
case parser.LogicalExpression:
if v.Operator == op {
return walk(e, false)
} else {
return walk(e, true)
}
default:
return walk(e, true)
}
}
func walk(e parser.Expression, isChild bool) string {
switch v := e.(type) {
case parser.LogicalExpression:
lhVal := checkNestedLogic(v.Left, v.Operator)
rhVal := checkNestedLogic(v.Right, v.Operator)
if isChild && v.Operator == parser.OR {
return fmt.Sprintf("(%v or %v)", lhVal, rhVal)
} else {
return fmt.Sprintf("%v %v %v", lhVal, v.Operator, rhVal)
}
case parser.NotExpression:
subExpression := v.Expression
// Note, because of not() brackets, can treat as top level
subExpressionString := walk(subExpression, false)
return fmt.Sprintf("not(%v)", subExpressionString)
case parser.PrecedenceExpression:
subExpressionString := walk(v.Expression, false)
return fmt.Sprintf("(%v)", subExpressionString)
case parser.ValuePathExpression:
return walk(v.VPathFilter, true)
// case idqlCondition.AttributeExpression:
default:
return v.String()
}
}