1 package ldap
2
3 import (
4 "reflect"
5 "testing"
6 )
7
8 func TestSuccessfulDNParsing(t *testing.T) {
9 testcases := map[string]DN{
10 "": {[]*RelativeDN{}},
11 "cn=Jim\\2C \\22Hasse Hö\\22 Hansson!,dc=dummy,dc=com": {[]*RelativeDN{
12 {[]*AttributeTypeAndValue{{"cn", "Jim, \"Hasse Hö\" Hansson!"}}},
13 {[]*AttributeTypeAndValue{{"dc", "dummy"}}},
14 {[]*AttributeTypeAndValue{{"dc", "com"}}},
15 }},
16 "UID=jsmith,DC=example,DC=net": {[]*RelativeDN{
17 {[]*AttributeTypeAndValue{{"UID", "jsmith"}}},
18 {[]*AttributeTypeAndValue{{"DC", "example"}}},
19 {[]*AttributeTypeAndValue{{"DC", "net"}}},
20 }},
21 "OU=Sales+CN=J. Smith,DC=example,DC=net": {[]*RelativeDN{
22 {[]*AttributeTypeAndValue{
23 {"OU", "Sales"},
24 {"CN", "J. Smith"},
25 }},
26 {[]*AttributeTypeAndValue{{"DC", "example"}}},
27 {[]*AttributeTypeAndValue{{"DC", "net"}}},
28 }},
29 "1.3.6.1.4.1.1466.0=#04024869": {[]*RelativeDN{
30 {[]*AttributeTypeAndValue{{"1.3.6.1.4.1.1466.0", "Hi"}}},
31 }},
32 "1.3.6.1.4.1.1466.0=#04024869,DC=net": {[]*RelativeDN{
33 {[]*AttributeTypeAndValue{{"1.3.6.1.4.1.1466.0", "Hi"}}},
34 {[]*AttributeTypeAndValue{{"DC", "net"}}},
35 }},
36 "CN=Lu\\C4\\8Di\\C4\\87": {[]*RelativeDN{
37 {[]*AttributeTypeAndValue{{"CN", "Lučić"}}},
38 }},
39 " CN = Lu\\C4\\8Di\\C4\\87 ": {[]*RelativeDN{
40 {[]*AttributeTypeAndValue{{"CN", "Lučić"}}},
41 }},
42 ` A = 1 , B = 2 `: {[]*RelativeDN{
43 {[]*AttributeTypeAndValue{{"A", "1"}}},
44 {[]*AttributeTypeAndValue{{"B", "2"}}},
45 }},
46 ` A = 1 + B = 2 `: {[]*RelativeDN{
47 {[]*AttributeTypeAndValue{
48 {"A", "1"},
49 {"B", "2"},
50 }},
51 }},
52 ` \ \ A\ \ = \ \ 1\ \ , \ \ B\ \ = \ \ 2\ \ `: {[]*RelativeDN{
53 {[]*AttributeTypeAndValue{{" A ", " 1 "}}},
54 {[]*AttributeTypeAndValue{{" B ", " 2 "}}},
55 }},
56 ` \ \ A\ \ = \ \ 1\ \ + \ \ B\ \ = \ \ 2\ \ `: {[]*RelativeDN{
57 {[]*AttributeTypeAndValue{
58 {" A ", " 1 "},
59 {" B ", " 2 "},
60 }},
61 }},
62
63 `cn=john.doe;dc=example,dc=net`: {[]*RelativeDN{
64 {[]*AttributeTypeAndValue{{"cn", "john.doe"}}},
65 {[]*AttributeTypeAndValue{{"dc", "example"}}},
66 {[]*AttributeTypeAndValue{{"dc", "net"}}},
67 }},
68
69
70 `cn=john.doe\;weird name,dc=example,dc=net`: {[]*RelativeDN{
71 {[]*AttributeTypeAndValue{{"cn", "john.doe;weird name"}}},
72 {[]*AttributeTypeAndValue{{"dc", "example"}}},
73 {[]*AttributeTypeAndValue{{"dc", "net"}}},
74 }},
75 `cn=ZXhhbXBsZVRleHQ=,dc=dummy,dc=com`: {[]*RelativeDN{
76 {[]*AttributeTypeAndValue{{"cn", "ZXhhbXBsZVRleHQ="}}},
77 {[]*AttributeTypeAndValue{{"dc", "dummy"}}},
78 {[]*AttributeTypeAndValue{{"dc", "com"}}},
79 }},
80 }
81
82 for test, answer := range testcases {
83 dn, err := ParseDN(test)
84 if err != nil {
85 t.Errorf(err.Error())
86 continue
87 }
88 if !reflect.DeepEqual(dn, &answer) {
89 t.Errorf("Parsed DN %s is not equal to the expected structure", test)
90 t.Logf("Expected:")
91 for _, rdn := range answer.RDNs {
92 for _, attribs := range rdn.Attributes {
93 t.Logf("#%v\n", attribs)
94 }
95 }
96 t.Logf("Actual:")
97 for _, rdn := range dn.RDNs {
98 for _, attribs := range rdn.Attributes {
99 t.Logf("#%v\n", attribs)
100 }
101 }
102 }
103 }
104 }
105
106 func TestErrorDNParsing(t *testing.T) {
107 testcases := map[string]string{
108 "*": "DN ended with incomplete type, value pair",
109 "cn=Jim\\0Test": "failed to decode escaped character: encoding/hex: invalid byte: U+0054 'T'",
110 "cn=Jim\\0": "got corrupted escaped character",
111 "DC=example,=net": "DN ended with incomplete type, value pair",
112 "1=#0402486": "failed to decode BER encoding: encoding/hex: odd length hex string",
113 "test,DC=example,DC=com": "incomplete type, value pair",
114 "=test,DC=example,DC=com": "incomplete type, value pair",
115 }
116
117 for test, answer := range testcases {
118 _, err := ParseDN(test)
119 if err == nil {
120 t.Errorf("Expected %s to fail parsing but succeeded\n", test)
121 } else if err.Error() != answer {
122 t.Errorf("Unexpected error on %s:\n%s\nvs.\n%s\n", test, answer, err.Error())
123 }
124 }
125 }
126
127 func TestDNEqual(t *testing.T) {
128 testcases := []struct {
129 A string
130 B string
131 Equal bool
132 }{
133
134 {"", "", true},
135 {"o=A", "o=A", true},
136 {"o=A", "o=B", false},
137
138 {"o=A,o=B", "o=A,o=B", true},
139 {"o=A,o=B", "o=A,o=C", false},
140
141 {"o=A+o=B", "o=A+o=B", true},
142 {"o=A+o=B", "o=A+o=C", false},
143
144
145 {"o=A", "O=A", true},
146 {"o=A,o=B", "o=A,O=B", true},
147 {"o=A+o=B", "o=A+O=B", true},
148
149
150 {"o=a", "O=A", false},
151 {"o=a,o=B", "o=A,O=B", false},
152 {"o=a+o=B", "o=A+O=B", false},
153
154
155 {"o=A+o=B", "O=B+o=A", true},
156
157 {"o=A+o=B", "O=B+o=A+O=B", false},
158
159
160 {"o=A+o=B", "O=B+o=A+O=C", false},
161 {"o=A+o=B+o=C", "O=B+o=A", false},
162
163
164
165 {
166 "cn=John Doe, ou=People, dc=sun.com",
167 "cn=John Doe, ou=People, dc=sun.com",
168 true,
169 },
170
171 {
172 "cn=\\ John\\20Doe, ou=People, dc=sun.com",
173 "cn= \\ John Doe,ou=People,dc=sun.com",
174 true,
175 },
176
177 {
178 "cn=John Doe, ou=People, dc=sun.com",
179 "cn=John Doe, ou=People, dc=sun.com",
180 false,
181 },
182
183 {"cn=john;dc=example,dc=com", "cn=john,dc=example,dc=com", true},
184 }
185
186 for i, tc := range testcases {
187 a, err := ParseDN(tc.A)
188 if err != nil {
189 t.Errorf("%d: %v", i, err)
190 continue
191 }
192 b, err := ParseDN(tc.B)
193 if err != nil {
194 t.Errorf("%d: %v", i, err)
195 continue
196 }
197 if expected, actual := tc.Equal, a.Equal(b); expected != actual {
198 t.Errorf("%d: when comparing %q and %q expected %v, got %v", i, a, b, expected, actual)
199 continue
200 }
201 if expected, actual := tc.Equal, b.Equal(a); expected != actual {
202 t.Errorf("%d: when comparing %q and %q expected %v, got %v", i, a, b, expected, actual)
203 continue
204 }
205
206 if expected, actual := a.Equal(b), a.String() == b.String(); expected != actual {
207 t.Errorf("%d: when asserting string comparison of %q and %q expected equal %v, got %v", i, a, b, expected, actual)
208 continue
209 }
210 }
211 }
212
213 func TestDNEqualFold(t *testing.T) {
214 testcases := []struct {
215 A string
216 B string
217 Equal bool
218 }{
219
220 {"o=A", "o=a", true},
221 {"o=A,o=b", "o=a,o=B", true},
222 {"o=a+o=B", "o=A+o=b", true},
223 {
224 "cn=users,ou=example,dc=com",
225 "cn=Users,ou=example,dc=com",
226 true,
227 },
228
229
230 {"o=A", "O=a", true},
231 {"o=A,o=b", "o=a,O=B", true},
232 {"o=a+o=B", "o=A+O=b", true},
233 }
234
235 for i, tc := range testcases {
236 a, err := ParseDN(tc.A)
237 if err != nil {
238 t.Errorf("%d: %v", i, err)
239 continue
240 }
241 b, err := ParseDN(tc.B)
242 if err != nil {
243 t.Errorf("%d: %v", i, err)
244 continue
245 }
246 if expected, actual := tc.Equal, a.EqualFold(b); expected != actual {
247 t.Errorf("%d: when comparing '%s' and '%s' expected %v, got %v", i, tc.A, tc.B, expected, actual)
248 continue
249 }
250 if expected, actual := tc.Equal, b.EqualFold(a); expected != actual {
251 t.Errorf("%d: when comparing '%s' and '%s' expected %v, got %v", i, tc.A, tc.B, expected, actual)
252 continue
253 }
254 }
255 }
256
257 func TestDNAncestor(t *testing.T) {
258 testcases := []struct {
259 A string
260 B string
261 Ancestor bool
262 }{
263
264 {"", "", false},
265 {"o=A", "o=A", false},
266 {"o=A,o=B", "o=A,o=B", false},
267 {"o=A+o=B", "o=A+o=B", false},
268
269
270 {"ou=C,ou=B,o=A", "ou=E,ou=D,ou=B,o=A", false},
271
272
273 {"ou=C,ou=B,o=A", "ou=E,ou=C,ou=B,o=A", true},
274 }
275
276 for i, tc := range testcases {
277 a, err := ParseDN(tc.A)
278 if err != nil {
279 t.Errorf("%d: %v", i, err)
280 continue
281 }
282 b, err := ParseDN(tc.B)
283 if err != nil {
284 t.Errorf("%d: %v", i, err)
285 continue
286 }
287 if expected, actual := tc.Ancestor, a.AncestorOf(b); expected != actual {
288 t.Errorf("%d: when comparing '%s' and '%s' expected %v, got %v", i, tc.A, tc.B, expected, actual)
289 continue
290 }
291 }
292 }
293
View as plain text