all files / swagger-node-runner/fittings/ swagger_security.js

93.1% Statements 54/58
80.56% Branches 29/36
88.89% Functions 8/9
92.45% Lines 49/53
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 94 95 96 97 98 99 100 101 102 103 104 105 106        13×   13×   13×   12× 12×   12× 12×     13×   93×   93× 93× 93×   93×   20×   20×   20×   20× 20×   20×   20×   16×             20×     20×           20× 20×   20×                             12× 12×   12×           12×   12×    
'use strict';
 
var debug = require('debug')('swagger:swagger_security');
var async = require('async');
var helpers = require('../lib/helpers');
var _ = require('lodash');
var path = require('path');
 
module.exports = function create(fittingDef, bagpipes) {
 
  debug('config: %j', fittingDef);
 
  var runner = bagpipes.config.swaggerNodeRunner;
 
  if (fittingDef.securityHandlersModule && !runner.config.securityHandlers) {
 
    var appRoot = runner.config.swagger.appRoot;
    var handlersPath = path.resolve(appRoot, fittingDef.securityHandlersModule);
 
    runner.securityHandlers = require(handlersPath);
    debug('loaded handlers: %s from: %s', Object.keys(runner.securityHandlers), handlersPath);
  }
 
  return function swagger_security(context, cb) {
 
    debug('exec');
 
    var handlers = runner.securityHandlers || {};
    var req = context.request;
    var operation = req.swagger.operation;
 
    if (!operation || !operation.security) { return cb(); }
 
    async.map(operation.security, // logical OR - any one can allow
      function orCheck(securityRequirement, cb) {
        var secName;
 
        async.map(Object.keys(securityRequirement), // logical AND - all must allow
          function andCheck(name, cb) {
            var secDef = operation.securityDefinitions[name];
            var handler = handlers[name];
 
            secName = name;
 
            if (!handler) { return cb(new Error('Unknown security handler: ' + name));}
 
            if (handler.length === 4) {
              // swagger-tools style handler
              return handler(req, secDef, getScopeOrAPIKey(req, secDef, name, securityRequirement), cb);
            } else {
              // connect-style handler
              return handler(req, context.response, cb);
            }
          },
          function andCheckDone(err) {
            debug('Security check (%s): %s', secName, _.isNull(err) ? 'allowed' : 'denied');
 
            // swap normal err and result to short-circuit the logical OR
            if (err) { return cb(undefined, err); }
 
            return cb(new Error('OK'));
          });
      },
      function orCheckDone(ok, errors) { // note swapped results
 
        var allowed = !_.isNull(ok) && ok.message === 'OK';
        debug('Request allowed: %s', allowed);
 
        allowed ? cb() : sendSecurityError(errors[0], context.response, cb);
      });
  }
};
 
function getScopeOrAPIKey(req, securityDefinition, name, securityRequirement) {
 
  var scopeOrKey;
 
  Iif (securityDefinition.type === 'oauth2') {
    scopeOrKey = securityRequirement[name];
  } else Eif (securityDefinition.type === 'apiKey') {
    Iif (securityDefinition.in === 'query') {
      scopeOrKey = helpers.queryString(req)[securityDefinition.name];
    } else Eif (securityDefinition.in === 'header') {
      scopeOrKey = req.headers[securityDefinition.name.toLowerCase()];
    }
  }
 
  return scopeOrKey;
}
 
function sendSecurityError(err, res, next) {
 
  Eif (!err.code) { err.code = 'server_error'; }
  Eif (!err.statusCode) { err.statusCode = 403; }
 
  Iif (err.headers) {
    _.each(err.headers, function (header, name) {
      res.setHeader(name, header);
    });
  }
 
  res.statusCode = err.statusCode;
 
  next(err);
}