UNPKG

3.4 kBJavaScriptView Raw
1'use strict'
2
3const fileAuthorizers = require('./fileAuthorizers')
4
5exports.getAuthorizers = getAuthorizers
6exports.createAuthCheck = createAuthCheck
7
8function 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
14function getDefinitionIds(security) {
15 return Object.keys(security || {})
16 .filter(id => !id.startsWith('x-'))
17}
18
19function 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
28function 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
37function createAuthCheck(operation, authorizers) {
38 let security = operation.security || []
39 if (security && !Array.isArray(security)) security = [ security ]
40 if (!security.length) return null
41
42 const securityExt = operation['x-security']
43
44 return function authorize(req, res, next) {
45 return Promise.all(security.map(scheme => {
46 const id = Object.keys(scheme)[0]
47 if (!id || id.startsWith('x-')) return null
48
49 return new Promise((resolve, reject) => {
50 const authorizer = authorizers.get(id)
51 const ext = (securityExt && securityExt[id])
52 ? securityExt[id]
53 : {}
54
55 if (typeof authorizer === 'function') {
56 const requiredScopes = scheme[id]
57 req.verifyScopes = function verifyScopes(scopes) {
58 return verifyRequiredScopes(requiredScopes, scopes, ext)
59 }
60 try {
61 const result = authorizer(req, res, err => err ? reject(err) : resolve())
62 if (result && result.catch) result.catch(e => reject(e))
63 } catch(e) {
64 reject(e)
65 }
66 } else {
67 // Unable to determine at this point if authorized but don't
68 // have correct scope(s), or if authorization is required.
69 // Assume the latter.
70 const e = new Error('Unauthorized')
71 e.statusCode = e.status = 401
72 reject(e)
73 }
74 })
75 }))
76 .then(() => next())
77 .catch(e => next(e))
78 }
79}
80
81function verifyRequiredScopes(requiredScopes, scopes, ext) {
82 if (!requiredScopes || !requiredScopes.length) return undefined
83 if (!scopes) scopes = []
84
85 let hasRequiredScopes = false
86 if (ext && ext.OR_scopes) {
87 // This extension allows for the logical OR of token scopes, so if one
88 // or more scopes exist, access is permitted.
89 hasRequiredScopes = requiredScopes.some(scope => scopes.indexOf(scope) !== -1)
90 } else {
91 hasRequiredScopes = requiredScopes.every(scope => scopes.indexOf(scope) !== -1)
92 }
93 if (!hasRequiredScopes) {
94 const e = new Error('Forbidden')
95 e.statusCode = e.status = 403
96 e.requiredScopes = requiredScopes
97 return e
98 }
99 return undefined
100}