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 | 1× 1× 1× 1× 1× 1× 13× 13× 13× 12× 12× 12× 12× 13× 93× 93× 93× 93× 93× 20× 20× 20× 20× 20× 20× 20× 16× 8× 8× 20× 20× 8× 20× 20× 20× 1× 8× 8× 8× 8× 8× 8× 8× 1× 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); } |