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 CHANGED
@@ -1,5 +1,5 @@
1
1
  const assert = require('assert')
2
- const ldap = require('ldapjs')
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
- return new Promise(function (resolve, reject) {
97
- ldapOpts.connectTimeout = ldapOpts.connectTimeout || 5000
98
- let client = ldap.createClient(ldapOpts)
100
+ ldapOpts.connectTimeout = ldapOpts.connectTimeout || 5000
101
+ let client = new ldapts.Client(ldapOpts)
99
102
 
100
- client.on('connect', function () {
101
- if (starttls) {
102
- client.starttls(ldapOpts.tlsOptions, null, function (error) {
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
- client.on('connectError', function (error) {
140
- if (error) {
141
- reject(error)
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
- return new Promise(function (resolve, reject) {
157
- let filter = new ldap.filters.EqualityFilter({
158
- attribute: usernameAttribute,
159
- value: username,
160
- })
161
- let searchOptions = {
162
- filter: filter,
163
- scope: 'sub',
164
- attributes: attributes,
165
- }
166
- if (attributes) {
167
- searchOptions.attributes = attributes
168
- }
169
- ldapClient.search(searchBase, searchOptions, function (err, res) {
170
- let user = null
171
- if (err) {
172
- reject(err)
173
- return
174
- }
175
- res.on('searchEntry', function (entry) {
176
- user = _searchResultToUser(entry.pojo)
177
- })
178
- res.on('searchReference', function (referral) {
179
- // TODO: we don't support reference yet
180
- // If the server was able to locate the entry referred to by the baseObject
181
- // but could not search one or more non-local entries,
182
- // the server may return one or more SearchResultReference messages,
183
- // each containing a reference to another set of servers for continuing the operation.
184
- // referral.uris
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
- return new Promise(function (resolve, reject) {
210
- ldapClient.search(
211
- searchBase,
212
- {
213
- filter: `(&(objectclass=${groupClass})(${groupMemberAttribute}=${user[groupMemberUserAttribute]}))`,
214
- scope: 'sub',
215
- },
216
- function (err, res) {
217
- let groups = []
218
- if (err) {
219
- reject(err)
220
- return
221
- }
222
- res.on('searchEntry', function (entry) {
223
- groups.push(_recursiveParseHexString(entry.pojo))
224
- })
225
- res.on('searchReference', function (referral) {})
226
- res.on('error', function (err) {
227
- reject(err)
228
- })
229
- res.on('end', function (result) {
230
- if (result.status != 0) {
231
- reject(new Error('ldap search status is not 0, search failed'))
232
- } else {
233
- resolve(groups)
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.2.6",
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
- "ldapjs": "^3.0.7"
39
+ "ldapts": "^7.3.1"
40
40
  },
41
41
  "devDependencies": {
42
- "jasmine": "^5.3.0"
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].objectName).toEqual(
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
  )