| 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);
}
|