ldap-authentication 3.3.4 → 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
@@ -106,6 +128,14 @@ async function _searchUser(
106
128
  }
107
129
  }
108
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
+ }
109
139
  return user
110
140
  }
111
141
 
@@ -170,7 +200,8 @@ async function authenticateWithAdmin(
170
200
  groupClass,
171
201
  groupMemberAttribute = 'member',
172
202
  groupMemberUserAttribute = 'dn',
173
- attributes = null
203
+ attributes = null,
204
+ explicitBufferAttributes = null
174
205
  ) {
175
206
  let ldapAdminClient
176
207
  try {
@@ -191,7 +222,8 @@ async function authenticateWithAdmin(
191
222
  userSearchBase,
192
223
  usernameAttribute,
193
224
  username,
194
- attributes
225
+ attributes,
226
+ explicitBufferAttributes
195
227
  )
196
228
  if (!user || !user.dn) {
197
229
  ldapOpts.log &&
@@ -241,7 +273,8 @@ async function authenticateWithUser(
241
273
  groupClass,
242
274
  groupMemberAttribute = 'member',
243
275
  groupMemberUserAttribute = 'dn',
244
- attributes = null
276
+ attributes = null,
277
+ explicitBufferAttributes = null
245
278
  ) {
246
279
  let ldapUserClient
247
280
  try {
@@ -262,7 +295,8 @@ async function authenticateWithUser(
262
295
  userSearchBase,
263
296
  usernameAttribute,
264
297
  username,
265
- attributes
298
+ attributes,
299
+ explicitBufferAttributes
266
300
  )
267
301
  if (!user || !user.dn) {
268
302
  ldapOpts.log &&
@@ -301,7 +335,8 @@ async function verifyUserExists(
301
335
  groupClass,
302
336
  groupMemberAttribute = 'member',
303
337
  groupMemberUserAttribute = 'dn',
304
- attributes = null
338
+ attributes = null,
339
+ explicitBufferAttributes = null
305
340
  ) {
306
341
  let ldapAdminClient
307
342
  try {
@@ -322,7 +357,8 @@ async function verifyUserExists(
322
357
  userSearchBase,
323
358
  usernameAttribute,
324
359
  username,
325
- attributes
360
+ attributes,
361
+ explicitBufferAttributes
326
362
  )
327
363
  if (!user || !user.dn) {
328
364
  ldapOpts.log &&
@@ -384,7 +420,8 @@ async function authenticate(options) {
384
420
  options.groupClass,
385
421
  options.groupMemberAttribute,
386
422
  options.groupMemberUserAttribute,
387
- options.attributes
423
+ options.attributes,
424
+ options.explicitBufferAttributes
388
425
  )
389
426
  }
390
427
  assert(options.userPassword, 'userPassword must be provided')
@@ -406,7 +443,8 @@ async function authenticate(options) {
406
443
  options.groupClass,
407
444
  options.groupMemberAttribute,
408
445
  options.groupMemberUserAttribute,
409
- options.attributes
446
+ options.attributes,
447
+ options.explicitBufferAttributes
410
448
  )
411
449
  }
412
450
  assert(options.userDn, 'adminDn/adminPassword OR userDn must be provided')
@@ -422,7 +460,8 @@ async function authenticate(options) {
422
460
  options.groupClass,
423
461
  options.groupMemberAttribute,
424
462
  options.groupMemberUserAttribute,
425
- options.attributes
463
+ options.attributes,
464
+ options.explicitBufferAttributes
426
465
  )
427
466
  }
428
467
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ldap-authentication",
3
- "version": "3.3.4",
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 () => {