restify
Version:
REST framework
152 lines (123 loc) • 3.81 kB
JavaScript
// Copyright 2012 Mark Cavage, Inc. All rights reserved.
;
var httpSignature = require('http-signature');
var errors = require('restify-errors');
///--- Globals
var InvalidHeaderError = errors.InvalidHeaderError;
var OPTIONS = {
algorithms: [
'rsa-sha1',
'rsa-sha256',
'rsa-sha512',
'dsa-sha1',
'hmac-sha1',
'hmac-sha256',
'hmac-sha512'
]
};
///--- Helpers
function parseBasic(string) {
var decoded;
var index;
var pieces;
decoded = new Buffer(string, 'base64').toString('utf8');
if (!decoded) {
throw new InvalidHeaderError('Authorization header invalid');
}
index = decoded.indexOf(':');
if (index === -1) {
pieces = [decoded];
} else {
pieces = [decoded.slice(0, index), decoded.slice(index + 1)];
}
if (!pieces || typeof pieces[0] !== 'string') {
throw new InvalidHeaderError('Authorization header invalid');
}
// Allows for usernameless authentication
if (!pieces[0]) {
pieces[0] = null;
}
// Allows for passwordless authentication
if (!pieces[1]) {
pieces[1] = null;
}
return {
username: pieces[0],
password: pieces[1]
};
}
function parseSignature(request, options) {
var opts = options || {};
opts.algorithms = OPTIONS.algorithms;
try {
return httpSignature.parseRequest(request, options);
} catch (e) {
throw new InvalidHeaderError(
'Authorization header invalid: ' + e.message
);
}
}
/**
* Parses out the `Authorization` header as best restify can.
* Currently only HTTP Basic Auth and
* [HTTP Signature](https://github.com/joyent/node-http-signature)
* schemes are supported.
*
* @public
* @function authorizationParser
* @throws {InvalidArgumentError}
* @param {Object} [options] - an optional options object that is
* passed to http-signature
* @returns {Function} Handler
* @example
* <caption>
* Subsequent handlers will see `req.authorization`, which looks like above.
*
* `req.username` will also be set, and defaults to 'anonymous'. If the scheme
* is unrecognized, the only thing available in `req.authorization` will be
* `scheme` and `credentials` - it will be up to you to parse out the rest.
* </caption>
* {
* scheme: "<Basic|Signature|...>",
* credentials: "<Undecoded value of header>",
* basic: {
* username: $user
* password: $password
* }
* }
*/
function authorizationParser(options) {
function parseAuthorization(req, res, next) {
req.authorization = {};
req.username = 'anonymous';
if (!req.headers.authorization) {
return next();
}
var pieces = req.headers.authorization.split(' ', 2);
if (!pieces || pieces.length !== 2) {
var e = new InvalidHeaderError('BasicAuth content is invalid.');
return next(e);
}
req.authorization.scheme = pieces[0];
req.authorization.credentials = pieces[1];
try {
switch (pieces[0].toLowerCase()) {
case 'basic':
req.authorization.basic = parseBasic(pieces[1]);
req.username = req.authorization.basic.username;
break;
case 'signature':
req.authorization.signature = parseSignature(req, options);
req.username = req.authorization.signature.keyId;
break;
default:
break;
}
} catch (e2) {
return next(e2);
}
return next();
}
return parseAuthorization;
}
module.exports = authorizationParser;