@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.
- package/README.md +3 -0
- package/blz-base/health/index.js +215 -0
- package/blz-base/index.js +1466 -0
- package/blz-cache/LruCache.js +44 -0
- package/blz-cache/index.js +29 -0
- package/blz-config/index.js +434 -0
- package/blz-core/index.js +364 -0
- package/blz-cryptography/index.js +54 -0
- package/blz-datetimes/index.js +356 -0
- package/blz-file/example.dat +2545 -0
- package/blz-file/fileService.js +205 -0
- package/blz-file/index.js +94 -0
- package/blz-file/index.test.js +31 -0
- package/blz-file/lab.js +33 -0
- package/blz-hazelcast/index.js +189 -0
- package/blz-hazelcast/lib/credentials.js +25 -0
- package/blz-hazelcast/lib/credentialsFactory.js +12 -0
- package/blz-hazelcast/lib/hazelcastCache.js +234 -0
- package/blz-iterable/index.js +446 -0
- package/blz-json-schema/index.js +11 -0
- package/blz-jwt/index.js +121 -0
- package/blz-kafka/index.js +522 -0
- package/blz-math/index.js +131 -0
- package/blz-mongodb/index.js +326 -0
- package/blz-rds/__test__/scape.test.js +58 -0
- package/blz-rds/blz-rds-executor.js +578 -0
- package/blz-rds/blz-rds-helper.js +310 -0
- package/blz-rds/commands/core/add.js +13 -0
- package/blz-rds/commands/core/and.js +18 -0
- package/blz-rds/commands/core/asc.js +10 -0
- package/blz-rds/commands/core/avg.js +10 -0
- package/blz-rds/commands/core/column-ref.js +8 -0
- package/blz-rds/commands/core/count-distinct.js +10 -0
- package/blz-rds/commands/core/count.js +10 -0
- package/blz-rds/commands/core/decimal.js +8 -0
- package/blz-rds/commands/core/desc.js +10 -0
- package/blz-rds/commands/core/distinct.js +10 -0
- package/blz-rds/commands/core/divide.js +11 -0
- package/blz-rds/commands/core/embedded-exists.js +17 -0
- package/blz-rds/commands/core/embedded-select.js +17 -0
- package/blz-rds/commands/core/equals.js +9 -0
- package/blz-rds/commands/core/false.js +8 -0
- package/blz-rds/commands/core/greater-or-equal.js +9 -0
- package/blz-rds/commands/core/greater.js +9 -0
- package/blz-rds/commands/core/in.js +9 -0
- package/blz-rds/commands/core/integer.js +8 -0
- package/blz-rds/commands/core/is-not-null.js +11 -0
- package/blz-rds/commands/core/is-null-or-value.js +10 -0
- package/blz-rds/commands/core/is-null.js +11 -0
- package/blz-rds/commands/core/less-or-equal.js +9 -0
- package/blz-rds/commands/core/less-unary.js +12 -0
- package/blz-rds/commands/core/less.js +9 -0
- package/blz-rds/commands/core/like.js +12 -0
- package/blz-rds/commands/core/max.js +10 -0
- package/blz-rds/commands/core/min.js +10 -0
- package/blz-rds/commands/core/multiply.js +13 -0
- package/blz-rds/commands/core/not-equals.js +9 -0
- package/blz-rds/commands/core/not-in.js +9 -0
- package/blz-rds/commands/core/not.js +13 -0
- package/blz-rds/commands/core/null.js +8 -0
- package/blz-rds/commands/core/nvl.js +11 -0
- package/blz-rds/commands/core/or.js +13 -0
- package/blz-rds/commands/core/parameter.js +34 -0
- package/blz-rds/commands/core/remainder.js +16 -0
- package/blz-rds/commands/core/string.js +8 -0
- package/blz-rds/commands/core/subtract.js +13 -0
- package/blz-rds/commands/core/sum.js +10 -0
- package/blz-rds/commands/core/true.js +8 -0
- package/blz-rds/commands/core/tuple.js +13 -0
- package/blz-rds/commands/datetimes/add-days.js +11 -0
- package/blz-rds/commands/datetimes/add-hours.js +11 -0
- package/blz-rds/commands/datetimes/add-milliseconds.js +11 -0
- package/blz-rds/commands/datetimes/add-minutes.js +11 -0
- package/blz-rds/commands/datetimes/add-months.js +11 -0
- package/blz-rds/commands/datetimes/add-seconds.js +11 -0
- package/blz-rds/commands/datetimes/add-years.js +11 -0
- package/blz-rds/commands/datetimes/date-diff.js +11 -0
- package/blz-rds/commands/datetimes/date.js +12 -0
- package/blz-rds/commands/datetimes/datetime-diff.js +11 -0
- package/blz-rds/commands/datetimes/datetime.js +15 -0
- package/blz-rds/commands/datetimes/day.js +10 -0
- package/blz-rds/commands/datetimes/hour.js +10 -0
- package/blz-rds/commands/datetimes/millisecond.js +10 -0
- package/blz-rds/commands/datetimes/minute.js +10 -0
- package/blz-rds/commands/datetimes/month-text.js +10 -0
- package/blz-rds/commands/datetimes/month.js +10 -0
- package/blz-rds/commands/datetimes/now.js +9 -0
- package/blz-rds/commands/datetimes/second.js +10 -0
- package/blz-rds/commands/datetimes/subtract-days.js +11 -0
- package/blz-rds/commands/datetimes/subtract-hours.js +11 -0
- package/blz-rds/commands/datetimes/subtract-milliseconds.js +11 -0
- package/blz-rds/commands/datetimes/subtract-minutes.js +11 -0
- package/blz-rds/commands/datetimes/subtract-seconds.js +11 -0
- package/blz-rds/commands/datetimes/time-diff.js +11 -0
- package/blz-rds/commands/datetimes/time.js +13 -0
- package/blz-rds/commands/datetimes/today.js +9 -0
- package/blz-rds/commands/datetimes/week-day-text.js +10 -0
- package/blz-rds/commands/datetimes/week-day.js +10 -0
- package/blz-rds/commands/datetimes/week.js +10 -0
- package/blz-rds/commands/datetimes/year.js +10 -0
- package/blz-rds/commands/math/abs.js +10 -0
- package/blz-rds/commands/math/acos.js +10 -0
- package/blz-rds/commands/math/asin.js +10 -0
- package/blz-rds/commands/math/atan.js +10 -0
- package/blz-rds/commands/math/atan2.js +11 -0
- package/blz-rds/commands/math/ceil.js +10 -0
- package/blz-rds/commands/math/cos.js +10 -0
- package/blz-rds/commands/math/cosh.js +10 -0
- package/blz-rds/commands/math/exp.js +10 -0
- package/blz-rds/commands/math/floor.js +10 -0
- package/blz-rds/commands/math/log.js +18 -0
- package/blz-rds/commands/math/log10.js +10 -0
- package/blz-rds/commands/math/pow.js +11 -0
- package/blz-rds/commands/math/random.js +9 -0
- package/blz-rds/commands/math/round.js +18 -0
- package/blz-rds/commands/math/sign.js +10 -0
- package/blz-rds/commands/math/sin.js +10 -0
- package/blz-rds/commands/math/sinh.js +10 -0
- package/blz-rds/commands/math/sqrt.js +10 -0
- package/blz-rds/commands/math/tan.js +10 -0
- package/blz-rds/commands/math/tanh.js +10 -0
- package/blz-rds/commands/math/trunc.js +18 -0
- package/blz-rds/commands/strings/concat.js +20 -0
- package/blz-rds/commands/strings/contains.js +12 -0
- package/blz-rds/commands/strings/ends-with.js +12 -0
- package/blz-rds/commands/strings/index-of.js +11 -0
- package/blz-rds/commands/strings/is-null-or-empty.js +11 -0
- package/blz-rds/commands/strings/is-null-or-white-space.js +11 -0
- package/blz-rds/commands/strings/join.js +22 -0
- package/blz-rds/commands/strings/last-index-of.js +11 -0
- package/blz-rds/commands/strings/length.js +10 -0
- package/blz-rds/commands/strings/pad-left.js +20 -0
- package/blz-rds/commands/strings/pad-right.js +20 -0
- package/blz-rds/commands/strings/replace.js +12 -0
- package/blz-rds/commands/strings/starts-with.js +12 -0
- package/blz-rds/commands/strings/substring.js +12 -0
- package/blz-rds/commands/strings/to-lower.js +10 -0
- package/blz-rds/commands/strings/to-upper.js +10 -0
- package/blz-rds/commands/strings/trim-end.js +10 -0
- package/blz-rds/commands/strings/trim-start.js +10 -0
- package/blz-rds/commands/strings/trim.js +10 -0
- package/blz-rds/index.js +744 -0
- package/blz-rds-mysql/base.js +857 -0
- package/blz-rds-mysql/connection-manager.js +129 -0
- package/blz-rds-mysql/execute-bulk-insert.js +35 -0
- package/blz-rds-mysql/execute-bulk-merge.js +45 -0
- package/blz-rds-mysql/execute-non-query.js +34 -0
- package/blz-rds-mysql/execute-query.js +50 -0
- package/blz-rds-mysql/index.js +41 -0
- package/blz-rds-mysql/stored-procedure.js +207 -0
- package/blz-rds-mysql/syntaxis.json +114 -0
- package/blz-rds-mysqlx/base.js +846 -0
- package/blz-rds-mysqlx/connection-manager.js +141 -0
- package/blz-rds-mysqlx/execute-bulk-insert.js +35 -0
- package/blz-rds-mysqlx/execute-bulk-merge.js +45 -0
- package/blz-rds-mysqlx/execute-non-query.js +29 -0
- package/blz-rds-mysqlx/execute-query.js +39 -0
- package/blz-rds-mysqlx/index.js +41 -0
- package/blz-rds-mysqlx/stored-procedure.js +179 -0
- package/blz-rds-mysqlx/syntaxis.json +105 -0
- package/blz-rds-oracle/index.js +540 -0
- package/blz-rds-oracle/syntaxis.json +112 -0
- package/blz-rds-postgres/base.js +861 -0
- package/blz-rds-postgres/connection-manager.js +225 -0
- package/blz-rds-postgres/execute-bulk-insert.js +81 -0
- package/blz-rds-postgres/execute-bulk-merge.js +93 -0
- package/blz-rds-postgres/execute-non-query.js +23 -0
- package/blz-rds-postgres/execute-query.js +37 -0
- package/blz-rds-postgres/index.js +41 -0
- package/blz-rds-postgres/result-set.js +51 -0
- package/blz-rds-postgres/stored-procedure.js +116 -0
- package/blz-rds-postgres/syntaxis.json +114 -0
- package/blz-redis/index.js +217 -0
- package/blz-redis/lib/redisCache.js +265 -0
- package/blz-regex/index.js +25 -0
- package/blz-security/.eslintrc.js +15 -0
- package/blz-security/__test__/AuthorizationKpn.yaml +1043 -0
- package/blz-security/__test__/FinancingSetting.yaml +177 -0
- package/blz-security/__test__/KpnConfigPortal.yaml +330 -0
- package/blz-security/__test__/OrderManagement.yaml +5190 -0
- package/blz-security/__test__/Security.yaml +128 -0
- package/blz-security/__test__/autorization.test.js +105 -0
- package/blz-security/__test__/orderManagement.test.js +26 -0
- package/blz-security/__test__/secureUrl.test.js +79 -0
- package/blz-security/__test__/solveMergeRule.test.js +109 -0
- package/blz-security/__test__/sqlInjectionGuard.test.js +203 -0
- package/blz-security/__test__/xssGuard.test.js +204 -0
- package/blz-security/authorizationService.js +536 -0
- package/blz-security/config/global.js +8 -0
- package/blz-security/config/welcome +8 -0
- package/blz-security/doc/README.md +75 -0
- package/blz-security/filescanner/index.js +46 -0
- package/blz-security/helpers/consts.js +229 -0
- package/blz-security/helpers/utils.js +267 -0
- package/blz-security/implementations/cache.js +90 -0
- package/blz-security/implementations/oidc.js +404 -0
- package/blz-security/implementations/pkceCacheStore.js +23 -0
- package/blz-security/implementations/saml.js +10 -0
- package/blz-security/implementations/uma.js +63 -0
- package/blz-security/implementations/webAuthn.js +9 -0
- package/blz-security/implementations/wstg.js +72 -0
- package/blz-security/index.js +77 -0
- package/blz-security/lab/index.js +27 -0
- package/blz-security/middleware/HapiServerAzureAd.js +641 -0
- package/blz-security/middleware/HapiServerKeycloak.js +840 -0
- package/blz-security/middleware/HapiServerSimToken.js +247 -0
- package/blz-security/middleware/hapi.js +515 -0
- package/blz-security/middleware/hapiServer.js +974 -0
- package/blz-security/navigationMemoryRepository.js +15 -0
- package/blz-security/navigationMongoDbRepository.js +73 -0
- package/blz-security/secureUrlService.js +47 -0
- package/blz-security/securityService.js +409 -0
- package/blz-security/sqlInjectionGuard.js +162 -0
- package/blz-security/templates/forbidden.html +0 -0
- package/blz-security/templates/session-iframe-azure-ad.html +7 -0
- package/blz-security/templates/session-iframe.html +73 -0
- package/blz-security/templates/unauthorized.html +1 -0
- package/blz-security/xssGuard.js +87 -0
- package/blz-strings/index.js +167 -0
- package/blz-uuid/index.js +7 -0
- package/blz-yaml/index.js +19 -0
- package/index.js +84 -0
- package/package.json +97 -0
- 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
|
+
})()
|