128 lines
4.7 KiB
JavaScript
128 lines
4.7 KiB
JavaScript
/**
|
|
* Module dependencies.
|
|
*/
|
|
var utils = require('../utils')
|
|
, AuthorizationError = require('../errors/authorizationerror')
|
|
, ForbiddenError = require('../errors/forbiddenerror');
|
|
|
|
|
|
/**
|
|
* Handle authorization decisions from resource owners.
|
|
*
|
|
* Obtaining authorization via OAuth 2.0 consists of a sequence of discrete
|
|
* steps. First, the client requests authorization from the user (in this case
|
|
* using an authorization server as an intermediary). The authorization server
|
|
* conducts an approval dialog with the user to obtain permission. After access
|
|
* has been allowed, a grant is issued to the client which can be exchanged for
|
|
* an access token.
|
|
*
|
|
* This middleware is used to process a user's decision about whether to allow
|
|
* or deny access. The client that initiated the authorization transaction will
|
|
* be sent a response, including a grant if access was allowed.
|
|
*
|
|
* The exact form of the grant will depend on the type requested by the client.
|
|
* The `server`'s response handling functions are used to issue the grant and
|
|
* send the response. An application can implement support for these types as
|
|
* necessary, including taking advantage of bundled grant middleware.
|
|
*
|
|
* Callbacks:
|
|
*
|
|
* An optional `parse` callback can be passed as an argument, for which the
|
|
* function signature is as follows:
|
|
*
|
|
* function(req, done) { ... }
|
|
*
|
|
* `req` is the request, which can be parsed for any additional parameters found
|
|
* in query as required by the service provider. `done` is a callback which
|
|
* must be invoked with the following signature:
|
|
*
|
|
* done(err, params);
|
|
*
|
|
* `params` are the additional parameters parsed from the request. These will
|
|
* be set on the transaction at `req.oauth2.res`. If an error occurs, `done`
|
|
* should be invoked with `err` set in idomatic Node.js fashion.
|
|
*
|
|
* Options:
|
|
*
|
|
* cancelField name of field that is set if user denied access (default: 'cancel')
|
|
* userProperty property of `req` which contains the authenticated user (default: 'user')
|
|
* sessionKey key under which transactions are stored in the session (default: 'authorize')
|
|
*
|
|
* Examples:
|
|
*
|
|
* app.post('/dialog/authorize/decision',
|
|
* login.ensureLoggedIn(),
|
|
* server.decision());
|
|
*
|
|
* app.post('/dialog/authorize/decision',
|
|
* login.ensureLoggedIn(),
|
|
* server.decision(function(req, done) {
|
|
* return done(null, { scope: req.scope })
|
|
* }));
|
|
*
|
|
* @param {Server} server
|
|
* @param {Object} options
|
|
* @param {Function} parse
|
|
* @return {Function}
|
|
* @api protected
|
|
*/
|
|
module.exports = function(server, options, parse, complete) {
|
|
if (typeof options == 'function') {
|
|
complete = parse;
|
|
parse = options;
|
|
options = undefined;
|
|
}
|
|
options = options || {};
|
|
parse = parse || function(req, done) { return done(); };
|
|
|
|
if (!server) { throw new TypeError('oauth2orize.decision middleware requires a server argument'); }
|
|
|
|
var cancelField = options.cancelField || 'cancel'
|
|
, userProperty = options.userProperty || 'user';
|
|
|
|
return function decision(req, res, next) {
|
|
if (!req.body) { return next(new Error('OAuth2orize requires body parsing. Did you forget app.use(express.bodyParser())?')); }
|
|
if (!req.oauth2) { return next(new Error('OAuth2orize requires transaction support. Did you forget oauth2orize.transactionLoader(...)?')); }
|
|
|
|
parse(req, function(err, ares, locals) {
|
|
if (err) { return next(err); }
|
|
|
|
var tid = req.oauth2.transactionID;
|
|
req.oauth2.user = req[userProperty];
|
|
req.oauth2.res = ares || {};
|
|
if (locals) {
|
|
req.oauth2.locals = req.oauth2.locals || {};
|
|
utils.merge(req.oauth2.locals, locals);
|
|
}
|
|
|
|
if (req.oauth2.res.allow === undefined) {
|
|
if (!req.body[cancelField]) { req.oauth2.res.allow = true; }
|
|
else { req.oauth2.res.allow = false; }
|
|
}
|
|
|
|
// proxy end() to delete the transaction
|
|
var end = res.end;
|
|
res.end = function(chunk, encoding) {
|
|
if (server._txnStore.legacy == true) {
|
|
server._txnStore.remove(options, req, req.oauth2.transactionID, function noop(){});
|
|
} else {
|
|
server._txnStore.remove(req, req.oauth2.transactionID, function noop(){});
|
|
}
|
|
|
|
res.end = end;
|
|
res.end(chunk, encoding);
|
|
};
|
|
req.oauth2._endProxied = true;
|
|
|
|
function completing(cb) {
|
|
if (!complete) { return cb(); }
|
|
complete(req, req.oauth2, cb);
|
|
}
|
|
|
|
server._respond(req.oauth2, res, completing, function(err) {
|
|
if (err) { return next(err); }
|
|
return next(new AuthorizationError('Unsupported response type: ' + req.oauth2.req.type, 'unsupported_response_type'));
|
|
});
|
|
});
|
|
};
|
|
};
|