Permalink
Browse files

Initial commit for public release.

  • Loading branch information...
0 parents commit d48731bf82e73c03e9afb77bb94e7e888163aeab @jaredhanson committed Jun 22, 2012
@@ -0,0 +1,5 @@
+# Mac OS X
+.DS_Store
+# Node.js
+node_modules
+npm-debug.log
@@ -0,0 +1,15 @@
+# Project
+README.md
+Makefile
+docs/
+examples/
+test/
+
+# Mac OS X
+.DS_Store
+# Node.js
+.npmignore
+node_modules/
+npm-debug.log
+# Git
+.git*
20 LICENSE
@@ -0,0 +1,20 @@
+(The MIT License)
+
+Copyright (c) 2012 Jared Hanson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,19 @@
+NODE = node
+TEST = ./node_modules/.bin/vows
+TESTS ?= test/*-test.js test/**/*-test.js
+
+test:
+ @NODE_ENV=test NODE_PATH=lib $(TEST) $(TEST_FLAGS) $(TESTS)
+
+docs: docs/api.html
+
+docs/api.html: lib/oauthorize/*.js
+ dox \
+ --title oauthorize \
+ --desc "OAuth service provider toolkit for Node.js" \
+ $(shell find lib/oauthorize/* -type f) > $@
+
+docclean:
+ rm -f docs/*.{1,html}
+
+.PHONY: test docs docclean
@@ -0,0 +1,3 @@
+# OAuthorize
+
+More info soon. :)
@@ -0,0 +1,36 @@
+/**
+ * `AuthorizationError` error.
+ *
+ * @api public
+ */
+function AuthorizationError(message, code, status) {
+ if (!status) {
+ switch (code) {
+ case 'version_rejected': status = 400; break;
+ case 'parameter_absent': status = 400; break;
+ case 'parameter_rejected': status = 400; break;
+ case 'timestamp_refused': status = 400; break;
+ case 'nonce_used': status = 400; break;
+ case 'signature_method_rejected': status = 400; break;
+ case 'permission_denied': status = 403; break;
+ }
+ }
+
+ Error.call(this);
+ Error.captureStackTrace(this, arguments.callee);
+ this.name = 'AuthorizationError';
+ this.message = message || null;
+ this.code = code || 'token_rejected';
+ this.status = status || 401;
+};
+
+/**
+ * Inherit from `Error`.
+ */
+AuthorizationError.prototype.__proto__ = Error.prototype;
+
+
+/**
+ * Expose `AuthorizationError`.
+ */
+module.exports = AuthorizationError;
@@ -0,0 +1,22 @@
+/**
+ * `BadRequestError` error.
+ *
+ * @api public
+ */
+function BadRequestError(message) {
+ Error.call(this);
+ Error.captureStackTrace(this, arguments.callee);
+ this.name = 'BadRequestError';
+ this.message = message || null;
+};
+
+/**
+ * Inherit from `Error`.
+ */
+BadRequestError.prototype.__proto__ = Error.prototype;
+
+
+/**
+ * Expose `BadRequestError`.
+ */
+module.exports = BadRequestError;
@@ -0,0 +1,33 @@
+/**
+ * Module dependencies.
+ */
+var Server = require('./server')
+ , requestToken = require('./middleware/requestToken')
+ , accessToken = require('./middleware/accessToken')
+
+
+// expose createServer() as the module
+exports = module.exports = createServer;
+
+/**
+ * Create an OAuth service provider.
+ *
+ * @return {Server}
+ * @api public
+ */
+function createServer() {
+ var server = new Server();
+ return server;
+}
+
+/**
+ * Expose `.createServer()` as module method.
+ */
+exports.createServer = createServer;
+exports.createServiceProvider = createServer;
+
+/**
+ * Expose bundled middleware.
+ */
+exports.requestToken = requestToken;
+exports.accessToken = accessToken;
@@ -0,0 +1,81 @@
+/**
+ * Module dependencies.
+ */
+var utils = require('../utils')
+ , AuthorizationError = require('../errors/authorizationerror');
+
+
+/**
+ * Handle requests to obtain an access token.
+ *
+ * Assumptions:
+ *
+ * `req.authInfo` must be set on the request and contain `requestToken` and
+ * `verifier` properties. Due to the nature of OAuth, these parameters are
+ * transmitted along with authentication credentials and are parsed during that
+ * step, *prior* to this middleware being invoked.
+ *
+ * By design, this integrates with the `ConsumerStrategy` provided by
+ * [passport-http-oauth](https://github.com/jaredhanson/passport-http-oauth).
+ * That module is recommended for authentication; however, any middleware
+ * satisfying these assumptions is usable.
+ *
+ * References:
+ * - [Token Credentials](http://tools.ietf.org/html/rfc5849#section-2.3)
+ * - [Obtaining an Access Token](http://oauth.net/core/1.0a/#auth_step3)
+ * - [Obtaining an Access Token](http://oauth.net/core/1.0/#auth_step3)
+ *
+ * @param {Object} options
+ * @param {Function} issue
+ * @return {Function}
+ * @api public
+ */
+module.exports = function accessToken(options, issue) {
+ if (typeof options == 'function') {
+ issue = options;
+ options = {};
+ }
+ options = options || {};
+
+ if (!issue) throw new Error('OAuth accessToken middleware requires an issue function.');
+
+ var userProp = options.userProperty || 'user';
+
+ return function accessToken(req, res, next) {
+ if (!req.authInfo) { return next(new Error('authentication info not available')); }
+
+ var consumer = req[userProp]
+ , requestToken = req.authInfo.requestToken
+ , verifier = req.authInfo.verifier;
+
+ function issued(err, token, tokenSecret, params) {
+ if (err) { return next(err); }
+ if (!token) {
+ return next(new AuthorizationError('access token not issued', 'token_rejected'));
+ }
+
+ params = params || {};
+ params['oauth_token'] = token;
+ params['oauth_token_secret'] = tokenSecret;
+
+ // TODO: Implement support for other response formats, as described by
+ // (OAuth Extension for Response Data Format - Draft 1)[http://oauth.googlecode.com/svn/spec/ext/response_data_format/1.0/drafts/1/oauth_response_data_format_ext.html]
+
+ var fue = Object.keys(params).map(function(key) {
+ return utils.encode(key) + '=' + utils.encode(params[key]);
+ }).join('&');
+
+ res.setHeader('Content-Type', 'x-www-form-urlencoded');
+ res.setHeader('Cache-Control', 'no-store');
+ res.setHeader('Pragma', 'no-cache');
+ res.end(fue);
+ }
+
+ var arity = issue.length;
+ if (arity == 4) {
+ issue(consumer, requestToken, verifier, issued);
+ } else { // arity == 5
+ issue(consumer, requestToken, verifier, req.authInfo, issued);
+ }
+ }
+}
@@ -0,0 +1,81 @@
+/**
+ * Module dependencies.
+ */
+var url = require('url')
+ , utils = require('../utils')
+
+
+/**
+ * Handles errors encountered in OAuth endpoints.
+ *
+ * References:
+ * - [Problem Reporting](http://wiki.oauth.net/w/page/12238543/ProblemReporting)
+ *
+ * @param {Object} options
+ * @return {Function}
+ * @api public
+ */
+module.exports = function errorHandler(options) {
+ options = options || {};
+
+ var mode = options.mode || 'direct';
+ var realm = options.realm || 'Clients';
+
+ return function errorHandler(err, req, res, next) {
+
+ if (mode == 'direct') {
+ if (err.status) { res.statusCode = err.status; }
+ if (!res.statusCode || res.statusCode < 400) { res.statusCode = 500; }
+
+ // TODO: Implement support for `oauth_error_in_response_body` parameter.
+ // This will require re-parsing the `Authorization` header for OAuth
+ // params, which is best implemented as reusable oauthParser
+ // middleware.
+
+ var params = {};
+ params['oauth_problem'] = err.code || 'server_error';
+ if (err.message) { params['oauth_problem_advice'] = err.message; }
+
+ if (res.statusCode == 401 || res.statusCode == 403) {
+ var comps = { realm: realm };
+ utils.merge(comps, params);
+
+ var ac = Object.keys(comps).map(function(key) {
+ if (key === 'realm') { return 'realm="' + realm + '"'; }
+ return utils.encode(key) + '="' + utils.encode(comps[key]) + '"';
+ }).join(',');
+
+ res.setHeader('WWW-Authenticate', 'OAuth ' + ac);
+ }
+
+ // TODO: Implement support for other response formats, as described by
+ // (OAuth Extension for Response Data Format - Draft 1)[http://oauth.googlecode.com/svn/spec/ext/response_data_format/1.0/drafts/1/oauth_response_data_format_ext.html]
+
+ var fue = Object.keys(params).map(function(key) {
+ return utils.encode(key) + '=' + utils.encode(params[key]);
+ }).join('&');
+
+ res.setHeader('Content-Type', 'x-www-form-urlencoded');
+ return res.end(fue);
+
+ } else if (mode == 'indirect') {
+ // If a callbackURL is not being used by this transaction, or it has been
+ // explicitly set to `oob`, `next()` immediately into the application's
+ // error handler. This allows information to be rendered for display to
+ // the user as necessary.
+ if (!req.oauth || !req.oauth.callbackURL || req.oauth.callbackURL == 'oob') { return next(err); }
+
+ var callbackURL = req.oauth.callbackURL;
+ var parsed = url.parse(callbackURL, true);
+ delete parsed.search;
+ parsed.query['oauth_problem'] = err.code || 'server_error';
+ if (err.message) { parsed.query['oauth_problem_advice'] = err.message; }
+
+ var location = url.format(parsed);
+ return res.redirect(location);
+
+ } else {
+ return next(err);
+ }
+ }
+}
Oops, something went wrong.

0 comments on commit d48731b

Please sign in to comment.