diff --git a/CHANGES.md b/CHANGES.md index b99f770..563c9b2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,7 @@ ## Changes +* v0.6.0 + * Added option `credentialsLookup` that can be used eg. to add Basic Auth header parsing support. * v0.5.0 * Updated deps. ldapauth-fork update changes bind credentials handling to work better with falsy values needed in anonymous bind. * v0.4.0 diff --git a/README.md b/README.md index 7f8e802..28f7140 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ passport.use(new LdapStrategy({ * `tlsOptions`: Optional object with options accepted by Node.js [tls](http://nodejs.org/api/tls.html#tls_tls_connect_options_callback) module. * `usernameField`: Field name where the username is found, defaults to _username_ * `passwordField`: Field name where the password is found, defaults to _password_ +* `creadentialsLookup`: Optional, synchronous function that provides the login credentials from `req`. See [below](#credentials-lookup) for more. * `passReqToCallback`: When `true`, `req` is the first argument to the verify callback (default: `false`): passport.use(new LdapStrategy(..., function(req, user, done) { @@ -132,6 +133,18 @@ var opts = { }; ... ``` + +## `credentialsLookup` + +A synchronous function that receives the `req` object and returns an objec with keys `username` and `password` (or `name` and `pass`) can be provided. Note, that when this is provided the default lookup is not performed. This can be used to eg. enable basic auth header support: + +```javascript +var basicAuth = require('basic-auth'); +var ldapOpts = { + server: { ... }, + credentialsLookup: basicAuth +} +``` ## Asynchronous configuration retrieval diff --git a/lib/passport-ldapauth/strategy.js b/lib/passport-ldapauth/strategy.js index de7872f..faec28e 100644 --- a/lib/passport-ldapauth/strategy.js +++ b/lib/passport-ldapauth/strategy.js @@ -130,8 +130,18 @@ var handleAuthentication = function(req, options) { var username, password, ldap; 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 (typeof this.options.credentialsLookup === 'function') { + var credentials = this.options.credentialsLookup(req); + if (credentials != null) { + // name and pass as a courtesy for those who use basic-auth directly as + // they're likely the main user group. + username = credentials.username || credentials.name; + password = credentials.password || credentials.pass; + } + } else { + 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({message: options.badRequestMessage || 'Missing credentials'}, 400); @@ -199,12 +209,14 @@ Strategy.prototype.authenticate = function(req, options) { if ((typeof this.options === 'object') && (!this.getOptions)) { return handleAuthentication.call(this, req, options); } + var callback = function(err, configuration) { if (err) return this.fail(err); this.options = setDefaults(configuration); handleAuthentication.call(this, req, options); }; + // Added functionality: getOptions can accept now up to 2 parameters if (this.getOptions.length ===1) { // Accepts 1 parameter, backwards compatibility this.getOptions(callback.bind(this)); diff --git a/package.json b/package.json index 76e47bd..d2bb6f3 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "ldapauth-fork": "~2.5.0" }, "devDependencies": { + "basic-auth": "1.0.x", "body-parser": "1.15.x", "chai": "3.5.x", "express": "4.14.x", diff --git a/test/strategy-test.js b/test/strategy-test.js index 957156d..f925143 100644 --- a/test/strategy-test.js +++ b/test/strategy-test.js @@ -1,6 +1,7 @@ var should = require('chai').Should(), LdapStrategy = require('passport-ldapauth'), request = require('supertest'), + basicAuth = require('basic-auth'), ldapserver = require('./ldapserver'), appserver = require('./appserver'); @@ -208,6 +209,19 @@ describe("LDAP authentication strategy", function() { s.authenticate(req); }); }); + + it("should allow access with valid credentials in the header", function(cb) { + var OPTS = JSON.parse(JSON.stringify(BASE_OPTS)); + OPTS.credentialsLookup = basicAuth; + + start_servers(OPTS, BASE_TEST_OPTS)(function() { + request(expressapp) + .post('/login') + .set('Authorization', 'Basic dmFsaWQ6dmFsaWQ=') + .expect(200) + .end(cb); + }); + }); }); describe("with options as function", function() {