ldap-authentication 2.2.7 → 2.3.0
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.
- package/LICENSE +1 -1
- package/README.md +24 -2
- package/index.d.ts +33 -0
- package/index.js +156 -55
- package/package.json +5 -5
- package/test/jasmine.js +50 -2
- package/test/test.js +78 -4
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ Make authentication with an LDAP server easy.
|
|
|
9
9
|
|
|
10
10
|
## Description
|
|
11
11
|
|
|
12
|
-
This library use `ldapjs` as the underneath library. It has
|
|
12
|
+
This library use `ldapjs` as the underneath library. It has three modes of authentications:
|
|
13
13
|
|
|
14
14
|
1. **Admin authenticate mode**. If an admin user is provided, the library will login (ldap bind) with the admin user,
|
|
15
15
|
then search for the user to be authenticated, get its DN (distinguish name), then use
|
|
@@ -23,6 +23,9 @@ This library use `ldapjs` as the underneath library. It has two modes of authent
|
|
|
23
23
|
Otherwise, the lib does a login with the `userDn` and `userPassword` (ldap bind),
|
|
24
24
|
then does a search on the user and return the user's details.
|
|
25
25
|
|
|
26
|
+
3. **Verify user exists**. If an `verifyUserExists : true` is provided, the library will login (ldap bind) with the admin user,
|
|
27
|
+
then search for the user to be verified. If the user exists, user details will be returned (without verifying the user's password).
|
|
28
|
+
|
|
26
29
|
## Features
|
|
27
30
|
|
|
28
31
|
- Can use an admin to search and authenticate a user
|
|
@@ -64,6 +67,20 @@ let authenticated = await authenticate({
|
|
|
64
67
|
userSearchBase: 'dc=example,dc=com',
|
|
65
68
|
usernameAttribute: 'uid',
|
|
66
69
|
username: 'gauss',
|
|
70
|
+
attributes: ['dn', 'sn', 'cn'],
|
|
71
|
+
})
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
#### User exists verification and return user details (without user's password)
|
|
75
|
+
|
|
76
|
+
```javascript
|
|
77
|
+
let authenticated = await authenticate({
|
|
78
|
+
ldapOpts: { url: 'ldap://ldap.forumsys.com' },
|
|
79
|
+
userDn: 'uid=gauss,dc=example,dc=com',
|
|
80
|
+
verifyUserExists: true,
|
|
81
|
+
userSearchBase: 'dc=example,dc=com',
|
|
82
|
+
usernameAttribute: 'uid',
|
|
83
|
+
username: 'gauss',
|
|
67
84
|
})
|
|
68
85
|
```
|
|
69
86
|
|
|
@@ -80,6 +97,7 @@ let authenticated = await authenticate({
|
|
|
80
97
|
groupsSearchBase: 'dc=example,dc=com',
|
|
81
98
|
groupClass: 'groupOfUniqueNames',
|
|
82
99
|
groupMemberAttribute: 'uniqueMember',
|
|
100
|
+
// groupMemberUserAttribute: 'dn'
|
|
83
101
|
})
|
|
84
102
|
```
|
|
85
103
|
|
|
@@ -138,7 +156,8 @@ auth()
|
|
|
138
156
|
- `adminPassword`: The password of the admin.
|
|
139
157
|
- `userDn`: The DN of the user to be authenticated. This is only needed if `adminDn` and `adminPassword` are not provided.
|
|
140
158
|
Example: `uid=gauss,dc=example,dc=com`
|
|
141
|
-
- `userPassword`: The password of the user
|
|
159
|
+
- `userPassword`: The password of the user
|
|
160
|
+
- `verifyUserExists` : if `true` user existence will be verified without password
|
|
142
161
|
- `userSearchBase`: The ldap base DN to search the user. Example: `dc=example,dc=com`
|
|
143
162
|
- `usernameAttribute`: The ldap search equality attribute name corresponding to the user's username.
|
|
144
163
|
It will be used with the value in `username` to construct an ldap filter as `({attribute}={username})`
|
|
@@ -150,7 +169,10 @@ auth()
|
|
|
150
169
|
- `username`: The username to authenticate with. It is used together with the name in `usernameAttribute`
|
|
151
170
|
to construct an ldap filter as `({attribute}={username})`
|
|
152
171
|
to find the user and get user details in LDAP. Example: `some user input`
|
|
172
|
+
- `attributes`: A list of attributes of a user details to be returned from the LDAP server.
|
|
173
|
+
If is set to `[]` or ommited, all details will be returned. Example: `['sn', 'cn']`
|
|
153
174
|
- `starttls`: Boolean. Use `STARTTLS` or not
|
|
154
175
|
- `groupsSearchBase`: if specified with groupClass, will serve as search base for authenticated user groups
|
|
155
176
|
- `groupClass`: if specified with groupsSearchBase, will be used as objectClass in search filter for authenticated user groups
|
|
156
177
|
- `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
|
|
178
|
+
- `groupMemberUserAttribute`: if specified with groupClass and groupsSearchBase, will be used as the attribute on the user object (if not specified this defaults to `dn`) in search filter for authenticated user groups
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
declare module 'ldap-authentication' {
|
|
2
|
+
type LDAPOpts = {
|
|
3
|
+
url: string
|
|
4
|
+
tlsOptions?: {
|
|
5
|
+
rejectUnauthorized: boolean
|
|
6
|
+
}
|
|
7
|
+
connectTimeout?: number
|
|
8
|
+
}
|
|
9
|
+
export type AuthenticationOptions = {
|
|
10
|
+
ldapOpts: LDAPOpts
|
|
11
|
+
userDn?: string
|
|
12
|
+
adminDn?: string
|
|
13
|
+
adminPassword?: string
|
|
14
|
+
userSearchBase?: string
|
|
15
|
+
usernameAttribute?: string
|
|
16
|
+
username?: string
|
|
17
|
+
verifyUserExists?: boolean
|
|
18
|
+
starttls?: Boolean
|
|
19
|
+
groupsSearchBase?: string
|
|
20
|
+
groupClass?: string
|
|
21
|
+
groupMemberAttribute?: string
|
|
22
|
+
groupMemberUserAttribute?: string
|
|
23
|
+
userPassword?: string
|
|
24
|
+
attributes?: string[]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function authenticate(options: AuthenticationOptions): Promise<any>
|
|
28
|
+
|
|
29
|
+
export class LdapAuthenticationError extends Error {
|
|
30
|
+
constructor(message: any)
|
|
31
|
+
name: string
|
|
32
|
+
}
|
|
33
|
+
}
|
package/index.js
CHANGED
|
@@ -35,27 +35,26 @@ function _ldapBind(dn, password, starttls, ldapOpts) {
|
|
|
35
35
|
resolve(client)
|
|
36
36
|
})
|
|
37
37
|
}
|
|
38
|
-
})
|
|
38
|
+
})
|
|
39
39
|
|
|
40
40
|
//Fix for issue https://github.com/shaozi/ldap-authentication/issues/13
|
|
41
41
|
client.on('timeout', (err) => {
|
|
42
|
-
reject(err)
|
|
43
|
-
})
|
|
42
|
+
reject(err)
|
|
43
|
+
})
|
|
44
44
|
client.on('connectTimeout', (err) => {
|
|
45
|
-
reject(err)
|
|
46
|
-
})
|
|
45
|
+
reject(err)
|
|
46
|
+
})
|
|
47
47
|
client.on('error', (err) => {
|
|
48
|
-
reject(err)
|
|
49
|
-
})
|
|
48
|
+
reject(err)
|
|
49
|
+
})
|
|
50
50
|
|
|
51
|
-
client.on('connectError', function(error){
|
|
51
|
+
client.on('connectError', function (error) {
|
|
52
52
|
if (error) {
|
|
53
53
|
reject(error)
|
|
54
54
|
return
|
|
55
55
|
}
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
});
|
|
56
|
+
})
|
|
57
|
+
})
|
|
59
58
|
}
|
|
60
59
|
|
|
61
60
|
// search a user and return the object
|
|
@@ -63,46 +62,48 @@ async function _searchUser(
|
|
|
63
62
|
ldapClient,
|
|
64
63
|
searchBase,
|
|
65
64
|
usernameAttribute,
|
|
66
|
-
username
|
|
65
|
+
username,
|
|
66
|
+
attributes = null
|
|
67
67
|
) {
|
|
68
68
|
return new Promise(function (resolve, reject) {
|
|
69
69
|
var filter = new ldap.filters.EqualityFilter({
|
|
70
70
|
attribute: usernameAttribute,
|
|
71
71
|
value: username,
|
|
72
72
|
})
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
user = entry.object
|
|
88
|
-
})
|
|
89
|
-
res.on('searchReference', function (referral) {
|
|
90
|
-
console.log('referral: ' + referral.uris.join())
|
|
91
|
-
})
|
|
92
|
-
res.on('error', function (err) {
|
|
93
|
-
reject(err)
|
|
94
|
-
ldapClient.unbind()
|
|
95
|
-
})
|
|
96
|
-
res.on('end', function (result) {
|
|
97
|
-
if (result.status != 0) {
|
|
98
|
-
reject(new Error('ldap search status is not 0, search failed'))
|
|
99
|
-
} else {
|
|
100
|
-
resolve(user)
|
|
101
|
-
}
|
|
102
|
-
ldapClient.unbind()
|
|
103
|
-
})
|
|
73
|
+
let searchOptions = {
|
|
74
|
+
filter: filter,
|
|
75
|
+
scope: 'sub',
|
|
76
|
+
attributes: attributes,
|
|
77
|
+
}
|
|
78
|
+
if (attributes) {
|
|
79
|
+
searchOptions.attributes = attributes
|
|
80
|
+
}
|
|
81
|
+
ldapClient.search(searchBase, searchOptions, function (err, res) {
|
|
82
|
+
var user = null
|
|
83
|
+
if (err) {
|
|
84
|
+
reject(err)
|
|
85
|
+
ldapClient.unbind()
|
|
86
|
+
return
|
|
104
87
|
}
|
|
105
|
-
|
|
88
|
+
res.on('searchEntry', function (entry) {
|
|
89
|
+
user = entry.object
|
|
90
|
+
})
|
|
91
|
+
res.on('searchReference', function (referral) {
|
|
92
|
+
console.log('referral: ' + referral.uris.join())
|
|
93
|
+
})
|
|
94
|
+
res.on('error', function (err) {
|
|
95
|
+
reject(err)
|
|
96
|
+
ldapClient.unbind()
|
|
97
|
+
})
|
|
98
|
+
res.on('end', function (result) {
|
|
99
|
+
if (result.status != 0) {
|
|
100
|
+
reject(new Error('ldap search status is not 0, search failed'))
|
|
101
|
+
} else {
|
|
102
|
+
resolve(user)
|
|
103
|
+
}
|
|
104
|
+
ldapClient.unbind()
|
|
105
|
+
})
|
|
106
|
+
})
|
|
106
107
|
})
|
|
107
108
|
}
|
|
108
109
|
|
|
@@ -112,13 +113,14 @@ async function _searchUserGroups(
|
|
|
112
113
|
searchBase,
|
|
113
114
|
user,
|
|
114
115
|
groupClass,
|
|
115
|
-
groupMemberAttribute = 'member'
|
|
116
|
+
groupMemberAttribute = 'member',
|
|
117
|
+
groupMemberUserAttribute = 'dn'
|
|
116
118
|
) {
|
|
117
119
|
return new Promise(function (resolve, reject) {
|
|
118
120
|
ldapClient.search(
|
|
119
121
|
searchBase,
|
|
120
122
|
{
|
|
121
|
-
filter: `(&(objectclass=${groupClass})(${groupMemberAttribute}=${user
|
|
123
|
+
filter: `(&(objectclass=${groupClass})(${groupMemberAttribute}=${user[groupMemberUserAttribute]}))`,
|
|
122
124
|
scope: 'sub',
|
|
123
125
|
},
|
|
124
126
|
function (err, res) {
|
|
@@ -162,7 +164,9 @@ async function authenticateWithAdmin(
|
|
|
162
164
|
ldapOpts,
|
|
163
165
|
groupsSearchBase,
|
|
164
166
|
groupClass,
|
|
165
|
-
groupMemberAttribute = 'member'
|
|
167
|
+
groupMemberAttribute = 'member',
|
|
168
|
+
groupMemberUserAttribute = 'dn',
|
|
169
|
+
attributes = null
|
|
166
170
|
) {
|
|
167
171
|
var ldapAdminClient
|
|
168
172
|
try {
|
|
@@ -179,7 +183,8 @@ async function authenticateWithAdmin(
|
|
|
179
183
|
ldapAdminClient,
|
|
180
184
|
userSearchBase,
|
|
181
185
|
usernameAttribute,
|
|
182
|
-
username
|
|
186
|
+
username,
|
|
187
|
+
attributes
|
|
183
188
|
)
|
|
184
189
|
ldapAdminClient.unbind()
|
|
185
190
|
if (!user || !user.dn) {
|
|
@@ -215,7 +220,8 @@ async function authenticateWithAdmin(
|
|
|
215
220
|
groupsSearchBase,
|
|
216
221
|
user,
|
|
217
222
|
groupClass,
|
|
218
|
-
groupMemberAttribute
|
|
223
|
+
groupMemberAttribute,
|
|
224
|
+
groupMemberUserAttribute
|
|
219
225
|
)
|
|
220
226
|
user.groups = groups
|
|
221
227
|
ldapAdminClient.unbind()
|
|
@@ -233,7 +239,9 @@ async function authenticateWithUser(
|
|
|
233
239
|
ldapOpts,
|
|
234
240
|
groupsSearchBase,
|
|
235
241
|
groupClass,
|
|
236
|
-
groupMemberAttribute = 'member'
|
|
242
|
+
groupMemberAttribute = 'member',
|
|
243
|
+
groupMemberUserAttribute = 'dn',
|
|
244
|
+
attributes = null
|
|
237
245
|
) {
|
|
238
246
|
let ldapUserClient
|
|
239
247
|
try {
|
|
@@ -250,7 +258,8 @@ async function authenticateWithUser(
|
|
|
250
258
|
ldapUserClient,
|
|
251
259
|
userSearchBase,
|
|
252
260
|
usernameAttribute,
|
|
253
|
-
username
|
|
261
|
+
username,
|
|
262
|
+
attributes
|
|
254
263
|
)
|
|
255
264
|
if (!user || !user.dn) {
|
|
256
265
|
ldapOpts.log &&
|
|
@@ -273,7 +282,8 @@ async function authenticateWithUser(
|
|
|
273
282
|
groupsSearchBase,
|
|
274
283
|
user,
|
|
275
284
|
groupClass,
|
|
276
|
-
groupMemberAttribute
|
|
285
|
+
groupMemberAttribute,
|
|
286
|
+
groupMemberUserAttribute
|
|
277
287
|
)
|
|
278
288
|
user.groups = groups
|
|
279
289
|
ldapUserClient.unbind()
|
|
@@ -281,6 +291,73 @@ async function authenticateWithUser(
|
|
|
281
291
|
return user
|
|
282
292
|
}
|
|
283
293
|
|
|
294
|
+
async function verifyUserExists(
|
|
295
|
+
adminDn,
|
|
296
|
+
adminPassword,
|
|
297
|
+
userSearchBase,
|
|
298
|
+
usernameAttribute,
|
|
299
|
+
username,
|
|
300
|
+
starttls,
|
|
301
|
+
ldapOpts,
|
|
302
|
+
groupsSearchBase,
|
|
303
|
+
groupClass,
|
|
304
|
+
groupMemberAttribute = 'member',
|
|
305
|
+
groupMemberUserAttribute = 'dn',
|
|
306
|
+
attributes = null
|
|
307
|
+
) {
|
|
308
|
+
var ldapAdminClient
|
|
309
|
+
try {
|
|
310
|
+
ldapAdminClient = await _ldapBind(
|
|
311
|
+
adminDn,
|
|
312
|
+
adminPassword,
|
|
313
|
+
starttls,
|
|
314
|
+
ldapOpts
|
|
315
|
+
)
|
|
316
|
+
} catch (error) {
|
|
317
|
+
throw { admin: error }
|
|
318
|
+
}
|
|
319
|
+
var user = await _searchUser(
|
|
320
|
+
ldapAdminClient,
|
|
321
|
+
userSearchBase,
|
|
322
|
+
usernameAttribute,
|
|
323
|
+
username,
|
|
324
|
+
attributes
|
|
325
|
+
)
|
|
326
|
+
ldapAdminClient.unbind()
|
|
327
|
+
if (!user || !user.dn) {
|
|
328
|
+
ldapOpts.log &&
|
|
329
|
+
ldapOpts.log.trace(
|
|
330
|
+
`admin did not find user! (${usernameAttribute}=${username})`
|
|
331
|
+
)
|
|
332
|
+
throw new LdapAuthenticationError(
|
|
333
|
+
'user not found or usernameAttribute is wrong'
|
|
334
|
+
)
|
|
335
|
+
}
|
|
336
|
+
if (groupsSearchBase && groupClass && groupMemberAttribute) {
|
|
337
|
+
try {
|
|
338
|
+
ldapAdminClient = await _ldapBind(
|
|
339
|
+
adminDn,
|
|
340
|
+
adminPassword,
|
|
341
|
+
starttls,
|
|
342
|
+
ldapOpts
|
|
343
|
+
)
|
|
344
|
+
} catch (error) {
|
|
345
|
+
throw error
|
|
346
|
+
}
|
|
347
|
+
var groups = await _searchUserGroups(
|
|
348
|
+
ldapAdminClient,
|
|
349
|
+
groupsSearchBase,
|
|
350
|
+
user,
|
|
351
|
+
groupClass,
|
|
352
|
+
groupMemberAttribute,
|
|
353
|
+
groupMemberUserAttribute
|
|
354
|
+
)
|
|
355
|
+
user.groups = groups
|
|
356
|
+
ldapAdminClient.unbind()
|
|
357
|
+
}
|
|
358
|
+
return user
|
|
359
|
+
}
|
|
360
|
+
|
|
284
361
|
async function authenticate(options) {
|
|
285
362
|
if (!options.userDn) {
|
|
286
363
|
assert(options.adminDn, 'Admin mode adminDn must be provided')
|
|
@@ -294,11 +371,31 @@ async function authenticate(options) {
|
|
|
294
371
|
} else {
|
|
295
372
|
assert(options.userDn, 'User mode userDn must be provided')
|
|
296
373
|
}
|
|
297
|
-
assert(options.userPassword, 'userPassword must be provided')
|
|
298
374
|
assert(
|
|
299
375
|
options.ldapOpts && options.ldapOpts.url,
|
|
300
376
|
'ldapOpts.url must be provided'
|
|
301
377
|
)
|
|
378
|
+
if (options.verifyUserExists) {
|
|
379
|
+
assert(options.adminDn, 'Admin mode adminDn must be provided')
|
|
380
|
+
assert(
|
|
381
|
+
options.adminPassword,
|
|
382
|
+
'adminDn and adminPassword must be both provided.'
|
|
383
|
+
)
|
|
384
|
+
return await verifyUserExists(
|
|
385
|
+
options.adminDn,
|
|
386
|
+
options.adminPassword,
|
|
387
|
+
options.userSearchBase,
|
|
388
|
+
options.usernameAttribute,
|
|
389
|
+
options.username,
|
|
390
|
+
options.starttls,
|
|
391
|
+
options.ldapOpts,
|
|
392
|
+
options.groupsSearchBase,
|
|
393
|
+
options.groupClass,
|
|
394
|
+
options.groupMemberAttribute,
|
|
395
|
+
options.groupMemberUserAttribute
|
|
396
|
+
)
|
|
397
|
+
}
|
|
398
|
+
assert(options.userPassword, 'userPassword must be provided')
|
|
302
399
|
if (options.adminDn) {
|
|
303
400
|
assert(
|
|
304
401
|
options.adminPassword,
|
|
@@ -315,7 +412,9 @@ async function authenticate(options) {
|
|
|
315
412
|
options.ldapOpts,
|
|
316
413
|
options.groupsSearchBase,
|
|
317
414
|
options.groupClass,
|
|
318
|
-
options.groupMemberAttribute
|
|
415
|
+
options.groupMemberAttribute,
|
|
416
|
+
options.groupMemberUserAttribute,
|
|
417
|
+
options.attributes
|
|
319
418
|
)
|
|
320
419
|
}
|
|
321
420
|
assert(options.userDn, 'adminDn/adminPassword OR userDn must be provided')
|
|
@@ -329,7 +428,9 @@ async function authenticate(options) {
|
|
|
329
428
|
options.ldapOpts,
|
|
330
429
|
options.groupsSearchBase,
|
|
331
430
|
options.groupClass,
|
|
332
|
-
options.groupMemberAttribute
|
|
431
|
+
options.groupMemberAttribute,
|
|
432
|
+
options.groupMemberUserAttribute,
|
|
433
|
+
options.attributes
|
|
333
434
|
)
|
|
334
435
|
}
|
|
335
436
|
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ldap-authentication",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "A simple async nodejs library for LDAP user authentication",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"types": "./index.d.ts",
|
|
6
7
|
"scripts": {
|
|
7
8
|
"test": "node test/jasmine.js"
|
|
8
9
|
},
|
|
@@ -29,16 +30,15 @@
|
|
|
29
30
|
"ldap-authenticate"
|
|
30
31
|
],
|
|
31
32
|
"author": "Jingshao Chen",
|
|
32
|
-
"license": "
|
|
33
|
+
"license": "BSD-2-Clause",
|
|
33
34
|
"bugs": {
|
|
34
35
|
"url": "https://github.com/shaozi/ldap-authentication/issues"
|
|
35
36
|
},
|
|
36
37
|
"homepage": "https://github.com/shaozi/ldap-authentication#readme",
|
|
37
38
|
"dependencies": {
|
|
38
|
-
"ldapjs": "^2.
|
|
39
|
+
"ldapjs": "^2.3.3"
|
|
39
40
|
},
|
|
40
41
|
"devDependencies": {
|
|
41
|
-
"jasmine": "^3.
|
|
42
|
-
"jasmine-console-reporter": "^3.1.0"
|
|
42
|
+
"jasmine": "^4.3.0"
|
|
43
43
|
}
|
|
44
44
|
}
|
package/test/jasmine.js
CHANGED
|
@@ -9,7 +9,55 @@ jasmine.loadConfig({
|
|
|
9
9
|
stopSpecOnExpectationFailure: false,
|
|
10
10
|
})
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
class MyConsoleReporter {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.suiteSeq = 1
|
|
15
|
+
}
|
|
13
16
|
|
|
14
|
-
|
|
17
|
+
_indentPrint(str) {
|
|
18
|
+
str
|
|
19
|
+
.trim()
|
|
20
|
+
.split('\n')
|
|
21
|
+
.forEach((line) => {
|
|
22
|
+
process.stdout.write(' ' + line + '\n')
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
jasmineStarted(suiteInfo) {
|
|
27
|
+
console.log(`Running suite with ${suiteInfo.totalSpecsDefined} tests.`)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
suiteStarted(result) {
|
|
31
|
+
console.log(`\n${this.suiteSeq}. ${result.fullName}`)
|
|
32
|
+
this.suiteSeq++
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
specStarted(result) {
|
|
36
|
+
process.stdout.write(` - ${result.description} `)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
specDone(result) {
|
|
40
|
+
process.stdout.write(
|
|
41
|
+
` ${result.status} [${result.passedExpectations.length}] (${result.duration} ms)`
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
for (var i = 0; i < result.failedExpectations.length; i++) {
|
|
45
|
+
console.log()
|
|
46
|
+
this._indentPrint(result.failedExpectations[i].message)
|
|
47
|
+
this._indentPrint(result.failedExpectations[i].stack)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
process.stdout.write(`\n`)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
jasmineDone(result) {
|
|
54
|
+
console.log('Overall result: ' + result.overallStatus)
|
|
55
|
+
for (var i = 0; i < result.failedExpectations.length; i++) {
|
|
56
|
+
console.log('Global ' + result.failedExpectations[i].message)
|
|
57
|
+
console.log(result.failedExpectations[i].stack)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
jasmine.jasmine.getEnv().addReporter(new MyConsoleReporter())
|
|
15
63
|
jasmine.execute()
|
package/test/test.js
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
const { authenticate, LdapAuthenticationError } = require('../index.js')
|
|
2
2
|
|
|
3
3
|
describe('ldap-authentication test', () => {
|
|
4
|
+
it('Use an admin user to check if user exists', async () => {
|
|
5
|
+
let options = {
|
|
6
|
+
ldapOpts: {
|
|
7
|
+
url: 'ldap://ldap.forumsys.com',
|
|
8
|
+
},
|
|
9
|
+
adminDn: 'cn=read-only-admin,dc=example,dc=com',
|
|
10
|
+
adminPassword: 'password',
|
|
11
|
+
verifyUserExists: true,
|
|
12
|
+
userSearchBase: 'dc=example,dc=com',
|
|
13
|
+
usernameAttribute: 'uid',
|
|
14
|
+
username: 'gauss',
|
|
15
|
+
}
|
|
16
|
+
let user = await authenticate(options)
|
|
17
|
+
expect(user).toBeTruthy()
|
|
18
|
+
expect(user.uid).toEqual('gauss')
|
|
19
|
+
})
|
|
4
20
|
it('Use an admin user to authenticate a regular user', async () => {
|
|
5
21
|
let options = {
|
|
6
22
|
ldapOpts: {
|
|
@@ -17,6 +33,25 @@ describe('ldap-authentication test', () => {
|
|
|
17
33
|
expect(user).toBeTruthy()
|
|
18
34
|
expect(user.uid).toEqual('gauss')
|
|
19
35
|
})
|
|
36
|
+
it('Use an admin user to authenticate a regular user and return attrubutes', async () => {
|
|
37
|
+
let options = {
|
|
38
|
+
ldapOpts: {
|
|
39
|
+
url: 'ldap://ldap.forumsys.com',
|
|
40
|
+
},
|
|
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
|
+
attributes: ['uid', 'sn'],
|
|
48
|
+
}
|
|
49
|
+
let user = await authenticate(options)
|
|
50
|
+
expect(user).toBeTruthy()
|
|
51
|
+
expect(user.uid).toEqual('gauss')
|
|
52
|
+
expect(user.sn).toEqual('Gauss')
|
|
53
|
+
expect(user.cn).toBeUndefined()
|
|
54
|
+
})
|
|
20
55
|
it('Use an regular user to authenticate iteself', async () => {
|
|
21
56
|
let options = {
|
|
22
57
|
ldapOpts: {
|
|
@@ -32,6 +67,24 @@ describe('ldap-authentication test', () => {
|
|
|
32
67
|
expect(user).toBeTruthy()
|
|
33
68
|
expect(user.uid).toEqual('einstein')
|
|
34
69
|
})
|
|
70
|
+
it('Use an regular user to authenticate iteself and return attributes', async () => {
|
|
71
|
+
let options = {
|
|
72
|
+
ldapOpts: {
|
|
73
|
+
url: 'ldap://ldap.forumsys.com',
|
|
74
|
+
},
|
|
75
|
+
userDn: 'uid=einstein,dc=example,dc=com',
|
|
76
|
+
userPassword: 'password',
|
|
77
|
+
userSearchBase: 'dc=example,dc=com',
|
|
78
|
+
usernameAttribute: 'uid',
|
|
79
|
+
username: 'einstein',
|
|
80
|
+
attributes: ['uid', 'sn'],
|
|
81
|
+
}
|
|
82
|
+
let user = await authenticate(options)
|
|
83
|
+
expect(user).toBeTruthy()
|
|
84
|
+
expect(user.uid).toEqual('einstein')
|
|
85
|
+
expect(user.sn).toEqual('Einstein')
|
|
86
|
+
expect(user.cn).toBeUndefined()
|
|
87
|
+
})
|
|
35
88
|
it('Use an regular user to authenticate iteself without search', async () => {
|
|
36
89
|
let options = {
|
|
37
90
|
ldapOpts: {
|
|
@@ -57,6 +110,7 @@ describe('ldap-authentication test', () => {
|
|
|
57
110
|
groupsSearchBase: 'dc=example,dc=com',
|
|
58
111
|
groupClass: 'groupOfUniqueNames',
|
|
59
112
|
groupMemberAttribute: 'uniqueMember',
|
|
113
|
+
groupMemberUserAttribute: 'dn',
|
|
60
114
|
}
|
|
61
115
|
let user = await authenticate(options)
|
|
62
116
|
expect(user).toBeTruthy()
|
|
@@ -75,12 +129,13 @@ describe('ldap-authentication test', () => {
|
|
|
75
129
|
groupsSearchBase: 'dc=example,dc=com',
|
|
76
130
|
groupClass: 'groupOfUniqueNames',
|
|
77
131
|
groupMemberAttribute: 'uniqueMember',
|
|
132
|
+
groupMemberUserAttribute: 'dn',
|
|
78
133
|
}
|
|
79
134
|
let user = await authenticate(options)
|
|
80
135
|
expect(user).toBeTruthy()
|
|
81
136
|
expect(user.groups.length).toBeGreaterThan(0)
|
|
82
137
|
})
|
|
83
|
-
it('Not specifying groupMemberAttribute should not cause an error and fallback
|
|
138
|
+
it('Not specifying groupMemberAttribute or groupMemberUserAttribute should not cause an error and fallback to default values', async () => {
|
|
84
139
|
let options = {
|
|
85
140
|
ldapOpts: {
|
|
86
141
|
url: 'ldap://ldap.forumsys.com',
|
|
@@ -275,14 +330,14 @@ describe('ldap-authentication negative test', () => {
|
|
|
275
330
|
let options = {
|
|
276
331
|
ldapOpts: {
|
|
277
332
|
url: 'ldap://x.forumsys.com',
|
|
278
|
-
|
|
333
|
+
connectTimeout: 2000,
|
|
279
334
|
},
|
|
280
335
|
userDn: 'uid=einstein,dc=example,dc=com',
|
|
281
336
|
userPassword: 'password',
|
|
282
337
|
usernameAttribute: 'cn',
|
|
283
338
|
userSearchBase: 'dc=example,dc=com',
|
|
284
|
-
|
|
285
|
-
|
|
339
|
+
username: 'einstein',
|
|
340
|
+
starttls: true,
|
|
286
341
|
}
|
|
287
342
|
try {
|
|
288
343
|
await authenticate(options)
|
|
@@ -291,4 +346,23 @@ describe('ldap-authentication negative test', () => {
|
|
|
291
346
|
}
|
|
292
347
|
expect(e).toBeTruthy()
|
|
293
348
|
})
|
|
349
|
+
it('Unmatched supplied groupMemberUserAttribute should return empty group list', async () => {
|
|
350
|
+
let options = {
|
|
351
|
+
ldapOpts: {
|
|
352
|
+
url: 'ldap://ldap.forumsys.com',
|
|
353
|
+
},
|
|
354
|
+
userDn: 'uid=gauss,dc=example,dc=com',
|
|
355
|
+
userPassword: 'password',
|
|
356
|
+
userSearchBase: 'dc=example,dc=com',
|
|
357
|
+
usernameAttribute: 'uid',
|
|
358
|
+
username: 'gauss',
|
|
359
|
+
groupsSearchBase: 'dc=example,dc=com',
|
|
360
|
+
groupClass: 'groupOfUniqueNames',
|
|
361
|
+
groupMemberAttribute: 'uniqueMember',
|
|
362
|
+
groupMemberUserAttribute: 'notARealGroupMemberUserAttribute',
|
|
363
|
+
}
|
|
364
|
+
let user = await authenticate(options)
|
|
365
|
+
expect(user).toBeTruthy()
|
|
366
|
+
expect(user.groups.length).toBeLessThan(1)
|
|
367
|
+
})
|
|
294
368
|
})
|