├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── examples └── express3 │ ├── README.md │ ├── app.js │ ├── package.json │ └── views │ ├── account.ejs │ ├── index.ejs │ ├── layout.ejs │ └── login.ejs ├── lib └── passport-localapikey │ ├── errors │ └── badrequesterror.js │ ├── index.js │ └── strategy.js ├── package.json └── test ├── index-test.js └── strategy-test.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.md 2 | .DS_Store 3 | .git* 4 | Makefile 5 | docs/ 6 | examples/ 7 | support/ 8 | test/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: "node_js" 2 | node_js: 3 | - 0.8 4 | deploy: 5 | provider: npm 6 | api_key: "ZixErx27oTHZk83keqzc" 7 | on: 8 | tags: true 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2011 Jared Hanson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | NODE = node 2 | TEST = ./node_modules/.bin/vows 3 | TESTS ?= test/*-test.js 4 | 5 | test: 6 | @NODE_ENV=test NODE_PATH=lib $(TEST) $(TEST_FLAGS) $(TESTS) 7 | 8 | docs: docs/api.html 9 | 10 | docs/api.html: lib/passport-localapikey/*.js 11 | dox \ 12 | --title Passport-Localapikey \ 13 | --desc "Local apikey authentication strategy for Passport" \ 14 | $(shell find lib/passport-localapikey/* -type f) > $@ 15 | 16 | docclean: 17 | rm -f docs/*.{1,html} 18 | 19 | .PHONY: test docs docclean -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Passport-LocalAPIKey 2 | 3 | [Passport](http://passportjs.org/) strategy for authenticating with a apikey. 4 | 5 | This module lets you authenticate using a apikey in your Node.js 6 | applications which is used to build rest apis.By plugging into Passport, local apikey authentication can be easily and 7 | unobtrusively integrated into any application or framework that supports 8 | [Connect](http://www.senchalabs.org/connect/)-style middleware, including 9 | [Express](http://expressjs.com/). 10 | 11 | ## Installation 12 | 13 | $ npm install passport-localapikey 14 | 15 | ## Usage 16 | 17 | #### Configure Strategy 18 | 19 | The local api key authentication strategy authenticates users using a apikey. 20 | The strategy requires a `verify` callback, which accepts these 21 | credentials and calls `done` providing a user. 22 | 23 | passport.use(new LocalAPIKeyStrategy( 24 | function(apikey, done) { 25 | User.findOne({ apikey: apikey }, function (err, user) { 26 | if (err) { return done(err); } 27 | if (!user) { return done(null, false); } 28 | return done(null, user); 29 | }); 30 | } 31 | )); 32 | 33 | #### Authenticate Requests 34 | 35 | Use `passport.authenticate()`, specifying the `'localapikey'` strategy, to 36 | authenticate requests. 37 | 38 | For example, as route middleware in an [Express](http://expressjs.com/) 39 | application: 40 | 41 | app.post('/api/authenticate', 42 | passport.authenticate('localapikey', { session: false,failureRedirect: '/api/unauthorized' }), 43 | function(req, res) { 44 | res.json({ message: "Authenticated" }) 45 | }); 46 | 47 | ## Examples 48 | 49 | curl -v -d "apikey=asdasjsdgfjkjhg" http://127.0.0.1:3000/api/authenticate 50 | 51 | ## Tests 52 | 53 | $ npm install --dev 54 | $ make test 55 | 56 | [![Build Status](https://secure.travis-ci.org/cholalabs/passport-localapikey.png)](http://travis-ci.org/cholalabs/passport-localapikey) 57 | 58 | ## Credits 59 | 60 | - [Sudhakar Mani](http://twitter.com/sudhakarmani) 61 | 62 | ## License 63 | 64 | (The MIT License) 65 | 66 | Copyright (c) 2012 Sudhakar Mani 67 | 68 | Permission is hereby granted, free of charge, to any person obtaining a copy of 69 | this software and associated documentation files (the "Software"), to deal in 70 | the Software without restriction, including without limitation the rights to 71 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 72 | the Software, and to permit persons to whom the Software is furnished to do so, 73 | subject to the following conditions: 74 | 75 | The above copyright notice and this permission notice shall be included in all 76 | copies or substantial portions of the Software. 77 | 78 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 79 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 80 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 81 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 82 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 83 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 84 | -------------------------------------------------------------------------------- /examples/express3/README.md: -------------------------------------------------------------------------------- 1 | #test 2 | -------------------------------------------------------------------------------- /examples/express3/app.js: -------------------------------------------------------------------------------- 1 | var express = require('express') 2 | , passport = require('passport') 3 | , flash = require('connect-flash') 4 | , util = require('util') 5 | , LocalStrategy = require('passport-localapikey').Strategy; 6 | 7 | 8 | var users = [ 9 | { id: 1, username: 'bob', password: 'secret', email: 'bob@example.com',apikey: 'asdasjsdgfjkjhg' } 10 | , { id: 2, username: 'joe', password: 'birthday', email: 'joe@example.com',apikey: 'gfsdgsfgsfg' } 11 | ]; 12 | 13 | function findById(id, fn) { 14 | var idx = id - 1; 15 | if (users[idx]) { 16 | fn(null, users[idx]); 17 | } else { 18 | fn(new Error('User ' + id + ' does not exist')); 19 | } 20 | } 21 | 22 | function findByUsername(username, fn) { 23 | for (var i = 0, len = users.length; i < len; i++) { 24 | var user = users[i]; 25 | if (user.username === username) { 26 | return fn(null, user); 27 | } 28 | } 29 | return fn(null, null); 30 | } 31 | 32 | 33 | function findByApiKey(apikey, fn) { 34 | for (var i = 0, len = users.length; i < len; i++) { 35 | var user = users[i]; 36 | if (user.apikey === apikey) { 37 | return fn(null, user); 38 | } 39 | } 40 | return fn(null, null); 41 | } 42 | 43 | 44 | 45 | 46 | // Passport session setup. 47 | // To support persistent login sessions, Passport needs to be able to 48 | // serialize users into and deserialize users out of the session. Typically, 49 | // this will be as simple as storing the user ID when serializing, and finding 50 | // the user by ID when deserializing. 51 | passport.serializeUser(function(user, done) { 52 | done(null, user.id); 53 | }); 54 | 55 | passport.deserializeUser(function(id, done) { 56 | findById(id, function (err, user) { 57 | done(err, user); 58 | }); 59 | }); 60 | 61 | 62 | // Use the LocalStrategy within Passport. 63 | // Strategies in passport require a `verify` function, which accept 64 | // credentials (in this case, a username and password), and invoke a callback 65 | // with a user object. In the real world, this would query a database; 66 | // however, in this example we are using a baked-in set of users. 67 | passport.use(new LocalStrategy( 68 | function(apikey, done) { 69 | // asynchronous verification, for effect... 70 | process.nextTick(function () { 71 | 72 | // Find the user by username. If there is no user with the given 73 | // username, or the password is not correct, set the user to `false` to 74 | // indicate failure and set a flash message. Otherwise, return the 75 | // authenticated `user`. 76 | findByApiKey(apikey, function(err, user) { 77 | if (err) { return done(err); } 78 | if (!user) { return done(null, false, { message: 'Unknown apikey : ' + apikey }); } 79 | // if (user.password != password) { return done(null, false, { message: 'Invalid password' }); } 80 | return done(null, user); 81 | }) 82 | }); 83 | } 84 | )); 85 | 86 | 87 | 88 | 89 | var app = express(); 90 | 91 | // configure Express 92 | app.configure(function() { 93 | app.set('views', __dirname + '/views'); 94 | app.set('view engine', 'ejs'); 95 | app.engine('ejs', require('ejs-locals')); 96 | app.use(express.logger()); 97 | app.use(express.cookieParser()); 98 | app.use(express.bodyParser()); 99 | app.use(express.methodOverride()); 100 | app.use(express.session({ secret: 'keyboard cat' })); 101 | app.use(flash()); 102 | // Initialize Passport! Also use passport.session() middleware, to support 103 | // persistent login sessions (recommended). 104 | app.use(passport.initialize()); 105 | app.use(passport.session()); 106 | app.use(app.router); 107 | app.use(express.static(__dirname + '/../../public')); 108 | }); 109 | 110 | 111 | app.get('/', function(req, res){ 112 | res.json({ message: "Authenticated" }) 113 | }); 114 | 115 | app.get('/api/account', ensureAuthenticated, function(req, res){ 116 | res.json({ message: "Authenticated" }) 117 | }); 118 | 119 | app.get('/api/unauthorized', function(req, res){ 120 | res.json({ message: "Authentication Error" }) 121 | }); 122 | 123 | // POST /login 124 | // Use passport.authenticate() as route middleware to authenticate the 125 | // request. If authentication fails, the user will be redirected back to the 126 | // login page. Otherwise, the primary route function function will be called, 127 | // which, in this example, will redirect the user to the home page. 128 | // 129 | // curl -v -d "apikey=asdasjsdgfjkjhg" http://127.0.0.1:3000/api/authenticate 130 | app.post('/api/authenticate', 131 | passport.authenticate('localapikey', { failureRedirect: '/api/unauthorized', failureFlash: true }), 132 | function(req, res) { 133 | res.json({ message: "Authenticated" }) 134 | }); 135 | 136 | // POST /login 137 | // This is an alternative implementation that uses a custom callback to 138 | // acheive the same functionality. 139 | /* 140 | app.post('/login', function(req, res, next) { 141 | passport.authenticate('local', function(err, user, info) { 142 | if (err) { return next(err) } 143 | if (!user) { 144 | req.flash('error', info.message); 145 | return res.redirect('/login') 146 | } 147 | req.logIn(user, function(err) { 148 | if (err) { return next(err); } 149 | return res.redirect('/users/' + user.username); 150 | }); 151 | })(req, res, next); 152 | }); 153 | */ 154 | 155 | app.get('/logout', function(req, res){ 156 | req.logout(); 157 | res.redirect('/'); 158 | }); 159 | 160 | app.listen(3000); 161 | 162 | console.log("Server running on port 3000"); 163 | 164 | // Simple route middleware to ensure user is authenticated. 165 | // Use this route middleware on any resource that needs to be protected. If 166 | // the request is authenticated (typically via a persistent login session), 167 | // the request will proceed. Otherwise, the user will be redirected to the 168 | // login page. 169 | function ensureAuthenticated(req, res, next) { 170 | if (req.isAuthenticated()) { return next(); } 171 | res.redirect('/api/unauthorized') 172 | } 173 | -------------------------------------------------------------------------------- /examples/express3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "passport-local-examples-login", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "express": "3.x.x", 6 | "connect-flash": "0.1.x", 7 | "ejs": ">= 0.0.0", 8 | "ejs-locals": ">= 0.0.0", 9 | "passport": ">= 0.0.0", 10 | "passport-localapikey": ">= 0.0.0", 11 | "passport-local": ">= 0.0.0" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/express3/views/account.ejs: -------------------------------------------------------------------------------- 1 | <% layout('layout') -%> 2 |

Username: <%= user.username %>

3 |

Email: <%= user.email %>

4 | 5 | -------------------------------------------------------------------------------- /examples/express3/views/index.ejs: -------------------------------------------------------------------------------- 1 | <% layout('layout') -%> 2 | <% if (!user) { %> 3 |

Welcome! Please log in.

4 | <% } else { %> 5 |

Hello, <%= user.username %>.

6 | <% } %> 7 | -------------------------------------------------------------------------------- /examples/express3/views/layout.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Passport-Local Example 5 | 6 | 7 | <% if (!user) { %> 8 |

9 | Home | 10 | Log In 11 |

12 | <% } else { %> 13 |

14 | Home | 15 | Account | 16 | Log Out 17 |

18 | <% } %> 19 | <%- body %> 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/express3/views/login.ejs: -------------------------------------------------------------------------------- 1 | <% layout('layout') -%> 2 | <% if (message) { %> 3 |

<%= message %>

4 | <% } %> 5 |
6 |
7 | 8 |
9 |
10 |
11 | 12 | 13 |
14 |
15 | 16 |
17 |
18 |

Hint - bob:secret

19 | -------------------------------------------------------------------------------- /lib/passport-localapikey/errors/badrequesterror.js: -------------------------------------------------------------------------------- 1 | /** 2 | * `BadRequestError` error. 3 | * 4 | * @api public 5 | */ 6 | function BadRequestError(message) { 7 | Error.call(this); 8 | Error.captureStackTrace(this, arguments.callee); 9 | this.name = 'BadRequestError'; 10 | this.message = message || null; 11 | }; 12 | 13 | /** 14 | * Inherit from `Error`. 15 | */ 16 | BadRequestError.prototype.__proto__ = Error.prototype; 17 | 18 | 19 | /** 20 | * Expose `BadRequestError`. 21 | */ 22 | module.exports = BadRequestError; 23 | -------------------------------------------------------------------------------- /lib/passport-localapikey/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Module dependencies. 3 | */ 4 | var Strategy = require('./strategy') 5 | , BadRequestError = require('./errors/badrequesterror'); 6 | 7 | 8 | /** 9 | * Framework version. 10 | */ 11 | require('pkginfo')(module, 'version'); 12 | 13 | /** 14 | * Expose constructors. 15 | */ 16 | exports.Strategy = Strategy; 17 | 18 | exports.BadRequestError = BadRequestError; 19 | -------------------------------------------------------------------------------- /lib/passport-localapikey/strategy.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Module dependencies. 3 | */ 4 | var passport = require('passport') 5 | , util = require('util') 6 | , BadRequestError = require('./errors/badrequesterror'); 7 | 8 | 9 | /** 10 | * `Strategy` constructor. 11 | * 12 | * The local api key authentication strategy authenticates requests based on the 13 | * credentials submitted through an HTML-based login form. 14 | * 15 | * Applications must supply a `verify` callback which accepts `username` and 16 | * `password` credentials, and then calls the `done` callback supplying a 17 | * `user`, which should be set to `false` if the credentials are not valid. 18 | * If an exception occured, `err` should be set. 19 | * 20 | * Optionally, `options` can be used to change the fields in which the 21 | * credentials are found. 22 | * 23 | * Options: 24 | * - `apiKeyField` field name where the apikey is found, defaults to _apiKey_ 25 | * - `apiKeyHeader` header name where the apikey is found, defaults to _apiKey_ 26 | * - `passReqToCallback` when `true`, `req` is the first argument to the verify callback (default: `false`) 27 | * 28 | * Examples: 29 | * 30 | * passport.use(new LocalAPIKeyStrategy( 31 | * function(apikey, done) { 32 | * User.findOne({ apikey: apikey }, function (err, user) { 33 | * done(err, user); 34 | * }); 35 | * } 36 | * )); 37 | * 38 | * @param {Object} options 39 | * @param {Function} verify 40 | * @api public 41 | */ 42 | function Strategy(options, verify) { 43 | if (typeof options == 'function') { 44 | verify = options; 45 | options = {}; 46 | } 47 | if (!verify) throw new Error('local authentication strategy requires a verify function'); 48 | 49 | this._apiKeyField = options.apiKeyField || 'apikey'; 50 | this._apiKeyHeader = options.apiKeyHeader || 'apikey'; 51 | 52 | passport.Strategy.call(this); 53 | this.name = 'localapikey'; 54 | this._verify = verify; 55 | this._passReqToCallback = options.passReqToCallback; 56 | } 57 | 58 | /** 59 | * Inherit from `passport.Strategy`. 60 | */ 61 | util.inherits(Strategy, passport.Strategy); 62 | 63 | /** 64 | * Authenticate request based on the contents of a form submission. 65 | * 66 | * @param {Object} req 67 | * @api protected 68 | */ 69 | Strategy.prototype.authenticate = function(req, options) { 70 | options = options || {}; 71 | var apikey = lookup(req.body, this._apiKeyField) 72 | || lookup(req.query, this._apiKeyField) 73 | || lookup(req.headers, this._apiKeyHeader); 74 | 75 | if (!apikey) { 76 | return this.fail(new BadRequestError(options.badRequestMessage || 'Missing API Key')); 77 | } 78 | 79 | var self = this; 80 | 81 | function verified(err, user, info) { 82 | if (err) { return self.error(err); } 83 | if (!user) { return self.fail(info); } 84 | self.success(user, info); 85 | } 86 | 87 | if (self._passReqToCallback) { 88 | this._verify(req, apikey, verified); 89 | } else { 90 | this._verify(apikey, verified); 91 | } 92 | 93 | function lookup(obj, field) { 94 | if (!obj) { return null; } 95 | var chain = field.split(']').join('').split('['); 96 | for (var i = 0, len = chain.length; i < len; i++) { 97 | var prop = obj[chain[i]]; 98 | if (typeof(prop) === 'undefined') { return null; } 99 | if (typeof(prop) !== 'object') { return prop; } 100 | obj = prop; 101 | } 102 | return null; 103 | } 104 | } 105 | 106 | 107 | /** 108 | * Expose `Strategy`. 109 | */ 110 | module.exports = Strategy; 111 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "passport-localapikey", 3 | "version": "0.0.4", 4 | "description": "Local api key authentication strategy for Passport.", 5 | "author": { "name": "Sudhakar Mani", "email": "mail4sudhakar@gmail.com", "url": "http://www.sudhakarmani.com/" }, 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/cholalabs/passport-localapikey.git" 9 | }, 10 | "bugs": { 11 | "url": "https://github.com/cholalabs/passport-localapikey/issues" 12 | }, 13 | "main": "./lib/passport-localapikey", 14 | "dependencies": { 15 | "pkginfo": "0.2.x", 16 | "passport": "~0.1.1" 17 | }, 18 | "devDependencies": { 19 | "vows": "0.7.x" 20 | }, 21 | "scripts": { 22 | "test": "NODE_PATH=lib node_modules/.bin/vows test/*-test.js" 23 | }, 24 | "engines": { "node": ">= 0.4.0" }, 25 | "licenses": [ { 26 | "type": "MIT", 27 | "url": "http://www.opensource.org/licenses/MIT" 28 | } ], 29 | "keywords": ["passport", "passport apikey","local apikey", "auth", "authn", "authentication"] 30 | } 31 | -------------------------------------------------------------------------------- /test/index-test.js: -------------------------------------------------------------------------------- 1 | var vows = require('vows'); 2 | var assert = require('assert'); 3 | var util = require('util'); 4 | var localapikey = require('passport-localapikey'); 5 | 6 | vows.describe('passport-localapikey').addBatch({ 7 | 8 | 'module': { 9 | 'should report a version': function (x) { 10 | assert.isString(localapikey.version); 11 | }, 12 | 13 | 'should export BadRequestError': function (x) { 14 | assert.isFunction(localapikey.BadRequestError); 15 | }, 16 | }, 17 | 18 | }).export(module); 19 | -------------------------------------------------------------------------------- /test/strategy-test.js: -------------------------------------------------------------------------------- 1 | var vows = require('vows'); 2 | var assert = require('assert'); 3 | var util = require('util'); 4 | var LocalAPIKeyStrategy = require('passport-localapikey/strategy'); 5 | var BadRequestError = require('passport-localapikey/errors/badrequesterror'); 6 | 7 | 8 | vows.describe('LocalAPIKeyStrategy').addBatch({ 9 | 10 | 'strategy': { 11 | topic: function() { 12 | return new LocalAPIKeyStrategy(function(){}); 13 | }, 14 | 15 | 'should be named session': function (strategy) { 16 | assert.equal(strategy.name, 'localapikey'); 17 | }, 18 | }, 19 | 20 | 'strategy handling a request': { 21 | topic: function() { 22 | var strategy = new LocalAPIKeyStrategy(function(){}); 23 | return strategy; 24 | }, 25 | 26 | 'after augmenting with actions': { 27 | topic: function(strategy) { 28 | var self = this; 29 | var req = {}; 30 | strategy.success = function(user) { 31 | self.callback(null, user); 32 | } 33 | strategy.fail = function() { 34 | self.callback(new Error('should-not-be-called')); 35 | } 36 | 37 | strategy._verify = function(apikey, done) { 38 | done(null, { apikey: apikey }); 39 | } 40 | 41 | req.body = {}; 42 | req.body.apikey = 'a6578936DBJJJqwewrtrt'; 43 | 44 | process.nextTick(function () { 45 | strategy.authenticate(req); 46 | }); 47 | }, 48 | 49 | 'should not generate an error' : function(err, user) { 50 | assert.isNull(err); 51 | }, 52 | 'should authenticate' : function(err, user) { 53 | assert.equal(user.apikey, 'a6578936DBJJJqwewrtrt'); 54 | 55 | }, 56 | }, 57 | }, 58 | 59 | 'strategy handling a request with credentials in query': { 60 | topic: function() { 61 | var strategy = new LocalAPIKeyStrategy(function(){}); 62 | return strategy; 63 | }, 64 | 65 | 'after augmenting with actions': { 66 | topic: function(strategy) { 67 | var self = this; 68 | var req = {}; 69 | strategy.success = function(user) { 70 | self.callback(null, user); 71 | } 72 | strategy.fail = function() { 73 | self.callback(new Error('should-not-be-called')); 74 | } 75 | 76 | strategy._verify = function(apikey, done) { 77 | done(null, { apikey: apikey }); 78 | } 79 | 80 | req.query = {}; 81 | req.query.apikey = 'a6578936DBJJJqwewrtrt'; 82 | 83 | process.nextTick(function () { 84 | strategy.authenticate(req); 85 | }); 86 | }, 87 | 88 | 'should not generate an error' : function(err, user) { 89 | assert.isNull(err); 90 | }, 91 | 'should authenticate' : function(err, user) { 92 | assert.equal(user.apikey, 'a6578936DBJJJqwewrtrt'); 93 | 94 | }, 95 | }, 96 | }, 97 | 98 | 'strategy handling a request with credentials in header': { 99 | topic: function() { 100 | var strategy = new LocalAPIKeyStrategy(function(){}); 101 | return strategy; 102 | }, 103 | 104 | 'after augmenting with actions': { 105 | topic: function(strategy) { 106 | var self = this; 107 | var req = {}; 108 | strategy.success = function(user) { 109 | self.callback(null, user); 110 | } 111 | strategy.fail = function() { 112 | self.callback(new Error('should-not-be-called')); 113 | } 114 | 115 | strategy._verify = function(apikey, done) { 116 | done(null, { apikey: apikey }); 117 | } 118 | 119 | req.headers = {}; 120 | req.headers.apikey = 'a6578936DBJJJqwewrtrt'; 121 | 122 | process.nextTick(function () { 123 | strategy.authenticate(req); 124 | }); 125 | }, 126 | 127 | 'should not generate an error' : function(err, user) { 128 | assert.isNull(err); 129 | }, 130 | 'should authenticate' : function(err, user) { 131 | assert.equal(user.apikey, 'a6578936DBJJJqwewrtrt'); 132 | }, 133 | }, 134 | }, 135 | 136 | 'strategy handling a request with req argument to callback': { 137 | topic: function() { 138 | var strategy = new LocalAPIKeyStrategy({passReqToCallback: true}, function(){}); 139 | return strategy; 140 | }, 141 | 142 | 'after augmenting with actions': { 143 | topic: function(strategy) { 144 | var self = this; 145 | var req = {}; 146 | req.foo = 'bar'; 147 | strategy.success = function(user) { 148 | self.callback(null, user); 149 | } 150 | strategy.fail = function() { 151 | self.callback(new Error('should-not-be-called')); 152 | } 153 | 154 | strategy._verify = function(req, apikey, done) { 155 | done(null, { foo: req.foo, apikey: apikey }); 156 | } 157 | 158 | req.body = {}; 159 | req.body.apikey = 'a6578936DBJJJqwewrtrt'; 160 | 161 | process.nextTick(function () { 162 | strategy.authenticate(req); 163 | }); 164 | }, 165 | 166 | 'should not generate an error' : function(err, user) { 167 | assert.isNull(err); 168 | }, 169 | 'should authenticate' : function(err, user) { 170 | assert.equal(user.apikey, 'a6578936DBJJJqwewrtrt'); 171 | 172 | }, 173 | 'should have request details' : function(err, user) { 174 | assert.equal(user.foo, 'bar'); 175 | }, 176 | }, 177 | }, 178 | 179 | 'strategy handling a request with parameter options set to plain string': { 180 | topic: function() { 181 | var strategy = new LocalAPIKeyStrategy({apikeyField: 'apikey'}, function(){}); 182 | return strategy; 183 | }, 184 | 185 | 'after augmenting with actions': { 186 | topic: function(strategy) { 187 | var self = this; 188 | var req = {}; 189 | strategy.success = function(user) { 190 | self.callback(null, user); 191 | } 192 | strategy.fail = function() { 193 | self.callback(new Error('should-not-be-called')); 194 | } 195 | 196 | strategy._verify = function(apikey, done) { 197 | done(null, { apikey: apikey }); 198 | } 199 | 200 | req.body = {}; 201 | req.body.apikey = 'a6578936DBJJJqwewrtrt'; 202 | 203 | process.nextTick(function () { 204 | strategy.authenticate(req); 205 | }); 206 | }, 207 | 208 | 'should not generate an error' : function(err, user) { 209 | assert.isNull(err); 210 | }, 211 | 'should authenticate' : function(err, user) { 212 | assert.equal(user.apikey, 'a6578936DBJJJqwewrtrt'); 213 | 214 | }, 215 | }, 216 | }, 217 | 218 | 219 | 'strategy handling a request with additional info': { 220 | topic: function() { 221 | var strategy = new LocalAPIKeyStrategy(function(){}); 222 | return strategy; 223 | }, 224 | 225 | 'after augmenting with actions': { 226 | topic: function(strategy) { 227 | var self = this; 228 | var req = {}; 229 | strategy.success = function(user, info) { 230 | self.callback(null, user, info); 231 | } 232 | strategy.fail = function() { 233 | self.callback(new Error('should-not-be-called')); 234 | } 235 | 236 | strategy._verify = function(apikey, done) { 237 | done(null, { apikey:apikey }, { message: 'Welcome' }); 238 | } 239 | 240 | req.body = {}; 241 | req.body.apikey = 'a6578936DBJJJqwewrtrt'; 242 | 243 | process.nextTick(function () { 244 | strategy.authenticate(req); 245 | }); 246 | }, 247 | 248 | 'should not generate an error' : function(err, user, info) { 249 | assert.isNull(err); 250 | }, 251 | 'should authenticate' : function(err, user) { 252 | assert.equal(user.apikey, 'a6578936DBJJJqwewrtrt'); 253 | 254 | }, 255 | 'should pass additional info' : function(err, user, info) { 256 | assert.equal(info.message, 'Welcome'); 257 | }, 258 | }, 259 | }, 260 | 261 | 'strategy handling a request that is not verified': { 262 | topic: function() { 263 | var strategy = new LocalAPIKeyStrategy(function(){}); 264 | return strategy; 265 | }, 266 | 267 | 'after augmenting with actions': { 268 | topic: function(strategy) { 269 | var self = this; 270 | var req = {}; 271 | strategy.success = function(user) { 272 | self.callback(new Error('should-not-be-called')); 273 | } 274 | strategy.fail = function() { 275 | self.callback(); 276 | } 277 | 278 | strategy._verify = function(apikey, done) { 279 | done(null, false); 280 | } 281 | 282 | req.body = {}; 283 | req.body.apikey = 'a6578936DBJJJqwewrtrt'; 284 | 285 | process.nextTick(function () { 286 | strategy.authenticate(req); 287 | }); 288 | }, 289 | 290 | 'should fail authentication' : function(err, user) { 291 | // fail action was called, resulting in test callback 292 | assert.isNull(err); 293 | }, 294 | }, 295 | }, 296 | 297 | 'strategy handling a request that is not verified with additional info': { 298 | topic: function() { 299 | var strategy = new LocalAPIKeyStrategy(function(){}); 300 | return strategy; 301 | }, 302 | 303 | 'after augmenting with actions': { 304 | topic: function(strategy) { 305 | var self = this; 306 | var req = {}; 307 | strategy.success = function(user) { 308 | self.callback(new Error('should-not-be-called')); 309 | } 310 | strategy.fail = function(info) { 311 | self.callback(null, info); 312 | } 313 | 314 | strategy._verify = function(apikey, done) { 315 | done(null, false, { message: 'Wrong ApiKey' }); 316 | } 317 | 318 | req.body = {}; 319 | req.body.apikey = 'a6578936DBJJJqwewrtrt'; 320 | 321 | process.nextTick(function () { 322 | strategy.authenticate(req); 323 | }); 324 | }, 325 | 326 | 'should fail authentication' : function(err, info) { 327 | // fail action was called, resulting in test callback 328 | assert.isNull(err); 329 | }, 330 | 'should pass additional info' : function(err, info) { 331 | assert.equal(info.message, 'Wrong ApiKey'); 332 | }, 333 | }, 334 | }, 335 | 336 | 'strategy handling a request that encounters an error during verification': { 337 | topic: function() { 338 | var strategy = new LocalAPIKeyStrategy(function(){}); 339 | return strategy; 340 | }, 341 | 342 | 'after augmenting with actions': { 343 | topic: function(strategy) { 344 | var self = this; 345 | var req = {}; 346 | strategy.success = function(user) { 347 | self.callback(new Error('should-not-be-called')); 348 | } 349 | strategy.fail = function() { 350 | self.callback(new Error('should-not-be-called')); 351 | } 352 | strategy.error = function(err) { 353 | self.callback(null, err); 354 | } 355 | 356 | strategy._verify = function(apikey, done) { 357 | done(new Error('something-went-wrong')); 358 | } 359 | 360 | req.body = {}; 361 | req.body.apikey = 'a6578936DBJJJqwewrtrt'; 362 | 363 | process.nextTick(function () { 364 | strategy.authenticate(req); 365 | }); 366 | }, 367 | 368 | 'should not call success or fail' : function(err, e) { 369 | assert.isNull(err); 370 | }, 371 | 'should call error' : function(err, e) { 372 | assert.instanceOf(e, Error); 373 | }, 374 | }, 375 | }, 376 | 377 | 'strategy handling a request without a body': { 378 | topic: function() { 379 | var strategy = new LocalAPIKeyStrategy(function(){}); 380 | return strategy; 381 | }, 382 | 383 | 'after augmenting with actions': { 384 | topic: function(strategy) { 385 | var self = this; 386 | var req = {}; 387 | strategy.fail = function(info) { 388 | self.callback(null, info); 389 | } 390 | 391 | process.nextTick(function () { 392 | strategy.authenticate(req); 393 | }); 394 | }, 395 | 396 | 'should fail authentication' : function(err, info) { 397 | // fail action was called, resulting in test callback 398 | assert.isTrue(true); 399 | }, 400 | 'should pass BadReqestError as additional info' : function(err, info) { 401 | assert.instanceOf(info, Error); 402 | assert.instanceOf(info, BadRequestError); 403 | }, 404 | }, 405 | }, 406 | 407 | 'strategy handling a request with a body, but no apikey': { 408 | topic: function() { 409 | var strategy = new LocalAPIKeyStrategy(function(){}); 410 | return strategy; 411 | }, 412 | 413 | 'after augmenting with actions': { 414 | topic: function(strategy) { 415 | var self = this; 416 | var req = {}; 417 | strategy.fail = function(info) { 418 | self.callback(null, info); 419 | } 420 | 421 | req.body = {}; 422 | process.nextTick(function () { 423 | strategy.authenticate(req); 424 | }); 425 | }, 426 | 427 | 'should fail authentication' : function(err) { 428 | // fail action was called, resulting in test callback 429 | assert.isTrue(true); 430 | }, 431 | 'should pass BadReqestError as additional info' : function(err, info) { 432 | assert.instanceOf(info, Error); 433 | assert.instanceOf(info, BadRequestError); 434 | }, 435 | }, 436 | }, 437 | 438 | 'strategy handling a request with a body, but no apikey, and badRequestMessage option': { 439 | topic: function() { 440 | var strategy = new LocalAPIKeyStrategy(function(){}); 441 | return strategy; 442 | }, 443 | 444 | 'after augmenting with actions': { 445 | topic: function(strategy) { 446 | var self = this; 447 | var req = {}; 448 | strategy.fail = function(info) { 449 | self.callback(null, info); 450 | } 451 | 452 | req.body = {}; 453 | process.nextTick(function () { 454 | strategy.authenticate(req, { badRequestMessage: 'Something is wrong with this request' }); 455 | }); 456 | }, 457 | 458 | 'should fail authentication' : function(err) { 459 | // fail action was called, resulting in test callback 460 | assert.isTrue(true); 461 | }, 462 | 'should pass BadReqestError as additional info' : function(err, info) { 463 | assert.instanceOf(info, Error); 464 | assert.instanceOf(info, BadRequestError); 465 | }, 466 | 'should set message correctly' : function(err, info) { 467 | assert.equal(info.message, 'Something is wrong with this request'); 468 | }, 469 | }, 470 | }, 471 | 472 | 'strategy constructed without a verify callback': { 473 | 'should throw an error': function (strategy) { 474 | assert.throws(function() { new LocalAPIKeyStrategy() }); 475 | }, 476 | }, 477 | 478 | }).export(module); 479 | --------------------------------------------------------------------------------