-
Notifications
You must be signed in to change notification settings - Fork 90
/
security-definitions-ibm.js
132 lines (113 loc) · 3.95 KB
/
security-definitions-ibm.js
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// From swagger-tools -
// Assertation 1: Security requirements defined in securityDefinitions should be used in the spec
// Assertation 2: Each scope defined in an OAuth2 scheme should be used in the spec
const each = require('lodash/each');
module.exports.validate = function({ resolvedSpec, isOAS3 }, config) {
const result = {};
result.error = [];
result.warning = [];
config = config.security_definitions;
const definedSchemes = {};
const definedScopes = {};
// collect the security requirements and all relevant scopes
const securityDefinitions = isOAS3
? resolvedSpec.components && resolvedSpec.components.securitySchemes
: resolvedSpec.securityDefinitions;
each(securityDefinitions, (scheme, name) => {
if (name.slice(0, 2) === 'x-') return;
definedSchemes[name] = {};
definedSchemes[name].used = false;
definedSchemes[name].type = scheme.type;
// collect scopes in oauth2 schemes
if (scheme.type.toLowerCase() === 'oauth2') {
if (isOAS3) {
if (scheme.flows) {
each(scheme.flows, (flow, flowType) => {
if (flow.scopes) {
Object.keys(flow.scopes).forEach(scope => {
definedScopes[scope] = {};
definedScopes[scope].used = false;
definedScopes[scope].scheme = name;
definedScopes[scope].flow = flowType;
});
}
});
}
} else {
Object.keys(scheme.scopes).forEach(scope => {
definedScopes[scope] = {};
definedScopes[scope].used = false;
definedScopes[scope].scheme = name;
});
}
}
});
// check all instances of 'security' objects
// security objects can exist at either:
// 1) the top level of the spec (global definition)
if (resolvedSpec.security) {
flagUsedDefinitions(resolvedSpec.security);
}
// 2) within operations objects
const paths = resolvedSpec.paths;
each(paths, (operations, pathName) => {
if (pathName.slice(0, 2) === 'x-') return;
each(operations, (operation, opName) => {
if (opName.slice(0, 2) === 'x-') return;
if (operation.security) {
flagUsedDefinitions(operation.security);
}
});
});
function flagUsedDefinitions(security) {
security.forEach(scheme => {
// each object in this array should only have one key - the name of the scheme
const name = Object.keys(scheme)[0];
// make sure this scheme was in the security definitions, then label as used
if (definedSchemes[name]) {
definedSchemes[name].used = true;
const type = definedSchemes[name].type;
const scopesArray = scheme[name];
if (type.toLowerCase() === 'oauth2') {
scopesArray.forEach(scope => {
if (definedScopes[scope]) {
definedScopes[scope].used = true;
}
});
}
}
});
}
// check what has been used and what has not been
each(definedSchemes, (info, name) => {
if (info.used === false) {
const checkStatus = config.unused_security_schemes;
if (checkStatus !== 'off') {
const location = isOAS3
? 'components.securitySchemes'
: 'securityDefinitions';
result[checkStatus].push({
path: `${location}.${name}`,
message: `A security scheme is defined but never used: ${name}`
});
}
}
});
each(definedScopes, (info, name) => {
if (info.used === false) {
const checkStatus = config.unused_security_scopes;
if (checkStatus !== 'off') {
const path = isOAS3
? `components.securitySchemes.${info.scheme}.flows.${
info.flow
}.scopes.${name}`
: `securityDefinitions.${info.scheme}.scopes.${name}`;
result[checkStatus].push({
path,
message: `A security scope is defined but never used: ${name}`
});
}
}
});
return { errors: result.error, warnings: result.warning };
};