1 | 'use strict'
|
2 |
|
3 | const fileAuthorizers = require('./fileAuthorizers')
|
4 |
|
5 | exports.getAuthorizers = getAuthorizers
|
6 | exports.createAuthCheck = createAuthCheck
|
7 |
|
8 | function getAuthorizers(securityDefinitions, options) {
|
9 | return getDefinitionIds(securityDefinitions)
|
10 | .map(id => ({ id, auth: getAuthorizer(id, securityDefinitions[id], options) }))
|
11 | .reduce((authorizers, info) => authorizers.set(info.id, info.auth), new Map())
|
12 | }
|
13 |
|
14 | function getDefinitionIds(security) {
|
15 | return Object.keys(security || {})
|
16 | .filter(id => !id.startsWith('x-'))
|
17 | }
|
18 |
|
19 | function getAuthorizer(id, securityScheme, options) {
|
20 | let authorizer
|
21 | if (typeof options.authorizers.create === 'function') authorizer = options.authorizers.create(id, securityScheme)
|
22 | if (authorizer) fileAuthorizers.disableAuthorizer(id, options)
|
23 | else authorizer = requireAuthorizer(id, securityScheme, options)
|
24 | if (authorizer && authorizer.default) authorizer = authorizer.default
|
25 | return authorizer
|
26 | }
|
27 |
|
28 | function requireAuthorizer(id, securityScheme, options) {
|
29 | const fileInfo = fileAuthorizers.enableAuthorizer(id, securityScheme, options)
|
30 | try { return require(fileInfo.path) }
|
31 | catch(e) {
|
32 | if (e.code === 'MODULE_NOT_FOUND') return null
|
33 | else throw e
|
34 | }
|
35 | }
|
36 |
|
37 | function createAuthCheck(operation, authorizers) {
|
38 | let security = operation.security || []
|
39 | if (security && !Array.isArray(security)) security = [ security ]
|
40 | if (!security.length) return null
|
41 |
|
42 | return function authorize(req, res, next) {
|
43 | return Promise.all(security.map(scheme => {
|
44 | const id = Object.keys(scheme)[0]
|
45 | if (!id || id.startsWith('x-')) return null
|
46 |
|
47 | return new Promise((resolve, reject) => {
|
48 | const authorizer = authorizers.get(id)
|
49 | if (typeof authorizer === 'function') {
|
50 | const requiredScopes = scheme[id]
|
51 | req.verifyScopes = function verifyScopes(scopes) {
|
52 | return verifyRequiredScopes(requiredScopes, scopes)
|
53 | }
|
54 | try {
|
55 | const result = authorizer(req, res, err => err ? reject(err) : resolve())
|
56 | if (result && result.catch) result.catch(e => reject(e))
|
57 | } catch(e) {
|
58 | reject(e)
|
59 | }
|
60 | } else {
|
61 |
|
62 |
|
63 |
|
64 | const e = new Error('Unauthorized')
|
65 | e.statusCode = e.status = 401
|
66 | reject(e)
|
67 | }
|
68 | })
|
69 | }))
|
70 | .then(() => next())
|
71 | .catch(e => next(e))
|
72 | }
|
73 | }
|
74 |
|
75 | function verifyRequiredScopes(requiredScopes, scopes) {
|
76 | if (!requiredScopes || !requiredScopes.length) return undefined
|
77 | if (!scopes) scopes = []
|
78 |
|
79 | const hasRequiredScopes = requiredScopes.every(scope => scopes.indexOf(scope) !== -1)
|
80 | if (!hasRequiredScopes) {
|
81 | const e = new Error('Forbidden')
|
82 | e.statusCode = e.status = 403
|
83 | e.requiredScopes = requiredScopes
|
84 | return e
|
85 | }
|
86 | return undefined
|
87 | }
|