ldap-authentication 3.2.6 → 3.3.1
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/index.js +75 -122
- package/package.json +3 -3
- package/test/test.spec.js +3 -3
package/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const assert = require('assert')
|
|
2
|
-
const
|
|
2
|
+
const ldapts = require('ldapts')
|
|
3
3
|
// escape the , in CN in DN
|
|
4
4
|
function _ldapEscapeDN(s) {
|
|
5
5
|
let ret = "";
|
|
@@ -78,6 +78,8 @@ function _recursiveParseHexString(obj) {
|
|
|
78
78
|
}
|
|
79
79
|
return obj
|
|
80
80
|
}
|
|
81
|
+
/*
|
|
82
|
+
// UPDATE: This function is not used in this version, because ldapts library already does the conversion
|
|
81
83
|
// convert a SearchResultEntry object in ldapjs 3.0
|
|
82
84
|
// to a user object to maintain backward compatibility
|
|
83
85
|
|
|
@@ -90,59 +92,21 @@ function _searchResultToUser(pojo) {
|
|
|
90
92
|
})
|
|
91
93
|
return _recursiveParseHexString(user)
|
|
92
94
|
}
|
|
95
|
+
*/
|
|
93
96
|
// bind and return the ldap client
|
|
94
|
-
function _ldapBind(dn, password, starttls, ldapOpts) {
|
|
97
|
+
async function _ldapBind(dn, password, starttls, ldapOpts) {
|
|
98
|
+
// TODO: check if ldapts expects escaped dn or not (possible double escaping problems?)
|
|
95
99
|
dn = _ldapEscapeDN(dn)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
let client = ldap.createClient(ldapOpts)
|
|
100
|
+
ldapOpts.connectTimeout = ldapOpts.connectTimeout || 5000
|
|
101
|
+
let client = new ldapts.Client(ldapOpts)
|
|
99
102
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (error) {
|
|
104
|
-
reject(error)
|
|
105
|
-
return
|
|
106
|
-
}
|
|
107
|
-
client.bind(dn, password, function (err) {
|
|
108
|
-
if (err) {
|
|
109
|
-
reject(err)
|
|
110
|
-
return
|
|
111
|
-
}
|
|
112
|
-
ldapOpts.log && ldapOpts.log.trace('bind success!')
|
|
113
|
-
resolve(client)
|
|
114
|
-
})
|
|
115
|
-
})
|
|
116
|
-
} else {
|
|
117
|
-
client.bind(dn, password, function (err) {
|
|
118
|
-
if (err) {
|
|
119
|
-
reject(err)
|
|
120
|
-
return
|
|
121
|
-
}
|
|
122
|
-
ldapOpts.log && ldapOpts.log.trace('bind success!')
|
|
123
|
-
resolve(client)
|
|
124
|
-
})
|
|
125
|
-
}
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
//Fix for issue https://github.com/shaozi/ldap-authentication/issues/13
|
|
129
|
-
client.on('timeout', (err) => {
|
|
130
|
-
reject(err)
|
|
131
|
-
})
|
|
132
|
-
client.on('connectTimeout', (err) => {
|
|
133
|
-
reject(err)
|
|
134
|
-
})
|
|
135
|
-
client.on('error', (err) => {
|
|
136
|
-
reject(err)
|
|
137
|
-
})
|
|
103
|
+
if(starttls) {
|
|
104
|
+
await client.startTLS(ldapOpts.tlsOptions)
|
|
105
|
+
}
|
|
138
106
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
return
|
|
143
|
-
}
|
|
144
|
-
})
|
|
145
|
-
})
|
|
107
|
+
await client.bind(dn, password)
|
|
108
|
+
ldapOpts.log && ldapOpts.log.trace('bind success!')
|
|
109
|
+
return client
|
|
146
110
|
}
|
|
147
111
|
|
|
148
112
|
// search a user and return the object
|
|
@@ -153,48 +117,36 @@ async function _searchUser(
|
|
|
153
117
|
username,
|
|
154
118
|
attributes = null
|
|
155
119
|
) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
res.on('error', function (err) {
|
|
187
|
-
reject(err)
|
|
188
|
-
})
|
|
189
|
-
res.on('end', function (result) {
|
|
190
|
-
if (result.status != 0) {
|
|
191
|
-
reject(new Error('ldap search status is not 0, search failed'))
|
|
192
|
-
} else {
|
|
193
|
-
resolve(user)
|
|
194
|
-
}
|
|
195
|
-
})
|
|
196
|
-
})
|
|
197
|
-
})
|
|
120
|
+
|
|
121
|
+
let filter = new ldapts.EqualityFilter({
|
|
122
|
+
attribute: usernameAttribute,
|
|
123
|
+
value: username,
|
|
124
|
+
});
|
|
125
|
+
let searchOptions = {
|
|
126
|
+
filter: filter,
|
|
127
|
+
scope: 'sub',
|
|
128
|
+
attributes: attributes,
|
|
129
|
+
};
|
|
130
|
+
if (attributes) {
|
|
131
|
+
searchOptions.attributes = attributes;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// TODO: we don't support reference yet
|
|
135
|
+
// If the server was able to locate the entry referred to by the baseObject
|
|
136
|
+
// but could not search one or more non-local entries,
|
|
137
|
+
// the server may return one or more SearchResultReference messages,
|
|
138
|
+
// each containing a reference to another set of servers for continuing the operation.
|
|
139
|
+
// referral.uris
|
|
140
|
+
const { searchEntries, searchReferences } = await ldapClient.search(searchBase, searchOptions);
|
|
141
|
+
|
|
142
|
+
let user;
|
|
143
|
+
if(!searchEntries || searchEntries.length < 1 || !searchEntries[0] || !searchEntries[0].dn) {
|
|
144
|
+
user = null;
|
|
145
|
+
} else {
|
|
146
|
+
user = searchEntries[0];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return user;
|
|
198
150
|
}
|
|
199
151
|
|
|
200
152
|
// search a groups which user is member
|
|
@@ -206,36 +158,37 @@ async function _searchUserGroups(
|
|
|
206
158
|
groupMemberAttribute = 'member',
|
|
207
159
|
groupMemberUserAttribute = 'dn'
|
|
208
160
|
) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
}
|
|
161
|
+
// Below works, but prefer using ldapts Filter subclasses to build this search, so that correct escaping is done
|
|
162
|
+
// const filter = `(&(objectclass=${groupClass})(${groupMemberAttribute}=${user[groupMemberUserAttribute]}))`
|
|
163
|
+
const filter = new ldapts.AndFilter({
|
|
164
|
+
filters: [
|
|
165
|
+
new ldapts.EqualityFilter({ attribute: 'objectclass', value: groupClass }),
|
|
166
|
+
new ldapts.EqualityFilter({ attribute: groupMemberAttribute, value: user[groupMemberUserAttribute] }),
|
|
167
|
+
],
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const { searchEntries, searchReferences } = await ldapClient.search(
|
|
171
|
+
searchBase,
|
|
172
|
+
{
|
|
173
|
+
filter: filter,
|
|
174
|
+
scope: 'sub',
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
let groups;
|
|
179
|
+
if(!searchEntries || searchEntries.length < 1) {
|
|
180
|
+
groups = [];
|
|
181
|
+
} else {
|
|
182
|
+
groups = searchEntries;
|
|
183
|
+
}
|
|
184
|
+
// ldapjs has group.objectName, ldapts does not have it. instead, use dn
|
|
185
|
+
// add objectName back for backward compatibility
|
|
186
|
+
for (let group of groups) {
|
|
187
|
+
if (typeof group.objectName === 'undefined') {
|
|
188
|
+
group.objectName = group.dn
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return groups;
|
|
239
192
|
}
|
|
240
193
|
|
|
241
194
|
async function authenticateWithAdmin(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ldap-authentication",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.1",
|
|
4
4
|
"description": "A simple async nodejs library for LDAP user authentication",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "./index.d.ts",
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
},
|
|
37
37
|
"homepage": "https://github.com/shaozi/ldap-authentication#readme",
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"
|
|
39
|
+
"ldapts": "^7.3.1"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"jasmine": "^5.
|
|
42
|
+
"jasmine": "^5.6.0"
|
|
43
43
|
}
|
|
44
44
|
}
|
package/test/test.spec.js
CHANGED
|
@@ -144,9 +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].
|
|
148
|
-
'cn=科学A部,ou=users,dc=example,dc=com'
|
|
149
|
-
)
|
|
147
|
+
expect(user.groups[0].dn).toEqual('cn=科学A部,ou=users,dc=example,dc=com')
|
|
150
148
|
})
|
|
151
149
|
it('Use regular user to authenticate and fetch user group information', async () => {
|
|
152
150
|
let options = {
|
|
@@ -167,6 +165,8 @@ describe('ldap-authentication test', () => {
|
|
|
167
165
|
let user = await authenticate(options)
|
|
168
166
|
expect(user).toBeTruthy()
|
|
169
167
|
expect(user.groups.length).toBeGreaterThan(0)
|
|
168
|
+
expect(user.groups[0].dn).toEqual('cn=科学A部,ou=users,dc=example,dc=com')
|
|
169
|
+
// backward compatible with 3.2
|
|
170
170
|
expect(user.groups[0].objectName).toEqual(
|
|
171
171
|
'cn=科学A部,ou=users,dc=example,dc=com'
|
|
172
172
|
)
|