ldap-authentication 3.3.3 → 3.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,7 +8,7 @@ services:
8
8
  command: sleep infinity
9
9
 
10
10
  ldap:
11
- image: bitnami/openldap
11
+ image: symas/openldap:2.6
12
12
  ports:
13
13
  - '1389:1389'
14
14
  - '1636:1636'
package/README.md CHANGED
@@ -147,6 +147,43 @@ async function auth() {
147
147
  auth()
148
148
  ```
149
149
 
150
+ ### Example with StartTLS
151
+
152
+ ```javascript
153
+ import { authenticate } from 'ldap-authentication'
154
+
155
+ async function auth() {
156
+ // auth with admin
157
+ let options = {
158
+ ldapOpts: {
159
+ url: 'ldap://ldap.example.com',
160
+ tlsOptions: {
161
+ rejectUnauthorized: false, // For self-signed certificates
162
+ minVersion: 'TLSv1.2',
163
+ servername: 'ldap.example.com' // For SNI (Server Name Indication)
164
+ }
165
+ },
166
+ starttls: true, // Enable StartTLS
167
+ adminDn: 'cn=admin,dc=example,dc=com',
168
+ adminPassword: 'password',
169
+ userPassword: 'password',
170
+ userSearchBase: 'dc=example,dc=com',
171
+ usernameAttribute: 'uid',
172
+ username: 'testuser'
173
+ }
174
+
175
+ let user = await authenticate(options)
176
+ console.log(user)
177
+ }
178
+
179
+ auth()
180
+ ```
181
+
182
+ **Important Notes for StartTLS:**
183
+ - Use `ldap://` URLs with `starttls: true` (not `ldaps://`)
184
+ - For `ldaps://` URLs, omit `starttls` and the connection will use TLS from the start
185
+ - TLS options like `rejectUnauthorized`, `minVersion`, and `servername` can be specified in `ldapOpts.tlsOptions`
186
+
150
187
  ## Parameters
151
188
 
152
189
  - `ldapOpts`: This is passed to `ldapts` client directly
@@ -172,7 +209,9 @@ auth()
172
209
  to find the user and get user details in LDAP. Example: `some user input`
173
210
  - `attributes`: A list of attributes of a user details to be returned from the LDAP server.
174
211
  If is set to `[]` or ommited, all details will be returned. Example: `['sn', 'cn']`
175
- - `starttls`: Boolean. Use `STARTTLS` or not
212
+ - `starttls`: Boolean. Use `STARTTLS` or not. When `true`, the connection will be upgraded to TLS
213
+ using the STARTTLS extended operation. TLS options can be specified in `ldapOpts.tlsOptions`.
214
+ Note: Use `starttls: true` with `ldap://` URLs, not `ldaps://` URLs
176
215
  - `groupsSearchBase`: if specified with groupClass, will serve as search base for authenticated user groups
177
216
  - `groupClass`: if specified with groupsSearchBase, will be used as objectClass in search filter for authenticated user groups
178
217
  - `groupMemberAttribute`: if specified with groupClass and groupsSearchBase, will be used as member name (if not specified this defaults to `member`) in search filter for authenticated user groups
@@ -1,6 +1,6 @@
1
1
  services:
2
2
  ldap:
3
- image: bitnami/openldap:2.6.3
3
+ image: symas/openldap:2.6
4
4
  ports:
5
5
  - '1389:1389'
6
6
  - '1636:1636'
package/index.d.ts CHANGED
@@ -17,6 +17,7 @@ declare module 'ldap-authentication' {
17
17
  groupMemberUserAttribute?: string
18
18
  userPassword?: string
19
19
  attributes?: string[]
20
+ explicitBufferAttributes?: string[]
20
21
  }
21
22
 
22
23
  export function authenticate(options: AuthenticationOptions): Promise<any>
package/index.js CHANGED
@@ -43,7 +43,25 @@ async function _ldapBind(dn, password, starttls, ldapOpts) {
43
43
  // TODO: check if ldapts expects escaped dn or not (possible double escaping problems?)
44
44
  dn = _ldapEscapeDN(dn)
45
45
  ldapOpts.connectTimeout = ldapOpts.connectTimeout || 5000
46
- let client = new ldapts.Client(ldapOpts)
46
+
47
+ // When using StartTLS, we need to exclude tlsOptions from the Client constructor
48
+ // and only pass them to the startTLS() method to avoid connection conflicts.
49
+ // According to ldapts documentation:
50
+ // - For LDAPS (ldaps://): pass tlsOptions to Client constructor
51
+ // - For StartTLS (ldap://): do NOT pass tlsOptions to Client constructor, only to startTLS()
52
+ // - For plain LDAP (ldap://): do NOT pass tlsOptions to Client constructor
53
+ let clientOpts = ldapOpts
54
+ const isLdaps = ldapOpts.url && ldapOpts.url.startsWith('ldaps://')
55
+
56
+ // Only pass tlsOptions to Client constructor if using ldaps:// protocol
57
+ // For ldap:// protocol (plain or StartTLS), exclude tlsOptions from constructor
58
+ if (!isLdaps && ldapOpts.tlsOptions) {
59
+ // Create a shallow copy of ldapOpts without tlsOptions for the Client constructor
60
+ const { tlsOptions, ...optsWithoutTls } = ldapOpts
61
+ clientOpts = optsWithoutTls
62
+ }
63
+
64
+ let client = new ldapts.Client(clientOpts)
47
65
 
48
66
  if (starttls) {
49
67
  await client.startTLS(ldapOpts.tlsOptions)
@@ -60,7 +78,8 @@ async function _searchUser(
60
78
  searchBase,
61
79
  usernameAttribute,
62
80
  username,
63
- attributes = null
81
+ attributes = null,
82
+ explicitBufferAttributes = null
64
83
  ) {
65
84
  let filter = new ldapts.EqualityFilter({
66
85
  attribute: usernameAttribute,
@@ -74,6 +93,9 @@ async function _searchUser(
74
93
  if (attributes) {
75
94
  searchOptions.attributes = attributes
76
95
  }
96
+ if(explicitBufferAttributes) {
97
+ searchOptions.explicitBufferAttributes = explicitBufferAttributes
98
+ }
77
99
 
78
100
  // TODO: we don't support reference yet
79
101
  // If the server was able to locate the entry referred to by the baseObject
@@ -98,6 +120,22 @@ async function _searchUser(
98
120
  user = searchEntries[0]
99
121
  }
100
122
 
123
+ // when attribute endwith ;binary, ldapts returns Buffer, we convert them into base64 string
124
+ if (user != null && attributes != null) {
125
+ for (let attr of attributes) {
126
+ if (attr.endsWith(';binary') && Buffer.isBuffer(user[attr])) {
127
+ user[attr] = user[attr].toString('base64')
128
+ }
129
+ }
130
+ }
131
+ // when attribute is one of the explicitBufferAttributes, should convert to base64 string
132
+ if (user != null && explicitBufferAttributes != null) {
133
+ for (let attr of explicitBufferAttributes) {
134
+ if (Buffer.isBuffer(user[attr])) {
135
+ user[attr] = user[attr].toString('base64')
136
+ }
137
+ }
138
+ }
101
139
  return user
102
140
  }
103
141
 
@@ -162,7 +200,8 @@ async function authenticateWithAdmin(
162
200
  groupClass,
163
201
  groupMemberAttribute = 'member',
164
202
  groupMemberUserAttribute = 'dn',
165
- attributes = null
203
+ attributes = null,
204
+ explicitBufferAttributes = null
166
205
  ) {
167
206
  let ldapAdminClient
168
207
  try {
@@ -183,7 +222,8 @@ async function authenticateWithAdmin(
183
222
  userSearchBase,
184
223
  usernameAttribute,
185
224
  username,
186
- attributes
225
+ attributes,
226
+ explicitBufferAttributes
187
227
  )
188
228
  if (!user || !user.dn) {
189
229
  ldapOpts.log &&
@@ -233,7 +273,8 @@ async function authenticateWithUser(
233
273
  groupClass,
234
274
  groupMemberAttribute = 'member',
235
275
  groupMemberUserAttribute = 'dn',
236
- attributes = null
276
+ attributes = null,
277
+ explicitBufferAttributes = null
237
278
  ) {
238
279
  let ldapUserClient
239
280
  try {
@@ -254,7 +295,8 @@ async function authenticateWithUser(
254
295
  userSearchBase,
255
296
  usernameAttribute,
256
297
  username,
257
- attributes
298
+ attributes,
299
+ explicitBufferAttributes
258
300
  )
259
301
  if (!user || !user.dn) {
260
302
  ldapOpts.log &&
@@ -293,7 +335,8 @@ async function verifyUserExists(
293
335
  groupClass,
294
336
  groupMemberAttribute = 'member',
295
337
  groupMemberUserAttribute = 'dn',
296
- attributes = null
338
+ attributes = null,
339
+ explicitBufferAttributes = null
297
340
  ) {
298
341
  let ldapAdminClient
299
342
  try {
@@ -314,7 +357,8 @@ async function verifyUserExists(
314
357
  userSearchBase,
315
358
  usernameAttribute,
316
359
  username,
317
- attributes
360
+ attributes,
361
+ explicitBufferAttributes
318
362
  )
319
363
  if (!user || !user.dn) {
320
364
  ldapOpts.log &&
@@ -376,7 +420,8 @@ async function authenticate(options) {
376
420
  options.groupClass,
377
421
  options.groupMemberAttribute,
378
422
  options.groupMemberUserAttribute,
379
- options.attributes
423
+ options.attributes,
424
+ options.explicitBufferAttributes
380
425
  )
381
426
  }
382
427
  assert(options.userPassword, 'userPassword must be provided')
@@ -398,7 +443,8 @@ async function authenticate(options) {
398
443
  options.groupClass,
399
444
  options.groupMemberAttribute,
400
445
  options.groupMemberUserAttribute,
401
- options.attributes
446
+ options.attributes,
447
+ options.explicitBufferAttributes
402
448
  )
403
449
  }
404
450
  assert(options.userDn, 'adminDn/adminPassword OR userDn must be provided')
@@ -414,7 +460,8 @@ async function authenticate(options) {
414
460
  options.groupClass,
415
461
  options.groupMemberAttribute,
416
462
  options.groupMemberUserAttribute,
417
- options.attributes
463
+ options.attributes,
464
+ options.explicitBufferAttributes
418
465
  )
419
466
  }
420
467
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ldap-authentication",
3
- "version": "3.3.3",
3
+ "version": "3.3.6",
4
4
  "description": "A simple async nodejs library for LDAP user authentication",
5
5
  "main": "index.js",
6
6
  "types": "./index.d.ts",
@@ -0,0 +1,115 @@
1
+ const { Change } = require('ldapts')
2
+ const { authenticate, LdapAuthenticationError } = require('../index.js')
3
+ const ldapts = require('ldapts')
4
+ const { Attribute } = require('ldapts')
5
+
6
+ const url = process.env.INGITHUB ? 'ldap://localhost:1389' : 'ldap://ldap:1389'
7
+
8
+ describe('ldap-authentication binary attributes test', () => {
9
+ const jpegPhotoBase64 =
10
+ '/9j/4AAQSkZJRgABAQEASABIAAD/2wBDACgcHiMeGSgjISMtKygwPGRBPDc3PHtYXUlkkYCZlo+AjIqgtObDoKrarYqMyP/L2u71////m8H////6/+b9//j/2wBDASstLTw1PHZBQXb4pYyl+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj/wAARCACBAGQDAREAAhEBAxEB/8QAGQAAAwEBAQAAAAAAAAAAAAAAAAECAwQF/8QALRAAAgEDAwMCBQQDAAAAAAAAAAECAxEhBBIxMkFRInEFE2GBsRU0QlJikaH/xAAXAQEBAQEAAAAAAAAAAAAAAAAAAQID/8QAGxEBAQEAAwEBAAAAAAAAAAAAAAERAhIhMUH/2gAMAwEAAhEDEQA/APMIAAKAgChp2AdwAAACBlAQUkmu5RkAAACuAAADsAZQDWQKRA7AL7gAEFCbAQDAYAAXAdwBYAogAAAAgokBgADAEr8Ab09JWqZcdq8yJpjb9Pa5qr/ROy4l6Ga6ZxfvgdoYiemqw6o49yoyAAACCiQKa4AAN9PpnWy3aP5Jbiya9ClRhBJRjby/Ji1qRqRQBMkuwMZSk2trdiys2PPqR2zaNspAAIKE0A+yA201H51TPSuSW4smvTilFJJWSOdbi0RTZQghPgK56nNwzXLXtvx4NxhiUAEABQ0nJpJcgejpkoR2rtyznWo3uRpE5S4i8hfRCrPKm0wLlUUUrgZSruXTD/oROZPISuat1s3GGRQgIKADp0kFNy8pYM2rJrshBQ4M1qNErojTOdFyjZTcfqhKWaqFPObuyAdeKlBfRhcZrT01JzXdWsXWc/U7XF5IVlqWm1waYczKhXKIKEB0aOW2uvDwZvxZ9ejbBlq+CLsZaWrMAckvSgpSW6DQVNKW6ObXRUTVd5BmuKp1M05s2USBmaABpS60Qeg41rqUXeMcszjW61auroliyi7sZaFk1YKirVnSVopyXkqajTNtSv3YouXU/oWM8nHLLZWENFCsBiaAB1aCj86tnpjlko9javBlUVY29SWO4VizNaiVBJcu/m5FJwvyFTGmqct+Como3Juz5EZrnZplLKhWAw5NDZxisW47gen8NpqOncsepmarrIBZwwOWunSf+L4ZmxqVnvI1puoU1nObs347BLS7FZLZ8x27sIwqQcJuMuUaRAGdKN5X8ZKHJu+Qrq02venpbNilnGbDB3UNXHUJ7dqmv4szfA46luVnTbf0ZNFyqUpxcKnpv2kUclWiqT9LvF8O5mtRNnZO+ChSTccAOzsGShVhSlullrhFHPObnNyfLKiAHQW2lKfngqxk3dgSyhwm4TUk3dPDIPV0OrhWltmlGr2fkxYrqrUVVg0+ez8GdHPGhLa0/uaRMFeW1K9wrd6e7vJ2XhFRjKnGqtlNtPyyTB5MrqV28nRFxnf3JgogSqp0FBKzRVZlAEKKyFCbjO6eUQexotaq6UKjtUXf+xz5ccWOmas91u2RKVjHZSlaTe210yoipqHNbY3UfyTVEI7nbyUc+r0vLiuFc1Kjz7WNItSxkmCShAAAgCeXewURbTusNBHs6LWRrpQqO1T8nOzGmtamnG1unK9gM4UknfgqNYxSzZsBuTtiOL2ZKPJ1lFU6zt0yymblRhYonuQD4KEAAOXIUkEa6f8AcQ90Sq92r2+5zioXWvY0jQqJkRXn/EeiHuywcS4NI//Z'
11
+
12
+ const baseOptions = {
13
+ ldapOpts: {
14
+ url: url,
15
+ },
16
+ adminDn: 'cn=read-only-admin,dc=example,dc=com',
17
+ adminPassword: 'password',
18
+ verifyUserExists: true,
19
+ userSearchBase: 'dc=example,dc=com',
20
+ usernameAttribute: 'uid',
21
+ }
22
+
23
+ it('Add jpegPhoto attribute', async () => {
24
+ let client = new ldapts.Client({
25
+ ...baseOptions.ldapOpts,
26
+ })
27
+ try {
28
+ await client.bind(baseOptions.adminDn, baseOptions.adminPassword)
29
+
30
+ // https://github.com/ldapts/ldapts/issues/12
31
+ await client.modify(
32
+ 'cn=gauss,ou=users,dc=example,dc=com',
33
+ new Change({
34
+ operation: 'replace',
35
+ modification: new Attribute({
36
+ type: 'jpegPhoto',
37
+ values: [Buffer.from(jpegPhotoBase64, 'base64')],
38
+ }),
39
+ })
40
+ )
41
+ } finally {
42
+ await client.unbind()
43
+ }
44
+ })
45
+
46
+ it('Should return broken jpegPhoto attribute (no attribute selection nor ;binary) - But it really depends on LDAP server, it is not always true. Sometimes a buffer is returned directly.', async () => {
47
+ let user = await authenticate({
48
+ ...baseOptions,
49
+ username: 'gauss',
50
+ })
51
+
52
+ expect(user).toBeTruthy()
53
+ expect(user.uid).toEqual('gauss')
54
+ expect(user.sn).toEqual('Bar1')
55
+ expect(typeof user.uidNumber === 'string').toBe(true)
56
+ expect(user.uidNumber).toEqual('1000')
57
+
58
+ expect(user.jpegPhoto).toBeDefined()
59
+ // some ldap server returns a string, some ldap server returns a buffer
60
+ expect(
61
+ typeof user.jpegPhoto === 'string' || Buffer.isBuffer(user.jpegPhoto)
62
+ ).toBe(true)
63
+ if (typeof user.jpegPhoto === 'string') {
64
+ expect(user.jpegPhoto).not.toEqual(jpegPhotoBase64)
65
+ }
66
+ if (Buffer.isBuffer(user.jpegPhoto)) {
67
+ expect(
68
+ user.jpegPhoto.equals(Buffer.from(jpegPhotoBase64, 'base64'))
69
+ ).toBeTrue()
70
+ }
71
+ })
72
+
73
+ it('Should return nothing in the base64 jpegPhoto (using ;binary)', async () => {
74
+ let user = await authenticate({
75
+ ...baseOptions,
76
+ username: 'gauss',
77
+ attributes: ['uid', 'sn', 'jpegPhoto;binary'],
78
+ })
79
+
80
+ expect(user).toBeTruthy()
81
+ expect(user.uid).toEqual('gauss')
82
+ expect(user.sn).toEqual('Bar1')
83
+ expect(user.cn).toBeUndefined()
84
+
85
+ expect(user.jpegPhoto).toBeUndefined()
86
+
87
+ expect(user['jpegPhoto;binary']).toBeDefined()
88
+ expect(Array.isArray(user['jpegPhoto;binary'])).toBe(true)
89
+ expect(user['jpegPhoto;binary'].length).toBe(0)
90
+ })
91
+
92
+ it('Should return base64 jpegPhoto (using explicitBufferAttributes)', async () => {
93
+ let user = await authenticate({
94
+ ...baseOptions,
95
+ username: 'gauss',
96
+ attributes: ['uid', 'sn', 'jpegPhoto'],
97
+ explicitBufferAttributes: ['jpegPhoto'],
98
+ })
99
+
100
+ expect(user).toBeTruthy()
101
+ expect(user.uid).toEqual('gauss')
102
+ expect(user.sn).toEqual('Bar1')
103
+ expect(user.cn).toBeUndefined()
104
+
105
+ expect(user['jpegPhoto;binary']).toBeUndefined()
106
+
107
+ expect(user.jpegPhoto).toBeDefined()
108
+ expect(typeof user.jpegPhoto === 'string').toBe(true)
109
+ expect(user.jpegPhoto).toEqual(jpegPhotoBase64)
110
+
111
+ const buffer = Buffer.from(user.jpegPhoto, 'base64')
112
+ expect(buffer).toBeDefined()
113
+ expect(buffer.length).toBeGreaterThan(0)
114
+ })
115
+ })
@@ -0,0 +1,126 @@
1
+ const { authenticate, LdapAuthenticationError } = require('../index.js')
2
+
3
+ const url = process.env.INGITHUB ? 'ldap://localhost:1389' : 'ldap://ldap:1389'
4
+
5
+ describe('ldap-authentication StartTLS and TLS options test', () => {
6
+ it('Plain LDAP with tlsOptions in ldapOpts should work (ldap:// protocol)', async () => {
7
+ // Regression test: Before fix, having tlsOptions with ldap:// URL caused issues
8
+ // After fix: tlsOptions are properly excluded from Client constructor for ldap:// URLs
9
+ let options = {
10
+ ldapOpts: {
11
+ url: url,
12
+ tlsOptions: {
13
+ rejectUnauthorized: false,
14
+ },
15
+ },
16
+ adminDn: 'cn=read-only-admin,dc=example,dc=com',
17
+ adminPassword: 'password',
18
+ userPassword: 'password',
19
+ userSearchBase: 'dc=example,dc=com',
20
+ usernameAttribute: 'uid',
21
+ username: 'gauss',
22
+ }
23
+
24
+ let user = await authenticate(options)
25
+ expect(user).toBeTruthy()
26
+ expect(user.uid).toEqual('gauss')
27
+ })
28
+
29
+ it('Use an admin user to authenticate with StartTLS (may skip if TLS not configured)', async () => {
30
+ // Note: This test may not fully succeed if the LDAP server lacks TLS certificates
31
+ // However, it should NOT fail with the original ECONNRESET bug
32
+ let options = {
33
+ ldapOpts: {
34
+ url: url,
35
+ tlsOptions: {
36
+ rejectUnauthorized: false,
37
+ minVersion: 'TLSv1.2',
38
+ },
39
+ },
40
+ starttls: true,
41
+ adminDn: 'cn=read-only-admin,dc=example,dc=com',
42
+ adminPassword: 'password',
43
+ userPassword: 'password',
44
+ userSearchBase: 'dc=example,dc=com',
45
+ usernameAttribute: 'uid',
46
+ username: 'gauss',
47
+ }
48
+
49
+ try {
50
+ let user = await authenticate(options)
51
+ // If this succeeds, StartTLS is fully working!
52
+ expect(user).toBeTruthy()
53
+ expect(user.uid).toEqual('gauss')
54
+ } catch (error) {
55
+ // Expected if StartTLS is not configured on the server
56
+ // The critical check: should NOT be the original ECONNRESET bug
57
+ if (error.code === 'ECONNRESET' &&
58
+ error.message && error.message.includes('Client network socket disconnected before secure TLS connection')) {
59
+ fail('ECONNRESET bug detected: tlsOptions should NOT be passed to Client constructor when using ldap:// URL')
60
+ }
61
+ // Other errors are acceptable (e.g., server doesn't support StartTLS)
62
+ expect(error).toBeTruthy()
63
+ }
64
+ })
65
+
66
+ it('Use a regular user to authenticate with StartTLS (self mode)', async () => {
67
+ let options = {
68
+ ldapOpts: {
69
+ url: url,
70
+ tlsOptions: {
71
+ rejectUnauthorized: false,
72
+ minVersion: 'TLSv1.2',
73
+ },
74
+ },
75
+ starttls: true,
76
+ userDn: 'cn=einstein,ou=users,dc=example,dc=com',
77
+ userPassword: 'password',
78
+ userSearchBase: 'dc=example,dc=com',
79
+ usernameAttribute: 'uid',
80
+ username: 'einstein',
81
+ }
82
+
83
+ try {
84
+ let user = await authenticate(options)
85
+ expect(user).toBeTruthy()
86
+ expect(user.uid).toEqual('einstein')
87
+ } catch (error) {
88
+ if (error.code === 'ECONNRESET' &&
89
+ error.message && error.message.includes('Client network socket disconnected before secure TLS connection')) {
90
+ fail('ECONNRESET bug detected: tlsOptions should NOT be passed to Client constructor when using ldap:// URL')
91
+ }
92
+ expect(error).toBeTruthy()
93
+ }
94
+ })
95
+
96
+ it('Verify user exists with StartTLS', async () => {
97
+ let options = {
98
+ ldapOpts: {
99
+ url: url,
100
+ tlsOptions: {
101
+ rejectUnauthorized: false,
102
+ minVersion: 'TLSv1.2',
103
+ },
104
+ },
105
+ starttls: true,
106
+ adminDn: 'cn=read-only-admin,dc=example,dc=com',
107
+ adminPassword: 'password',
108
+ verifyUserExists: true,
109
+ userSearchBase: 'dc=example,dc=com',
110
+ usernameAttribute: 'uid',
111
+ username: 'gauss',
112
+ }
113
+
114
+ try {
115
+ let user = await authenticate(options)
116
+ expect(user).toBeTruthy()
117
+ expect(user.uid).toEqual('gauss')
118
+ } catch (error) {
119
+ if (error.code === 'ECONNRESET' &&
120
+ error.message && error.message.includes('Client network socket disconnected before secure TLS connection')) {
121
+ fail('ECONNRESET bug detected: tlsOptions should NOT be passed to Client constructor when using ldap:// URL')
122
+ }
123
+ expect(error).toBeTruthy()
124
+ }
125
+ })
126
+ })
package/test/test.spec.js CHANGED
@@ -144,7 +144,7 @@ describe('ldap-authentication test', () => {
144
144
  let user = await authenticate(options)
145
145
  expect(user).toBeTruthy()
146
146
  expect(user.groups.length).toBeGreaterThan(0)
147
- expect(user.groups[0].dn).toEqual('cn=科学A部,ou=users,dc=example,dc=com')
147
+ expect(user.groups[0].dn).toEqual('cn=科学A部,ou=groups,dc=example,dc=com')
148
148
  })
149
149
  it('Use regular user to authenticate and fetch user group information', async () => {
150
150
  let options = {
@@ -165,10 +165,10 @@ describe('ldap-authentication test', () => {
165
165
  let user = await authenticate(options)
166
166
  expect(user).toBeTruthy()
167
167
  expect(user.groups.length).toBeGreaterThan(0)
168
- expect(user.groups[0].dn).toEqual('cn=科学A部,ou=users,dc=example,dc=com')
168
+ expect(user.groups[0].dn).toEqual('cn=科学A部,ou=groups,dc=example,dc=com')
169
169
  // backward compatible with 3.2
170
170
  expect(user.groups[0].objectName).toEqual(
171
- 'cn=科学A部,ou=users,dc=example,dc=com'
171
+ 'cn=科学A部,ou=groups,dc=example,dc=com'
172
172
  )
173
173
  })
174
174
  it('Not specifying groupMemberAttribute or groupMemberUserAttribute should not cause an error and fallback to default values', async () => {