-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
WIP: First version of cosJwt with a happy case test - #70
- Loading branch information
Showing
4 changed files
with
137 additions
and
12 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
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,91 @@ | ||
'use strict'; | ||
|
||
/** | ||
* Citizen OS specific JWT logic | ||
* | ||
* @param {Object} app Express app | ||
* | ||
* @returns {Object} | ||
*/ | ||
module.exports = function (app) { | ||
|
||
var config = app.get('config'); | ||
var jwt = app.get('jwt'); | ||
|
||
var TOKEN_OPTIONS_SIGN_DEFAULTS = { | ||
algorithm: config.session.algorithm | ||
}; | ||
|
||
var TOKEN_OPTIONS_VERIFY_DEFAULTS = { | ||
algorithms: [config.session.algorithm] | ||
}; | ||
|
||
/** | ||
* Get restricted use token | ||
* | ||
* @param {Object} payload Payload object to sign, note that "scope" 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) | ||
* | ||
* @private | ||
* | ||
* @returns {Promise} Promise | ||
*/ | ||
var _getTokenRestrictedUse = function (payload, audience, options) { | ||
if (!audience) { | ||
throw new Error('Missing required parameter "audience". Please specify scope to which the usage is restricted!'); | ||
} | ||
|
||
if (options && options.audience) { | ||
throw new Error('Property "audience" is reserved for specifying usage scope of the token. Use "audience" parameter to specify the audience (scope).'); | ||
} | ||
|
||
var effectiveOptions = Object.assign({}, TOKEN_OPTIONS_SIGN_DEFAULTS, options); | ||
effectiveOptions.audience = typeof audience === 'string' ? [audience] : audience; | ||
|
||
effectiveOptions.audience.forEach(function (aud) { | ||
if (!(/^(GET|POST|PUT|DELETE|PATCH) \/.*/).test(aud)) { | ||
throw new Error('Invalid value in "audience" parameter detected - "' + aud + '"'); | ||
} | ||
}); | ||
|
||
|
||
return new Promise(function (resolve, reject) { | ||
jwt.sign(payload, config.session.privateKey, effectiveOptions, function (token) { | ||
return resolve(token); | ||
}); | ||
}); | ||
}; | ||
|
||
/** | ||
* Verify a restricted use token | ||
* | ||
* @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. | ||
* | ||
* @private | ||
* | ||
* @returns {Promise} Promise | ||
*/ | ||
var _verifyTokenRestrictedUse = function (token, audience, options) { | ||
var effectiveOptions = Object.assign({}, TOKEN_OPTIONS_VERIFY_DEFAULTS, options); | ||
effectiveOptions.audience = audience; | ||
|
||
return new Promise(function (resolve, reject) { | ||
jwt.verify(token, config.session.publicKey, effectiveOptions, function (err, payload) { | ||
if (err) { | ||
return reject(err); | ||
} | ||
|
||
return resolve(payload); | ||
}); | ||
}); | ||
}; | ||
|
||
|
||
return { | ||
getTokenRestrictedUse: _getTokenRestrictedUse, | ||
verifyTokenRestrictedUse: _verifyTokenRestrictedUse | ||
}; | ||
}; |
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,33 @@ | ||
'use strict'; | ||
|
||
suite('cosJwt', function () { | ||
var assert = require('chai').assert; | ||
var shared = require('../utils/shared'); | ||
|
||
var app = require('../../app'); | ||
var cosJwt = app.get('cosJwt'); | ||
|
||
suiteTeardown(function (done) { | ||
shared | ||
.closeDb() | ||
.finally(done); | ||
}); | ||
|
||
test('Success', function (done) { | ||
var testPayload = {foo: 'bar'}; | ||
var testAudience = 'POST /api/foo/bar'; | ||
|
||
cosJwt | ||
.getTokenRestrictedUse(testPayload, testAudience) | ||
.then(function (token) { | ||
return cosJwt.verifyTokenRestrictedUse(token, testAudience); | ||
}) | ||
.then(function (decoded) { | ||
assert.equal(decoded.foo, testPayload.foo); | ||
|
||
return done(); | ||
}) | ||
.catch(done); | ||
}); | ||
|
||
}); |
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