Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

express-passport-ldap-mongoose

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

express-passport-ldap-mongoose - npm Package Compare versions

Comparing version 2.1.0 to 3.0.0

.vscode/launch.json

6

example/model.js

@@ -7,6 +7,6 @@ let mongoose = require('mongoose')

// these fields are from ldap
uid: { type: String, lowercase: true },
givenName: { type: String},
username: { type: String, lowercase: true },
cn: { type: String},
sn: { type: String},
displayName: {type: String},
dn: {type: String},
mail: { type: String, lowercase: true}

@@ -13,0 +13,0 @@ },

@@ -40,5 +40,46 @@ /* jshint node:true */

// use the library express-passport-ldap-mongoose
LdapAuth.init(CONFIG.ldap.dn, CONFIG.ldap.url, app,
// backward compatible mode
/*LdapAuth.init(CONFIG.ldap.dn, CONFIG.ldap.url, app,
(id) => User.findOne({ uid: id }).exec(),
(user) => User.findOneAndUpdate({ uid: user.uid }, user, { upsert: true, new: true }).exec()
)*/
// new mode, simple user
let usernameAttr = 'uid'
let searchBase = CONFIG.ldap.dn
let options = {
ldapOpts: {
url: CONFIG.ldap.url
},
userDn: `uid={{username}},${CONFIG.ldap.dn}`,
userSearchBase: searchBase,
usernameAttribute: usernameAttr
}
let admOptions = {
ldapOpts: {
url: CONFIG.ldap.url,
//tlsOptions: { rejectUnauthorized: false }
},
adminDn: `cn=read-only-admin,dc=example,dc=com`,
adminPassword: 'password',
userSearchBase: searchBase,
usernameAttribute: usernameAttr
//starttls: true
}
let userOptions = {
ldapOpts: {
url: CONFIG.ldap.url,
//tlsOptions: { rejectUnauthorized: false }
},
userDn: `uid={{username}},dc=example,dc=com`,
userSearchBase: searchBase,
usernameAttribute: usernameAttr
//starttls: true
}
LdapAuth.init(userOptions, '', app,
(id) => User.findOne({ username: id }).exec(),
(user) => {
console.log(`${user[usernameAttr]} has logged in`)
return User.findOneAndUpdate({ username: user[usernameAttr] }, user, { upsert: true, new: true }).exec()
}
)

@@ -51,2 +92,4 @@

// Start server
app.listen(4000, '127.0.0.1')
let port=4000
console.log(`server listen on port ${port}`)
app.listen(port, '127.0.0.1')

@@ -6,6 +6,7 @@ /**

const passport = require('passport')
const LdapStrategy = require('passport-ldapauth')
const CustomStrategy = require('passport-custom').Strategy
const { authenticate } = require('ldap-authentication')
var _backwardCompatible = false
var _dn
var _ldapurl
var _findFunc

@@ -15,3 +16,3 @@ var _insertFunc

var _logoutUrl
var _router
var _usernameAttributeName

@@ -21,4 +22,5 @@ /**

*
* @param {string} dn - ldap dn
* @param {string} ldapurl - ldap server url
* @param {object|string} opt - if is an object, the options object to pass to ldapauth. if is a string, is ldap search base (backward compatible)
* in opt object, literal `{{username}}` will be replaced with value in req.body.username
* @param {string} ldapurl - ldap server url (if url is defined in opt, this will be ignored)
* @param {object} router - express router

@@ -30,5 +32,9 @@ * @param {function} findFunc - function(id) to find the user in local db by id

*/
var init = function (dn, ldapurl, router, findFunc, insertFunc, loginUrl, logoutUrl) {
_dn = dn
_ldapurl = ldapurl
var init = function (opt, ldapurl, router, findFunc, insertFunc, loginUrl, logoutUrl) {
if (typeof(opt) === 'string') {
// backward compatible mode
console.log('express-passport-ldap-mongoose: DeprecationWarning: calling init with DN string as first argument will be removed in a future version. Use an option object instead')
_dn = opt
_backwardCompatible = true
}
_router = router

@@ -39,28 +45,61 @@ _findFunc = findFunc

_logoutUrl = logoutUrl || '/logout'
passport.use(new LdapStrategy((req, callback) => {
// Fetching things from database or whatever
// use x-www-form-urlencoded to fill in username and password
// req should be already urlencodedParser ed. body
// should be filled with username and password.
process.nextTick(() => {
var opts = {
server: {
url: _ldapurl,
bindDn: `uid=${req.body.username},${_dn}`,
bindCredentials: `${req.body.password}`,
searchBase: _dn,
searchFilter: `uid=${req.body.username}`,
reconnect: true
_usernameAttributeName = ''
passport.use('ldap', new CustomStrategy(async (req, done) => {
try {
if (!req.body.username || !req.body.password) {
throw new Error('username and password must be both provided')
}
let username = req.body.username
let password = req.body.password
// construct the parameter to pass in authenticate() function
let options
if (_backwardCompatible) {
_usernameAttributeName = 'uid'
options = {
ldapOpts: {
url: ldapurl
},
userDn: `uid=${username},${_dn}`,
userPassword: password,
userSearchBase: _dn,
usernameAttribute: 'uid',
username: username
}
} else {
_usernameAttributeName = opt.usernameAttribute
options = {
ldapOpts: opt.ldapOpts,
userPassword: password,
userSearchBase: opt.userSearchBase,
usernameAttribute: _usernameAttributeName,
username: username,
starttls: opt.starttls
}
if (opt.userDn) {
options.userDn = opt.userDn.replace('{{username}}', username)
}
if (opt.adminDn) {
options.adminDn = opt.adminDn
}
if (opt.adminPassword) {
options.adminPassword = opt.adminPassword
}
}
callback(null, opts)
})
},
(user, done) => {
return done(null, user)
}))
// ldap authenticate the user
let user = await authenticate(options)
// success
done(null, user)
} catch (error) {
// authentication failure
done(error, null)
}
}))
passport.serializeUser((user, done) => {
done(null, user.uid)
if (user[_usernameAttributeName]) {
done(null, user[_usernameAttributeName])
} else {
done('User from ldap server does not have field ' + _usernameAttributeName)
}
})

@@ -110,8 +149,9 @@

var login = function (req, res, next) {
passport.authenticate('ldapauth', (err, user, info) => {
passport.authenticate('ldap', (err, user) => {
if (err) {
return next(err)
res.status(401).json({success: false, message: err.message})
return
}
if (!user) {
res.status(401).json({ success: false, message: info.message })
res.status(401).json({ success: false, message: 'User cannot be found' })
} else {

@@ -118,0 +158,0 @@ req.login(user, loginErr => {

{
"name": "express-passport-ldap-mongoose",
"version": "2.1.0",
"version": "3.0.0",
"description": "A library to use passport-ldapauth and local MongoDB to authenticate and save users",

@@ -10,4 +10,5 @@ "main": "index.js",

"dependencies": {
"ldap-authentication": "^2.1.1",
"passport": "^0.4.1",
"passport-ldapauth": "^2.1.3"
"passport-custom": "^1.1.0"
},

@@ -20,4 +21,4 @@ "devDependencies": {

"jest": "^24.9.0",
"mongoose": "^5.8.4",
"superagent": "^5.1.3",
"mongoose": "^5.8.6",
"superagent": "^5.2.1",
"supertest": "^4.0.2"

@@ -24,0 +25,0 @@ },

@@ -6,15 +6,18 @@ # express-passport-ldap-mongoose

A library to use passport-ldapauth and local MongoDB to authenticate and save users
A turn key library that uses [ldap-authentication](https://github.com/shaozi/ldap-authentication)
with Passport and local database (MongoDB) to authenticate and save users
When an application needs to authenticate a user against an LDAP server, it normally also needs to
save the user into local MongoDB for further references. `express-passport-ldap-mongoose` is designed
to handle this requirement with a simple wrapper layer on top of expressjs, passportjs, passport-ldapauth,
to handle this requirement with a simple wrapper layer on top of expressjs, passportjs,
[ldap-authentication](https://github.com/shaozi/ldap-authentication),
and MongoDB.
## Requirement
## Requirements
* node Express
* Mongoose
* Mongoose (optional)
* Passport
* Passport-ldapauth
* [ldap-authentication](https://github.com/shaozi/ldap-authentication)
* The login submit field names should be `username` for username, and `password` for password

@@ -28,2 +31,3 @@ ## Installation

## Usage
`express-passport-ldap-mongoose` configures passportjs and adds the login and logout route to

@@ -37,28 +41,65 @@ your express app or router. All you need to do is call the `init` function of the library

app.use(sessionMiddleWare)
LdapAuth.init(dn, ldapurl, app, findUserFunc, upsertUserFunc, loginPath, logoutPath)
LdapAuth.init(options, '', app, findUserFunc, upsertUserFunc, loginPath, logoutPath)
```
## MongoDB model
The `User` model in local MongoDB must have the `uid` key that maps to LDAP `uid` property. This
`uid` field is used to uniquely identify a user and is normally the user's login name.
When search for a user by its username in LDAP, a `usernameAttribute` is needed.
The `User` model in local MongoDB must have the same key as the value of `usernameAttribute`
that maps to the LDAP attribute. In some cases, and in the example we are using `uid`.
it is used to uniquely identify a user and equals to the user's login username.
## Parameters
* `dn`: The bind DN of LDAP server. Example: `dc=example.com,dc=com`
* `ldapurl`: URL of LDAP server. Example: `ldaps://ldap.example.com`, `ldap://ldap.example.com`
* `options`: If the first parameter is an object,
it is the options object to pass to `ldap-authentication`'s `authenticate()` function.
If is a string (deprecated), is the ldap search base (for backward compatible)
If options is an object, literal `{{username}}` in the `userDn` will be replaced with the value in
`req.body.username` which will be the user input username.
See [ldap-authentication](https://github.com/shaozi/ldap-authentication) for detail explanation on each options.
String Example (deprecated): `dc=example.com,dc=com`
Options object Example:
```javascript
let options = {
ldapOpts: {
url: 'ldap://localhost'
},
// note in this example it only use the user to directly
// bind to the LDAP server. You can also use an admin
// here. See the document of ldap-authentication.
userDn: `uid=${req.body.username},${ldapBaseDn}`,
userPassword: req.body.password,
userSearchBase: ldapBaseDn,
usernameAttribute: 'uid',
username: req.body.username
}
```
* `ldapurl` (deprecated): URL of LDAP server. Example: `ldaps://ldap.example.com`, `ldap://ldap.example.com`
It will be ignored if the first parameter of the function is an object
* `app`: Express app or router
* `findUserFunc`: `function(id)`. A function takes a string id and return a promise that resolves to a user or null.
* `findUserFunc`: `function(id)`. A function takes a string id and return a promise that resolves to a user or null.
This function is called everytime passport do deserialization. It is normally a `FindOne` or `FindById` call against
local mongo database. Example: `(id) => {return User.findOne({ uid: id }).exec()}`
local mongo database. Example: `(id) => {return User.findOne({ uid: id }).exec()}`. However, it does not have to be
any database related. It is just a functin that can return a user from a user id.
* `upsertUserFunc`: `function(user)`. A function take a user object (obtained from ldap server and saved in express `req`)
and upsert into local database; returns a promise that resolves to a local db user object.
and upsert into local database; returns a promise that resolves to a local db user object. Again, it does not have to
be any database related. It is essentially a function that update some internal record of a user.
Example: `(user) => {return User.findOneAndUpdate({ uid: user.uid }, user, { upsert: true, new: true }).exec()}`
* `loginPath`: (optional, default `/login`) The login path for express to parse the login posted json data. The posted data
must be in json format, and with `username` and `password` as the key names. An `app.post(loginPath, loginHandler)`
must be in json format, and with `username` and `password` as the key names. An `app.post(loginPath, loginHandler)`
will be automatically added and handled by the library.
* `logoutPath`: (optional, default `/logout`) The logout path for express to parse the logout request. An `app.get(logoutPath, logoutHandler)`
* `logoutPath`: (optional, default `/logout`) The logout path for express to parse the logout request. An `app.get(logoutPath, logoutHandler)`
will be automatically added and handled by the library.
## Example
Complete example is at https://github.com/shaozi/express-passport-ldap-mongoose-example
Complete example is in the example folder.
Another example on how to use Passport and [ldap-authentication](https://github.com/shaozi/ldap-authentication) can be found in [passport-ldap-example](https://github.com/shaozi/passport-ldap-example).
```javascript

@@ -96,6 +137,17 @@ const mongoose = require('mongoose')

// use the library express-passport-ldap-mongoose
LdapAuth.init(CONFIG.ldap.dn, CONFIG.ldap.url, app, (id) => {
return User.findOne({ uid: id }).exec()
let usernameAttributeName = 'uid'
LdapAuth.init({
ldapOpts: {
url: 'ldap://localhost'
},
// note in this example it only use the user to directly
// bind to the LDAP server. You can also use an admin
// here. See the document of ldap-authentication.
userDn: `uid={{username}},${ldapBaseDn}`,
userSearchBase: ldapBaseDn,
usernameAttribute: usernameAttributeName
}, '', app, (id) => {
return User.findOne({ usernameAttributeName: id }).exec()
}, (user) => {
return User.findOneAndUpdate({ uid: user.uid }, user, { upsert: true, new: true }).exec()
return User.findOneAndUpdate({ username: user[usernameAttributeName] }, user, { upsert: true, new: true }).exec()
})

@@ -102,0 +154,0 @@

@@ -47,3 +47,12 @@ const request = require('supertest');

auth.init('dc=example,dc=com', 'ldap://ldap.forumsys.com', app,
let userOptions = {
ldapOpts: {
url: 'ldap://ldap.forumsys.com'
},
userDn: `uid={{username}},dc=example,dc=com`,
userSearchBase: 'dc=example,dc=com',
usernameAttribute: 'uid'
}
auth.init(userOptions, '', app,
findUserById, upsertUser

@@ -61,2 +70,4 @@ )

expect(response.statusCode).toBe(401)
expect(response.body.success).toBeFalsy()
expect(response.body.message).toEqual("username and password must be both provided")
})

@@ -71,5 +82,5 @@ })

expect(response.body.success).toBeFalsy()
expect(response.body.message).toEqual("Invalid username/password")
expect(response.body.message).toEqual("Invalid Credentials")
expect(response.body.user).toBeUndefined()
user = User.find(u => { return u.uid === "gauss" })
user = User.find(u => { return u.username === "gauss" })
expect(user).toBeUndefined()

@@ -76,0 +87,0 @@ })

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc