-
Notifications
You must be signed in to change notification settings - Fork 0
/
whitelist-validator.js
88 lines (74 loc) · 2.54 KB
/
whitelist-validator.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
const HTTPError = require('node-http-error')
const jwt = require('jsonwebtoken')
const { prop, pathOr, not, isEmpty, find, isNil } = require('ramda')
module.exports = async options => {
const { req, apiErrorDocsURL } = options
const authorizationHeader = pathOr('', ['headers', 'authorization'], req)
const [scheme, token] = authorizationHeader.split(' ')
if (scheme !== 'Bearer' || (isEmpty(token) || isNil(token))) {
const err = new HTTPError(
401,
`Unauthorized. Authorization header must include a Bearer token.`,
{
name: `Missing Bearer Token`,
errorCode: `missing-bearer-token`,
errorReference: `${apiErrorDocsURL}/missing-bearer-token`
}
)
return { ok: false, err }
}
if (not(prop('whitelist', req))) {
const err = new HTTPError(
500,
`Unable to validate jwt due to missing whitelist.`,
{
name: `Missing Whitelist`,
errorCode: `missing-whitelist`,
errorReference: `${apiErrorDocsURL}/missing-whitelist`
}
)
return { ok: false, err }
}
const decoded = jwt.decode(token, { complete: true })
const iss = pathOr('', ['payload', 'iss'], decoded)
const tenant = pathOr(
pathOr('', ['payload', 'sub'], decoded),
['payload', 'tenant'],
decoded
)
// The `tenant` or `sub` property is optional on the JWT.
// If the tenant exists, then
// use it first when validating CDS Hook client against whitelist.
// Otherwise, we assume the iss is unique.
// If iss is not unique then the EHR must provide a `tenant` value in the JWT
const { whitelist } = req
// if (process.env.NODE_ENV === "test") {
// console.log({ whitelist, tenant, token, decoded });
// }
const byIssAndTenant = listItem =>
listItem.iss === iss &&
listItem.tenant === tenant &&
listItem.enabled === true
const byIss = listItem => listItem.iss === iss && listItem.enabled === true
const foundWhiteListItem = isEmpty(tenant)
? find(byIss, whitelist)
: find(byIssAndTenant, whitelist)
if (not(foundWhiteListItem)) {
const err = new HTTPError(
401,
`Unauthorized. We were unable to verify a valid iss or tenant. If tenant value not provided in JWT, then iss value must be unique in whitelist.`,
{
name: `Not Found on Whitelist`,
errorCode: `not-found-on-whitelist`,
errorReference: `${apiErrorDocsURL}/not-found-on-whitelist`
}
)
return { ok: false, err }
}
return {
ok: true,
whiteListItem: foundWhiteListItem,
decodedToken: decoded,
token
}
}