@blazedpath/commons 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/README.md +3 -0
  2. package/blz-base/health/index.js +215 -0
  3. package/blz-base/index.js +1466 -0
  4. package/blz-cache/LruCache.js +44 -0
  5. package/blz-cache/index.js +29 -0
  6. package/blz-config/index.js +434 -0
  7. package/blz-core/index.js +364 -0
  8. package/blz-cryptography/index.js +54 -0
  9. package/blz-datetimes/index.js +356 -0
  10. package/blz-file/example.dat +2545 -0
  11. package/blz-file/fileService.js +205 -0
  12. package/blz-file/index.js +94 -0
  13. package/blz-file/index.test.js +31 -0
  14. package/blz-file/lab.js +33 -0
  15. package/blz-hazelcast/index.js +189 -0
  16. package/blz-hazelcast/lib/credentials.js +25 -0
  17. package/blz-hazelcast/lib/credentialsFactory.js +12 -0
  18. package/blz-hazelcast/lib/hazelcastCache.js +234 -0
  19. package/blz-iterable/index.js +446 -0
  20. package/blz-json-schema/index.js +11 -0
  21. package/blz-jwt/index.js +121 -0
  22. package/blz-kafka/index.js +522 -0
  23. package/blz-math/index.js +131 -0
  24. package/blz-mongodb/index.js +326 -0
  25. package/blz-rds/__test__/scape.test.js +58 -0
  26. package/blz-rds/blz-rds-executor.js +578 -0
  27. package/blz-rds/blz-rds-helper.js +310 -0
  28. package/blz-rds/commands/core/add.js +13 -0
  29. package/blz-rds/commands/core/and.js +18 -0
  30. package/blz-rds/commands/core/asc.js +10 -0
  31. package/blz-rds/commands/core/avg.js +10 -0
  32. package/blz-rds/commands/core/column-ref.js +8 -0
  33. package/blz-rds/commands/core/count-distinct.js +10 -0
  34. package/blz-rds/commands/core/count.js +10 -0
  35. package/blz-rds/commands/core/decimal.js +8 -0
  36. package/blz-rds/commands/core/desc.js +10 -0
  37. package/blz-rds/commands/core/distinct.js +10 -0
  38. package/blz-rds/commands/core/divide.js +11 -0
  39. package/blz-rds/commands/core/embedded-exists.js +17 -0
  40. package/blz-rds/commands/core/embedded-select.js +17 -0
  41. package/blz-rds/commands/core/equals.js +9 -0
  42. package/blz-rds/commands/core/false.js +8 -0
  43. package/blz-rds/commands/core/greater-or-equal.js +9 -0
  44. package/blz-rds/commands/core/greater.js +9 -0
  45. package/blz-rds/commands/core/in.js +9 -0
  46. package/blz-rds/commands/core/integer.js +8 -0
  47. package/blz-rds/commands/core/is-not-null.js +11 -0
  48. package/blz-rds/commands/core/is-null-or-value.js +10 -0
  49. package/blz-rds/commands/core/is-null.js +11 -0
  50. package/blz-rds/commands/core/less-or-equal.js +9 -0
  51. package/blz-rds/commands/core/less-unary.js +12 -0
  52. package/blz-rds/commands/core/less.js +9 -0
  53. package/blz-rds/commands/core/like.js +12 -0
  54. package/blz-rds/commands/core/max.js +10 -0
  55. package/blz-rds/commands/core/min.js +10 -0
  56. package/blz-rds/commands/core/multiply.js +13 -0
  57. package/blz-rds/commands/core/not-equals.js +9 -0
  58. package/blz-rds/commands/core/not-in.js +9 -0
  59. package/blz-rds/commands/core/not.js +13 -0
  60. package/blz-rds/commands/core/null.js +8 -0
  61. package/blz-rds/commands/core/nvl.js +11 -0
  62. package/blz-rds/commands/core/or.js +13 -0
  63. package/blz-rds/commands/core/parameter.js +34 -0
  64. package/blz-rds/commands/core/remainder.js +16 -0
  65. package/blz-rds/commands/core/string.js +8 -0
  66. package/blz-rds/commands/core/subtract.js +13 -0
  67. package/blz-rds/commands/core/sum.js +10 -0
  68. package/blz-rds/commands/core/true.js +8 -0
  69. package/blz-rds/commands/core/tuple.js +13 -0
  70. package/blz-rds/commands/datetimes/add-days.js +11 -0
  71. package/blz-rds/commands/datetimes/add-hours.js +11 -0
  72. package/blz-rds/commands/datetimes/add-milliseconds.js +11 -0
  73. package/blz-rds/commands/datetimes/add-minutes.js +11 -0
  74. package/blz-rds/commands/datetimes/add-months.js +11 -0
  75. package/blz-rds/commands/datetimes/add-seconds.js +11 -0
  76. package/blz-rds/commands/datetimes/add-years.js +11 -0
  77. package/blz-rds/commands/datetimes/date-diff.js +11 -0
  78. package/blz-rds/commands/datetimes/date.js +12 -0
  79. package/blz-rds/commands/datetimes/datetime-diff.js +11 -0
  80. package/blz-rds/commands/datetimes/datetime.js +15 -0
  81. package/blz-rds/commands/datetimes/day.js +10 -0
  82. package/blz-rds/commands/datetimes/hour.js +10 -0
  83. package/blz-rds/commands/datetimes/millisecond.js +10 -0
  84. package/blz-rds/commands/datetimes/minute.js +10 -0
  85. package/blz-rds/commands/datetimes/month-text.js +10 -0
  86. package/blz-rds/commands/datetimes/month.js +10 -0
  87. package/blz-rds/commands/datetimes/now.js +9 -0
  88. package/blz-rds/commands/datetimes/second.js +10 -0
  89. package/blz-rds/commands/datetimes/subtract-days.js +11 -0
  90. package/blz-rds/commands/datetimes/subtract-hours.js +11 -0
  91. package/blz-rds/commands/datetimes/subtract-milliseconds.js +11 -0
  92. package/blz-rds/commands/datetimes/subtract-minutes.js +11 -0
  93. package/blz-rds/commands/datetimes/subtract-seconds.js +11 -0
  94. package/blz-rds/commands/datetimes/time-diff.js +11 -0
  95. package/blz-rds/commands/datetimes/time.js +13 -0
  96. package/blz-rds/commands/datetimes/today.js +9 -0
  97. package/blz-rds/commands/datetimes/week-day-text.js +10 -0
  98. package/blz-rds/commands/datetimes/week-day.js +10 -0
  99. package/blz-rds/commands/datetimes/week.js +10 -0
  100. package/blz-rds/commands/datetimes/year.js +10 -0
  101. package/blz-rds/commands/math/abs.js +10 -0
  102. package/blz-rds/commands/math/acos.js +10 -0
  103. package/blz-rds/commands/math/asin.js +10 -0
  104. package/blz-rds/commands/math/atan.js +10 -0
  105. package/blz-rds/commands/math/atan2.js +11 -0
  106. package/blz-rds/commands/math/ceil.js +10 -0
  107. package/blz-rds/commands/math/cos.js +10 -0
  108. package/blz-rds/commands/math/cosh.js +10 -0
  109. package/blz-rds/commands/math/exp.js +10 -0
  110. package/blz-rds/commands/math/floor.js +10 -0
  111. package/blz-rds/commands/math/log.js +18 -0
  112. package/blz-rds/commands/math/log10.js +10 -0
  113. package/blz-rds/commands/math/pow.js +11 -0
  114. package/blz-rds/commands/math/random.js +9 -0
  115. package/blz-rds/commands/math/round.js +18 -0
  116. package/blz-rds/commands/math/sign.js +10 -0
  117. package/blz-rds/commands/math/sin.js +10 -0
  118. package/blz-rds/commands/math/sinh.js +10 -0
  119. package/blz-rds/commands/math/sqrt.js +10 -0
  120. package/blz-rds/commands/math/tan.js +10 -0
  121. package/blz-rds/commands/math/tanh.js +10 -0
  122. package/blz-rds/commands/math/trunc.js +18 -0
  123. package/blz-rds/commands/strings/concat.js +20 -0
  124. package/blz-rds/commands/strings/contains.js +12 -0
  125. package/blz-rds/commands/strings/ends-with.js +12 -0
  126. package/blz-rds/commands/strings/index-of.js +11 -0
  127. package/blz-rds/commands/strings/is-null-or-empty.js +11 -0
  128. package/blz-rds/commands/strings/is-null-or-white-space.js +11 -0
  129. package/blz-rds/commands/strings/join.js +22 -0
  130. package/blz-rds/commands/strings/last-index-of.js +11 -0
  131. package/blz-rds/commands/strings/length.js +10 -0
  132. package/blz-rds/commands/strings/pad-left.js +20 -0
  133. package/blz-rds/commands/strings/pad-right.js +20 -0
  134. package/blz-rds/commands/strings/replace.js +12 -0
  135. package/blz-rds/commands/strings/starts-with.js +12 -0
  136. package/blz-rds/commands/strings/substring.js +12 -0
  137. package/blz-rds/commands/strings/to-lower.js +10 -0
  138. package/blz-rds/commands/strings/to-upper.js +10 -0
  139. package/blz-rds/commands/strings/trim-end.js +10 -0
  140. package/blz-rds/commands/strings/trim-start.js +10 -0
  141. package/blz-rds/commands/strings/trim.js +10 -0
  142. package/blz-rds/index.js +744 -0
  143. package/blz-rds-mysql/base.js +857 -0
  144. package/blz-rds-mysql/connection-manager.js +129 -0
  145. package/blz-rds-mysql/execute-bulk-insert.js +35 -0
  146. package/blz-rds-mysql/execute-bulk-merge.js +45 -0
  147. package/blz-rds-mysql/execute-non-query.js +34 -0
  148. package/blz-rds-mysql/execute-query.js +50 -0
  149. package/blz-rds-mysql/index.js +41 -0
  150. package/blz-rds-mysql/stored-procedure.js +207 -0
  151. package/blz-rds-mysql/syntaxis.json +114 -0
  152. package/blz-rds-mysqlx/base.js +846 -0
  153. package/blz-rds-mysqlx/connection-manager.js +141 -0
  154. package/blz-rds-mysqlx/execute-bulk-insert.js +35 -0
  155. package/blz-rds-mysqlx/execute-bulk-merge.js +45 -0
  156. package/blz-rds-mysqlx/execute-non-query.js +29 -0
  157. package/blz-rds-mysqlx/execute-query.js +39 -0
  158. package/blz-rds-mysqlx/index.js +41 -0
  159. package/blz-rds-mysqlx/stored-procedure.js +179 -0
  160. package/blz-rds-mysqlx/syntaxis.json +105 -0
  161. package/blz-rds-oracle/index.js +540 -0
  162. package/blz-rds-oracle/syntaxis.json +112 -0
  163. package/blz-rds-postgres/base.js +861 -0
  164. package/blz-rds-postgres/connection-manager.js +225 -0
  165. package/blz-rds-postgres/execute-bulk-insert.js +81 -0
  166. package/blz-rds-postgres/execute-bulk-merge.js +93 -0
  167. package/blz-rds-postgres/execute-non-query.js +23 -0
  168. package/blz-rds-postgres/execute-query.js +37 -0
  169. package/blz-rds-postgres/index.js +41 -0
  170. package/blz-rds-postgres/result-set.js +51 -0
  171. package/blz-rds-postgres/stored-procedure.js +116 -0
  172. package/blz-rds-postgres/syntaxis.json +114 -0
  173. package/blz-redis/index.js +217 -0
  174. package/blz-redis/lib/redisCache.js +265 -0
  175. package/blz-regex/index.js +25 -0
  176. package/blz-security/.eslintrc.js +15 -0
  177. package/blz-security/__test__/AuthorizationKpn.yaml +1043 -0
  178. package/blz-security/__test__/FinancingSetting.yaml +177 -0
  179. package/blz-security/__test__/KpnConfigPortal.yaml +330 -0
  180. package/blz-security/__test__/OrderManagement.yaml +5190 -0
  181. package/blz-security/__test__/Security.yaml +128 -0
  182. package/blz-security/__test__/autorization.test.js +105 -0
  183. package/blz-security/__test__/orderManagement.test.js +26 -0
  184. package/blz-security/__test__/secureUrl.test.js +79 -0
  185. package/blz-security/__test__/solveMergeRule.test.js +109 -0
  186. package/blz-security/__test__/sqlInjectionGuard.test.js +203 -0
  187. package/blz-security/__test__/xssGuard.test.js +204 -0
  188. package/blz-security/authorizationService.js +536 -0
  189. package/blz-security/config/global.js +8 -0
  190. package/blz-security/config/welcome +8 -0
  191. package/blz-security/doc/README.md +75 -0
  192. package/blz-security/filescanner/index.js +46 -0
  193. package/blz-security/helpers/consts.js +229 -0
  194. package/blz-security/helpers/utils.js +267 -0
  195. package/blz-security/implementations/cache.js +90 -0
  196. package/blz-security/implementations/oidc.js +404 -0
  197. package/blz-security/implementations/pkceCacheStore.js +23 -0
  198. package/blz-security/implementations/saml.js +10 -0
  199. package/blz-security/implementations/uma.js +63 -0
  200. package/blz-security/implementations/webAuthn.js +9 -0
  201. package/blz-security/implementations/wstg.js +72 -0
  202. package/blz-security/index.js +77 -0
  203. package/blz-security/lab/index.js +27 -0
  204. package/blz-security/middleware/HapiServerAzureAd.js +641 -0
  205. package/blz-security/middleware/HapiServerKeycloak.js +840 -0
  206. package/blz-security/middleware/HapiServerSimToken.js +247 -0
  207. package/blz-security/middleware/hapi.js +515 -0
  208. package/blz-security/middleware/hapiServer.js +974 -0
  209. package/blz-security/navigationMemoryRepository.js +15 -0
  210. package/blz-security/navigationMongoDbRepository.js +73 -0
  211. package/blz-security/secureUrlService.js +47 -0
  212. package/blz-security/securityService.js +409 -0
  213. package/blz-security/sqlInjectionGuard.js +162 -0
  214. package/blz-security/templates/forbidden.html +0 -0
  215. package/blz-security/templates/session-iframe-azure-ad.html +7 -0
  216. package/blz-security/templates/session-iframe.html +73 -0
  217. package/blz-security/templates/unauthorized.html +1 -0
  218. package/blz-security/xssGuard.js +87 -0
  219. package/blz-strings/index.js +167 -0
  220. package/blz-uuid/index.js +7 -0
  221. package/blz-yaml/index.js +19 -0
  222. package/index.js +84 -0
  223. package/package.json +97 -0
  224. package/process-managers/index.js +422 -0
@@ -0,0 +1,404 @@
1
+ /**
2
+ * @author Blazedpath Team
3
+ * @implements OpenID Connect specifications
4
+ * @description It is an identity protocol that is designed to authenticate
5
+ * users through relying parties (RP or applications) with an external server
6
+ * called OpenID Connect Provider (OP); this server typically gets the user
7
+ * information from an identity provider for access control.
8
+ * @see https://openid.net/specs/openid-connect-core-1_0.html
9
+ */
10
+
11
+ const CryptoJS = require('crypto-js') // Crypto standards
12
+ const { Issuer, generators, custom } = require('openid-client') // OpenID Certified Relying Party.
13
+ const Jsonwebtoken = require('jsonwebtoken') // Implementations of JSON Web Tokens.
14
+ const JwksClient = require('jwks-rsa') // Retrieve RSA public keys from a JWKS.
15
+ const Uuid = require('uuid') // Support for RFC4122 version 1, 3, 4, and 5 UUIDs.
16
+ const { METADATA } = require('../helpers/consts')
17
+ // const cache = require('../implementations/cache')
18
+ const { trace, Exception: Exception, getTokenTolerance } = require('../helpers/utils')
19
+
20
+ /**
21
+ * @param OP OpenId Provider
22
+ * @param RP Relying Party (Client)
23
+ */
24
+
25
+ /**
26
+ * Variables with a global scope
27
+ */
28
+
29
+ let jwks // Provide the client with the jwks which exposes signing keys.
30
+ let clientOidc // Client instance for the authorization server of that issuer.
31
+
32
+ custom.setHttpOptionsDefaults({
33
+ timeout: process.env.TIMEOUT_HTTP || 30e3
34
+ })
35
+
36
+ /**
37
+ * @name Iss
38
+ * @api public
39
+ * @description Entity that issues a set of claims
40
+ */
41
+ class Iss {
42
+ /**
43
+ * @constructor
44
+ * @param {Object} metadata
45
+ */
46
+ constructor (metadata) {
47
+ if (!metadata.id_token_signing_alg_values_supported) {
48
+ metadata.id_token_signing_alg_values_supported = ['RS256']
49
+ }
50
+ if (!metadata.response_types_supported) {
51
+ metadata.response_types_supported = ['code', 'none', 'id_token', 'token', 'id_token token', 'code id_token', 'code token', 'code id_token token']
52
+ }
53
+ if (!metadata.subject_types_supported) {
54
+ metadata.subject_types_supported = ['public']
55
+ }
56
+ const claimsRequired = METADATA.filter(({ type }) => type === 'REQUIRED')
57
+ const attributes = Object.entries(metadata)
58
+ for (let i = 0; i < attributes.length; i++) {
59
+ claimsRequired.forEach((claim, index) => {
60
+ if (attributes[i][0] === claim.name && attributes[i][1]) {
61
+ claimsRequired.splice(index, 1)
62
+ }
63
+ })
64
+ }
65
+ if (claimsRequired.length > 0) {
66
+ throw new Exception(JSON.stringify(claimsRequired), 'ClaimError', 403)
67
+ }
68
+ jwks = JwksClient({
69
+ cache: true, // Signature key verification results are cached to prevent excessive HTTP requests.
70
+ rateLimit: true, // Limit requests that are made to the jwks per minute.
71
+ cacheMaxAge: 60e3, // 1 minute to cache because a key rotation could have taken place.
72
+ jwksRequestsPerMinute: 15, // Max requests per minute.
73
+ jwksUri: metadata.jwks_uri // https://issuer/.well-known/jwks.json or https://issuer/openid-connect/certs
74
+ })
75
+ const issuer = metadata.Client ? metadata : new Issuer(metadata)
76
+ // Client instance for the authorization server of that issuer.
77
+ const clientPayload = {
78
+ client_id: metadata.clientId,
79
+ response_type: 'code'
80
+ }
81
+ if (metadata.clientSecret) {
82
+ clientPayload.client_secret = metadata.clientSecret
83
+ }
84
+ clientOidc = new issuer.Client(clientPayload)
85
+ }
86
+ }
87
+ class Oidc {
88
+ constructor (cache, config) {
89
+ this.cache = cache
90
+ this.config = config
91
+ if (this.config.authServer) {
92
+ if (this.config.authServer.PrivateKey && this.config.authServer.PublicKey) {
93
+ this.config.authServer.PrivateKey = this.config.authServer.PrivateKey.replace(/\\n/g, '\n')
94
+ this.config.authServer.PublicKey = this.config.authServer.PublicKey.replace(/\\n/g, '\n')
95
+ } else if (process.env.PRIVATE_KEY && process.env.PUBLIC_KEY) {
96
+ this.config.authServer.PrivateKey = process.env.PRIVATE_KEY
97
+ this.config.authServer.PublicKey = process.env.PUBLIC_KEY
98
+ } else {
99
+ throw new Exception('Private and public keys are mandatory', 'AttributeError', 403)
100
+ }
101
+ if (!this.config.authServer.Signature) {
102
+ if (process.env.OIDC_SIGNATURE)
103
+ this.config.authServer.Signature = process.env.OIDC_SIGNATURE
104
+ else
105
+ this.config.authServer.Signature = '--'
106
+ }
107
+ }
108
+ }
109
+
110
+ oidcMetadataKey() {
111
+ return this.config.authServer.sessionCookiesDomain || 'oidcMetadata'
112
+ }
113
+
114
+ async oidcMetadata() {
115
+ return await this.cache.get(this.oidcMetadataKey())
116
+ }
117
+
118
+ /**
119
+ * @name configuration
120
+ * @api public
121
+ * @param {String} uri OP configuration information
122
+ */
123
+ async configuration (context) {
124
+ let metadata = await this.cache.get(this.oidcMetadataKey())
125
+ if (typeof context === 'string' && !context.match(/(https?:\/\/.*):?(\d*)\/?(.*)/gi)) {
126
+ throw new Exception('Wrong OpenId Provider configuration URI entered', 'AttributeError', 403)
127
+ }
128
+ if (!metadata || !metadata.issuer) {
129
+ if (context.issuer) {
130
+ metadata = { ...(metadata || {}), ...context }
131
+ } else {
132
+ metadata = metadata || {}
133
+ metadata.openid_configuration = context
134
+ metadata = { ...metadata, ...(await Issuer.discover(context)) } // Discover an issuer configuration.
135
+ }
136
+ await this.cache.set(this.oidcMetadataKey(), metadata, 864e5) // 1 day of cache
137
+ }
138
+ return new Iss(metadata)
139
+ }
140
+
141
+ expiresIn (tokensSet) {
142
+ return Math.round((tokensSet.expires_at * 1000 - Date.now()) / 1000)
143
+ }
144
+
145
+ expired (tokensSet) {
146
+ return this.expiresIn(tokensSet) < getTokenTolerance()
147
+ }
148
+
149
+ /**
150
+ * @name tokenSet
151
+ * @generator PKCE is mandatory in OAuth 2.1.
152
+ * @see https://tools.ietf.org/html/draft-ietf-oauth-v2-1-02
153
+ * @see https://tools.ietf.org/html/rfc7636
154
+ */
155
+ async tokenSet () {
156
+ return {
157
+ /**
158
+ * @name tokens
159
+ * @api public
160
+ * @param sessionState String that represents the End-User's login state at the OP.
161
+ * @returns Tokens set
162
+ */
163
+ tokens: async (sessionState) => {
164
+ if (!sessionState) {
165
+ throw new Exception('Session state is mandatory', 'AttributeError', 404)
166
+ }
167
+ const tokensSet = await this.cache.get(sessionState)
168
+ if (!tokensSet || !tokensSet.access_token) {
169
+ throw new Exception(`No token found fo session_state: ${sessionState}`, 'TokenError', 403)
170
+ }
171
+ // Get the payload by the public key and verify it.
172
+ // const publicKey = (hdr, cb) => jwks.getSigningKey(hdr.kid, async (err, key) => cb(err, key ? key.publicKey || key.rsaPublicKey : key))
173
+ // const [error] = await new Promise((resolve) => {
174
+ // Jsonwebtoken.verify(tokensSet.access_token, publicKey, null, async (err, res) => {
175
+ // resolve([err, res])
176
+ // })
177
+ // })
178
+ // if (error) {
179
+ // throw new Exception(error.message, 'TokenInvalid', 403)
180
+ // }
181
+ if (this.expired(tokensSet) && tokensSet.refresh_token) {
182
+ const [error, payload] = await clientOidc.refresh(tokensSet.refresh_token, {
183
+ exchangeBody: {
184
+ client_id: clientOidc.clientId
185
+ }
186
+ }).then((tokenSet) => [null, tokenSet]).catch((error) => [error, null])
187
+ if (error || !payload.access_token) {
188
+ await this.cache.del(sessionState)
189
+ throw new Exception(`Can not refresh token for session_state: ${sessionState}`, 'ExpirationError', 403)
190
+ }
191
+ trace('INFO', `Refresh token for session_state: ${sessionState}`)
192
+ await this.cache.set(sessionState, payload, (payload.refresh_expires_in || payload.expires_in) * 1e3)
193
+ return payload
194
+ }
195
+ if (tokensSet.refresh_expires_in < getTokenTolerance()) {
196
+ await this.cache.del(sessionState)
197
+ throw new Exception(`Token expired, remove session_state: ${sessionState}`, 'ExpirationError', 403)
198
+ }
199
+ trace('INFO', `Get token of session_state: ${sessionState}`)
200
+ return tokensSet
201
+ },
202
+ /**
203
+ * @name generate
204
+ * @api public
205
+ * @param {code, scope, redirect_uri}
206
+ * @description Generate token with authorization flow with PKCE.
207
+ */
208
+ generate: async ({ code, scope = 'openid', redirectUri = '', sid }) => {
209
+ if (!sid) {
210
+ throw new Exception('SID is mandatory', '')
211
+ }
212
+ const { codeVerifier } = await this.pkceCode(sid)
213
+ const tokensResponse = await clientOidc.callback(redirectUri,
214
+ {
215
+ grant_type: 'authorization_code',
216
+ code,
217
+ scope,
218
+ client_id: clientOidc.client_id,
219
+ client_secret: clientOidc.client_secret || ' ',
220
+ redirect_uri: redirectUri
221
+ },
222
+ {
223
+ code_verifier: codeVerifier
224
+ }).then((tokenSet) => tokenSet).catch((error) => error)
225
+
226
+ if (tokensResponse && tokensResponse.access_token) {
227
+ tokensResponse.session_state = tokensResponse.session_state || Uuid.v4()
228
+ if (tokensResponse.refresh_expires_in <= getTokenTolerance(0)) {
229
+ throw new Exception(`Invalid refresh token expiration ${tokensResponse.refresh_expires_in}`, 'ExpirationError', 403)
230
+ }
231
+ const expirationTime = (tokensResponse.refresh_expires_in || tokensResponse.expires_in) * 1e3
232
+ if (expirationTime > 0) {
233
+ await this.cache.set(tokensResponse.session_state, tokensResponse, expirationTime)
234
+ return tokensResponse
235
+ } else {
236
+ trace('ERROR', `Expiration time: ${expirationTime}`)
237
+ return null
238
+ }
239
+ }
240
+ if (tokensResponse.message && tokensResponse.exp <= tokensResponse.now) {
241
+ throw new Exception(tokensResponse.message, 'ExpirationError', 403)
242
+ }
243
+ throw new Exception(tokensResponse.error_description || tokensResponse.error || tokensResponse.message, 'TokenError', 403)
244
+ },
245
+ /**
246
+ * @name userInfo
247
+ * @api public
248
+ * @param {String} sessionState
249
+ * @returns userInfo Returns previously consented user profile information to the RP.
250
+ * @see https://openid.net/specs/openid-connect-core-1_0.html#UserInfo
251
+ */
252
+ userInfo: async (sessionState) => {
253
+ const tokensSet = await this.cache.get(sessionState)
254
+ let userInfo = {}
255
+ if (!tokensSet || !tokensSet.access_token) {
256
+ throw new Exception('Access token is mandatory', 'TokenError', 401)
257
+ }
258
+ if (clientOidc.issuer && clientOidc.issuer.userinfo_endpoint) {
259
+ userInfo = await clientOidc.userinfo(tokensSet.access_token).then((info) => info).catch((err) => err)
260
+ } else {
261
+ userInfo = Jsonwebtoken.decode(tokensSet.id_token)
262
+ }
263
+ if (!userInfo.user_name && userInfo.name) {
264
+ userInfo.user_name = userInfo.name
265
+ }
266
+ if (userInfo.error) {
267
+ throw new Exception(userInfo.error, 'UserInfoError', 403)
268
+ }
269
+ return userInfo
270
+ }
271
+ }
272
+ }
273
+
274
+ getUseTokenType() {
275
+ return this.config.authServer.useTokenType || 'access_token'
276
+ }
277
+
278
+ async getUseToken (sessionState) {
279
+ const tokenSet = await this.tokenSet();
280
+ if (tokenSet && sessionState) {
281
+ const tokens = await tokenSet.tokens(sessionState);
282
+ if (tokens) {
283
+ return tokens[this.getUseTokenType()];
284
+ }
285
+ }
286
+ return null;
287
+ }
288
+
289
+ /**
290
+ * @name pkceCode
291
+ * @api public
292
+ * @description The properties "code_challenge" and "code_verifier" are adopted from the OAuth 2.0 extension
293
+ * known as "Proof-Key for Code Exchange", or PKCE [RFC7636].
294
+ * @see https://datatracker.ietf.org/doc/html/rfc7636
295
+ * @param {String} code
296
+ * @returns
297
+ */
298
+ async pkceCode (code) {
299
+ if (!code) {
300
+ const codeVerifier = generators.codeVerifier()
301
+ const data = {
302
+ jti: Uuid.v4(),
303
+ iat: Math.floor(Date.now() / 1e3),
304
+ typ: 'Serialized-ID',
305
+ state_checker: CryptoJS.AES.encrypt(
306
+ JSON.stringify({
307
+ codeVerifier, // Is a random string.
308
+ codeChallenge: generators.codeChallenge(codeVerifier) // BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))
309
+ }),
310
+ this.config.authServer.Signature
311
+ ).toString()
312
+ }
313
+ const token = Jsonwebtoken.sign(data, this.config.authServer.PrivateKey, { expiresIn: '1m', algorithm: 'RS256' })
314
+ return token
315
+ }
316
+ try {
317
+ const decoded = await Jsonwebtoken.verify(code, this.config.authServer.PublicKey, { algorithms: ['RS256'] })
318
+ const { state_checker: stateChecker } = decoded
319
+ const codeVerifier = JSON.parse(CryptoJS.AES.decrypt(stateChecker, this.config.authServer.Signature).toString(CryptoJS.enc.Utf8))
320
+ return codeVerifier
321
+ } catch (error) {
322
+ throw new Exception(error, 'pkceCode', 403)
323
+ }
324
+ }
325
+
326
+ /**
327
+ * @name authorizationUrl
328
+ * @api public
329
+ * @param {scope, redirect_uri}
330
+ * @returns authorization endpoint with PKCE
331
+ */
332
+ async authorizationUrl ({ scope = 'openid', redirectUri = '', pkceCode }) {
333
+ const { codeChallenge } = await this.pkceCode(pkceCode)
334
+ const oidcMetadata = await this.cache.get(this.oidcMetadataKey())
335
+ if (!clientOidc && !oidcMetadata) {
336
+ throw new Exception('Unable to fetch configuration from identity provider', 'ConfigurationError', 404)
337
+ }
338
+ await this.configuration(oidcMetadata.openid_configuration)
339
+ // Authorization url with code_challenge and code_challenge_method.
340
+ return clientOidc.authorizationUrl({
341
+ scope,
342
+ code_challenge: codeChallenge,
343
+ code_challenge_method: 'S256',
344
+ redirect_uri: redirectUri.replace(/\/(logout|invalid-session).*/gm, '/')
345
+ })
346
+ }
347
+
348
+ /**
349
+ * @name endSessionUrl
350
+ * @api public
351
+ * @param {session_state, redirect_uri}
352
+ * @returns end session url
353
+ */
354
+ async endSessionUrl ({ sessionState, redirectUri }) {
355
+ redirectUri = redirectUri.replace(/logout|invalid-session/gmi, '')
356
+ // Log off specific session.
357
+ trace('INFO', `Logout session_state: ${sessionState}`)
358
+ if (sessionState) {
359
+ const tokensSet = await this.cache.get(sessionState)
360
+ await this.cache.del(sessionState)
361
+ if (tokensSet) {
362
+ return clientOidc.endSessionUrl({
363
+ id_token_hint: tokensSet.id_token,
364
+ post_logout_redirect_uri: redirectUri,
365
+ state: sessionState
366
+ })
367
+ }
368
+ }
369
+ if (!clientOidc) {
370
+ throw new Exception('Unable to fetch configuration from identity provider', 'ConfigurationError', 404)
371
+ }
372
+ return clientOidc.endSessionUrl({
373
+ post_logout_redirect_uri: redirectUri
374
+ })
375
+ }
376
+
377
+ /**
378
+ * @name client
379
+ * @api public
380
+ * @description set client ID and secret in metadata object
381
+ * @param {clientId, clientSecret}
382
+ */
383
+ async client ({ clientId, clientSecret }) {
384
+ if (!clientId) {
385
+ throw new Exception('Client ID is wrong', 'AttributeError', 404)
386
+ }
387
+ const metadata = await this.cache.get(this.oidcMetadataKey())
388
+ if (clientSecret) {
389
+ await this.cache.set(this.oidcMetadataKey(), { ...(metadata || {}), ...{ clientId, clientSecret } }, 864e5)
390
+ } else {
391
+ await this.cache.set(this.oidcMetadataKey(), { ...(metadata || {}), ...{ clientId } }, 864e5)
392
+ }
393
+ }
394
+
395
+ jwt () {
396
+ return {
397
+ sign: ({ payload, secret, algorithm = 'RS256' }) => {
398
+ return Jsonwebtoken.sign(payload, secret, { algorithm: algorithm })
399
+ }
400
+ }
401
+ }
402
+ }
403
+
404
+ module.exports = { Oidc }
@@ -0,0 +1,23 @@
1
+ // Simple in-memory store (can be in a separate module/file)
2
+ const pkceStore = new Map();
3
+
4
+ // Store verifier with a TTL (5 minutes)
5
+ function saveVerifier(stateId, codeVerifier) {
6
+ pkceStore.set(stateId, codeVerifier);
7
+
8
+ // Remove after 5 minutes to avoid memory leaks
9
+ setTimeout(() => {
10
+ pkceStore.delete(stateId);
11
+ }, 5 * 60 * 1000);
12
+ }
13
+
14
+ // Retrieve and remove verifier (one-time use)
15
+ function getVerifier(stateId) {
16
+ const verifier = pkceStore.get(stateId);
17
+ if (verifier) {
18
+ pkceStore.delete(stateId);
19
+ }
20
+ return verifier;
21
+ }
22
+
23
+ module.exports = { saveVerifier, getVerifier };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @author Blazedpath Team
3
+ * @implements Security Assertion Markup Language 2.0 specifications
4
+ * @description It is a standardized way of telling external applications
5
+ * and services that a user is whom they say they are, making it possible
6
+ * to authenticate a user across multiple applications.
7
+ * @see http://saml.xml.org/saml-specifications
8
+ */
9
+
10
+ /** Work-in-progress [WIP] * */
@@ -0,0 +1,63 @@
1
+ /**
2
+ * @author Blazedpath Team
3
+ * @implements User-Managed Access (UMA) 2.0 specifications
4
+ * @description Defines how a client (RP - requesting party) uses a
5
+ * permission ticket to request an access token to get a protected resource
6
+ * asynchronously from the short time the resource owner authorizes access.
7
+ * @see https://tools.ietf.org/html/draft-maler-oauth-umagrant-00
8
+ */
9
+
10
+ const Got = require('got') // HTTP request library
11
+
12
+ /**
13
+ * @param RPT Requesting Party Token
14
+ * @param PAT Protection API Token
15
+ * @param AS Authorization Server
16
+ * @param RS Resource Server
17
+ */
18
+
19
+ /**
20
+ * @name Uma
21
+ * @api public
22
+ * @description Managing access to protected resources.
23
+ */
24
+ class Uma {
25
+ /**
26
+ * @name permission
27
+ * @api public
28
+ * @description
29
+ * @returns
30
+ */
31
+ static async permission () {
32
+ return {
33
+ /**
34
+ * @name ticket
35
+ * @api public
36
+ * @description Through grant type xx:uma-ticket, clients can send authorization
37
+ * requests and get an RPT with all permissions granted by auth server.
38
+ * @param {token_url, token, audience}
39
+ * @returns token
40
+ */
41
+ ticket: async ({ tokenUrl, token, audience }) => {
42
+ const searchParams = new URLSearchParams([
43
+ ['grant_type', 'urn:ietf:params:oauth:grant-type:uma-ticket'],
44
+ ['audience', audience]
45
+ ])
46
+ // Get token with permissions.
47
+ let { body: response } = await Got.post(tokenUrl, {
48
+ headers: {
49
+ Authorization: `Bearer ${token}`,
50
+ 'Content-Type': 'application/x-www-form-urlencoded'
51
+ },
52
+ body: searchParams.toString()
53
+ })
54
+ if (typeof response === 'string') {
55
+ response = JSON.parse(response)
56
+ }
57
+ return response
58
+ }
59
+ }
60
+ }
61
+ }
62
+
63
+ module.exports = Uma
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @author Blazedpath Team
3
+ * @implements Web Authentication (WebAuthn).
4
+ * @description It is a new W3C global standard for secure authentication
5
+ * on the Web supported by all leading browsers and platforms.
6
+ * @see https://www.w3.org/TR/webauthn-2/
7
+ */
8
+
9
+ /** Work-in-progress [WIP] * */
@@ -0,0 +1,72 @@
1
+ /**
2
+ * @author Blazedpath Team
3
+ * @implements OWASP Web Security Testing
4
+ * @description The WSTG is a comprehensive guide to testing the security
5
+ * of web applications and services that provides a framework of best practices
6
+ * used by penetration testers and organizations all over the world.
7
+ * @see https://owasp.org/www-project-web-security-testing-guide/stable/
8
+ */
9
+ const Fs = require('fs')
10
+ const { filePathList } = require('../helpers/utils')
11
+ const { log } = require('../helpers/utils')
12
+
13
+ /**
14
+ * @name informationGathering
15
+ * @api private
16
+ * @param {string} path
17
+ * @description 4-Web Application Security Testing > 01-Information Gathering
18
+ * @see https://owasp.org/www-project-web-security-testing-guide/stable/4-Web_Application_Security_Testing/01-Information_Gathering/
19
+ * @returns testing methods
20
+ */
21
+ const informationGathering = (path) => {
22
+ /**
23
+ * @name reviewLeakage
24
+ * @description Review Webpage Content for Information Leakage (WSTG-INFO-05)
25
+ */
26
+ const reviewLeakage = () => {
27
+ const files = filePathList(path, 'public')
28
+ for (let i = 0; i < files.length; i += 1) {
29
+ const file = files[i]
30
+ if ([/^(.*\.((html?|(tp|ft)l|s?[c|a]ss|less|m?js(on)?)))$/gmi].some((reg) => reg.test(file))) {
31
+ let regex = /( )*<!--((.*)|[^<]*|[^!]*|[^-]*|[^>]*)-->\n*/gm
32
+ let fileContent = Fs.readFileSync(file, 'utf8')
33
+ if ([/^(.*\.((s?[c|a]ss|less)?))$/gmi].some((reg) => reg.test(file))) {
34
+ regex = /\/\*[^*]*\*+([^/*][^*]*\*+)*\//gm
35
+ } else if ([/^(.*\.((m?js(on)?)))$/gmi].some((reg) => reg.test(file))) {
36
+ if (!fileContent.split(/\r?\n/).some(line => line.length > 250 && line.match(/class|Blz|function/gm))) {
37
+ fileContent = fileContent.replace(/(?<=(("([^"\\]|\\.|\\\n)*"|'([^'\\]|\\.|\\\n)*'|`([^`\\]|\\.|\\\n)*`)|\/.*\/(g|m|i|y|u|s)+|\{|\}|\*\/|\)|;|\]|^|\r*))\/{2}[^'"].*/gm, '')
38
+ }
39
+ regex = /(?<=[^'|"|`])\/\*[^*"^]*\*+(?:[^/*][^*]*\*+)*\//gm
40
+ }
41
+ fileContent = fileContent.replace(regex, '')
42
+ Fs.writeFileSync(file, fileContent, 'utf8')
43
+ log({ message: `Applying rules to the file ${file}`, withDateTime: true })
44
+ }
45
+ }
46
+ return files
47
+ }
48
+ return {
49
+ reviewLeakage
50
+ }
51
+ }
52
+
53
+ /**
54
+ * @name testing
55
+ * @api public
56
+ * @param {object} context
57
+ * @description Security testing
58
+ * @returns functions
59
+ */
60
+ const testing = (context) => {
61
+ const fix = () => {
62
+ const path = typeof context === 'string' ? context : context[Object.keys(context).find((key) => typeof context[key] === 'string')]
63
+ if (path && [/^.*[/ | \\].*$/gm].some((reg) => reg.test(path))) {
64
+ informationGathering(path).reviewLeakage()
65
+ }
66
+ }
67
+ return { fix }
68
+ }
69
+
70
+ module.exports = {
71
+ testing
72
+ }
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * @author
5
+ * Blazedpath Team
6
+ *
7
+ * @implements Security client specifications
8
+ * @description Security protocols for authentication (AuthN) and authorization (AuthZ)
9
+ * such as Open authorization 2.0, OpenID connect, UMA 2.0, SAML 2.0, WebAuth, etc.
10
+ * @see https://resilient-networks.com/concept-week-saml-oauth2-openid-connect/
11
+ *
12
+ * Environment variables needed:
13
+ * NAVIGATION_INFO_MONGODB_URL=<MongoDB connection string>
14
+ * NAVIGATION_INFO_MONGODB_DB=<Database name>
15
+ * NAVIGATION_INFO_MONGODB_COLLECTION=<Collection name>
16
+ * JWT_SECRET_KEY=<secret for signing JWTs>
17
+ */
18
+
19
+ const AuthorizationService = require('./authorizationService');
20
+ const SecurityService = require('./securityService');
21
+ const SqlInjectionGuard = require('./sqlInjectionGuard');
22
+ const XssGuard = require('./xssGuard');
23
+ const SecureUrlService = require('./secureUrlService');
24
+
25
+ const _ = require('underscore');
26
+ const logger = require('pino')();
27
+ let navigationRepository = null;
28
+
29
+ const createNavigationRepository = function () {
30
+ const isMongoDbConfigured =
31
+ process.env.NAVIGATION_INFO_MONGODB_URL &&
32
+ process.env.NAVIGATION_INFO_MONGODB_DB &&
33
+ process.env.NAVIGATION_INFO_MONGODB_COLLECTION;
34
+
35
+ if (isMongoDbConfigured) {
36
+ const NavigationMongoDbRepository = require('./navigationMongoDbRepository');
37
+ return new NavigationMongoDbRepository(
38
+ process.env.NAVIGATION_INFO_MONGODB_URL,
39
+ process.env.NAVIGATION_INFO_MONGODB_DB,
40
+ process.env.NAVIGATION_INFO_MONGODB_COLLECTION,
41
+ process.env.NAVIGATION_INFO_MONGODB_CERTIFICATE
42
+ );
43
+ } else {
44
+ logger.warn("MongoDB configuration is missing. Using in-memory repository.");
45
+ const NavigationMemoryRepository = require('./navigationMemoryRepository');
46
+ return new NavigationMemoryRepository();
47
+ }
48
+ };
49
+
50
+ try {
51
+ navigationRepository = createNavigationRepository();
52
+ async function gracefulShutdown() {
53
+ try {
54
+ if (navigationRepository && navigationRepository.close) {
55
+ await navigationRepository.close();
56
+ logger.info("Navigation repository connection closed.");
57
+ }
58
+ } catch (error) {
59
+ logger.error("Error during shutdown:", error);
60
+ } finally {
61
+ process.exit(0);
62
+ }
63
+ }
64
+ process.on('SIGINT', gracefulShutdown);
65
+ } catch (error) {
66
+ logger.error("Error during startup:", error);
67
+ process.exit(1);
68
+ }
69
+
70
+ module.exports = new SecurityService(
71
+ new AuthorizationService(_, logger),
72
+ new SqlInjectionGuard(logger),
73
+ new XssGuard(logger),
74
+ navigationRepository,
75
+ new SecureUrlService(logger),
76
+ logger
77
+ );
@@ -0,0 +1,27 @@
1
+ const { h3lp } = require('h3lp')
2
+ const Yaml = require('js-yaml')
3
+ const path = require('path')
4
+ const AuthorizationService = require('../authorizationService')
5
+ const _ = require('underscore')
6
+ const logger = require('pino')()
7
+
8
+ async function getAuthorizationService(configPath) {
9
+ const authorizationService = new AuthorizationService(_,logger)
10
+ const content = await h3lp.fs.read(path.join(__dirname, configPath))
11
+ const list = await Yaml.loadAll(content)
12
+ const config = list[0]
13
+ authorizationService.importSecurityConfig(config)
14
+ return authorizationService
15
+ }
16
+
17
+
18
+ ;(async () => {
19
+
20
+ const authorizationService = await getAuthorizationService('../__test__/AuthorizationKpn.yaml')
21
+ console.log(authorizationService.defaultAuthorized('/payment-responsibles', null, ['Collections.ViewOnly']))
22
+ console.log(authorizationService.defaultAuthorized('/taskManagement/mainInboxes/', null, ['Collections.ViewOnly']))
23
+ console.log(authorizationService.defaultAuthorized('/colm/autopay', null, ['Collections.ViewOnly']))
24
+ console.log(authorizationService.defaultAuthorized('/colm/refundorders', null, ['Collections.ViewOnly']))
25
+ console.log(authorizationService.defaultAuthorized('/debtors', null, ['Collections.ViewOnly']))
26
+
27
+ })()