@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,73 @@
|
|
|
1
|
+
const { MongoClient } = require("mongodb");
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
|
|
4
|
+
module.exports = class NavigationMongoDbRepository {
|
|
5
|
+
constructor(url, database, collectionName,certificate) {
|
|
6
|
+
if (certificate) {
|
|
7
|
+
const tempFile = '/tmp/mongo-cert.pem';
|
|
8
|
+
fs.writeFileSync(tempFile, certificate);
|
|
9
|
+
this.client = new MongoClient(url,{ tls: true,tlsCAFile: tempFile})
|
|
10
|
+
} else {
|
|
11
|
+
this.client = new MongoClient(url);
|
|
12
|
+
}
|
|
13
|
+
this.database = database;
|
|
14
|
+
this.collectionName = collectionName;
|
|
15
|
+
this.connected = false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async connect() {
|
|
19
|
+
if (!this.connected) {
|
|
20
|
+
try {
|
|
21
|
+
await this.client.connect();
|
|
22
|
+
this.db = this.client.db(this.database);
|
|
23
|
+
this.collection = this.db.collection(this.collectionName);
|
|
24
|
+
this.connected = true;
|
|
25
|
+
console.log("Navigation info Connected to MongoDB.");
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error("Failed Navigation info to connect to MongoDB:", error);
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async close() {
|
|
34
|
+
if (this.connected) {
|
|
35
|
+
try {
|
|
36
|
+
await this.client.close();
|
|
37
|
+
this.connected = false;
|
|
38
|
+
console.log("Connection to MongoDB closed.");
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error("Failed to close MongoDB connection:", error);
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async push(navigation) {
|
|
47
|
+
if (!this.connected) {
|
|
48
|
+
await this.connect();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
const result = await this.collection.insertOne(navigation);
|
|
53
|
+
return result.insertedId.toString();
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error("Failed to insert navigation:", error);
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async get () {
|
|
61
|
+
if (!this.connected) {
|
|
62
|
+
await this.connect();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
const cursor = this.collection.find({});
|
|
67
|
+
return await cursor.toArray();
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error("Failed to get navigation:", error);
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const { Exception, isBase64 } = require('./helpers/utils')
|
|
2
|
+
const CryptoJS = require('crypto-js');
|
|
3
|
+
|
|
4
|
+
module.exports = class SecureUrlService {
|
|
5
|
+
constructor(logger = console) {
|
|
6
|
+
this.logger = logger;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
validate(url, token, _session_key, timeoutMs) {
|
|
10
|
+
const path = decodeURIComponent(url.split('?')[0]);
|
|
11
|
+
if (!token) {
|
|
12
|
+
this.logger.error(`Token parameter 'tt' is missing in the URL. path:${path}`)
|
|
13
|
+
throw new Exception("Token parameter 'tt' is missing in the URL.", 'SecureUrlError', 404);
|
|
14
|
+
}
|
|
15
|
+
const session_key = isBase64(_session_key)?atob(_session_key):_session_key
|
|
16
|
+
const key = `${session_key}${btoa(path)}`;
|
|
17
|
+
const bytes = CryptoJS.AES.decrypt(decodeURIComponent(token), key);
|
|
18
|
+
const requestTimeStr = bytes.toString(CryptoJS.enc.Utf8);
|
|
19
|
+
if (!requestTimeStr) {
|
|
20
|
+
this.logger.error(`Token decryption failed or is invalid. token:${token} path:${path} session: ${session_key}`)
|
|
21
|
+
throw new Exception("Token decryption failed or is invalid.", 'SecureUrlError', 404);
|
|
22
|
+
}
|
|
23
|
+
let requestTime
|
|
24
|
+
try {
|
|
25
|
+
requestTime = parseInt(JSON.parse(requestTimeStr));
|
|
26
|
+
} catch (e) {
|
|
27
|
+
this.logger.error(`Malformed token content. path:${path} error: ${e.message}`)
|
|
28
|
+
throw new Exception("Malformed token content.", 'SecureUrlError', 400);
|
|
29
|
+
}
|
|
30
|
+
const timeout = requestTime + timeoutMs
|
|
31
|
+
const time = Date.now()
|
|
32
|
+
const isValid = time < timeout && requestTime < time;
|
|
33
|
+
if (!isValid) {
|
|
34
|
+
this.logger.error(`The token has expired. path:${path} timeout:${timeout} time: ${time}`)
|
|
35
|
+
throw new Exception("The token has expired.", 'SecureUrlError', 408);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
createToken(url, _session_key){
|
|
40
|
+
const path = url.split('?')[0];
|
|
41
|
+
const session_key = isBase64(_session_key)?atob(_session_key):_session_key
|
|
42
|
+
const key = `${session_key}${btoa(decodeURIComponent(path))}`;
|
|
43
|
+
const getNow = () => Function('"use strict";return (' + atob("bmV3IERhdGUoKS5nZXRUaW1lKCk=") + ')')();
|
|
44
|
+
const token = CryptoJS.AES.encrypt((getNow()).toString(), key).toString();
|
|
45
|
+
return encodeURIComponent(token);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
const { Hapi } = require('./middleware/hapi')
|
|
2
|
+
const { Oidc } = require('./implementations/oidc')
|
|
3
|
+
const { HapiServerSimToken } = require('./middleware/HapiServerSimToken');
|
|
4
|
+
const { HapiServerKeycloak } = require('./middleware/HapiServerKeycloak');
|
|
5
|
+
const { HapiServerAzureAd } = require('./middleware/HapiServerAzureAd');
|
|
6
|
+
const { RedisCache, LruCache } = require('./implementations/cache')
|
|
7
|
+
const { Exception, getMappingValues } = require('./helpers/utils')
|
|
8
|
+
const Jsonwebtoken = require('jsonwebtoken')
|
|
9
|
+
const micromatch = require('micromatch');
|
|
10
|
+
module.exports = class SecurityService {
|
|
11
|
+
constructor(authorizationService, sqlInjectionGuard, xssGuard, navigationRepository,secureUrlService, logger) {
|
|
12
|
+
this.authorizationService = authorizationService
|
|
13
|
+
this.sqlInjectionGuard = sqlInjectionGuard
|
|
14
|
+
this.xssGuard = xssGuard
|
|
15
|
+
this.navigationRepository = navigationRepository
|
|
16
|
+
this.secureUrlService = secureUrlService
|
|
17
|
+
this.logger = logger
|
|
18
|
+
this.cookiesName = null
|
|
19
|
+
this.blzConfig = null
|
|
20
|
+
this.oidc = null
|
|
21
|
+
this.hapi = null
|
|
22
|
+
this.config = null
|
|
23
|
+
this.middleware = null
|
|
24
|
+
this.protected = false
|
|
25
|
+
this.unProtected = []
|
|
26
|
+
this.useHapiServerFullStack = false;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async pushNavigation(navigation) {
|
|
30
|
+
if (this.navigationRepository) {
|
|
31
|
+
return this.navigationRepository.push(navigation)
|
|
32
|
+
} else {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async getNavigation() {
|
|
38
|
+
return this.navigationRepository ? this.navigationRepository.get() : {};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
setBlzConfig(blzConfig) {
|
|
42
|
+
this.blzConfig = blzConfig
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Same signature as your current function
|
|
46
|
+
sanitizeSqlParams(params) {
|
|
47
|
+
return this.sqlInjectionGuard.validateParamList(params);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// New helper for full SQL validation
|
|
51
|
+
sanitizeSql(sql) {
|
|
52
|
+
return this.sqlInjectionGuard.validateRawSql(sql);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
isExcludedFromSanitize(method, path) {
|
|
56
|
+
const raw = process.env.blz_securityExcludeSanitizePaths;
|
|
57
|
+
|
|
58
|
+
if (!raw || !raw.trim()) {
|
|
59
|
+
// No rules defined — sanitize by default
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const rules = raw
|
|
64
|
+
.split(',')
|
|
65
|
+
.map(rule => rule.trim().toLowerCase())
|
|
66
|
+
.filter(Boolean);
|
|
67
|
+
|
|
68
|
+
if (rules.length === 0) {
|
|
69
|
+
// All rules were empty or invalid
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return rules.some(rule => {
|
|
74
|
+
let [ruleMethod, rulePath] = rule.includes(':')
|
|
75
|
+
? rule.split(':')
|
|
76
|
+
: [null, rule]; // if no method is specified, apply to all methods
|
|
77
|
+
|
|
78
|
+
ruleMethod = ruleMethod?.toLowerCase();
|
|
79
|
+
|
|
80
|
+
// Normalize rulePath to use compatible wildcards
|
|
81
|
+
const normalizedPattern = rulePath
|
|
82
|
+
.replace(/\*\*/g, '**') // double wildcard
|
|
83
|
+
.replace(/\*/g, '*'); // single wildcard
|
|
84
|
+
|
|
85
|
+
return (!ruleMethod || ruleMethod === method.toLowerCase()) &&
|
|
86
|
+
micromatch.isMatch(path.toLowerCase(), normalizedPattern);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
validateObject(obj) {
|
|
91
|
+
return this.sqlInjectionGuard.validateObject(this.xssGuard.sanitizeObject(obj));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
validateSqlObject(obj) {
|
|
95
|
+
return this.sqlInjectionGuard.validateObject(obj);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
initializeCookiesNames() {
|
|
99
|
+
this.cookiesName = {
|
|
100
|
+
ACCESS_TOKEN: this.getCookieName('access_token'),
|
|
101
|
+
SID: this.getCookieName('sid'),
|
|
102
|
+
SESSION_STATE: this.getCookieName('session_state'),
|
|
103
|
+
SESSION: this.getCookieName('session')
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
getRoleProperty() {
|
|
108
|
+
const config = this.blzConfig.getConfig() || {}
|
|
109
|
+
if (config && config.authServer && config.authServer.roleProperty && config.authServer.roleProperty.trim() !== '') {
|
|
110
|
+
return config.authServer.roleProperty
|
|
111
|
+
}
|
|
112
|
+
return 'authorities'
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
getUseTonkenName() {
|
|
116
|
+
return this.config.authServer.useTokenType || 'access_token'
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async getRoles(request) {
|
|
120
|
+
if (this.useHapiServerFullStack) {
|
|
121
|
+
const token = request.headers.authorization?.replace('Bearer ', ''); // From Authorization header
|
|
122
|
+
// Decode and verify the token
|
|
123
|
+
const decoded = Jsonwebtoken.decode(token);
|
|
124
|
+
const rolePropertyName = this.getRoleProperty()
|
|
125
|
+
return decoded[rolePropertyName] || []
|
|
126
|
+
} else {
|
|
127
|
+
const sessionState = this.getSessionState(request)
|
|
128
|
+
const tokenSet = await this.tokenSet()
|
|
129
|
+
const tokens = await tokenSet.tokens(sessionState)
|
|
130
|
+
const tokenName = this.getUseTonkenName()
|
|
131
|
+
const token = tokens[tokenName]
|
|
132
|
+
const decodeToken = Jsonwebtoken.decode(token)
|
|
133
|
+
const rolePropertyName = this.getRoleProperty()
|
|
134
|
+
return decodeToken[rolePropertyName] || []
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
getCookieName(cookieName = '') {
|
|
139
|
+
const config = this.blzConfig.getConfig() || {}
|
|
140
|
+
const prefix = (config.authServer && config.authServer.sessionCookiesPrefix) || ''
|
|
141
|
+
return prefix + cookieName
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
getCache(config) {
|
|
145
|
+
if (process.env.SECURITY_REDIS_CACHE) {
|
|
146
|
+
return new RedisCache(process.env.SECURITY_REDIS_CACHE)
|
|
147
|
+
} else if (config && config.securityCache) {
|
|
148
|
+
const cnx = config.connections[config.securityCache]
|
|
149
|
+
if (cnx && cnx.type === 'Redis') {
|
|
150
|
+
const connection = `redis://${cnx.user || ''}:${cnx.password}@${cnx.host
|
|
151
|
+
}:${cnx.port || '6379'}/${cnx.db || '0'}`
|
|
152
|
+
return new RedisCache(connection)
|
|
153
|
+
} else {
|
|
154
|
+
return new LruCache()
|
|
155
|
+
}
|
|
156
|
+
} else {
|
|
157
|
+
return new LruCache()
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// This receives:
|
|
162
|
+
// middlehare: receives the hapiServer instance from the proxy
|
|
163
|
+
// config: the config options
|
|
164
|
+
async protect(middleware, config) {
|
|
165
|
+
if (!middleware) {
|
|
166
|
+
this.logger.error('The middleware context could not be analyzed')
|
|
167
|
+
throw new Exception(
|
|
168
|
+
'The middleware context could not be analyzed',
|
|
169
|
+
'MiddlewareError',
|
|
170
|
+
403
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
if (!config || (!config.callee && !config.authServer && !config.accessTokenSimulation)) {
|
|
174
|
+
this.logger.error('Authorization server configuration is mandatory')
|
|
175
|
+
throw new Exception(
|
|
176
|
+
'Authorization server configuration is mandatory',
|
|
177
|
+
'ConfigurationError',
|
|
178
|
+
403
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
|
+
this.config = config
|
|
182
|
+
this.middleware = middleware
|
|
183
|
+
const cache = this.getCache(this.config)
|
|
184
|
+
|
|
185
|
+
// Choose the hapi server version
|
|
186
|
+
if (this.config.accessTokenSimulation) {
|
|
187
|
+
this.oidc = new Oidc(cache, this.config);
|
|
188
|
+
this.openIdConnect = new Oidc(this.getCache(this.config), this.config);
|
|
189
|
+
this.hapiServer = new HapiServerSimToken(this.openIdConnect, this.cookiesName, cache);
|
|
190
|
+
await this.hapiServer.connect(this, this.middleware, this.config)
|
|
191
|
+
} else if (config.authServer.useHapiServerFullStack) {
|
|
192
|
+
// Use oauth0 with signing and authentication with an external oauth server
|
|
193
|
+
this.useHapiServerFullStack = true;
|
|
194
|
+
this.oidc = new Oidc(cache, this.config);
|
|
195
|
+
await this.protectExperimental(cache);
|
|
196
|
+
this.protected = true
|
|
197
|
+
return;
|
|
198
|
+
} else {
|
|
199
|
+
// legacy oauth0 authentication with local key signing
|
|
200
|
+
this.oidc = new Oidc(cache, this.config);
|
|
201
|
+
this.hapi = new Hapi(this.oidc, this.cookiesName);
|
|
202
|
+
this.protected = true
|
|
203
|
+
if (this.config.queryStringLimit) {
|
|
204
|
+
this.hapi.queryStringLimit = this.config.queryStringLimit
|
|
205
|
+
}
|
|
206
|
+
if (this.config.securityLoginTokenExpToleranceSeconds) {
|
|
207
|
+
this.hapi.securityLoginTokenExpToleranceSeconds = this.config.securityLoginTokenExpToleranceSeconds
|
|
208
|
+
}
|
|
209
|
+
await this.hapi.connect(this, this.middleware, this.config)
|
|
210
|
+
this.protected = true
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async protectExperimental(cache) {
|
|
215
|
+
//this.openIdConnect = new OpenIdConnect(this.getCache(this.config), this.config);
|
|
216
|
+
if (this.config.authServer.provider !== "ad-azure") {
|
|
217
|
+
this.hapiServer = new HapiServerKeycloak(this.openIdConnect, this.cookiesName, cache);
|
|
218
|
+
} else {
|
|
219
|
+
this.hapiServer = new HapiServerAzureAd(this.openIdConnect, this.cookiesName, cache);
|
|
220
|
+
}
|
|
221
|
+
this.openIdConnect = null
|
|
222
|
+
// heck for options in the config
|
|
223
|
+
if (this.config.queryStringLimit) {
|
|
224
|
+
this.hapiServer.queryStringLimit = this.config.queryStringLimit
|
|
225
|
+
}
|
|
226
|
+
if (this.config.securityLoginTokenExpToleranceSeconds) {
|
|
227
|
+
this.hapiServer.securityLoginTokenExpToleranceSeconds = this.config.securityLoginTokenExpToleranceSeconds
|
|
228
|
+
}
|
|
229
|
+
await this.hapiServer.connect(this, this.middleware, this.config)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async tokenSet() {
|
|
233
|
+
if (!this.oidc) {
|
|
234
|
+
this.logger.error('authServer and accessTokenSimulation undefined')
|
|
235
|
+
throw new Error('authServer and accessTokenSimulation undefined')
|
|
236
|
+
}
|
|
237
|
+
return await this.oidc.tokenSet()
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
async getUseToken(sessionState, request) {
|
|
241
|
+
if (this.useHapiServerFullStack) {
|
|
242
|
+
return this.extractTokenhNoDecode(request, this.config.authServer.PublicKey)
|
|
243
|
+
} else if (this.config.accessTokenSimulation) { } else {
|
|
244
|
+
return this.oidc.getUseToken(sessionState);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
getSessionState(request) {
|
|
249
|
+
const sessionState = request.state[this.cookiesName.SESSION_STATE]
|
|
250
|
+
const session = request.state[this.cookiesName.SESSION]
|
|
251
|
+
if (sessionState) {
|
|
252
|
+
return sessionState;
|
|
253
|
+
} else if (session) {
|
|
254
|
+
return session.id;
|
|
255
|
+
} else {
|
|
256
|
+
this.logger.error("getSessionState: Session cookie doesn't exist.")
|
|
257
|
+
throw new Exception("getSessionState: Session cookie doesn't exist.", 'CookiesError', 404)
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
getSecureUrlSessionKey(request) {
|
|
262
|
+
const session = request.state[this.blzConfig.getConfig()?.parameters?.SecureUrlCookieKey]
|
|
263
|
+
if (session) {
|
|
264
|
+
return session;
|
|
265
|
+
} else {
|
|
266
|
+
this.logger.error("getSecureUrlSessionKey: Session cookie doesn't exist.")
|
|
267
|
+
throw new Exception("getSecureUrlSessionKey: Session cookie doesn't exist.", 'CookiesError', 404)
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
enableSecureUrl() {
|
|
272
|
+
const key = this.blzConfig.getConfig()?.parameters?.SecureUrlCookieKey;
|
|
273
|
+
return !!key && key !== 'none';
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
getSecureUrlCookieKey() {
|
|
277
|
+
if (this.enableSecureUrl()) {
|
|
278
|
+
return this.blzConfig.getConfig()?.parameters?.SecureUrlCookieKey;
|
|
279
|
+
}
|
|
280
|
+
return undefined;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
validateSecureRequest(request) {
|
|
284
|
+
if (!request) return;
|
|
285
|
+
if (!this.enableSecureUrl()) {
|
|
286
|
+
return
|
|
287
|
+
}
|
|
288
|
+
let _session_key = this.getSecureUrlSessionKey(request);
|
|
289
|
+
const params = new URLSearchParams(request.query);
|
|
290
|
+
const token = params.get('sut');
|
|
291
|
+
const timeoutMs = this.blzConfig.getConfig()?.parameters?.SecureUrlTimeoutMs || 15000;
|
|
292
|
+
this.secureUrlService.validate(request.path,token,_session_key,timeoutMs)
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
async getUserInfo(request) {
|
|
296
|
+
let sourceData = null
|
|
297
|
+
let userInfo = {}
|
|
298
|
+
if (this.useHapiServerFullStack) {
|
|
299
|
+
sourceData = await this.extractAndDecodeToken(request, this.config.authServer.PublicKey)
|
|
300
|
+
return sourceData;
|
|
301
|
+
} else {
|
|
302
|
+
const sessionState = this.getSessionState(request)
|
|
303
|
+
const tokenSet = await this.tokenSet()
|
|
304
|
+
if (this.config.parameters && this.config.parameters.UserInfoSource) {
|
|
305
|
+
const strToken = await tokenSet.tokens(sessionState)
|
|
306
|
+
sourceData = Jsonwebtoken.decode(strToken[this.config.parameters.UserInfoSource])
|
|
307
|
+
} else {
|
|
308
|
+
userInfo = await tokenSet.userInfo(sessionState)
|
|
309
|
+
sourceData = userInfo
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Solve mapping form UserInfoMapping parameter
|
|
314
|
+
if (this.config.parameters && this.config.parameters.UserInfoMapping) {
|
|
315
|
+
const mappings = JSON.parse(this.config.parameters.UserInfoMapping)
|
|
316
|
+
const values = getMappingValues(sourceData, mappings)
|
|
317
|
+
return { ...userInfo, ...values }
|
|
318
|
+
}
|
|
319
|
+
return userInfo
|
|
320
|
+
}
|
|
321
|
+
async extractAndDecodeToken(request, secretOrPublicKey) {
|
|
322
|
+
const authorization = request.headers.authorization;
|
|
323
|
+
|
|
324
|
+
if (!authorization) {
|
|
325
|
+
this.logger.error('Authorization header is missing')
|
|
326
|
+
throw new Error('Authorization header is missing');
|
|
327
|
+
}
|
|
328
|
+
const [scheme, token] = authorization.split(' ');
|
|
329
|
+
|
|
330
|
+
if ((scheme !== 'Bearer' && scheme !== 'bearer') || !token) {
|
|
331
|
+
this.logger.error('Authorization header must be in the format: Bearer <token>')
|
|
332
|
+
throw new Error('Authorization header must be in the format: Bearer <token>');
|
|
333
|
+
}
|
|
334
|
+
if (this.hapiServer.authServerConfig.authServer.provider !== "ad-azure") {
|
|
335
|
+
const { artifacts } = request.auth;
|
|
336
|
+
secretOrPublicKey = await this.hapiServer.publicKeyFetch(artifacts);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
try {
|
|
340
|
+
// Decode and verify the JWT token
|
|
341
|
+
//const decoded = Jsonwebtoken.decode(token, secretOrPublicKey);
|
|
342
|
+
const decoded = Jsonwebtoken.decode(token);
|
|
343
|
+
return decoded;
|
|
344
|
+
} catch (err) {
|
|
345
|
+
this.logger.error(`Failed to decode token: ${err.message}`)
|
|
346
|
+
throw new Error(`Failed to decode token: ${err.message}`);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
async extractTokenhNoDecode(request) {
|
|
350
|
+
const authorization = request.headers.authorization;
|
|
351
|
+
|
|
352
|
+
if (!authorization) {
|
|
353
|
+
this.logger.error('Authorization header is missing')
|
|
354
|
+
throw new Error('Authorization header is missing');
|
|
355
|
+
}
|
|
356
|
+
const [scheme, rawToken] = authorization.split(' ');
|
|
357
|
+
|
|
358
|
+
if ((scheme !== 'Bearer' && scheme !== 'bearer') || !rawToken) {
|
|
359
|
+
this.logger.error('Authorization header must be in the format: Bearer <token>')
|
|
360
|
+
throw new Error('Authorization header must be in the format: Bearer <token>');
|
|
361
|
+
}
|
|
362
|
+
return rawToken
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
importSecurityConfig(config) {
|
|
366
|
+
this.authorizationService.importSecurityConfig(config)
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
async getFrontendSecurityRules(request) {
|
|
370
|
+
if (!this.protected) {
|
|
371
|
+
this.logger.error('Cannot get the security rules if the application is not using JWt.')
|
|
372
|
+
throw new Exception('Cannot get the security rules if the application is not using JWt.', 'SecurityRulesError', 500)
|
|
373
|
+
}
|
|
374
|
+
const domains = request.headers.domains ? request.headers.domains.split(',') : []
|
|
375
|
+
const roles = await this.getRoles(request)
|
|
376
|
+
const securityRules = this.authorizationService.getFrontendSecurityRules(roles, domains)
|
|
377
|
+
return securityRules
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
async getPermissions() {
|
|
381
|
+
return this.authorizationService.getPermissions()
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
async authorized(request) {
|
|
385
|
+
if (!this.protected) {
|
|
386
|
+
return true
|
|
387
|
+
}
|
|
388
|
+
let roles = null;
|
|
389
|
+
if (this.useHapiServerFullStack) {
|
|
390
|
+
// Token decoded
|
|
391
|
+
const userInfo = await this.getUserInfo(request);
|
|
392
|
+
roles = userInfo[this.getRoleProperty()]
|
|
393
|
+
} else {
|
|
394
|
+
roles = await this.getRoles(request)
|
|
395
|
+
}
|
|
396
|
+
const result = this.authorizationService.authorized(request.path, request.method, roles)
|
|
397
|
+
if (result !== null && result !== undefined) {
|
|
398
|
+
return result
|
|
399
|
+
}
|
|
400
|
+
if (this.config.activateTraceApiMethod && !this.unProtected.some((item) => item.path === request.path && item.method === request.method)) {
|
|
401
|
+
this.unProtected.push({ path: request.path, method: request.method })
|
|
402
|
+
}
|
|
403
|
+
return true
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
logUnProtected() {
|
|
407
|
+
this.logger.info('unprotected: ' + JSON.stringify(this.unProtected))
|
|
408
|
+
}
|
|
409
|
+
}
|