1 package ldap
2
3 import (
4 "bytes"
5 "fmt"
6 "reflect"
7 "runtime"
8 "testing"
9
10 ber "github.com/go-asn1-ber/asn1-ber"
11 )
12
13 func TestControlPaging(t *testing.T) {
14 runControlTest(t, NewControlPaging(0))
15 runControlTest(t, NewControlPaging(100))
16 }
17
18 func TestControlManageDsaIT(t *testing.T) {
19 runControlTest(t, NewControlManageDsaIT(true))
20 runControlTest(t, NewControlManageDsaIT(false))
21 }
22
23 func TestControlMicrosoftNotification(t *testing.T) {
24 runControlTest(t, NewControlMicrosoftNotification())
25 }
26
27 func TestControlMicrosoftShowDeleted(t *testing.T) {
28 runControlTest(t, NewControlMicrosoftShowDeleted())
29 }
30
31 func TestControlMicrosoftServerLinkTTL(t *testing.T) {
32 runControlTest(t, NewControlMicrosoftServerLinkTTL())
33 }
34
35 func TestControlSubtreeDelete(t *testing.T) {
36 runControlTest(t, NewControlSubtreeDelete())
37 }
38
39 func TestControlString(t *testing.T) {
40 runControlTest(t, NewControlString("x", true, "y"))
41 runControlTest(t, NewControlString("x", true, ""))
42 runControlTest(t, NewControlString("x", false, "y"))
43 runControlTest(t, NewControlString("x", false, ""))
44 }
45
46 func TestControlDirSync(t *testing.T) {
47 runControlTest(t, NewRequestControlDirSync(DirSyncObjectSecurity, 1000, nil))
48 runControlTest(t, NewRequestControlDirSync(DirSyncObjectSecurity, 1000, []byte("I'm a cookie!")))
49 }
50
51 func runControlTest(t *testing.T, originalControl Control) {
52 header := ""
53 if callerpc, _, line, ok := runtime.Caller(1); ok {
54 if caller := runtime.FuncForPC(callerpc); caller != nil {
55 header = fmt.Sprintf("%s:%d: ", caller.Name(), line)
56 }
57 }
58
59 encodedPacket := originalControl.Encode()
60 encodedBytes := encodedPacket.Bytes()
61
62
63 fromPacket, err := DecodeControl(encodedPacket)
64 if err != nil {
65 t.Errorf("%sdecoding encoded bytes control failed: %s", header, err)
66 }
67 if !bytes.Equal(encodedBytes, fromPacket.Encode().Bytes()) {
68 t.Errorf("%sround-trip from encoded packet failed", header)
69 }
70 if reflect.TypeOf(originalControl) != reflect.TypeOf(fromPacket) {
71 t.Errorf("%sgot different type decoding from encoded packet: %T vs %T", header, fromPacket, originalControl)
72 }
73
74
75 pkt, err := ber.DecodePacketErr(encodedBytes)
76 if err != nil {
77 t.Errorf("%sdecoding encoded bytes failed: %s", header, err)
78 }
79 fromBytes, err := DecodeControl(pkt)
80 if err != nil {
81 t.Errorf("%sdecoding control failed: %s", header, err)
82 }
83 if !bytes.Equal(encodedBytes, fromBytes.Encode().Bytes()) {
84 t.Errorf("%sround-trip from encoded bytes failed", header)
85 }
86 if reflect.TypeOf(originalControl) != reflect.TypeOf(fromPacket) {
87 t.Errorf("%sgot different type decoding from encoded bytes: %T vs %T", header, fromBytes, originalControl)
88 }
89 }
90
91 func TestDescribeControlManageDsaIT(t *testing.T) {
92 runAddControlDescriptions(t, NewControlManageDsaIT(false), "Control Type (Manage DSA IT)")
93 runAddControlDescriptions(t, NewControlManageDsaIT(true), "Control Type (Manage DSA IT)", "Criticality")
94 }
95
96 func TestDescribeControlPaging(t *testing.T) {
97 runAddControlDescriptions(t, NewControlPaging(100), "Control Type (Paging)", "Control Value (Paging)")
98 runAddControlDescriptions(t, NewControlPaging(0), "Control Type (Paging)", "Control Value (Paging)")
99 }
100
101 func TestDescribeControlSubtreeDelete(t *testing.T) {
102 runAddControlDescriptions(t, NewControlSubtreeDelete(), "Control Type (Subtree Delete Control)")
103 }
104
105 func TestDescribeControlMicrosoftNotification(t *testing.T) {
106 runAddControlDescriptions(t, NewControlMicrosoftNotification(), "Control Type (Change Notification - Microsoft)")
107 }
108
109 func TestDescribeControlMicrosoftShowDeleted(t *testing.T) {
110 runAddControlDescriptions(t, NewControlMicrosoftShowDeleted(), "Control Type (Show Deleted Objects - Microsoft)")
111 }
112
113 func TestDescribeControlMicrosoftServerLinkTTL(t *testing.T) {
114 runAddControlDescriptions(t, NewControlMicrosoftServerLinkTTL(), "Control Type (Return TTL-DNs for link values with associated expiry times - Microsoft)")
115 }
116
117 func TestDescribeControlString(t *testing.T) {
118 runAddControlDescriptions(t, NewControlString("x", true, "y"), "Control Type ()", "Criticality", "Control Value")
119 runAddControlDescriptions(t, NewControlString("x", true, ""), "Control Type ()", "Criticality")
120 runAddControlDescriptions(t, NewControlString("x", false, "y"), "Control Type ()", "Control Value")
121 runAddControlDescriptions(t, NewControlString("x", false, ""), "Control Type ()")
122 }
123
124 func TestDescribeControlDirSync(t *testing.T) {
125 runAddControlDescriptions(t, NewRequestControlDirSync(DirSyncObjectSecurity, 1000, nil), "Control Type (DirSync)", "Criticality", "Control Value")
126 }
127
128 func runAddControlDescriptions(t *testing.T, originalControl Control, childDescriptions ...string) {
129 header := ""
130 if callerpc, _, line, ok := runtime.Caller(1); ok {
131 if caller := runtime.FuncForPC(callerpc); caller != nil {
132 header = fmt.Sprintf("%s:%d: ", caller.Name(), line)
133 }
134 }
135
136 encodedControls := encodeControls([]Control{originalControl})
137 _ = addControlDescriptions(encodedControls)
138 encodedPacket := encodedControls.Children[0]
139 if len(encodedPacket.Children) != len(childDescriptions) {
140 t.Errorf("%sinvalid number of children: %d != %d", header, len(encodedPacket.Children), len(childDescriptions))
141 }
142 for i, desc := range childDescriptions {
143 if encodedPacket.Children[i].Description != desc {
144 t.Errorf("%sdescription not as expected: %s != %s", header, encodedPacket.Children[i].Description, desc)
145 }
146 }
147 }
148
149 func TestDecodeControl(t *testing.T) {
150 type args struct {
151 packet *ber.Packet
152 }
153
154 tests := []struct {
155 name string
156 args args
157 want Control
158 wantErr bool
159 }{
160 {
161 name: "timeBeforeExpiration", args: args{packet: ber.DecodePacket([]byte{0xa0, 0x29, 0x30, 0x27, 0x4, 0x19, 0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x32, 0x2e, 0x32, 0x2e, 0x32, 0x37, 0x2e, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x4, 0xa, 0x30, 0x8, 0xa0, 0x6, 0x80, 0x4, 0x7f, 0xff, 0xf6, 0x5c})},
162 want: &ControlBeheraPasswordPolicy{Expire: 2147481180, Grace: -1, Error: -1, ErrorString: ""}, wantErr: false,
163 },
164 {
165 name: "graceAuthNsRemaining", args: args{packet: ber.DecodePacket([]byte{0xa0, 0x26, 0x30, 0x24, 0x4, 0x19, 0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x32, 0x2e, 0x32, 0x2e, 0x32, 0x37, 0x2e, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x4, 0x7, 0x30, 0x5, 0xa0, 0x3, 0x81, 0x1, 0x11})},
166 want: &ControlBeheraPasswordPolicy{Expire: -1, Grace: 17, Error: -1, ErrorString: ""}, wantErr: false,
167 },
168 {
169 name: "passwordExpired", args: args{packet: ber.DecodePacket([]byte{0xa0, 0x24, 0x30, 0x22, 0x4, 0x19, 0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x32, 0x2e, 0x32, 0x2e, 0x32, 0x37, 0x2e, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x4, 0x5, 0x30, 0x3, 0x81, 0x1, 0x0})},
170 want: &ControlBeheraPasswordPolicy{Expire: -1, Grace: -1, Error: 0, ErrorString: "Password expired"}, wantErr: false,
171 },
172 {
173 name: "accountLocked", args: args{packet: ber.DecodePacket([]byte{0xa0, 0x24, 0x30, 0x22, 0x4, 0x19, 0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x32, 0x2e, 0x32, 0x2e, 0x32, 0x37, 0x2e, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x4, 0x5, 0x30, 0x3, 0x81, 0x1, 0x1})},
174 want: &ControlBeheraPasswordPolicy{Expire: -1, Grace: -1, Error: 1, ErrorString: "Account locked"}, wantErr: false,
175 },
176 {
177 name: "passwordModNotAllowed", args: args{packet: ber.DecodePacket([]byte{0xa0, 0x24, 0x30, 0x22, 0x4, 0x19, 0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x32, 0x2e, 0x32, 0x2e, 0x32, 0x37, 0x2e, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x4, 0x5, 0x30, 0x3, 0x81, 0x1, 0x3})},
178 want: &ControlBeheraPasswordPolicy{Expire: -1, Grace: -1, Error: 3, ErrorString: "Policy prevents password modification"}, wantErr: false,
179 },
180 {
181 name: "mustSupplyOldPassword", args: args{packet: ber.DecodePacket([]byte{0xa0, 0x24, 0x30, 0x22, 0x4, 0x19, 0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x32, 0x2e, 0x32, 0x2e, 0x32, 0x37, 0x2e, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x4, 0x5, 0x30, 0x3, 0x81, 0x1, 0x4})},
182 want: &ControlBeheraPasswordPolicy{Expire: -1, Grace: -1, Error: 4, ErrorString: "Policy requires old password in order to change password"}, wantErr: false,
183 },
184 {
185 name: "insufficientPasswordQuality", args: args{packet: ber.DecodePacket([]byte{0xa0, 0x24, 0x30, 0x22, 0x4, 0x19, 0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x32, 0x2e, 0x32, 0x2e, 0x32, 0x37, 0x2e, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x4, 0x5, 0x30, 0x3, 0x81, 0x1, 0x5})},
186 want: &ControlBeheraPasswordPolicy{Expire: -1, Grace: -1, Error: 5, ErrorString: "Password fails quality checks"}, wantErr: false,
187 },
188 {
189 name: "passwordTooShort", args: args{packet: ber.DecodePacket([]byte{0xa0, 0x24, 0x30, 0x22, 0x4, 0x19, 0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x32, 0x2e, 0x32, 0x2e, 0x32, 0x37, 0x2e, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x4, 0x5, 0x30, 0x3, 0x81, 0x1, 0x6})},
190 want: &ControlBeheraPasswordPolicy{Expire: -1, Grace: -1, Error: 6, ErrorString: "Password is too short for policy"}, wantErr: false,
191 },
192 {
193 name: "passwordTooYoung", args: args{packet: ber.DecodePacket([]byte{0xa0, 0x24, 0x30, 0x22, 0x4, 0x19, 0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x32, 0x2e, 0x32, 0x2e, 0x32, 0x37, 0x2e, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x4, 0x5, 0x30, 0x3, 0x81, 0x1, 0x7})},
194 want: &ControlBeheraPasswordPolicy{Expire: -1, Grace: -1, Error: 7, ErrorString: "Password has been changed too recently"}, wantErr: false,
195 },
196 {
197 name: "passwordInHistory", args: args{packet: ber.DecodePacket([]byte{0xa0, 0x24, 0x30, 0x22, 0x4, 0x19, 0x31, 0x2e, 0x33, 0x2e, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x32, 0x2e, 0x32, 0x2e, 0x32, 0x37, 0x2e, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x4, 0x5, 0x30, 0x3, 0x81, 0x1, 0x8})},
198 want: &ControlBeheraPasswordPolicy{Expire: -1, Grace: -1, Error: 8, ErrorString: "New password is in list of old passwords"}, wantErr: false,
199 },
200 }
201 for i := range tests {
202 err := addControlDescriptions(tests[i].args.packet)
203 if err != nil {
204 t.Fatal(err)
205 }
206 tests[i].args.packet = tests[i].args.packet.Children[0]
207 }
208
209 for _, tt := range tests {
210 t.Run(tt.name, func(t *testing.T) {
211 got, err := DecodeControl(tt.args.packet)
212 if (err != nil) != tt.wantErr {
213 t.Errorf("DecodeControl() error = %v, wantErr %v", err, tt.wantErr)
214 return
215 }
216 if !reflect.DeepEqual(got, tt.want) {
217 t.Errorf("DecodeControl() got = %v, want %v", got, tt.want)
218 }
219 })
220 }
221 }
222
223 func TestControlServerSideSortingDecoding(t *testing.T) {
224 control := NewControlServerSideSortingWithSortKeys([]*SortKey{{
225 MatchingRule: "foo",
226 AttributeType: "foobar",
227 Reverse: true,
228 }, {
229 MatchingRule: "foo",
230 AttributeType: "foobar",
231 Reverse: false,
232 }, {
233 MatchingRule: "",
234 AttributeType: "",
235 Reverse: false,
236 }, {
237 MatchingRule: "totoRule",
238 AttributeType: "",
239 Reverse: false,
240 }, {
241 MatchingRule: "",
242 AttributeType: "totoType",
243 Reverse: false,
244 }})
245
246 controlDecoded, err := NewControlServerSideSorting(control.Encode())
247 if err != nil {
248 t.Fatal(err)
249 }
250
251 if control.GetControlType() != controlDecoded.GetControlType() {
252 t.Fatalf("control type mismatch: control:%s - decoded:%s", control.GetControlType(), controlDecoded.GetControlType())
253 }
254
255 if len(control.SortKeys) != len(controlDecoded.SortKeys) {
256 t.Fatalf("sort keys length mismatch (control: %d - decoded: %d)", len(control.SortKeys), len(controlDecoded.SortKeys))
257 }
258
259 for i, sk := range control.SortKeys {
260 dsk := controlDecoded.SortKeys[i]
261
262 if sk.AttributeType != dsk.AttributeType {
263 t.Fatalf("attribute type mismatch for sortkey %d", i)
264 }
265
266 if sk.MatchingRule != dsk.MatchingRule {
267 t.Fatalf("matching rule mismatch for sortkey %d", i)
268 }
269
270 if sk.Reverse != dsk.Reverse {
271 t.Fatalf("reverse mismtach for sortkey %d", i)
272 }
273 }
274 }
275
View as plain text