/
builder.go
117 lines (93 loc) · 2.61 KB
/
builder.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
package xacml
import (
"fmt"
xml "github.com/beevik/etree"
)
// convenience wrapper to be able to add multiple child nodes at once,
// see children function.
type xNode struct {
label *xml.Element
}
func node(label *xml.Element) xNode {
return xNode{label: label}
}
func emptyNode() xNode {
return xNode{}
}
func (n xNode) isEmpty() bool {
return n.label == nil
}
// serialize current node to XML doc.
func (n xNode) writeDoc() string {
doc := xml.NewDocument()
doc.CreateProcInst("xml", `version="1.0" encoding="UTF-8"`)
if !n.isEmpty() {
doc.SetRoot(n.label)
}
doc.Indent(2)
serialized, _ := doc.WriteToString()
return serialized
}
// NOTE. Performance. For now XACML requests are pretty small, so we can
// afford to keep the whole thing in memory. In general tough a better
// option would be to stream the doc into the HTTP request as the XML
// gets written. I couldn't find any decent streaming solution in Go,
// e.g. something like Haskell pipes, conduit, etc. If workarounds are
// your thing, here's one
// - https://medium.com/stupid-gopher-tricks/streaming-data-in-go-without-buffering-3285ddd2a1e5
// but watch out for concurrency!!
// convenience function to be able to add multiple child nodes at once.
func (n xNode) children(ts ...xNode) xNode {
for _, t := range ts {
if !t.isEmpty() {
n.label.AddChild(t.label)
}
}
return n
}
// generic constructors for XACML request elements.
// see builderfw for specialized constructors.
func attrValue(dataType string, value interface{}) xNode {
e := xml.NewElement("AttributeValue")
e.CreateAttr("DataType", dataType)
v := fmt.Sprintf("%v", value)
e.SetText(v)
return node(e)
}
func stringAttr(v string) xNode {
typ := "http://www.w3.org/2001/XMLSchema#string"
return attrValue(typ, v)
}
func listOfStringAttr(vs []string) []xNode {
xs := make([]xNode, len(vs))
for k, v := range vs {
xs[k] = stringAttr(v)
}
return xs
}
func boolAttr(v bool) xNode {
typ := "http://www.w3.org/2001/XMLSchema#boolean"
return attrValue(typ, v)
}
func uriAttr(v string) xNode {
typ := "http://www.w3.org/2001/XMLSchema#anyURI"
return attrValue(typ, v)
}
func attr(id string) xNode {
e := xml.NewElement("Attribute")
e.CreateAttr("AttributeId", id)
e.CreateAttr("IncludeInResult", "false")
return node(e)
}
func attrCategory(id string) xNode {
e := xml.NewElement("Attributes")
e.CreateAttr("Category", id)
return node(e)
}
func request() xNode {
e := xml.NewElement("Request")
e.CreateAttr("xmlns", "urn:oasis:names:tc:xacml:3.0:core:schema:wd-17")
e.CreateAttr("CombinedDecision", "false")
e.CreateAttr("ReturnPolicyIdList", "false")
return node(e)
}