Last active
August 29, 2015 13:56
-
-
Save MichaelBailly/8843669 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
/** | |
* Passport wrapper for ldapauth | |
*/ | |
var passport = require('passport'), | |
LdapAuth = require('ldapauth-fork'), | |
util = require('util'); | |
/** | |
* Strategy constructor | |
* | |
* The LDAP authentication strategy authenticates requests based on the | |
* credentials submitted through an HTML-based login form. | |
* | |
* Applications may supply a `verify` callback which accepts `user` object | |
* and then calls the `done` callback supplying a `user`, which should be set | |
* to `false` if user is not allowed to authenticate. If an exception occured, | |
* `err` should be set. | |
* | |
* Options: | |
* - `server` options for ldapauth, see https://github.com/trentm/node-ldapauth | |
* - `usernameField` field name where the username is found, defaults to _username_ | |
* - `passwordField` field name where the password is found, defaults to _password_ | |
* - `passReqToCallback` when `true`, `req` is the first argument to the verify callback (default: `false`) | |
* | |
* Example: | |
* | |
* var LdapStrategy = require('passport-ldapauth').Strategy; | |
* passport.use(new LdapStrategy({ | |
* server: { | |
* url: 'ldap://localhost:389', | |
* adminDn: 'cn=root', | |
* adminPassword: 'secret', | |
* searchBase: 'ou=passport-ldapauth', | |
* searchFilter: '(uid={{username}})' | |
* } | |
* }, | |
* function(user, done) { | |
* return cb(null, user); | |
* } | |
* )); | |
*/ | |
var Strategy = function(options, verify) { | |
this.options = null; | |
this.getOptions = null; | |
if (typeof options === 'object' ) { | |
this.options = addDefaults(options); | |
} else if ( typeof options === 'function') { | |
this.getOptions = options; | |
} else { | |
throw new Error('LDAP authentication strategy requires options'); | |
} | |
passport.Strategy.call(this); | |
this.name = 'ldapauth'; | |
this.verify = verify; | |
if (typeof options === 'object') { | |
} | |
}; | |
util.inherits(Strategy, passport.Strategy); | |
/** | |
* Add default options if not set | |
*/ | |
var addDefaults = function(options) { | |
options.usernameField || (options.usernameField = 'username'); | |
options.passwordField || (options.passwordField = 'password'); | |
return options; | |
}; | |
/** | |
* Get value for given field from given object. Taken from passport-local | |
*/ | |
var lookup = function (obj, field) { | |
var i, len, chain, prop; | |
if (!obj) { return null; } | |
chain = field.split(']').join('').split('['); | |
for (i = 0, len = chain.length; i < len; i++) { | |
prop = obj[chain[i]]; | |
if (typeof(prop) === 'undefined') { return null; } | |
if (typeof(prop) !== 'object') { return prop; } | |
obj = prop; | |
} | |
return null; | |
}; | |
/** | |
* Verify the outcome of caller verify function - even if authentication (and | |
* usually authorization) is taken care by LDAP there may be reasons why | |
* a verify callback is provided, and again reasons why it may reject login | |
* for a valid user. | |
*/ | |
var verify = function(self) { | |
// Callback given to user given verify function. | |
return function(err, user, info) { | |
if (err) return self.error(err); | |
if (!user) return self.fail(info); | |
return self.success(user, info); | |
}; | |
}; | |
var handleAuthentication = function(req, options) { | |
var username, password, ldap, self; | |
options || (options = {}); | |
username = lookup(req.body, this.options.usernameField) || lookup(req.query, this.options.usernameField); | |
password = lookup(req.body, this.options.passwordField) || lookup(req.query, this.options.passwordField); | |
if (!username || !password) return this.fail('Missing credentials'); | |
self = this; | |
ldap = new LdapAuth(self.options.server); | |
ldap.authenticate(username, password, function(err, user) { | |
ldap.close(function(){}); // We don't care about the closing | |
if (err) { | |
// Invalid credentials / user not found are not errors but login failures | |
if (err.name === 'InvalidCredentialsError' || err.name === 'NoSuchObjectError' || (typeof err === 'string' && err.match(/no such user/i))) { | |
return self.fail('Invalid username/password'); | |
} | |
// Other errors are (most likely) real errors | |
return self.error(err); | |
} | |
if (!user) return self.fail('User not found'); | |
// Execute given verify function | |
if (self.verify) { | |
if (self.options.passReqToCallback) { | |
return self.verify(req, user, verify(self)); | |
} else { | |
return self.verify(user, verify(self)); | |
} | |
} else { | |
return self.success(user); | |
} | |
}); | |
}; | |
/** | |
* Authenticate the request coming from a form or such. | |
*/ | |
Strategy.prototype.authenticate = function(req, options) { | |
if ( typeof this.options === 'object' ) { | |
return handleAuthentication.call(this, req, options); | |
} | |
this.getOptions(function(err,configuration) { | |
if ( err ) { | |
return this.error(err); | |
} | |
this.options = addDefaults(configuration); | |
handleAuthentication.call(this, req, options); | |
}.bind(this)); | |
}; | |
module.exports = Strategy; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment