Permalink
Browse files

Initial commit.

  • Loading branch information...
0 parents commit 83ec9f932d0f74656e46fe26151975750bfeb638 @jaredhanson committed Oct 30, 2011
Showing with 396 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. +8 −0 .npmignore
  3. +20 −0 LICENSE
  4. +19 −0 Makefile
  5. +30 −0 README.md
  6. +15 −0 lib/passport-http-bearer/index.js
  7. +76 −0 lib/passport-http-bearer/strategy.js
  8. +16 −0 package.json
  9. +15 −0 test/index-test.js
  10. +195 −0 test/strategy-test.js
2 .gitignore
@@ -0,0 +1,2 @@
+.DS_Store
+node_modules
8 .npmignore
@@ -0,0 +1,8 @@
+*.md
+.DS_Store
+.git*
+Makefile
+docs/
+examples/
+support/
+test/
20 LICENSE
@@ -0,0 +1,20 @@
+(The MIT License)
+
+Copyright (c) 2011 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.
19 Makefile
@@ -0,0 +1,19 @@
+NODE = node
+TEST = vows
+TESTS ?= test/*-test.js
+
+test:
+ @NODE_ENV=test NODE_PATH=lib $(TEST) $(TEST_FLAGS) $(TESTS)
+
+docs: docs/api.html
+
+docs/api.html: lib/passport-http-bearer/*.js
+ dox \
+ --title Passport-HTTP-Bearer \
+ --desc "HTTP Bearer authentication strategy for Passport" \
+ $(shell find lib/passport-http-bearer/* -type f) > $@
+
+docclean:
+ rm -f docs/*.{1,html}
+
+.PHONY: test docs docclean
30 README.md
@@ -0,0 +1,30 @@
+# Passport-HTTP-Bearer
+
+HTTP Bearer authentication strategy for [Passport](https://github.com/jaredhanson/passport).
+
+## Credits
+
+ - [Jared Hanson](http://github.com/jaredhanson)
+
+## License
+
+(The MIT License)
+
+Copyright (c) 2011 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.
15 lib/passport-http-bearer/index.js
@@ -0,0 +1,15 @@
+/**
+ * Module dependencies.
+ */
+var Strategy = require('./strategy');
+
+
+/**
+ * Framework version.
+ */
+exports.version = '0.1.0';
+
+/**
+ * Expose constructors.
+ */
+exports.Strategy = Strategy;
76 lib/passport-http-bearer/strategy.js
@@ -0,0 +1,76 @@
+/**
+ * Module dependencies.
+ */
+var passport = require('passport')
+ , util = require('util');
+
+function Strategy(options, validate) {
+ if (typeof options == 'function') {
+ validate = options;
+ options = {};
+ }
+ if (!validate) throw new Error('HTTP Bearer authentication strategy requires a validate function');
+
+ passport.Strategy.call(this);
+ this.name = 'bearer';
+ this._validate = validate;
+ this._realm = options.realm || 'Users';
+}
+
+/**
+ * Inherit from `passport.Strategy`.
+ */
+util.inherits(Strategy, passport.Strategy);
+
+/**
+ * Authenticate request based on the contents of a HTTP Bearer authorization
+ * header, body parameter, or query parameter.
+ *
+ * @param {Object} req
+ * @api protected
+ */
+Strategy.prototype.authenticate = function(req) {
+ var token = undefined;
+
+ if (req.headers && req.headers['authorization']) {
+ var parts = req.headers['authorization'].split(' ');
+ if (parts.length == 2) {
+ var scheme = parts[0]
+ , credentials = parts[1];
+
+ if (/Bearer/i.test(scheme)) {
+ token = credentials;
+ }
+ }
+ }
+ else if (req.body && req.body['access_token']) {
+ token = req.body['access_token'];
+ }
+ else if (req.query && req.query['access_token']) {
+ token = req.query['access_token'];
+ }
+
+ if (!token) { return this.fail(this._challenge()); }
+
+ var self = this;
+ this._validate(token, function(err, user) {
+ if (err) { return self.error(err); }
+ if (!user) { return self.fail(self._challenge()); }
+ self.success(user);
+ });
+}
+
+/**
+ * Authentication challenge.
+ *
+ * @api private
+ */
+Strategy.prototype._challenge = function() {
+ return 'Bearer realm="' + this._realm + '"';
+}
+
+
+/**
+ * Expose `Strategy`.
+ */
+module.exports = Strategy;
16 package.json
@@ -0,0 +1,16 @@
+{
+ "name": "passport-http-bearer",
+ "version": "0.1.0",
+ "description": "HTTP Bearer authentication strategy for Passport.",
+ "author": "Jared Hanson <jaredhanson@gmail.com> (http://www.jaredhanson.net/)",
+ "repository": {
+ "type": "git",
+ "url": "http://github.com/jaredhanson/passport-http-bearer.git"
+ },
+ "main": "./lib/passport-http-bearer",
+ "dependencies": {
+ "passport": ">= 0.1.2"
+ },
+ "engines": { "node": ">= 0.4.0" },
+ "keywords": ["passport", "http", "bearer", "authn", "authentication"]
+}
15 test/index-test.js
@@ -0,0 +1,15 @@
+var vows = require('vows');
+var assert = require('assert');
+var util = require('util');
+var bearer = require('passport-http-bearer');
+
+
+vows.describe('passport-http-bearer').addBatch({
+
+ 'module': {
+ 'should report a version': function (x) {
+ assert.isString(bearer.version);
+ },
+ },
+
+}).export(module);
195 test/strategy-test.js
@@ -0,0 +1,195 @@
+var vows = require('vows');
+var assert = require('assert');
+var util = require('util');
+var BearerStrategy = require('passport-http-bearer/strategy');
+
+
+vows.describe('BearerStrategy').addBatch({
+
+ 'strategy': {
+ topic: function() {
+ return new BearerStrategy(function() {});
+ },
+
+ 'should be named bearer': function (strategy) {
+ assert.equal(strategy.name, 'bearer');
+ },
+ },
+
+ 'strategy handling a valid request with authorization header': {
+ topic: function() {
+ var strategy = new BearerStrategy(function(token, done) {
+ done(null, { token: token });
+ });
+ return strategy;
+ },
+
+ 'after augmenting with actions': {
+ topic: function(strategy) {
+ var self = this;
+ var req = {};
+ strategy.success = function(user) {
+ self.callback(null, user);
+ }
+ strategy.fail = function() {
+ self.callback(new Error('should not be called'));
+ }
+
+ req.headers = {};
+ req.headers.authorization = 'Bearer vF9dft4qmT';
+ process.nextTick(function () {
+ strategy.authenticate(req);
+ });
+ },
+
+ 'should not generate an error' : function(err, user) {
+ assert.isNull(err);
+ },
+ 'should authenticate' : function(err, user) {
+ assert.equal(user.token, 'vF9dft4qmT');
+ },
+ },
+ },
+
+ 'strategy handling a valid request with form-encoded body': {
+ topic: function() {
+ var strategy = new BearerStrategy(function(token, done) {
+ done(null, { token: token });
+ });
+ return strategy;
+ },
+
+ 'after augmenting with actions': {
+ topic: function(strategy) {
+ var self = this;
+ var req = {};
+ strategy.success = function(user) {
+ self.callback(null, user);
+ }
+ strategy.fail = function() {
+ self.callback(new Error('should not be called'));
+ }
+
+ req.body = {};
+ req.body.access_token = 'vF9dft4qmT';
+ process.nextTick(function () {
+ strategy.authenticate(req);
+ });
+ },
+
+ 'should not generate an error' : function(err, user) {
+ assert.isNull(err);
+ },
+ 'should authenticate' : function(err, user) {
+ assert.equal(user.token, 'vF9dft4qmT');
+ },
+ },
+ },
+
+ 'strategy handling a valid request with URI query': {
+ topic: function() {
+ var strategy = new BearerStrategy(function(token, done) {
+ done(null, { token: token });
+ });
+ return strategy;
+ },
+
+ 'after augmenting with actions': {
+ topic: function(strategy) {
+ var self = this;
+ var req = {};
+ strategy.success = function(user) {
+ self.callback(null, user);
+ }
+ strategy.fail = function() {
+ self.callback(new Error('should not be called'));
+ }
+
+ req.query = {};
+ req.query.access_token = 'vF9dft4qmT';
+ process.nextTick(function () {
+ strategy.authenticate(req);
+ });
+ },
+
+ 'should not generate an error' : function(err, user) {
+ assert.isNull(err);
+ },
+ 'should authenticate' : function(err, user) {
+ assert.equal(user.token, 'vF9dft4qmT');
+ },
+ },
+ },
+
+ 'strategy handling a request without authorization credentials': {
+ topic: function() {
+ var strategy = new BearerStrategy(function(token, done) {
+ done(null, { token: token });
+ });
+ return strategy;
+ },
+
+ 'after augmenting with actions': {
+ topic: function(strategy) {
+ var self = this;
+ var req = {};
+ strategy.success = function(user) {
+ self.callback(new Error('should not be called'));
+ }
+ strategy.fail = function(challenge) {
+ self.callback(null, challenge);
+ }
+
+ process.nextTick(function () {
+ strategy.authenticate(req);
+ });
+ },
+
+ 'should fail authentication with challenge' : function(err, challenge) {
+ // fail action was called, resulting in test callback
+ assert.isNull(err);
+ assert.equal(challenge, 'Bearer realm="Users"');
+ },
+ },
+ },
+
+ 'strategy handling a request without authorization credentials and realm option set': {
+ topic: function() {
+ var strategy = new BearerStrategy({ realm: 'Administrators' },
+ function(token, done) {
+ done(null, { token: token });
+ });
+ return strategy;
+ },
+
+ 'after augmenting with actions': {
+ topic: function(strategy) {
+ var self = this;
+ var req = {};
+ strategy.success = function(user) {
+ self.callback(new Error('should not be called'));
+ }
+ strategy.fail = function(challenge) {
+ self.callback(null, challenge);
+ }
+
+ process.nextTick(function () {
+ strategy.authenticate(req);
+ });
+ },
+
+ 'should fail authentication with challenge' : function(err, challenge) {
+ // fail action was called, resulting in test callback
+ assert.isNull(err);
+ assert.equal(challenge, 'Bearer realm="Administrators"');
+ },
+ },
+ },
+
+ 'strategy constructed without a validate callback': {
+ 'should throw an error': function (strategy) {
+ assert.throws(function() { new BearerStrategy() });
+ },
+ },
+
+}).export(module);

0 comments on commit 83ec9f9

Please sign in to comment.