/** * 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')); }); }); }; };