all files / apigateway-utils/src/ JWTSecuredRequest.js

100% Statements 40/40
100% Branches 34/34
100% Functions 6/6
100% Lines 40/40
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93                14× 14×       33×       11×         11×                                 15× 10×           24× 14× 10×                 21× 12×            
'use strict';
 
var _ = require('underscore'),
    jwt = require('jwt-simple'),
    Request = require('./Request'),
    BEARER_REGEX = /^Bearer /;
 
module.exports = Request.extend({
 
   init: function(evt, context) {
      this._super(evt, context);
      this._token = false;
   },
 
   getToken: function() {
      return this._token;
   },
 
   validateAuthorizationHeader: function(publicKey, validationUserOpts) {
      var rawHeader = this.header('Authorization') || '',
          rawToken = rawHeader.replace(BEARER_REGEX, ''),
          validationOpts = _.isObject(validationUserOpts) ? validationUserOpts : {},
          decoded;
 
      if (_.isEmpty(rawHeader) || _.isEmpty(rawToken)) {
         this._token = false;
         return { isValid: false, msg: 'No token supplied in Authorization header' };
      }
 
      if (!BEARER_REGEX.test(rawHeader)) {
         this._token = false;
         return { isValid: false, msg: 'Authorization header not in correct format' };
      }
 
      try {
         decoded = jwt.decode(rawToken, publicKey, false, 'RS256');
      } catch(err) {
         this._token = false;
         return { isValid: false, msg: 'Invalid authorization token', err: err.message };
      }
 
      decoded = this._validateTokenAudience(decoded, validationOpts.audience);
      decoded = this._validateTokenIssuer(decoded, validationOpts.issuer);
      decoded = this._validateRevocationList(decoded, validationOpts.revokedTokenIDs);
 
      this._token = decoded;
 
      if (this._token === false) {
         // TODO: add an err message here, which will require changing all the
         // _validate* functions
         return { isValid: false, msg: 'Invalid authorization token', err: 'TODO' };
      }
 
      return { isValid: true };
   },
 
   _validateTokenIssuer: function(token, issuer) {
      if (_.isEmpty(issuer)) {
         return token;
      } else if (!_.isObject(token)) {
         return token;
      }
 
      return token.iss === issuer ? token : false;
   },
 
   _validateTokenAudience: function(token, intendedAudience) {
      if (_.isEmpty(intendedAudience)) {
         return token;
      } else if (!_.isObject(token)) {
         return token;
      }
 
      if (_.isArray(token.aud)) {
         return _.contains(token.aud, intendedAudience) ? token : false;
      }
 
      // audience is a single value:
      return token.aud === intendedAudience ? token : false;
   },
 
   _validateRevocationList: function(token, revokedTokenIDs) {
      if (_.isEmpty(revokedTokenIDs)) {
         return token;
      } else if (!_.isObject(token)) {
         return token;
      }
 
      return _.contains(revokedTokenIDs, token.jti) ? false : token;
   },
 
});