-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathutils.go
152 lines (134 loc) · 3.25 KB
/
utils.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
144
145
146
147
148
149
150
151
152
package pkg
import (
"fmt"
"regexp"
"strings"
"github.com/go-ldap/ldap/v3"
"github.com/jwalton/go-supportscolor"
pretty "github.com/k0kubun/pp/v3"
)
var (
// pp for pretty printing
pp = func() *pretty.PrettyPrinter {
useColor := supportscolor.Stdout().SupportsColor
pp := pretty.New()
pp.SetColoringEnabled(useColor)
pp.SetExportedOnly(true)
return pp
}()
)
const (
// MinUID for POSIX accounts
MinUID = 2000
// MinGID for POSIX accounts, reserved for the users group
MinGID = 2000
)
// ParseDN parses a DN into its parts.
func ParseDN(dn string) map[string][]string {
parsed := make(map[string][]string)
re := regexp.MustCompile("([^,]+)=([^,]+)")
parts := re.FindAllStringSubmatch(dn, -1)
for _, part := range parts {
_, present := parsed[part[1]]
if !present {
parsed[part[1]] = []string{}
}
parsed[part[1]] = append(parsed[part[1]], part[2])
}
return parsed
}
// GroupDN returns the full group DN for a group name
func (m *LDAPManager) GroupDN(name string) string {
return fmt.Sprintf(
"cn=%s,%s",
EscapeDN(name),
m.GroupsDN,
)
}
// UserDN returns the full user DN for a user name
func (m *LDAPManager) UserDN(name string) string {
return fmt.Sprintf(
"%s=%s,%s",
m.AccountAttribute,
EscapeDN(name),
m.UserGroupDN,
)
}
// PrettyPrint formats an interface into a human readable string
func PrettyPrint(m interface{}) string {
return pp.Sprint(m)
}
// Dedup is a generic function that removes duplicates in a slice.
func Dedup[T comparable](list []T) []T {
seen := make(map[T]bool)
out := []T{}
for _, value := range list {
if _, present := seen[value]; !present {
seen[value] = true
out = append(out, value)
}
}
return out
}
// Contains is a generic function that checks if a collection contains a value
func Contains[T comparable](s []T, e T) bool {
for _, v := range s {
if v == e {
return true
}
}
return false
}
// EscapeFilter escapes an LDAP filter to avoid LDAP injection attacks
func EscapeFilter(s string) string {
return ldap.EscapeFilter(s)
}
// EscapeDN escapes an LDAP DN to avoid LDAP injection attacks
//
// source: https://github.com/go-ldap/ldap/blob/master/ldap.go
// Note: for the next ldap release, we can directly use `ldap.EscapeDN`
func EscapeDN(dn string) string {
if dn == "" {
return ""
}
builder := strings.Builder{}
for i, r := range dn {
// Escape leading and trailing spaces
if (i == 0 || i == len(dn)-1) && r == ' ' {
builder.WriteRune('\\')
builder.WriteRune(r)
continue
}
// Escape leading '#'
if i == 0 && r == '#' {
builder.WriteRune('\\')
builder.WriteRune(r)
continue
}
// Escape characters as defined in RFC4514
switch r {
case '"', '+', ',', ';', '<', '>', '\\':
builder.WriteRune('\\')
builder.WriteRune(r)
case '\x00': // Null byte may not be escaped by a leading backslash
builder.WriteString("\\00")
default:
builder.WriteRune(r)
}
}
return builder.String()
}
// BuildFilter escapes and concatenates multiple filter expressions
func BuildFilter(filters []string) string {
var filter string
for _, f := range filters {
if pair := strings.Split(f, "="); len(pair) == 2 {
attr := strings.ToLower(pair[0])
filter += fmt.Sprintf(
"(%s=*%s*)",
attr, EscapeFilter(pair[1]),
)
}
}
return filter
}