-
Notifications
You must be signed in to change notification settings - Fork 125
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
heroku example works. just need to get test coverage up by adding a f…
…ew more tests #9
- Loading branch information
Showing
5 changed files
with
322 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,5 @@ node_js: | |
- 0.10 | ||
- 0.12 | ||
- iojs | ||
env: | ||
- JWT_SECRET="EverythingIsAwesome!" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
var Hapi = require('hapi'); | ||
var hapiAuthJWT = require('../lib/'); // require('hapi-auth-jwt2'); | ||
var JWT = require('jsonwebtoken'); // used to sign our content | ||
var port = process.env.PORT || 8000; // allow port to be set | ||
var aguid = require('aguid') | ||
var redis = require('redis'); | ||
var url = require('url'); | ||
// if you don't already have a *FREE* RedisCloud Account | ||
// visit: https://addons.heroku.com/rediscloud (it works outside heroku! free!) | ||
var redisURL = url.parse(process.env.REDISCLOUD_URL); | ||
var redisClient = redis.createClient(redisURL.port, redisURL.hostname, | ||
{no_ready_check: true}); | ||
redisClient.auth(redisURL.auth.split(":")[1]); | ||
|
||
redisClient.set('redis', 'working'); | ||
redisClient.get('redis', function (err, reply) { | ||
console.log('redis is ' +reply.toString()); // confirm we can access redis | ||
}); | ||
|
||
// bring your own validation function | ||
var validate = function (decoded, request, callback) { | ||
console.log(" - - - - - - - DECODED token:"); | ||
console.log(decoded); | ||
// do your checks to see if the session is valid | ||
redisClient.get(decoded.id, function (rediserr, reply) { | ||
console.log(' - - - - - - - REDIS reply - - - - - - - ', reply); | ||
if(reply) { | ||
try { | ||
var session = JSON.parse(reply); | ||
} catch(e) { | ||
return callback(null, false); | ||
} | ||
} | ||
else { // unable to find session in redis ... reply is null | ||
return callback(null, false); | ||
} | ||
|
||
if (session.valid === true) { | ||
return callback(null, true); | ||
} | ||
else { | ||
return callback(null, false); | ||
} | ||
}); | ||
}; | ||
|
||
var server = new Hapi.Server(); | ||
server.connection({ port: port }); | ||
|
||
server.register(hapiAuthJWT, function (err) { | ||
// if(err) { // uncomment this in prod | ||
// console.log(err); | ||
// } | ||
// see: http://hapijs.com/api#serverauthschemename-scheme | ||
server.auth.strategy('jwt', 'jwt', true, | ||
{ key: process.env.JWT_SECRET, validateFunc: validate, | ||
verifyOptions: { ignoreExpiration: true } | ||
}); | ||
|
||
server.route([ | ||
{ | ||
method: "GET", path: "/", config: { auth: false }, | ||
handler: function(request, reply) { | ||
reply({text: 'Token not required'}); | ||
} | ||
}, | ||
{ | ||
method: ['GET','POST'], path: '/restricted', config: { auth: 'jwt' }, | ||
handler: function(request, reply) { | ||
reply({text: 'You used a Token!'}) | ||
.header("Authorization", request.headers.authorization); | ||
} | ||
}, | ||
{ | ||
method: ['GET','POST'], path: "/auth", config: { auth: false }, | ||
handler: function(request, reply) { | ||
// implement your own login/auth function here | ||
var session = { | ||
valid: true, // this could be set to false if the person logs out | ||
id: aguid(), // a random session id | ||
exp: new Date().getTime() + 30 * 60 * 1000 // expires in 30 minutes time | ||
} | ||
// create the session in Redis | ||
redisClient.set(session.id, JSON.stringify(session)); | ||
// sign the session as a JWT | ||
var token = JWT.sign(session, process.env.JWT_SECRET); // synchronous | ||
console.log(token); | ||
|
||
reply({text: 'Check Auth Header for your Token'}) | ||
.header("Authorization", token); | ||
} | ||
}, | ||
{ | ||
method: ['GET','POST'], path: "/logout", config: { auth: 'jwt' }, | ||
handler: function(request, reply) { | ||
// implement your own login/auth function here | ||
var decoded = JWT.decode(request.headers.authorization, | ||
process.env.JWT_SECRET); | ||
redisClient.get(decoded.id, function(rediserror, reply) { | ||
var session = JSON.parse(reply) | ||
console.log(' - - - - - - SESSION - - - - - - - -') | ||
console.log(session); | ||
// update the session to no longer valid: | ||
session.valid = false; | ||
session.ended = new Date().getTime(); | ||
// create the session in Redis | ||
redisClient.set(session.id, JSON.stringify(session)); | ||
reply({text: 'Successfully Logged Out! (Session no longer valid)'}) | ||
.header("Authorization", request.headers.authorization); | ||
}) | ||
} | ||
}, | ||
{ // remove this method if you use this in PROD! | ||
method: 'GET', path: '/end', config: { auth: false }, | ||
handler: function(request, reply) { | ||
redisClient.end(); | ||
reply({text: 'end'}); | ||
} | ||
} | ||
]); | ||
}); | ||
|
||
// server.start(); // uncomment this to run the server directly | ||
// console.log('Now Visit: http://127.0.0.1:'+port); | ||
module.exports = server; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
var test = require('tape'); | ||
var JWT = require('jsonwebtoken'); | ||
|
||
var server = require('../example/real_world_example_using_redis_on_heroku.js'); | ||
|
||
test("Confirm GET / does not require session token", function(t) { | ||
var options = { | ||
method: "GET", | ||
url: "/" | ||
}; | ||
// server.inject lets us similate an http request | ||
server.inject(options, function(response) { | ||
t.equal(response.statusCode, 200, "Base URL Does not Require "); | ||
t.end(); | ||
}); | ||
}); | ||
|
||
test("Attempt to access restricted content (without auth token)", function(t) { | ||
var options = { | ||
method: "POST", | ||
url: "/restricted" | ||
}; | ||
// server.inject lets us similate an http request | ||
server.inject(options, function(response) { | ||
t.equal(response.statusCode, 401, "No Token should fail"); | ||
t.end(); | ||
}); | ||
}); | ||
|
||
|
||
test("Attempt to access restricted content (with an INVALID Token)", function(t) { | ||
var options = { | ||
method: "POST", | ||
url: "/restricted", | ||
headers: { authorization: "Bearer fails.validation" } | ||
}; | ||
// server.inject lets us similate an http request | ||
server.inject(options, function(response) { | ||
t.equal(response.statusCode, 401, "INVALID Token should fail"); | ||
t.end(); | ||
}); | ||
}); | ||
|
||
test("Malformed JWT", function(t) { | ||
// use the token as the 'authorization' header in requests | ||
// var token = jwt.sign({ "id": 1 ,"name":"Old Greg" }, 'incorrectSecret'); | ||
// console.log(token); | ||
var options = { | ||
method: "POST", | ||
url: "/restricted", | ||
headers: { authorization: "Bearer my.invalid.token" } | ||
}; | ||
// server.inject lets us similate an http request | ||
server.inject(options, function(response) { | ||
console.log(response.result); | ||
console.log(' '); // blank line | ||
t.equal(response.statusCode, 401, "INVALID Token should fail"); | ||
// t.equal(JSON.parse(response.result).msg, 'Invalid Token', "INVALID Token should fail"); | ||
t.end(); | ||
}); | ||
}); | ||
|
||
test("Try using an incorrect secret to sign the JWT", function(t) { | ||
// use the token as the 'authorization' header in requests | ||
var token = JWT.sign({ id:123,"name":"Charlie" }, 'incorrectSecret'); | ||
console.log(" - - - - - - token - - - - -") | ||
console.log(token); | ||
var options = { | ||
method: "POST", | ||
url: "/restricted", | ||
headers: { authorization: "Bearer "+token } | ||
}; | ||
// server.inject lets us similate an http request | ||
server.inject(options, function(response) { | ||
t.equal(response.statusCode, 401, "Token signed with incorrect key fails"); | ||
t.equal(true, true, "true is true") | ||
t.end(); | ||
}); | ||
}); | ||
|
||
test("Token is well formed but session not in redis so should be denied", function(t) { | ||
// use the token as the 'authorization' header in requests | ||
// var token = jwt.sign({ "id": 1 ,"name":"Old Greg" }, 'incorrectSecret'); | ||
var token = JWT.sign({ id:321,"valid":true }, process.env.JWT_SECRET); | ||
var options = { | ||
method: "POST", | ||
url: "/restricted", | ||
headers: { authorization: "Bearer "+token } | ||
}; | ||
// server.inject lets us similate an http request | ||
server.inject(options, function(response) { | ||
t.equal(response.statusCode, 401, "Denied"); | ||
t.end(); | ||
}); | ||
}); | ||
|
||
test("Attempt to access restricted content with Well-formed Token but invalid secret", function(t) { | ||
// use the token as the 'authorization' header in requests | ||
var token = JWT.sign({ id:123, "valid":true }, 'badsecret'); | ||
var options = { | ||
method: "POST", | ||
url: "/restricted", | ||
headers: { authorization: "Bearer "+token } | ||
}; | ||
// server.inject lets us similate an http request | ||
server.inject(options, function(response) { | ||
console.log(" - - - - RESPONSE: ") | ||
console.log(response.result); | ||
t.equal(response.statusCode, 401, "InVALID Token should Error!"); | ||
|
||
t.end(); | ||
}); | ||
}); | ||
|
||
var token; // used in all subsequent tests | ||
|
||
test("Simulate Authentication", function(t) { | ||
// use the token as the 'authorization' header in requests | ||
var options = { | ||
method: "POST", | ||
url: "/auth" | ||
}; | ||
// server.inject lets us similate an http request | ||
server.inject(options, function(res) { | ||
token = res.headers.authorization; | ||
console.log(" - - - - RESPONSE: "); | ||
console.log(res.result); | ||
t.equal(res.statusCode, 200, "VALID Token should succeed!"); | ||
|
||
t.end(); | ||
}); | ||
}); | ||
|
||
test("Access restricted content with *VALID* JWT", function(t) { | ||
// use the token as the 'authorization' header in requests | ||
var options = { | ||
method: 'POST', | ||
url: '/restricted', | ||
headers: { 'Authorization' : token } // token from previous test | ||
}; | ||
// server.inject lets us similate an http request | ||
server.inject(options, function(res) { | ||
token = res.headers.authorization; | ||
console.log(" - - - - RESPONSE: "); | ||
console.log(res.result); | ||
t.equal(res.statusCode, 200, "VALID Token should succeed!"); | ||
t.end(); | ||
}); | ||
}); | ||
|
||
test("Attempt to Access restricted content with JWT which is no longer valid", function(t) { | ||
// use the token as the 'authorization' header in requests | ||
var options = { | ||
method: 'POST', | ||
url: '/restricted', | ||
headers: { 'Authorization' : token } // token from previous test | ||
}; | ||
// server.inject lets us similate an http request | ||
server.inject(options, function(res) { | ||
token = res.headers.authorization; | ||
console.log(" - - - - RESPONSE: "); | ||
console.log(res.result); | ||
t.equal(res.statusCode, 200, "VALID Token should succeed!"); | ||
t.end(); | ||
}); | ||
}); | ||
|
||
test("End Connection to RedisCloud", function(t) { | ||
var options = { | ||
method: "GET", | ||
url: "/end" | ||
}; | ||
server.inject(options, function(response) { | ||
t.equal(response.statusCode, 200, "Redis connection closed."); | ||
server.stop(); | ||
t.end(); | ||
}); | ||
}); |