ldap-authentication 3.2.2 → 3.2.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.
@@ -27,7 +27,7 @@ jobs:
27
27
  run: sudo apt-get install -y ldap-utils
28
28
 
29
29
  - name: Start containers
30
- run: docker-compose -f "docker-compose.yml" up -d
30
+ run: docker compose -f "docker-compose.yml" up -d
31
31
 
32
32
  - name: Wait for LDAP server to become available
33
33
  uses: nick-fields/retry@v2
@@ -51,4 +51,4 @@ jobs:
51
51
 
52
52
  - name: Stop containers
53
53
  if: always()
54
- run: docker-compose -f "docker-compose.yml" down
54
+ run: docker compose -f "docker-compose.yml" down
@@ -0,0 +1,33 @@
1
+ # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
2
+ # For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages
3
+
4
+ name: Publish to NPM
5
+
6
+ on:
7
+ release:
8
+ types: [created]
9
+
10
+ jobs:
11
+ build:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - uses: actions/setup-node@v4
16
+ with:
17
+ node-version: 20
18
+ - run: npm ci
19
+
20
+
21
+ publish-npm:
22
+ needs: build
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ - uses: actions/setup-node@v4
27
+ with:
28
+ node-version: 20
29
+ registry-url: https://registry.npmjs.org/
30
+ - run: npm ci
31
+ - run: npm publish
32
+ env:
33
+ NODE_AUTH_TOKEN: ${{secrets.npm_token}}
package/README.md CHANGED
@@ -187,7 +187,7 @@ In version 2, The user object has a `raw` field that has the raw data from the L
187
187
  Buffer data can now be accessed by `user.raw.profilePhoto`, etc, instead of `user.profilePhoto`.
188
188
 
189
189
  In version 3, the `raw` field is no longer used. Instead, append `;binary` to the attributes you
190
- want to get back as buffer. Check the following example on how to get a user's profile photo:
190
+ want to get back as base64-encoded string. Check the following example on how to get a user's profile photo:
191
191
 
192
192
  ```javascript
193
193
  export async function verifyLogin(email: string, password: string) {
@@ -210,7 +210,7 @@ export async function verifyLogin(email: string, password: string) {
210
210
  const profilePhoto = ldapUser['thumbnailPhoto;binary'];
211
211
 
212
212
  /* using the image
213
- <img src={`data:image/*;base64,${user.profilePhoto}`} />
213
+ <img src={`data:image/*;base64,${profilePhoto}`} />
214
214
  */
215
215
  return { user: ldapUser };
216
216
  }
package/index.js CHANGED
@@ -1,5 +1,42 @@
1
1
  const assert = require('assert')
2
2
  const ldap = require('ldapjs')
3
+ // escape the , in CN in DN
4
+ function _ldapEscapeDN(s) {
5
+ let ret = "";
6
+ let comaPositions = [];
7
+ let done = false;
8
+ let countEq = 0;
9
+ for (let i = 0; !done && i < s.length; i++) {
10
+ switch (s[i]) {
11
+ case "\\":
12
+ // user already escapped, continue
13
+ i++;
14
+ break;
15
+ case ",":
16
+ if (countEq == 1) {
17
+ comaPositions.push(i);
18
+ }
19
+ break;
20
+ case "=":
21
+ countEq++;
22
+ if (countEq == 2) {
23
+ done = true;
24
+ }
25
+ break;
26
+ }
27
+ }
28
+ if (done) {
29
+ comaPositions.pop();
30
+ }
31
+ let lastIndex = 0;
32
+ for (let i of comaPositions) {
33
+ ret += s.substring(lastIndex, i);
34
+ ret += "\\,";
35
+ lastIndex = i + 1;
36
+ }
37
+ ret += s.substring(lastIndex);
38
+ return ret;
39
+ }
3
40
 
4
41
  // convert an escaped utf8 string returned from ldapjs
5
42
  function _isHex(c) {
@@ -55,6 +92,7 @@ function _searchResultToUser(pojo) {
55
92
  }
56
93
  // bind and return the ldap client
57
94
  function _ldapBind(dn, password, starttls, ldapOpts) {
95
+ dn = _ldapEscapeDN(dn)
58
96
  return new Promise(function (resolve, reject) {
59
97
  ldapOpts.connectTimeout = ldapOpts.connectTimeout || 5000
60
98
  let client = ldap.createClient(ldapOpts)
@@ -406,7 +444,8 @@ async function authenticate(options) {
406
444
  options.groupsSearchBase,
407
445
  options.groupClass,
408
446
  options.groupMemberAttribute,
409
- options.groupMemberUserAttribute
447
+ options.groupMemberUserAttribute,
448
+ options.attributes
410
449
  )
411
450
  }
412
451
  assert(options.userPassword, 'userPassword must be provided')
@@ -467,4 +506,5 @@ module.exports.exportForTesting = {
467
506
  _isHex,
468
507
  _parseEscapedHexToUtf8,
469
508
  _recursiveParseHexString,
509
+ _ldapEscapeDN
470
510
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ldap-authentication",
3
- "version": "3.2.2",
3
+ "version": "3.2.6",
4
4
  "description": "A simple async nodejs library for LDAP user authentication",
5
5
  "main": "index.js",
6
6
  "types": "./index.d.ts",
@@ -39,6 +39,6 @@
39
39
  "ldapjs": "^3.0.7"
40
40
  },
41
41
  "devDependencies": {
42
- "jasmine": "^5.1.0"
42
+ "jasmine": "^5.3.0"
43
43
  }
44
44
  }
@@ -1,5 +1,5 @@
1
1
  const { exportForTesting } = require('../index.js')
2
- const { _isHex, _parseEscapedHexToUtf8, _recursiveParseHexString } =
2
+ const { _isHex, _parseEscapedHexToUtf8, _recursiveParseHexString, _ldapEscapeDN } =
3
3
  exportForTesting
4
4
 
5
5
  describe('string conversion test', () => {
@@ -41,3 +41,22 @@ describe('string conversion test', () => {
41
41
  expect(converted).toEqual(target)
42
42
  })
43
43
  })
44
+
45
+ describe('escape , in the DN test', ()=>{
46
+ let cases = [
47
+ { s: "a", want: "a" },
48
+ { s: "", want: "" },
49
+ { s: "CN=a,DN=b", want: "CN=a,DN=b" },
50
+ { s: "CN=a, c,DN=b", want: "CN=a\\, c,DN=b" },
51
+ { s: "CN=a\\, c,DN=b", want: "CN=a\\, c,DN=b" },
52
+ { s: "CN=a, b, c,DN=b", want: "CN=a\\, b\\, c,DN=b" },
53
+ { s: "CN=a, c", want: "CN=a\\, c" },
54
+ ]
55
+ for (let c of cases) {
56
+ it("escape "+c.s, ()=>{
57
+ let got = _ldapEscapeDN(c.s)
58
+ expect(got).toEqual(c.want)
59
+ })
60
+
61
+ }
62
+ })
package/test/test.spec.js CHANGED
@@ -20,6 +20,26 @@ describe('ldap-authentication test', () => {
20
20
  expect(user).toBeTruthy()
21
21
  expect(user.uid).toEqual('gauss')
22
22
  })
23
+ it('Use an admin user to check if user exists and return attributes', async () => {
24
+ let options = {
25
+ ldapOpts: {
26
+ url: url,
27
+ },
28
+ adminDn: 'cn=read-only-admin,dc=example,dc=com',
29
+ adminPassword: 'password',
30
+ verifyUserExists: true,
31
+ userSearchBase: 'dc=example,dc=com',
32
+ usernameAttribute: 'uid',
33
+ username: 'gauss',
34
+ attributes: ['uid', 'sn'],
35
+ }
36
+
37
+ let user = await authenticate(options)
38
+ expect(user).toBeTruthy()
39
+ expect(user.uid).toEqual('gauss')
40
+ expect(user.sn).toEqual('Bar1')
41
+ expect(user.cn).toBeUndefined()
42
+ })
23
43
  it('Use an admin user to authenticate a regular user', async () => {
24
44
  let options = {
25
45
  ldapOpts: {
@@ -37,7 +57,7 @@ describe('ldap-authentication test', () => {
37
57
  expect(user).toBeTruthy()
38
58
  expect(user.uid).toEqual('gauss')
39
59
  })
40
- it('Use an admin user to authenticate a regular user and return attrubutes', async () => {
60
+ it('Use an admin user to authenticate a regular user and return attributes', async () => {
41
61
  let options = {
42
62
  ldapOpts: {
43
63
  url: url,