1 package ldap
2
3 import (
4 "strings"
5 "testing"
6
7 ber "github.com/go-asn1-ber/asn1-ber"
8 )
9
10 type compileTest struct {
11 filterStr string
12
13 expectedFilter string
14 expectedType int
15 expectedErr string
16 }
17
18 var testFilters = []compileTest{
19 {
20 filterStr: "(&(sn=Miller)(givenName=Bob))",
21 expectedFilter: "(&(sn=Miller)(givenName=Bob))",
22 expectedType: FilterAnd,
23 },
24 {
25 filterStr: "(|(sn=Miller)(givenName=Bob))",
26 expectedFilter: "(|(sn=Miller)(givenName=Bob))",
27 expectedType: FilterOr,
28 },
29 {
30 filterStr: "(!(sn=Miller))",
31 expectedFilter: "(!(sn=Miller))",
32 expectedType: FilterNot,
33 },
34 {
35 filterStr: "(sn=Miller)",
36 expectedFilter: "(sn=Miller)",
37 expectedType: FilterEqualityMatch,
38 },
39 {
40 filterStr: "(sn=Mill*)",
41 expectedFilter: "(sn=Mill*)",
42 expectedType: FilterSubstrings,
43 },
44 {
45 filterStr: "(sn=*Mill)",
46 expectedFilter: "(sn=*Mill)",
47 expectedType: FilterSubstrings,
48 },
49 {
50 filterStr: "(sn=*Mill*)",
51 expectedFilter: "(sn=*Mill*)",
52 expectedType: FilterSubstrings,
53 },
54 {
55 filterStr: "(sn=*i*le*)",
56 expectedFilter: "(sn=*i*le*)",
57 expectedType: FilterSubstrings,
58 },
59 {
60 filterStr: "(sn=Mi*l*r)",
61 expectedFilter: "(sn=Mi*l*r)",
62 expectedType: FilterSubstrings,
63 },
64
65 {
66 filterStr: `(sn=Mi*함*r)`,
67 expectedFilter: `(sn=Mi*\ed\95\a8*r)`,
68 expectedType: FilterSubstrings,
69 },
70
71 {
72 filterStr: `(sn=Mi*\ed\95\a8*r)`,
73 expectedFilter: `(sn=Mi*\ed\95\a8*r)`,
74 expectedType: FilterSubstrings,
75 },
76 {
77 filterStr: "(sn=Mi*le*)",
78 expectedFilter: "(sn=Mi*le*)",
79 expectedType: FilterSubstrings,
80 },
81 {
82 filterStr: "(sn=*i*ler)",
83 expectedFilter: "(sn=*i*ler)",
84 expectedType: FilterSubstrings,
85 },
86 {
87 filterStr: "(sn>=Miller)",
88 expectedFilter: "(sn>=Miller)",
89 expectedType: FilterGreaterOrEqual,
90 },
91 {
92 filterStr: "(sn<=Miller)",
93 expectedFilter: "(sn<=Miller)",
94 expectedType: FilterLessOrEqual,
95 },
96 {
97 filterStr: "(sn=*)",
98 expectedFilter: "(sn=*)",
99 expectedType: FilterPresent,
100 },
101 {
102 filterStr: "(sn~=Miller)",
103 expectedFilter: "(sn~=Miller)",
104 expectedType: FilterApproxMatch,
105 },
106 {
107 filterStr: `(objectGUID='\fc\fe\a3\ab\f9\90N\aaGm\d5I~\d12)`,
108 expectedFilter: `(objectGUID='\fc\fe\a3\ab\f9\90N\aaGm\d5I~\d12)`,
109 expectedType: FilterEqualityMatch,
110 },
111 {
112 filterStr: `(objectGUID=абвгдеёжзийклмнопрстуфхцчшщъыьэюя)`,
113 expectedFilter: `(objectGUID=\d0\b0\d0\b1\d0\b2\d0\b3\d0\b4\d0\b5\d1\91\d0\b6\d0\b7\d0\b8\d0\b9\d0\ba\d0\bb\d0\bc\d0\bd\d0\be\d0\bf\d1\80\d1\81\d1\82\d1\83\d1\84\d1\85\d1\86\d1\87\d1\88\d1\89\d1\8a\d1\8b\d1\8c\d1\8d\d1\8e\d1\8f)`,
114 expectedType: FilterEqualityMatch,
115 },
116 {
117 filterStr: `(objectGUID=함수목록)`,
118 expectedFilter: `(objectGUID=\ed\95\a8\ec\88\98\eb\aa\a9\eb\a1\9d)`,
119 expectedType: FilterEqualityMatch,
120 },
121 {
122 filterStr: `(objectGUID=`,
123 expectedFilter: ``,
124 expectedType: 0,
125 expectedErr: "unexpected end of filter",
126 },
127 {
128 filterStr: `(objectGUID=함수목록`,
129 expectedFilter: ``,
130 expectedType: 0,
131 expectedErr: "unexpected end of filter",
132 },
133 {
134 filterStr: `((cn=)`,
135 expectedFilter: ``,
136 expectedType: 0,
137 expectedErr: "unexpected end of filter",
138 },
139 {
140 filterStr: `(&(objectclass=inetorgperson)(cn=中文))`,
141 expectedFilter: `(&(objectclass=inetorgperson)(cn=\e4\b8\ad\e6\96\87))`,
142 expectedType: 0,
143 },
144
145 {
146 filterStr: `(memberOf:=foo)`,
147 expectedFilter: `(memberOf:=foo)`,
148 expectedType: FilterExtensibleMatch,
149 },
150
151 {
152 filterStr: `(memberOf:test:=foo)`,
153 expectedFilter: `(memberOf:test:=foo)`,
154 expectedType: FilterExtensibleMatch,
155 },
156
157 {
158 filterStr: `(cn:1.2.3.4.5:=Fred Flintstone)`,
159 expectedFilter: `(cn:1.2.3.4.5:=Fred Flintstone)`,
160 expectedType: FilterExtensibleMatch,
161 },
162
163 {
164 filterStr: `(sn:dn:2.4.6.8.10:=Barney Rubble)`,
165 expectedFilter: `(sn:dn:2.4.6.8.10:=Barney Rubble)`,
166 expectedType: FilterExtensibleMatch,
167 },
168
169 {
170 filterStr: `(o:dn:=Ace Industry)`,
171 expectedFilter: `(o:dn:=Ace Industry)`,
172 expectedType: FilterExtensibleMatch,
173 },
174
175 {
176 filterStr: `(:dn:2.4.6.8.10:=Dino)`,
177 expectedFilter: `(:dn:2.4.6.8.10:=Dino)`,
178 expectedType: FilterExtensibleMatch,
179 },
180 {
181 filterStr: `(memberOf:1.2.840.113556.1.4.1941:=CN=User1,OU=blah,DC=mydomain,DC=net)`,
182 expectedFilter: `(memberOf:1.2.840.113556.1.4.1941:=CN=User1,OU=blah,DC=mydomain,DC=net)`,
183 expectedType: FilterExtensibleMatch,
184 },
185
186
187 }
188
189 var testInvalidFilters = []string{
190 `(objectGUID=\zz)`,
191 `(objectGUID=\a)`,
192 }
193
194 func TestFilter(t *testing.T) {
195
196 for _, i := range testFilters {
197 filter, err := CompileFilter(i.filterStr)
198 switch {
199 case err != nil:
200 if i.expectedErr == "" || !strings.Contains(err.Error(), i.expectedErr) {
201 t.Errorf("Problem compiling '%s' - '%v' (expected error to contain '%v')", i.filterStr, err, i.expectedErr)
202 }
203 case filter.Tag != ber.Tag(i.expectedType):
204 t.Errorf("%q Expected %q got %q", i.filterStr, FilterMap[uint64(i.expectedType)], FilterMap[uint64(filter.Tag)])
205 default:
206 o, err := DecompileFilter(filter)
207 if err != nil {
208 t.Errorf("Problem compiling %s - %s", i.filterStr, err.Error())
209 } else if i.expectedFilter != o {
210 t.Errorf("%q expected, got %q", i.expectedFilter, o)
211 }
212 }
213 }
214 }
215
216 func TestDecodeEscapedSymbols(t *testing.T) {
217 for _, testInfo := range []struct {
218 Src string
219 Err string
220 }{
221 {
222 Src: "a\u0100\x80",
223 Err: `LDAP Result Code 201 "Filter Compile Error": ldap: error reading rune at position 3`,
224 },
225 {
226 Src: `start\d`,
227 Err: `LDAP Result Code 201 "Filter Compile Error": ldap: missing characters for escape in filter`,
228 },
229 {
230 Src: `\`,
231 Err: `LDAP Result Code 201 "Filter Compile Error": ldap: invalid characters for escape in filter: EOF`,
232 },
233 {
234 Src: `start\--end`,
235 Err: `LDAP Result Code 201 "Filter Compile Error": ldap: invalid characters for escape in filter: encoding/hex: invalid byte: U+002D '-'`,
236 },
237 {
238 Src: `start\d0\hh`,
239 Err: `LDAP Result Code 201 "Filter Compile Error": ldap: invalid characters for escape in filter: encoding/hex: invalid byte: U+0068 'h'`,
240 },
241 } {
242
243 res, err := decodeEscapedSymbols([]byte(testInfo.Src))
244 if err == nil || err.Error() != testInfo.Err {
245 t.Fatal(testInfo.Src, "=> ", err, "!=", testInfo.Err)
246 }
247 if res != "" {
248 t.Fatal(testInfo.Src, "=> ", "invalid result", res)
249 }
250 }
251 }
252
253 func TestInvalidFilter(t *testing.T) {
254 for _, filterStr := range testInvalidFilters {
255 if _, err := CompileFilter(filterStr); err == nil {
256 t.Errorf("Problem compiling %s - expected err", filterStr)
257 }
258 }
259 }
260
261 func BenchmarkFilterCompile(b *testing.B) {
262 b.StopTimer()
263 filters := make([]string, len(testFilters))
264
265
266 for idx, i := range testFilters {
267 filters[idx] = i.filterStr
268 }
269
270 maxIdx := len(filters)
271 b.StartTimer()
272 for i := 0; i < b.N; i++ {
273 _, _ = CompileFilter(filters[i%maxIdx])
274 }
275 }
276
277 func BenchmarkFilterDecompile(b *testing.B) {
278 b.StopTimer()
279 filters := make([]*ber.Packet, len(testFilters))
280
281
282 for idx, i := range testFilters {
283 filters[idx], _ = CompileFilter(i.filterStr)
284 }
285
286 maxIdx := len(filters)
287 b.StartTimer()
288 for i := 0; i < b.N; i++ {
289 _, _ = DecompileFilter(filters[i%maxIdx])
290 }
291 }
292
View as plain text