Skip to content

Commit

Permalink
Merge 5b4b4bb into 3b9980f
Browse files Browse the repository at this point in the history
  • Loading branch information
sdbondi committed Nov 3, 2016
2 parents 3b9980f + 5b4b4bb commit 4de97eb
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 28 deletions.
9 changes: 8 additions & 1 deletion README.md
Expand Up @@ -50,6 +50,11 @@ This strategy takes an optional options hash before the function, e.g. `new Loca
The available options are:

* `usernameField` - Optional, defaults to 'username'

or

* `usernameFields` - Optional, defaults to ['username']

* `passwordField` - Optional, defaults to 'password'

Both fields define the name of the properties in the POST body that are sent to the server.
Expand All @@ -62,6 +67,8 @@ differently, options are available to change the defaults.

passport.use(new LocalStrategy({
usernameField: 'email',
// To allow multiple fields to be checked
// usernameFields: ['username', 'email', 'user[email]'],
passwordField: 'passwd',
session: false
},
Expand Down Expand Up @@ -98,7 +105,7 @@ For example, as route middleware in an [Express](http://expressjs.com/)
application:

```js
app.post('/login',
app.post('/login',
passport.authenticate('local', { failureRedirect: '/login' }),
function(req, res) {
res.redirect('/');
Expand Down
20 changes: 12 additions & 8 deletions lib/strategy.js
Expand Up @@ -45,10 +45,14 @@ function Strategy(options, verify) {
options = {};
}
if (!verify) { throw new TypeError('LocalStrategy requires a verify callback'); }

this._usernameField = options.usernameField || 'username';

var usernameFields = options.usernameFields || (
options.usernameField ? [options.usernameField] : undefined
);

this._usernameFields = usernameFields || ['username'];
this._passwordField = options.passwordField || 'password';

passport.Strategy.call(this);
this.name = 'local';
this._verify = verify;
Expand All @@ -68,21 +72,21 @@ util.inherits(Strategy, passport.Strategy);
*/
Strategy.prototype.authenticate = function(req, options) {
options = options || {};
var username = lookup(req.body, this._usernameField) || lookup(req.query, this._usernameField);
var username = lookup(req.body, this._usernameFields) || lookup(req.query, this._usernameFields);
var password = lookup(req.body, this._passwordField) || lookup(req.query, this._passwordField);

if (!username || !password) {
return this.fail({ message: options.badRequestMessage || 'Missing credentials' }, 400);
}

var self = this;

function verified(err, user, info) {
if (err) { return self.error(err); }
if (!user) { return self.fail(info); }
self.success(user, info);
}

try {
if (self._passReqToCallback) {
this._verify(req, username, password, verified);
Expand Down
25 changes: 17 additions & 8 deletions lib/utils.js
@@ -1,11 +1,20 @@
exports.lookup = function(obj, field) {
if (!obj) { return null; }
var chain = field.split(']').join('').split('[');
for (var i = 0, len = chain.length; i < len; i++) {
var prop = obj[chain[i]];
if (typeof(prop) === 'undefined') { return null; }
if (typeof(prop) !== 'object') { return prop; }
obj = prop;
exports.lookup = function(root, fields) {
if (!root) { return null; }

if (typeof fields === 'string') {
fields = [fields];
}

for (var i = 0; i < fields.length; i++) {
var obj = root;
var field = fields[i];
var chain = field.split(']').join('').split('[');
for (var j = 0, len = chain.length; j < len; j++) {
var prop = obj[chain[j]];
if (prop === null || prop === undefined) { break; }
if (typeof(prop) !== 'object') { return prop; }
obj = prop;
}
}
return null;
};
60 changes: 49 additions & 11 deletions test/strategy.fields.test.js
Expand Up @@ -6,18 +6,18 @@ var chai = require('chai')


describe('Strategy', function() {

describe('handling a request with valid credentials in body using custom field names', function() {
var strategy = new Strategy({ usernameField: 'userid', passwordField: 'passwd' }, function(username, password, done) {
if (username == 'johndoe' && password == 'secret') {
return done(null, { id: '1234' }, { scope: 'read' });
}
return done(null, false);
});

var user
, info;

before(function(done) {
chai.passport(strategy)
.success(function(u, i) {
Expand All @@ -32,29 +32,29 @@ describe('Strategy', function() {
})
.authenticate();
});

it('should supply user', function() {
expect(user).to.be.an.object;
expect(user.id).to.equal('1234');
});

it('should supply info', function() {
expect(info).to.be.an.object;
expect(info.scope).to.equal('read');
});
});

describe('handling a request with valid credentials in body using custom field names with object notation', function() {
var strategy = new Strategy({ usernameField: 'user[username]', passwordField: 'user[password]' }, function(username, password, done) {
if (username == 'johndoe' && password == 'secret') {
return done(null, { id: '1234' }, { scope: 'read' });
}
return done(null, false);
});

var user
, info;

before(function(done) {
chai.passport(strategy)
.success(function(u, i) {
Expand All @@ -70,16 +70,54 @@ describe('Strategy', function() {
})
.authenticate();
});

it('should supply user', function() {
expect(user).to.be.an.object;
expect(user.id).to.equal('1234');
});

it('should supply info', function() {
expect(info).to.be.an.object;
expect(info.scope).to.equal('read');
});
});


describe('handling a request with valid credentials in body using custom multiple field names with object notation', function() {
var strategy = new Strategy({ usernameFields: ['user[username]', 'user[email]'], passwordField: 'user[password]' }, function(username, password, done) {
if (username == 'johndoe@test.com' && password == 'secret') {
return done(null, { id: '1234' }, { scope: 'read' });
}
return done(null, false);
});

var user
, info;

before(function(done) {
chai.passport(strategy)
.success(function(u, i) {
user = u;
info = i;
done();
})
.req(function(req) {
req.body = {};
req.body.user = {};
req.body.user.email = 'johndoe@test.com';
req.body.user.password = 'secret';
})
.authenticate();
});

it('should supply user', function() {
expect(user).to.be.an.object;
expect(user.id).to.equal('1234');
});

it('should supply info', function() {
expect(info).to.be.an.object;
expect(info.scope).to.equal('read');
});
});

});

0 comments on commit 4de97eb

Please sign in to comment.