mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-07-15 05:41:34 +00:00
Added LDAP Auth Implementation
This commit is contained in:
parent
c2793fe29b
commit
464a1ea121
6 changed files with 459 additions and 25 deletions
14
index.js
14
index.js
|
|
@ -18,12 +18,20 @@ const PORT = process.env.PORT || 80
|
|||
const HOST = process.env.HOST
|
||||
const CONFIG_PATH = process.env.CONFIG_PATH || '/config'
|
||||
const METADATA_PATH = process.env.METADATA_PATH || '/metadata'
|
||||
const UID = process.env.AUDIOBOOKSHELF_UID
|
||||
const GID = process.env.AUDIOBOOKSHELF_GID
|
||||
const UID = process.env.AUDIOBOOKSHELF_UID || 99
|
||||
const GID = process.env.AUDIOBOOKSHELF_GID || 100
|
||||
|
||||
const LDAP_URL = process.env.LDAP_URL
|
||||
const LDAP_BASE_DN = process.env.LDAP_BASE_DN
|
||||
const LDAP_BIND_USER = process.env.LDAP_BIND_USER
|
||||
const LDAP_BIND_PASS = process.env.LDAP_BIND_PASS
|
||||
const LDAP_SEARCH_FILTER = process.env.LDAP_SEARCH_FILTER
|
||||
const LDAP_USERNAME_ATTRIBUTE = process.env.LDAP_USERNAME_ATTRIBUTE
|
||||
const LDAP_ENABLED = process.env.LDAP_ENABLED
|
||||
const SOURCE = process.env.SOURCE || 'docker'
|
||||
const ROUTER_BASE_PATH = process.env.ROUTER_BASE_PATH || ''
|
||||
|
||||
console.log('Config', CONFIG_PATH, METADATA_PATH)
|
||||
|
||||
const Server = new server(SOURCE, PORT, HOST, UID, GID, CONFIG_PATH, METADATA_PATH, ROUTER_BASE_PATH)
|
||||
const Server = new server(SOURCE, PORT, HOST, UID, GID, CONFIG_PATH, METADATA_PATH, ROUTER_BASE_PATH, LDAP_ENABLED, LDAP_URL, LDAP_BASE_DN, LDAP_BIND_USER, LDAP_BIND_PASS, LDAP_SEARCH_FILTER, LDAP_USERNAME_ATTRIBUTE)
|
||||
Server.start()
|
||||
|
|
|
|||
216
package-lock.json
generated
216
package-lock.json
generated
|
|
@ -13,6 +13,7 @@
|
|||
"express": "^4.17.1",
|
||||
"graceful-fs": "^4.2.10",
|
||||
"htmlparser2": "^8.0.1",
|
||||
"ldapjs": "^2.3.3",
|
||||
"node-tone": "^1.0.1",
|
||||
"nodemailer": "^6.9.2",
|
||||
"sequelize": "^6.32.1",
|
||||
|
|
@ -174,6 +175,11 @@
|
|||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
|
||||
},
|
||||
"node_modules/abstract-logging": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz",
|
||||
"integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA=="
|
||||
},
|
||||
"node_modules/accepts": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
||||
|
|
@ -311,6 +317,22 @@
|
|||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
|
||||
},
|
||||
"node_modules/asn1": {
|
||||
"version": "0.2.6",
|
||||
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
|
||||
"integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
|
||||
"dependencies": {
|
||||
"safer-buffer": "~2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
|
|
@ -325,6 +347,17 @@
|
|||
"form-data": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/backoff": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz",
|
||||
"integrity": "sha512-wC5ihrnUXmR2douXmXLCe5O3zg3GKIyvRi/hi58a/XyRxVI+3/yM0PYueQOZXPXQ9pxBislYkw+sF9b7C/RuMA==",
|
||||
"dependencies": {
|
||||
"precond": "0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
|
|
@ -545,6 +578,11 @@
|
|||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
|
||||
},
|
||||
"node_modules/core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="
|
||||
},
|
||||
"node_modules/cors": {
|
||||
"version": "2.8.5",
|
||||
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||
|
|
@ -835,6 +873,14 @@
|
|||
"node": ">= 0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/extsprintf": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz",
|
||||
"integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==",
|
||||
"engines": [
|
||||
"node >=0.6.0"
|
||||
]
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
|
|
@ -1308,6 +1354,35 @@
|
|||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/ldap-filter": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/ldap-filter/-/ldap-filter-0.3.3.tgz",
|
||||
"integrity": "sha512-/tFkx5WIn4HuO+6w9lsfxq4FN3O+fDZeO9Mek8dCD8rTUpqzRa766BOBO7BcGkn3X86m5+cBm1/2S/Shzz7gMg==",
|
||||
"dependencies": {
|
||||
"assert-plus": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/ldapjs": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/ldapjs/-/ldapjs-2.3.3.tgz",
|
||||
"integrity": "sha512-75QiiLJV/PQqtpH+HGls44dXweviFwQ6SiIK27EqzKQ5jU/7UFrl2E5nLdQ3IYRBzJ/AVFJI66u0MZ0uofKYwg==",
|
||||
"dependencies": {
|
||||
"abstract-logging": "^2.0.0",
|
||||
"asn1": "^0.2.4",
|
||||
"assert-plus": "^1.0.0",
|
||||
"backoff": "^2.5.0",
|
||||
"ldap-filter": "^0.3.3",
|
||||
"once": "^1.4.0",
|
||||
"vasync": "^2.2.0",
|
||||
"verror": "^1.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
|
|
@ -1870,6 +1945,14 @@
|
|||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/precond": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz",
|
||||
"integrity": "sha512-QCYG84SgGyGzqJ/vlMsxeXd/pgL/I94ixdNFyh1PusWmTCyVfPJjZ1K1jvHtsbfnXQs2TSkEP2fR7QiMZAnKFQ==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/promise-inflight": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
|
||||
|
|
@ -2598,6 +2681,43 @@
|
|||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/vasync": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/vasync/-/vasync-2.2.1.tgz",
|
||||
"integrity": "sha512-Hq72JaTpcTFdWiNA4Y22Amej2GH3BFmBaKPPlDZ4/oC8HNn2ISHLkFrJU4Ds8R3jcUi7oo5Y9jcMHKjES+N9wQ==",
|
||||
"engines": [
|
||||
"node >=0.6.0"
|
||||
],
|
||||
"dependencies": {
|
||||
"verror": "1.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vasync/node_modules/verror": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
|
||||
"integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==",
|
||||
"engines": [
|
||||
"node >=0.6.0"
|
||||
],
|
||||
"dependencies": {
|
||||
"assert-plus": "^1.0.0",
|
||||
"core-util-is": "1.0.2",
|
||||
"extsprintf": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/verror": {
|
||||
"version": "1.10.1",
|
||||
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz",
|
||||
"integrity": "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==",
|
||||
"dependencies": {
|
||||
"assert-plus": "^1.0.0",
|
||||
"core-util-is": "1.0.2",
|
||||
"extsprintf": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
|
|
@ -2818,6 +2938,11 @@
|
|||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
|
||||
},
|
||||
"abstract-logging": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz",
|
||||
"integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA=="
|
||||
},
|
||||
"accepts": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
||||
|
|
@ -2922,6 +3047,19 @@
|
|||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
|
||||
},
|
||||
"asn1": {
|
||||
"version": "0.2.6",
|
||||
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
|
||||
"integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
|
||||
"requires": {
|
||||
"safer-buffer": "~2.1.0"
|
||||
}
|
||||
},
|
||||
"assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw=="
|
||||
},
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
|
|
@ -2936,6 +3074,14 @@
|
|||
"form-data": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"backoff": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz",
|
||||
"integrity": "sha512-wC5ihrnUXmR2douXmXLCe5O3zg3GKIyvRi/hi58a/XyRxVI+3/yM0PYueQOZXPXQ9pxBislYkw+sF9b7C/RuMA==",
|
||||
"requires": {
|
||||
"precond": "0.2"
|
||||
}
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
|
|
@ -3102,6 +3248,11 @@
|
|||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="
|
||||
},
|
||||
"cors": {
|
||||
"version": "2.8.5",
|
||||
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||
|
|
@ -3324,6 +3475,11 @@
|
|||
"vary": "~1.1.2"
|
||||
}
|
||||
},
|
||||
"extsprintf": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz",
|
||||
"integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA=="
|
||||
},
|
||||
"fill-range": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
|
|
@ -3673,6 +3829,29 @@
|
|||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
||||
"optional": true
|
||||
},
|
||||
"ldap-filter": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/ldap-filter/-/ldap-filter-0.3.3.tgz",
|
||||
"integrity": "sha512-/tFkx5WIn4HuO+6w9lsfxq4FN3O+fDZeO9Mek8dCD8rTUpqzRa766BOBO7BcGkn3X86m5+cBm1/2S/Shzz7gMg==",
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"ldapjs": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/ldapjs/-/ldapjs-2.3.3.tgz",
|
||||
"integrity": "sha512-75QiiLJV/PQqtpH+HGls44dXweviFwQ6SiIK27EqzKQ5jU/7UFrl2E5nLdQ3IYRBzJ/AVFJI66u0MZ0uofKYwg==",
|
||||
"requires": {
|
||||
"abstract-logging": "^2.0.0",
|
||||
"asn1": "^0.2.4",
|
||||
"assert-plus": "^1.0.0",
|
||||
"backoff": "^2.5.0",
|
||||
"ldap-filter": "^0.3.3",
|
||||
"once": "^1.4.0",
|
||||
"vasync": "^2.2.0",
|
||||
"verror": "^1.8.1"
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
|
|
@ -4080,6 +4259,11 @@
|
|||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"dev": true
|
||||
},
|
||||
"precond": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz",
|
||||
"integrity": "sha512-QCYG84SgGyGzqJ/vlMsxeXd/pgL/I94ixdNFyh1PusWmTCyVfPJjZ1K1jvHtsbfnXQs2TSkEP2fR7QiMZAnKFQ=="
|
||||
},
|
||||
"promise-inflight": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
|
||||
|
|
@ -4602,6 +4786,36 @@
|
|||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
|
||||
},
|
||||
"vasync": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/vasync/-/vasync-2.2.1.tgz",
|
||||
"integrity": "sha512-Hq72JaTpcTFdWiNA4Y22Amej2GH3BFmBaKPPlDZ4/oC8HNn2ISHLkFrJU4Ds8R3jcUi7oo5Y9jcMHKjES+N9wQ==",
|
||||
"requires": {
|
||||
"verror": "1.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"verror": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
|
||||
"integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==",
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0",
|
||||
"core-util-is": "1.0.2",
|
||||
"extsprintf": "^1.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"verror": {
|
||||
"version": "1.10.1",
|
||||
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz",
|
||||
"integrity": "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==",
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0",
|
||||
"core-util-is": "1.0.2",
|
||||
"extsprintf": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
|
|
@ -4672,4 +4886,4 @@
|
|||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
"express": "^4.17.1",
|
||||
"graceful-fs": "^4.2.10",
|
||||
"htmlparser2": "^8.0.1",
|
||||
"ldapjs": "^2.3.3",
|
||||
"node-tone": "^1.0.1",
|
||||
"nodemailer": "^6.9.2",
|
||||
"sequelize": "^6.32.1",
|
||||
|
|
@ -44,4 +45,4 @@
|
|||
"devDependencies": {
|
||||
"nodemon": "^2.0.20"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
112
server/Auth.js
112
server/Auth.js
|
|
@ -1,11 +1,28 @@
|
|||
const bcrypt = require('./libs/bcryptjs')
|
||||
const ldap = require('./authProviders/ldap')
|
||||
const jwt = require('./libs/jsonwebtoken')
|
||||
const requestIp = require('./libs/requestIp')
|
||||
const User = require('./objects/user/User')
|
||||
const { getId } = require('./utils')
|
||||
const Logger = require('./Logger')
|
||||
const Database = require('./Database')
|
||||
|
||||
class Auth {
|
||||
constructor() { }
|
||||
|
||||
constructor() {
|
||||
if (global.ldapEnabled) {
|
||||
this.ldap = ldap
|
||||
}
|
||||
this.user = null
|
||||
}
|
||||
|
||||
get username() {
|
||||
return this.user ? this.user.username : 'nobody'
|
||||
}
|
||||
|
||||
get users() {
|
||||
return Database.users
|
||||
}
|
||||
|
||||
cors(req, res, next) {
|
||||
res.header('Access-Control-Allow-Origin', '*')
|
||||
|
|
@ -34,15 +51,18 @@ class Auth {
|
|||
// New token secret creation added in v2.1.0 so generate new API tokens for each user
|
||||
if (Database.users.length) {
|
||||
for (const user of Database.users) {
|
||||
user.token = await this.generateAccessToken({ userId: user.id, username: user.username })
|
||||
Logger.warn(`[Auth] User ${user.username} api token has been updated using new token secret`)
|
||||
if (user.token) {
|
||||
delete user.token
|
||||
}
|
||||
//Tokens should never be stored on the server, the entire point is that the server can cryptographically verify the token without storing it
|
||||
Logger.warn(`[Auth] User ${user.username} api token security hole has been removed`)
|
||||
}
|
||||
await Database.updateBulkUsers(Database.users)
|
||||
}
|
||||
}
|
||||
|
||||
async authMiddleware(req, res, next) {
|
||||
var token = null
|
||||
let token = null
|
||||
|
||||
// If using a get request, the token can be passed as a query string
|
||||
if (req.method === 'GET' && req.query && req.query.token) {
|
||||
|
|
@ -104,7 +124,16 @@ class Auth {
|
|||
})
|
||||
}
|
||||
|
||||
getUserLoginResponsePayload(user) {
|
||||
async getLdapUsers() {
|
||||
if (this.ldap) {
|
||||
const ldapUsers = await this.ldap.findAllUsers();
|
||||
return ldapUsers;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
async getUserLoginResponsePayload(user) {
|
||||
user.token = await this.generateAccessToken({ userId: user.id, username: user.username });
|
||||
return {
|
||||
user: user.toJSONForBrowser(),
|
||||
userDefaultLibraryId: user.getDefaultLibraryId(Database.libraries),
|
||||
|
|
@ -119,7 +148,28 @@ class Auth {
|
|||
const username = (req.body.username || '').toLowerCase()
|
||||
const password = req.body.password || ''
|
||||
|
||||
const user = Database.users.find(u => u.username.toLowerCase() === username)
|
||||
let user = Database.users.find(u => u.username.toLowerCase() === username)
|
||||
if (!user && this.ldap) {
|
||||
Logger.warn(`[Auth] Could not find user in database from ${ipAddress}, checking LDAP...`)
|
||||
const ldapUsers = await this.getLdapUsers()
|
||||
Logger.debug(ldapUsers);
|
||||
if (ldapUsers.filter(u => u[global.ldapUsernameAttribute].toLowerCase() == username.toLowerCase())) {
|
||||
const ldapUser = ldapUsers.find(v => v[global.ldapUsernameAttribute].toLowerCase() == username.toLowerCase())
|
||||
const newUser = new User({
|
||||
username: ldapUser[global.ldapUsernameAttribute],
|
||||
id: getId('usr'),
|
||||
isActive: true,
|
||||
isLocked: false,
|
||||
librariesAccessible: [],
|
||||
itemTagsAccessible: [],
|
||||
type: 'ldap'
|
||||
})
|
||||
const success = await Database.insertEntity('user', newUser)
|
||||
if (success) {
|
||||
user = Database.users.find(u => u.username.toLowerCase() === username)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!user?.isActive) {
|
||||
Logger.warn(`[Auth] Failed login attempt ${req.rateLimit.current} of ${req.rateLimit.limit} from ${ipAddress}`)
|
||||
|
|
@ -136,22 +186,46 @@ class Auth {
|
|||
return res.status(401).send('Invalid root password (hint: there is none)')
|
||||
} else {
|
||||
Logger.info(`[Auth] ${user.username} logged in from ${ipAddress}`)
|
||||
return res.json(this.getUserLoginResponsePayload(user))
|
||||
return res.json(await this.getUserLoginResponsePayload(user))
|
||||
}
|
||||
}
|
||||
|
||||
// Check password match
|
||||
const compare = await bcrypt.compare(password, user.pash)
|
||||
if (compare) {
|
||||
Logger.info(`[Auth] ${user.username} logged in from ${ipAddress}`)
|
||||
res.json(this.getUserLoginResponsePayload(user))
|
||||
} else {
|
||||
Logger.warn(`[Auth] Failed login attempt ${req.rateLimit.current} of ${req.rateLimit.limit} from ${ipAddress}`)
|
||||
if (req.rateLimit.remaining <= 2) {
|
||||
Logger.error(`[Auth] Failed login attempt for user ${user.username} from ip ${ipAddress}. Attempts: ${req.rateLimit.current}`)
|
||||
return res.status(401).send(`Invalid user or password (${req.rateLimit.remaining === 0 ? '1 attempt remaining' : `${req.rateLimit.remaining + 1} attempts remaining`})`)
|
||||
if (!user.pash || user.pash === '') {
|
||||
// Check LDAP for user.
|
||||
|
||||
const ldapUsers = await this.getLdapUsers()
|
||||
const ldapUser = ldapUsers.find(v => v[global.ldapUsernameAttribute].toLowerCase() == username.toLowerCase())
|
||||
if (ldapUser != null) {
|
||||
const adUserName = ldapUser.dn
|
||||
const authResult = await this.ldap.authenticateUser(adUserName, password);
|
||||
if (authResult) {
|
||||
res.json(await this.getUserLoginResponsePayload(user))
|
||||
} else {
|
||||
Logger.warn(`[Auth] Failed login attempt ${req.rateLimit.current} of ${req.rateLimit.limit} from ${ipAddress}`)
|
||||
if (req.rateLimit.remaining <= 2) {
|
||||
Logger.error(`[Auth] Failed login attempt for user ${user.username} from ip ${ipAddress}. Attempts: ${req.rateLimit.current}`)
|
||||
return res.status(401).send(`Invalid user or password (${req.rateLimit.remaining === 0 ? '1 attempt remaining' : `${req.rateLimit.remaining + 1} attempts remaining`})`)
|
||||
}
|
||||
return res.status(401).send('Invalid user or password')
|
||||
}
|
||||
} else {
|
||||
return res.status(401).send('Invalid user or password')
|
||||
}
|
||||
|
||||
} else {
|
||||
// Check password match
|
||||
const compare = await bcrypt.compare(password, user.pash)
|
||||
if (compare) {
|
||||
Logger.info(`[Auth] ${user.username} logged in from ${ipAddress}`)
|
||||
res.json(await this.getUserLoginResponsePayload(user))
|
||||
} else {
|
||||
Logger.warn(`[Auth] Failed login attempt ${req.rateLimit.current} of ${req.rateLimit.limit} from ${ipAddress}`)
|
||||
if (req.rateLimit.remaining <= 2) {
|
||||
Logger.error(`[Auth] Failed login attempt for user ${user.username} from ip ${ipAddress}. Attempts: ${req.rateLimit.current}`)
|
||||
return res.status(401).send(`Invalid user or password (${req.rateLimit.remaining === 0 ? '1 attempt remaining' : `${req.rateLimit.remaining + 1} attempts remaining`})`)
|
||||
}
|
||||
return res.status(401).send('Invalid user or password')
|
||||
}
|
||||
return res.status(401).send('Invalid user or password')
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -162,7 +236,7 @@ class Auth {
|
|||
}
|
||||
|
||||
async userChangePassword(req, res) {
|
||||
var { password, newPassword } = req.body
|
||||
const { password, newPassword } = req.body
|
||||
newPassword = newPassword || ''
|
||||
const matchingUser = Database.users.find(u => u.id === req.user.id)
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ const CronManager = require('./managers/CronManager')
|
|||
const TaskManager = require('./managers/TaskManager')
|
||||
|
||||
class Server {
|
||||
constructor(SOURCE, PORT, HOST, UID, GID, CONFIG_PATH, METADATA_PATH, ROUTER_BASE_PATH) {
|
||||
constructor(SOURCE, PORT, HOST, UID, GID, CONFIG_PATH, METADATA_PATH, ROUTER_BASE_PATH, LDAP_ENABLED, LDAP_URL, LDAP_BASE_DN, LDAP_BIND_USER, LDAP_BIND_PASS, LDAP_SEARCH_FILTER, LDAP_USERNAME_ATTRIBUTE) {
|
||||
this.Port = PORT
|
||||
this.Host = HOST
|
||||
global.Source = SOURCE
|
||||
|
|
@ -49,6 +49,19 @@ class Server {
|
|||
global.MetadataPath = fileUtils.filePathToPOSIX(Path.normalize(METADATA_PATH))
|
||||
global.RouterBasePath = ROUTER_BASE_PATH
|
||||
global.XAccel = process.env.USE_X_ACCEL
|
||||
global.ldapUrl = LDAP_URL
|
||||
global.ldapBaseDn = LDAP_BASE_DN
|
||||
global.ldapBindUser = LDAP_BIND_USER
|
||||
global.ldapBindPass = LDAP_BIND_PASS
|
||||
global.ldapSearchFilter = LDAP_SEARCH_FILTER
|
||||
global.ldapUsernameAttribute = LDAP_USERNAME_ATTRIBUTE
|
||||
global.ldapEnabled = LDAP_ENABLED
|
||||
|
||||
// Fix backslash if not on Windows
|
||||
if (process.platform !== 'win32') {
|
||||
global.ConfigPath = global.ConfigPath.replace(/\\/g, '/')
|
||||
global.MetadataPath = global.MetadataPath.replace(/\\/g, '/')
|
||||
}
|
||||
|
||||
if (!fs.pathExistsSync(global.ConfigPath)) {
|
||||
fs.mkdirSync(global.ConfigPath)
|
||||
|
|
|
|||
124
server/authProviders/ldap.js
Normal file
124
server/authProviders/ldap.js
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
const ldap = require('ldapjs');
|
||||
const Logger = require('../Logger');
|
||||
const { res } = require('../libs/dateAndTime');
|
||||
const { integer } = require('../libs/requestIp/isJs');
|
||||
|
||||
class LdapAuth {
|
||||
constructor() {}
|
||||
async getClient() {
|
||||
return await new Promise((resolve, reject) => {
|
||||
Logger.debug('Connecting...')
|
||||
const client = ldap.createClient({
|
||||
url: global.ldapUrl,
|
||||
bindDN: global.ldapBindUser,
|
||||
bindCredentials: global.ldapBindPass
|
||||
});
|
||||
let onError, onConnect, onTimeout;
|
||||
onError = err => {
|
||||
Logger.error('Error Connecting.')
|
||||
client.removeListener('connect', onConnect);
|
||||
reject(err);
|
||||
};
|
||||
onConnect = () => {
|
||||
Logger.debug('Connected.')
|
||||
Logger.debug('Binding...')
|
||||
client.removeListener('error', onError);
|
||||
client.bind(global.ldapBindUser, global.ldapBindPass, err => {
|
||||
if (err) {
|
||||
Logger.error('Error Binding.')
|
||||
reject(err);
|
||||
}
|
||||
else {
|
||||
Logger.debug('Bound.')
|
||||
resolve(client);
|
||||
}
|
||||
|
||||
// client.search
|
||||
})
|
||||
};
|
||||
onTimeout = () => {
|
||||
Logger.error('Timeout Connecting.')
|
||||
reject(new Error('LDAP connection timeout'));
|
||||
}
|
||||
client.once('connect', onConnect)
|
||||
client.once('error', onError)
|
||||
client.once('connectTimeout', onTimeout)
|
||||
})
|
||||
}
|
||||
async findAllUsers() {
|
||||
const client = await this.getClient();
|
||||
return await new Promise((resolve, reject) => {
|
||||
Logger.info('Searching...')
|
||||
Logger.debug(`global.ldapBaseDn: ${global.ldapBaseDn}`)
|
||||
Logger.debug(`global.ldapSearchFilter: ${global.ldapSearchFilter}`)
|
||||
client.search(global.ldapBaseDn, {
|
||||
scope: 'sub',
|
||||
filter: global.ldapSearchFilter
|
||||
}, (err, res) => {
|
||||
Logger.info('Search returned.')
|
||||
const items = []
|
||||
Logger.debug('Attaching to entry events...')
|
||||
res.on('searchEntry', entry => {
|
||||
Logger.debug('adding entry...')
|
||||
items.push(entry.object)
|
||||
})
|
||||
Logger.debug('Attaching to error events...')
|
||||
res.on('end', result => {
|
||||
Logger.debug('end of entries.')
|
||||
Logger.info(`Search complete, returning ${items.length} items.`)
|
||||
resolve(items);
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
authenticateUser(username, password) {
|
||||
Logger.info('Authenticating LDAP User...');
|
||||
return new Promise((resolve, reject) => {
|
||||
const tempClient = ldap.createClient({
|
||||
url: global.ldapUrl,
|
||||
bindDN: username,
|
||||
bindCredentials: password
|
||||
})
|
||||
let onError, onConnect, onTimeout;
|
||||
onError = err => {
|
||||
Logger.error('Error Connecting.')
|
||||
tempClient.removeListener('connect', onConnect);
|
||||
resolve(false);
|
||||
};
|
||||
onConnect = () => {
|
||||
Logger.debug('Connected.')
|
||||
Logger.debug('Binding...')
|
||||
tempClient.removeListener('error', onError);
|
||||
tempClient.bind(username, password, err => {
|
||||
if (err) {
|
||||
Logger.error('Error Binding.')
|
||||
resolve(false);
|
||||
}
|
||||
else {
|
||||
Logger.debug('Bound.')
|
||||
tempClient.unbind(err => {
|
||||
if (err) {
|
||||
Logger.error('Error Unbinding.')
|
||||
resolve(false);
|
||||
} else {
|
||||
Logger.info('User Authenticated.')
|
||||
resolve(true);
|
||||
}
|
||||
})
|
||||
}
|
||||
// client.search
|
||||
})
|
||||
};
|
||||
onTimeout = () => {
|
||||
Logger.error('Timeout Connecting.')
|
||||
resolve(false);
|
||||
}
|
||||
tempClient.once('connect', onConnect)
|
||||
tempClient.once('error', onError)
|
||||
tempClient.once('connectTimeout', onTimeout)
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
module.exports = new LdapAuth()
|
||||
Loading…
Add table
Add a link
Reference in a new issue