Skip to content

Commit

Permalink
WIP: Fixes to the cosJwt and added more tests - #70
Browse files Browse the repository at this point in the history
  • Loading branch information
tiblu committed Jan 8, 2019
1 parent ea5f182 commit 5f9d31c
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 7 deletions.
18 changes: 11 additions & 7 deletions libs/cosJwt.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*
* @param {Object} app Express app
*
* @returns {Object}
* @returns {Function} Function
*/
module.exports = function (app) {

Expand All @@ -23,16 +23,20 @@ module.exports = function (app) {
/**
* Get restricted use token
*
* @param {Object} payload Payload object to sign, note that "scope" property is reserved and will throw an error!
* @param {Object} payload Payload object to sign, note that "audience" property is reserved and will throw an error!
* @param {Array|String} audience Array of allowed audiences (usage scopes, paths with methods). For ex: ["POST /api/new/stuff", "GET /api/foo/bar"]. Audience is originally part of the jwt.sign options, but bringing it out separately as it is required by all tokens we issue.
* @param {Object} options jwt.sign options like expiresIn etc (https://github.com/auth0/node-jsonwebtoken/tree/cb33aabc432408ed7f3826c2f5b5930313b63f1e)
* @param {Object} [options] jwt.sign options like expiresIn etc (https://github.com/auth0/node-jsonwebtoken/tree/cb33aabc432408ed7f3826c2f5b5930313b63f1e)
*
* @private
*
* @returns {Promise} Promise
*/
var _getTokenRestrictedUse = function (payload, audience, options) {
if (!audience) {
if (!payload) {
throw new Error('Missing required parameter "payload"');
}

if (!audience || !audience.length) {
throw new Error('Missing required parameter "audience". Please specify scope to which the usage is restricted!');
}

Expand All @@ -49,8 +53,8 @@ module.exports = function (app) {
}
});


return new Promise(function (resolve, reject) {
return new Promise(function (resolve) {
// Interesting, jwt.sign (5.7.0) has no err object in the callback, the first argument is always the result. Code That Never Fails (tm)
jwt.sign(payload, config.session.privateKey, effectiveOptions, function (token) {
return resolve(token);
});
Expand All @@ -62,7 +66,7 @@ module.exports = function (app) {
*
* @param {string} token JWT token
* @param {string} audience Audience that is required. The format is "METHOD PATH". For example "POST /api/new/stuff". Audience is originally part of the jwt.verify options, but bringing it out separately as it is required by all tokens we issue.
* @param {Object} options jwt.verify options.
* @param {Object} [options] jwt.verify options.
*
* @private
*
Expand Down
127 changes: 127 additions & 0 deletions test/libs/cosJwt.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ suite('cosJwt', function () {

var app = require('../../app');
var cosJwt = app.get('cosJwt');
var jwt = app.get('jwt');

suiteTeardown(function (done) {
shared
Expand All @@ -24,10 +25,136 @@ suite('cosJwt', function () {
})
.then(function (decoded) {
assert.equal(decoded.foo, testPayload.foo);
assert.deepEqual(decoded.aud, [testAudience]);

return done();
})
.catch(done);
});

test('Success - multiple audiences (scopes)', function (done) {
var testPayload = {foo: 'bar'};
var testAudiences = ['GET /asd', 'POST /api/foo/bar'];

cosJwt
.getTokenRestrictedUse(testPayload, testAudiences)
.then(function (token) {
return cosJwt.verifyTokenRestrictedUse(token, testAudiences[0])
.then(function (decoded) {
assert.equal(decoded.foo, testPayload.foo);
assert.deepEqual(decoded.aud, testAudiences);

return token;
});
})
.then(function (token) {
return cosJwt.verifyTokenRestrictedUse(token, testAudiences[1]);
})
.then(function (decoded) {
assert.equal(decoded.foo, testPayload.foo);
assert.deepEqual(decoded.aud, testAudiences);

return done();
})
.catch(done);
});


test('Success - expiry', function (done) {
var testPayload = {foo: 'bar'};
var testAudience = 'POST /api/foo/bar';
var testOptions = {
expiresIn: '1m'
};

cosJwt
.getTokenRestrictedUse(testPayload, testAudience, testOptions)
.then(function (token) {
return cosJwt.verifyTokenRestrictedUse(token, testAudience);
})
.then(function (decoded) {
assert.equal(decoded.foo, testPayload.foo);
assert.property(decoded, 'exp');

return done();
})
.catch(done);
});

test('Fail - expired token', function (done) {
var testPayload = {foo: 'bar'};
var testAudience = 'POST /api/foo/bar';
var testOptions = {
expiresIn: '1ms'
};

cosJwt
.getTokenRestrictedUse(testPayload, testAudience, testOptions)
.then(function (token) {
return cosJwt.verifyTokenRestrictedUse(token, testAudience);
})
.then(function () {
return done(new Error('Should fail due to token expiry!'));
})
.catch(function (err) {
assert.instanceOf(err, jwt.TokenExpiredError);

done();
});
});

test('Fail - invalid audience (scope)', function (done) {
var testPayload = {foo: 'bar'};
var testAudience = 'POST /api/foo/bar';
var testInvalidAudience = 'POST /api/invalid';
var testOptions = {
expiresIn: '1m'
};

cosJwt
.getTokenRestrictedUse(testPayload, testAudience, testOptions)
.then(function (token) {
return cosJwt.verifyTokenRestrictedUse(token, testInvalidAudience);
})
.then(function () {
return done(new Error('Should fail due to invalid audience!'));
})
.catch(function (err) {
assert.instanceOf(err, jwt.JsonWebTokenError);
assert.equal(err.message, 'jwt audience invalid. expected: ' + testInvalidAudience);

done();
});
});

suite('getTokenRestrictedUse', function () {

test('Fail - missing required parameters - payload', function (done) {
try {
cosJwt.getTokenRestrictedUse();
} catch (err) {
return done();
}
done(new Error('Should throw an error if payload parameter is missing!'));
});

test('Fail - missing required parameters - audience', function (done) {
try {
cosJwt.getTokenRestrictedUse({foo: 'bar'});
} catch (err) {
return done();
}
done(new Error('Should throw an error if audience parameter is missing!'));
});

test('Fail - invalid parameters - audience in wrong format', function (done) {
try {
cosJwt.getTokenRestrictedUse({foo: 'bar'}, ['/no/method/for/path']);
} catch (err) {
return done();
}
done(new Error('Should throw an error if audience parameter value is in invalid format!'));
});

});
});

0 comments on commit 5f9d31c

Please sign in to comment.