Skip to content

Commit

Permalink
Merge db99684 into aa74207
Browse files Browse the repository at this point in the history
  • Loading branch information
kara-ryli committed Oct 16, 2015
2 parents aa74207 + db99684 commit d903c26
Showing 1 changed file with 165 additions and 147 deletions.
312 changes: 165 additions & 147 deletions lib/middleware/authenticate.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,20 @@ var http = require('http')
* otherwise. An optional `info` argument will be passed, containing additional
* details provided by the strategy's verify callback.
*
* app.get('/protected', function(req, res, next) {
* passport.authenticate('local', function(err, user, info) {
* if (err) { return next(err) }
* if (!user) { return res.redirect('/signin') }
* res.redirect('/account');
* })(req, res, next);
* });
* app.get('/protected',
* passport.authenticate('local',
* function(err, user, info, status, req, res, next) {
* if (err) { return next(err) }
* if (!user) { return res.redirect('/signin') }
* res.redirect('/account');
* }
* )
* );
*
* Note that if a callback is supplied, it becomes the application's
* responsibility to log-in the user, establish a session, and otherwise perform
* the desired operations.
* Note that if a callback is supplied, all other passport response handling
* is bypassed, and all options are ignored. This feature should be reserved
* for performance-critical applications where the base passport options are
* undesireable.
*
* Examples:
*
Expand All @@ -59,7 +62,152 @@ module.exports = function authenticate(passport, name, options, callback) {
options = {};
}
options = options || {};

function failed(challenges, statuses, req, res, next) {
// Strategies are ordered by priority. For the purpose of flashing a
// message, the first failure will be displayed.
var msg;
var failures = 1;
var challenge = challenges;
var status = statuses;
if (Array.isArray(challenges)) {
failures = challenge.length;
challenge = challenges[0];
status = statuses[0];
} else if (!challenge) {
challenge = {};
}

if (options.failureFlash) {
var flash = options.failureFlash;
if (typeof flash == 'string') {
flash = { type: 'error', message: flash };
}
flash.type = flash.type || 'error';

var type = flash.type || challenge.type || 'error';
msg = flash.message || challenge.message || challenge;
if (typeof msg == 'string') {
req.flash(type, msg);
}
}
if (options.failureMessage) {
msg = options.failureMessage;
if (typeof msg == 'boolean') {
msg = challenge.message || challenge;
}
if (typeof msg == 'string') {
req.session.messages = req.session.messages || [];
req.session.messages.push(msg);
}
}
if (options.failureRedirect) {
return res.redirect(options.failureRedirect);
}

// When failure handling is not delegated to the application, the default
// is to respond with 401 Unauthorized. Note that the WWW-Authenticate
// header will be set according to the strategies in use (see
// actions#fail). If multiple strategies failed, each of their challenges
// will be included in the response.
var rchallenge = typeof challenge == 'string' ? [challenge] : [];
var rstatus = status;

// starting at j = 1 because we've handled the first case already and
// if failures = 1, statuses is not an array.
for (var j = 1, len = failures; j < len; j++) {

rstatus = rstatus || statuses[j];
if (typeof challenges[j] == 'string') {
rchallenge.push(challenges[j]);
}
}

res.statusCode = rstatus || 401;
if (res.statusCode == 401 && rchallenge.length) {
res.setHeader('WWW-Authenticate', rchallenge);
}
if (options.failWithError) {
return next(new AuthenticationError(http.STATUS_CODES[res.statusCode], rstatus));
}
res.end(http.STATUS_CODES[res.statusCode]);
}

function succeeded(user, info, req, res, next) {
info = info || {};
var msg;

if (options.successFlash) {
var flash = options.successFlash;
if (typeof flash == 'string') {
flash = { type: 'success', message: flash };
}
flash.type = flash.type || 'success';

var type = flash.type || info.type || 'success';
msg = flash.message || info.message || info;
if (typeof msg == 'string') {
req.flash(type, msg);
}
}
if (options.successMessage) {
msg = options.successMessage;
if (typeof msg == 'boolean') {
msg = info.message || info;
}
if (typeof msg == 'string') {
req.session.messages = req.session.messages || [];
req.session.messages.push(msg);
}
}
if (options.assignProperty) {
req[options.assignProperty] = user;
return next();
}

req.logIn(user, options, function(err) {
if (err) { return next(err); }

function complete() {
if (options.successReturnToOrRedirect) {
var url = options.successReturnToOrRedirect;
if (req.session && req.session.returnTo) {
url = req.session.returnTo;
delete req.session.returnTo;
}
return res.redirect(url);
}
if (options.successRedirect) {
return res.redirect(options.successRedirect);
}
next();
}

if (options.authInfo !== false) {
passport.transformAuthInfo(info, req, function(err, tinfo) {
if (err) { return next(err); }
req.authInfo = tinfo;
complete();
});
} else {
complete();
}
});
}
function defaultCallback(err, user, info, status, req, res, next) {
if (err) {
next(err);
} else if (user) {
succeeded(user, info, req, res, next);
} else {
failed(info, status, req, res, next);
}
}

if (typeof callback != 'function') {
callback = defaultCallback;
}

var multi = true;

// Cast `name` to an array, allowing authentication to pass through a chain of
Expand All @@ -82,76 +230,12 @@ module.exports = function authenticate(passport, name, options, callback) {
var failures = [];

function allFailed() {
if (callback) {
if (!multi) {
return callback(null, false, failures[0].challenge, failures[0].status);
} else {
var challenges = failures.map(function(f) { return f.challenge; });
var statuses = failures.map(function(f) { return f.status; });
return callback(null, false, challenges, statuses);
}
}

// Strategies are ordered by priority. For the purpose of flashing a
// message, the first failure will be displayed.
var failure = failures[0] || {}
, challenge = failure.challenge || {}
, msg;

if (options.failureFlash) {
var flash = options.failureFlash;
if (typeof flash == 'string') {
flash = { type: 'error', message: flash };
}
flash.type = flash.type || 'error';

var type = flash.type || challenge.type || 'error';
msg = flash.message || challenge.message || challenge;
if (typeof msg == 'string') {
req.flash(type, msg);
}
}
if (options.failureMessage) {
msg = options.failureMessage;
if (typeof msg == 'boolean') {
msg = challenge.message || challenge;
}
if (typeof msg == 'string') {
req.session.messages = req.session.messages || [];
req.session.messages.push(msg);
}
}
if (options.failureRedirect) {
return res.redirect(options.failureRedirect);
}

// When failure handling is not delegated to the application, the default
// is to respond with 401 Unauthorized. Note that the WWW-Authenticate
// header will be set according to the strategies in use (see
// actions#fail). If multiple strategies failed, each of their challenges
// will be included in the response.
var rchallenge = []
, rstatus, status;

for (var j = 0, len = failures.length; j < len; j++) {
failure = failures[j];
challenge = failure.challenge;
status = failure.status;

rstatus = rstatus || status;
if (typeof challenge == 'string') {
rchallenge.push(challenge);
}
}

res.statusCode = rstatus || 401;
if (res.statusCode == 401 && rchallenge.length) {
res.setHeader('WWW-Authenticate', rchallenge);
}
if (options.failWithError) {
return next(new AuthenticationError(http.STATUS_CODES[res.statusCode], rstatus));
if (multi) {
var challenges = failures.map(function(f) { return f.challenge; });
var statuses = failures.map(function(f) { return f.status; });
return callback(null, false, challenges, statuses, req, res, next);
}
res.end(http.STATUS_CODES[res.statusCode]);
callback(null, false, failures[0].challenge, failures[0].status, req, res, next);
}

(function attempt(i) {
Expand Down Expand Up @@ -190,69 +274,7 @@ module.exports = function authenticate(passport, name, options, callback) {
* @api public
*/
strategy.success = function(user, info) {
if (callback) {
return callback(null, user, info);
}

info = info || {};
var msg;

if (options.successFlash) {
var flash = options.successFlash;
if (typeof flash == 'string') {
flash = { type: 'success', message: flash };
}
flash.type = flash.type || 'success';

var type = flash.type || info.type || 'success';
msg = flash.message || info.message || info;
if (typeof msg == 'string') {
req.flash(type, msg);
}
}
if (options.successMessage) {
msg = options.successMessage;
if (typeof msg == 'boolean') {
msg = info.message || info;
}
if (typeof msg == 'string') {
req.session.messages = req.session.messages || [];
req.session.messages.push(msg);
}
}
if (options.assignProperty) {
req[options.assignProperty] = user;
return next();
}

req.logIn(user, options, function(err) {
if (err) { return next(err); }

function complete() {
if (options.successReturnToOrRedirect) {
var url = options.successReturnToOrRedirect;
if (req.session && req.session.returnTo) {
url = req.session.returnTo;
delete req.session.returnTo;
}
return res.redirect(url);
}
if (options.successRedirect) {
return res.redirect(options.successRedirect);
}
next();
}

if (options.authInfo !== false) {
passport.transformAuthInfo(info, req, function(err, tinfo) {
if (err) { return next(err); }
req.authInfo = tinfo;
complete();
});
} else {
complete();
}
});
callback(null, user, info, null, req, res, next);
};

/**
Expand Down Expand Up @@ -329,11 +351,7 @@ module.exports = function authenticate(passport, name, options, callback) {
* @api public
*/
strategy.error = function(err) {
if (callback) {
return callback(err);
}

next(err);
callback(err, null, null, null, req, res, next);
};

// ----- END STRATEGY AUGMENTATION -----
Expand Down

0 comments on commit d903c26

Please sign in to comment.