scimgateway 5.4.1 → 5.4.2
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 +9 -0
- package/lib/logger.ts +11 -10
- package/lib/scimgateway.ts +72 -63
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1473,6 +1473,15 @@ MIT © [Jarle Elshaug](https://www.elshaug.xyz)
|
|
|
1473
1473
|
|
|
1474
1474
|
## Change log
|
|
1475
1475
|
|
|
1476
|
+
### v5.4.2
|
|
1477
|
+
|
|
1478
|
+
[Improved]
|
|
1479
|
+
|
|
1480
|
+
- baseEntity included as json-key in logs
|
|
1481
|
+
- Remote real-time logger now supports baseEntity. `http(s)://host/logger` gives all log entries for plugin. `http(s)://host/<baseEntity>/logger` gives only log entries for the baseEntity used.
|
|
1482
|
+
|
|
1483
|
+
Note, using `baseEntity` is optional. This is a parameter used for multi tenant or multi endpoint solutions. We could create several endpoint configurations having unique baseEntity. Also note that we can configure auth linked to baseEntity including readOnly.
|
|
1484
|
+
|
|
1476
1485
|
### v5.4.1
|
|
1477
1486
|
|
|
1478
1487
|
[Improved]
|
package/lib/logger.ts
CHANGED
|
@@ -294,32 +294,33 @@ export class Logger {
|
|
|
294
294
|
* @param level log level
|
|
295
295
|
* @param message the message that will be logged
|
|
296
296
|
*/
|
|
297
|
-
private async log(level: 'debug' | 'info' | 'warn' | 'error', message: string) {
|
|
297
|
+
private async log(level: 'debug' | 'info' | 'warn' | 'error', message: string, obj?: Record<string, any>) {
|
|
298
298
|
const time = new Date().toISOString()
|
|
299
299
|
message = this.maskSecret(message)
|
|
300
300
|
const msgObj: Record<string, any> = {
|
|
301
301
|
time,
|
|
302
|
-
category: this.category,
|
|
303
302
|
level,
|
|
303
|
+
category: this.category,
|
|
304
|
+
...(obj || {}),
|
|
304
305
|
message,
|
|
305
306
|
}
|
|
306
307
|
this.logChannel.publish(msgObj)
|
|
307
308
|
}
|
|
308
309
|
|
|
309
|
-
public debug(message: string) {
|
|
310
|
-
this.log('debug', message)
|
|
310
|
+
public debug(message: string, obj?: Record<string, any>) {
|
|
311
|
+
this.log('debug', message, obj)
|
|
311
312
|
}
|
|
312
313
|
|
|
313
|
-
public info(message: string) {
|
|
314
|
-
this.log('info', message)
|
|
314
|
+
public info(message: string, obj?: Record<string, any>) {
|
|
315
|
+
this.log('info', message, obj)
|
|
315
316
|
}
|
|
316
317
|
|
|
317
|
-
public warn(message: string) {
|
|
318
|
-
this.log('warn', message)
|
|
318
|
+
public warn(message: string, obj?: Record<string, any>) {
|
|
319
|
+
this.log('warn', message, obj)
|
|
319
320
|
}
|
|
320
321
|
|
|
321
|
-
public error(message: string) {
|
|
322
|
-
this.log('error', message)
|
|
322
|
+
public error(message: string, obj?: Record<string, any>) {
|
|
323
|
+
this.log('error', message, obj)
|
|
323
324
|
}
|
|
324
325
|
|
|
325
326
|
/**
|
package/lib/scimgateway.ts
CHANGED
|
@@ -586,11 +586,11 @@ export class ScimGateway {
|
|
|
586
586
|
|
|
587
587
|
if (ctx.response.status && (ctx.response.status < 200 || ctx.response.status > 299)) {
|
|
588
588
|
if (ctx.response.status === 412 || ctx.response.status === 304) {
|
|
589
|
-
logger.info(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] ${ellapsed} ${ctx.ip} ${userName} ${ctx.response.status} ${ctx.request.method} ${ctx.request.url} Inbound=${JSON.stringify(ctx.request.body)} Outbound=${outbound}
|
|
589
|
+
logger.info(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] ${ellapsed} ${ctx.ip} ${userName} ${ctx.response.status} ${ctx.request.method} ${ctx.request.url} Inbound=${JSON.stringify(ctx.request.body)} Outbound=${outbound}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
590
590
|
} else if (ctx.response.status === 404) {
|
|
591
|
-
logger.warn(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] ${ellapsed} ${ctx.ip} ${userName} ${ctx.response.status} ${ctx.request.method} ${ctx.request.url} Inbound=${JSON.stringify(ctx.request.body)} Outbound=${outbound}
|
|
592
|
-
} else logger.error(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] ${ellapsed} ${ctx.ip} ${userName} ${ctx.response.status} ${ctx.request.method} ${ctx.request.url} Inbound=${JSON.stringify(ctx.request.body)} Outbound=${outbound}
|
|
593
|
-
} else logger.info(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] ${ellapsed} ${ctx.ip} ${ctx.response.status} ${userName} ${ctx.request.method} ${ctx.request.url} Inbound=${JSON.stringify(ctx.request.body)} Outbound=${outbound}
|
|
591
|
+
logger.warn(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] ${ellapsed} ${ctx.ip} ${userName} ${ctx.response.status} ${ctx.request.method} ${ctx.request.url} Inbound=${JSON.stringify(ctx.request.body)} Outbound=${outbound}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
592
|
+
} else logger.error(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] ${ellapsed} ${ctx.ip} ${userName} ${ctx.response.status} ${ctx.request.method} ${ctx.request.url} Inbound=${JSON.stringify(ctx.request.body)} Outbound=${outbound}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
593
|
+
} else logger.info(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] ${ellapsed} ${ctx.ip} ${ctx.response.status} ${userName} ${ctx.request.method} ${ctx.request.url} Inbound=${JSON.stringify(ctx.request.body)} Outbound=${outbound}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
594
594
|
}
|
|
595
595
|
|
|
596
596
|
// start auth methods - used by auth
|
|
@@ -793,12 +793,12 @@ export class ScimGateway {
|
|
|
793
793
|
if (authType.length < 1) err = new Error(`${ctx.request.url} request is missing authentication information`)
|
|
794
794
|
else {
|
|
795
795
|
err = new Error(`${ctx.request.url} request having unsupported authentication or plugin configuration is missing`)
|
|
796
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] request authToken = ${authToken}
|
|
797
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] request jwt.decode(authToken) = ${JSON.stringify(jwt.decode(authToken))}
|
|
796
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] request authToken = ${authToken}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
797
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] request jwt.decode(authToken) = ${JSON.stringify(jwt.decode(authToken))}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
798
798
|
}
|
|
799
799
|
if (authType === 'Bearer') ctx.response.headers.set('WWW-Authenticate', 'Bearer realm=""')
|
|
800
800
|
else if (found.Basic) ctx.response.headers.set('WWW-Authenticate', 'Basic realm=""')
|
|
801
|
-
if (ctx.request.url !== '/favicon.ico' && !ctx.request.url.startsWith('/apple-touch-icon')) logger.error(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] ${err.message}
|
|
801
|
+
if (ctx.request.url !== '/favicon.ico' && !ctx.request.url.startsWith('/apple-touch-icon')) logger.error(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] ${err.message}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
802
802
|
return false
|
|
803
803
|
} catch (err: any) {
|
|
804
804
|
if (authType === 'Bearer') {
|
|
@@ -818,9 +818,9 @@ export class ScimGateway {
|
|
|
818
818
|
} else ctx.response.headers.set('WWW-Authenticate', 'Basic realm=""')
|
|
819
819
|
if (pwErrCount < 3) {
|
|
820
820
|
pwErrCount += 1
|
|
821
|
-
logger.error(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] ${ctx.request.url} ${err.message}
|
|
821
|
+
logger.error(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] ${ctx.request.url} ${err.message}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
822
822
|
} else { // delay brute force attempts
|
|
823
|
-
logger.error(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] ${ctx.request.url} ${err.message} => delaying response with 2 minutes to prevent brute force
|
|
823
|
+
logger.error(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] ${ctx.request.url} ${err.message} => delaying response with 2 minutes to prevent brute force`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
824
824
|
await new Promise((resolve) => {
|
|
825
825
|
setTimeout(() => { resolve(null) }, 1000 * 60 * 2)
|
|
826
826
|
})
|
|
@@ -833,7 +833,6 @@ export class ScimGateway {
|
|
|
833
833
|
const ipAllowList = (ipAddr: string): boolean => {
|
|
834
834
|
if (ipAllowListChecker === undefined) return true
|
|
835
835
|
if (ipAllowListChecker(ipAddr) === true) return true // if proxy, prereq: request includes header X-Forwarded-For
|
|
836
|
-
logger.debug(`${gwName}[${pluginName}] client ip ${ipAddr} not in ipAllowList`)
|
|
837
836
|
return false
|
|
838
837
|
}
|
|
839
838
|
|
|
@@ -887,6 +886,9 @@ export class ScimGateway {
|
|
|
887
886
|
|
|
888
887
|
const sub = async (msgObj: Record<string, any>) => {
|
|
889
888
|
if (logger.levelToInt(msgObj.level) < levelInt) return
|
|
889
|
+
if (ctx?.routeObj?.baseEntity !== 'undefined') { // if using baseEntity e.g. <host>/company1/logger, only include corresponding baseEntity logentries
|
|
890
|
+
if (ctx?.routeObj?.baseEntity !== msgObj.baseEntity) return
|
|
891
|
+
}
|
|
890
892
|
controller.enqueue(encoder.encode(`${JSON.stringify(msgObj)}\n`))
|
|
891
893
|
}
|
|
892
894
|
logger.subscribe(sub)
|
|
@@ -899,7 +901,7 @@ export class ScimGateway {
|
|
|
899
901
|
clearInterval(keepAliveInterval)
|
|
900
902
|
logger.unsubscribe(sub)
|
|
901
903
|
controller.close()
|
|
902
|
-
logger.info(`${gwName}[${pluginName}] remote logger disconnected from ip address ${ctx.ip}
|
|
904
|
+
logger.info(`${gwName}[${pluginName}] remote logger disconnected from ip address ${ctx.ip}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
903
905
|
}
|
|
904
906
|
|
|
905
907
|
ctx.request.signal.onabort = cleanup // Bun
|
|
@@ -921,9 +923,9 @@ export class ScimGateway {
|
|
|
921
923
|
|
|
922
924
|
// oauth token request, POST /oauth/token
|
|
923
925
|
const postHandlerOauthToken = async (ctx: Context) => {
|
|
924
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [oauth] token request
|
|
926
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [oauth] token request`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
925
927
|
if (!found.BearerOAuth) {
|
|
926
|
-
logger.error(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [oauth] token request, but plugin is missing auth.bearerOAuth configuration
|
|
928
|
+
logger.error(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [oauth] token request, but plugin is missing auth.bearerOAuth configuration`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
927
929
|
ctx.response.status = 500
|
|
928
930
|
return
|
|
929
931
|
}
|
|
@@ -931,7 +933,7 @@ export class ScimGateway {
|
|
|
931
933
|
try {
|
|
932
934
|
if (!jsonBody) throw new Error('missing body')
|
|
933
935
|
if (typeof jsonBody !== 'object') { // might have application/x-www-form-urlencoded or multipart/form-data body, but incorrect Content-Type header
|
|
934
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [oauth] continue request validation even though incorrect body vs header Content-Type: ${ctx.request.headers.get('content-type')}
|
|
936
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [oauth] continue request validation even though incorrect body vs header Content-Type: ${ctx.request.headers.get('content-type')}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
935
937
|
let body = utils.formUrlEncodedToJSON(jsonBody)
|
|
936
938
|
if (Object.keys(body).length < 1) {
|
|
937
939
|
body = utils.formDataMultipartToJSON(jsonBody)
|
|
@@ -942,7 +944,7 @@ export class ScimGateway {
|
|
|
942
944
|
}
|
|
943
945
|
jsonBody = utils.copyObj(jsonBody) // no changes to original
|
|
944
946
|
} catch (err: any) {
|
|
945
|
-
logger.error(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [oauth] token request error: ${err.message}
|
|
947
|
+
logger.error(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [oauth] token request error: ${err.message}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
946
948
|
ctx.response.status = 401
|
|
947
949
|
return
|
|
948
950
|
}
|
|
@@ -1001,7 +1003,7 @@ export class ScimGateway {
|
|
|
1001
1003
|
}
|
|
1002
1004
|
|
|
1003
1005
|
if (err) {
|
|
1004
|
-
logger.error(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [oauth] token request client_id: ${jsonBody ? jsonBody.client_id : ''} error: ${errDescr}
|
|
1006
|
+
logger.error(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [oauth] token request client_id: ${jsonBody ? jsonBody.client_id : ''} error: ${errDescr}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
1005
1007
|
ctx.response.status = 401
|
|
1006
1008
|
const errMsg = {
|
|
1007
1009
|
error: err,
|
|
@@ -1063,12 +1065,12 @@ export class ScimGateway {
|
|
|
1063
1065
|
value: id,
|
|
1064
1066
|
}
|
|
1065
1067
|
|
|
1066
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [Get ${handle.description}] ${getObj.attribute}=${getObj.value}
|
|
1068
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [Get ${handle.description}] ${getObj.attribute}=${getObj.value}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
1067
1069
|
|
|
1068
1070
|
try {
|
|
1069
1071
|
const ob = utils.copyObj(getObj)
|
|
1070
1072
|
const attributes = ctx.query.attributes ? ctx.query.attributes.split(',').map((item: string) => item.trim()) : []
|
|
1071
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling ${handle.getMethod} and awaiting result
|
|
1073
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling ${handle.getMethod} and awaiting result`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
1072
1074
|
let res = await (this as any)[handle.getMethod](baseEntity, ob, [], ctx.passThrough)
|
|
1073
1075
|
|
|
1074
1076
|
let scimdata: { [key: string]: any } = {
|
|
@@ -1273,7 +1275,7 @@ export class ScimGateway {
|
|
|
1273
1275
|
|
|
1274
1276
|
let info = ''
|
|
1275
1277
|
if (getObj.operator === 'eq' && ['id', 'userName', 'externalId', 'displayName', 'members.value'].includes(getObj.attribute)) info = ` ${getObj.attribute}=${getObj.value}`
|
|
1276
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [Get ${handle.description}s]${info}
|
|
1278
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [Get ${handle.description}s]${info}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
1277
1279
|
try {
|
|
1278
1280
|
getObj.startIndex = ctx.query.startIndex ? parseInt(ctx.query.startIndex) : undefined
|
|
1279
1281
|
getObj.count = ctx.query.count ? parseInt(ctx.query.count) : undefined
|
|
@@ -1309,7 +1311,7 @@ export class ScimGateway {
|
|
|
1309
1311
|
}
|
|
1310
1312
|
const chunk = 5
|
|
1311
1313
|
const chunkRes: Record<string, any>[] = []
|
|
1312
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling ${handle.getMethod} with chunks and awaiting result
|
|
1314
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling ${handle.getMethod} with chunks and awaiting result`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
1313
1315
|
do {
|
|
1314
1316
|
const arrChunk = getObjArr.splice(0, chunk)
|
|
1315
1317
|
const results = await Promise.allSettled(arrChunk.map(o => getObj(o))) as { status: 'fulfilled' | 'rejected', reason: any, value: any }[] // processing max chunk async
|
|
@@ -1328,7 +1330,7 @@ export class ScimGateway {
|
|
|
1328
1330
|
}
|
|
1329
1331
|
|
|
1330
1332
|
if (!res) { // standard
|
|
1331
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling ${handle.getMethod} and awaiting result
|
|
1333
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling ${handle.getMethod} and awaiting result`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
1332
1334
|
res = await (this as any)[handle.getMethod](baseEntity, obj, [], ctx.passThrough)
|
|
1333
1335
|
}
|
|
1334
1336
|
// check for user attribute groups and include if needed
|
|
@@ -1392,7 +1394,7 @@ export class ScimGateway {
|
|
|
1392
1394
|
const postHandler = async (ctx: Context) => {
|
|
1393
1395
|
const handle = handler[ctx.routeObj.handle]
|
|
1394
1396
|
const baseEntity = ctx.routeObj.baseEntity
|
|
1395
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [Create ${handle.description}]
|
|
1397
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [Create ${handle.description}]`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
1396
1398
|
let jsonBody = ctx.request.body
|
|
1397
1399
|
try {
|
|
1398
1400
|
if (!jsonBody) throw new Error('missing body')
|
|
@@ -1422,9 +1424,9 @@ export class ScimGateway {
|
|
|
1422
1424
|
return
|
|
1423
1425
|
}
|
|
1424
1426
|
|
|
1425
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] POST ${ctx.origin + ctx.path} body=${JSON.stringify(jsonBody)}
|
|
1427
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] POST ${ctx.origin + ctx.path} body=${JSON.stringify(jsonBody)}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
1426
1428
|
const [scimdata, err] = utilsScim.convertedScim(jsonBody, this.multiValueTypes)
|
|
1427
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] convertedBody=${JSON.stringify(scimdata)}
|
|
1429
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] convertedBody=${JSON.stringify(scimdata)}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
1428
1430
|
if (err) {
|
|
1429
1431
|
ctx.response.status = 500
|
|
1430
1432
|
const [e, customErrorCode] = utilsScim.jsonErr(this.config.scimgateway.scim.version, pluginName, ctx.response.status, err)
|
|
@@ -1444,7 +1446,7 @@ export class ScimGateway {
|
|
|
1444
1446
|
delete scimdata.groups
|
|
1445
1447
|
}
|
|
1446
1448
|
}
|
|
1447
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling ${handle.createMethod} and awaiting result
|
|
1449
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling ${handle.createMethod} and awaiting result`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
1448
1450
|
const res = await (this as any)[handle.createMethod](baseEntity, scimdata, ctx.passThrough)
|
|
1449
1451
|
for (const key in res) { // merge any result e.g: {'id': 'xxxx'}
|
|
1450
1452
|
jsonBody[key] = res[key]
|
|
@@ -1531,7 +1533,7 @@ export class ScimGateway {
|
|
|
1531
1533
|
ctx.response.body = JSON.stringify(e)
|
|
1532
1534
|
return
|
|
1533
1535
|
}
|
|
1534
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [Delete ${handle.description}] id=${id}
|
|
1536
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [Delete ${handle.description}] id=${id}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
1535
1537
|
|
|
1536
1538
|
try {
|
|
1537
1539
|
if (handle.deleteMethod === 'deleteUser') {
|
|
@@ -1547,7 +1549,7 @@ export class ScimGateway {
|
|
|
1547
1549
|
})) // result not handled - ignore any failures
|
|
1548
1550
|
}
|
|
1549
1551
|
}
|
|
1550
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling ${handle.deleteMethod} and awaiting result
|
|
1552
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling ${handle.deleteMethod} and awaiting result`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
1551
1553
|
await (this as any)[handle.deleteMethod](baseEntity, id, ctx.passThrough)
|
|
1552
1554
|
ctx.response.status = 204
|
|
1553
1555
|
} catch (err: any) {
|
|
@@ -1589,7 +1591,7 @@ export class ScimGateway {
|
|
|
1589
1591
|
return
|
|
1590
1592
|
}
|
|
1591
1593
|
|
|
1592
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [Modify ${handle.description}] id=${id}
|
|
1594
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [Modify ${handle.description}] id=${id}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
1593
1595
|
|
|
1594
1596
|
const eTagIfMatch = ctx.request.headers.get('if-match')?.split(',').map((item: string) => item.trim()).filter(Boolean)
|
|
1595
1597
|
const eTagIfNoneMatch = ctx.request.headers.get('if-none-match')?.split(',').map((item: string) => item.trim()).filter(Boolean)
|
|
@@ -1597,7 +1599,7 @@ export class ScimGateway {
|
|
|
1597
1599
|
let eTag = ''
|
|
1598
1600
|
if (handle.getMethod === handler.users.getMethod || handle.getMethod === handler.groups.getMethod) { // getUsers or getGroups implemented
|
|
1599
1601
|
const ob = { attribute: 'id', operator: 'eq', value: id }
|
|
1600
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling ${handle.getMethod} and awaiting result
|
|
1602
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling ${handle.getMethod} and awaiting result`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
1601
1603
|
const res = await (this as any)[handle.getMethod](baseEntity, ob, [], ctx.passThrough)
|
|
1602
1604
|
if (res) {
|
|
1603
1605
|
if (res.Resources && Array.isArray(res.Resources)) {
|
|
@@ -1629,7 +1631,7 @@ export class ScimGateway {
|
|
|
1629
1631
|
let scimdata: any, err: any
|
|
1630
1632
|
if (jsonBody.Operations) [scimdata, err] = utilsScim.convertedScim20(jsonBody, this.multiValueTypes) // v2.0
|
|
1631
1633
|
else [scimdata, err] = utilsScim.convertedScim(jsonBody, this.multiValueTypes) // v1.1
|
|
1632
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] convertedBody=${JSON.stringify(scimdata)}
|
|
1634
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] convertedBody=${JSON.stringify(scimdata)}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
1633
1635
|
if (err) {
|
|
1634
1636
|
ctx.response.status = 500
|
|
1635
1637
|
const [e, customErrorCode] = utilsScim.jsonErr(this.config.scimgateway.scim.version, pluginName, ctx.response.status, err)
|
|
@@ -1655,7 +1657,7 @@ export class ScimGateway {
|
|
|
1655
1657
|
if (Array.isArray(scimdata.members) && scimdata.members.length === 0 && handle.modifyMethod === 'modifyGroup') {
|
|
1656
1658
|
res = await replaceUsrGrp(ctx.routeObj.handle, baseEntity, id, scimdata, this.config.scimgateway.scim.usePutSoftSync, ctx.passThrough, undefined)
|
|
1657
1659
|
} else {
|
|
1658
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling ${handle.modifyMethod} and awaiting result
|
|
1660
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling ${handle.modifyMethod} and awaiting result`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
1659
1661
|
res = await (this as any)[handle.modifyMethod](baseEntity, id, scimdata, ctx.passThrough)
|
|
1660
1662
|
}
|
|
1661
1663
|
|
|
@@ -1680,7 +1682,7 @@ export class ScimGateway {
|
|
|
1680
1682
|
return
|
|
1681
1683
|
}
|
|
1682
1684
|
const ob = { attribute: 'id', operator: 'eq', value: id }
|
|
1683
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling ${handle.getMethod} and awaiting result
|
|
1685
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling ${handle.getMethod} and awaiting result`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
1684
1686
|
res = await (this as any)[handle.getMethod](baseEntity, ob, [], ctx.passThrough)
|
|
1685
1687
|
}
|
|
1686
1688
|
|
|
@@ -1732,9 +1734,9 @@ export class ScimGateway {
|
|
|
1732
1734
|
id = decodeURIComponent(id)
|
|
1733
1735
|
|
|
1734
1736
|
// get current object
|
|
1735
|
-
logger.debug(`${gwName}[${pluginName}][${baseEntity}] calling ${handle.getMethod} and awaiting result
|
|
1737
|
+
logger.debug(`${gwName}[${pluginName}][${baseEntity}] calling ${handle.getMethod} and awaiting result`, { baseEntity })
|
|
1736
1738
|
const res = await (this as any)[handle.getMethod](baseEntity, { attribute: 'id', operator: 'eq', value: id }, [], ctxPassThrough)
|
|
1737
|
-
logger.debug(`${gwName}[${pluginName}][${baseEntity}] "${handle.getMethod}" result: ${res ? JSON.stringify(res) : ''}
|
|
1739
|
+
logger.debug(`${gwName}[${pluginName}][${baseEntity}] "${handle.getMethod}" result: ${res ? JSON.stringify(res) : ''}`, { baseEntity })
|
|
1738
1740
|
let currentObj
|
|
1739
1741
|
if (res && res.Resources && Array.isArray(res.Resources)) {
|
|
1740
1742
|
if (res.Resources.length === 1) currentObj = res.Resources[0]
|
|
@@ -1792,7 +1794,7 @@ export class ScimGateway {
|
|
|
1792
1794
|
|
|
1793
1795
|
// update object
|
|
1794
1796
|
if (Object.keys(scimdata).length > 0) {
|
|
1795
|
-
logger.debug(`${gwName}[${pluginName}][${baseEntity}] calling ${handle.modifyMethod} and awaiting result
|
|
1797
|
+
logger.debug(`${gwName}[${pluginName}][${baseEntity}] calling ${handle.modifyMethod} and awaiting result`, { baseEntity })
|
|
1796
1798
|
await (this as any)[handle.modifyMethod](baseEntity, id, scimdata, ctxPassThrough)
|
|
1797
1799
|
}
|
|
1798
1800
|
|
|
@@ -1808,7 +1810,7 @@ export class ScimGateway {
|
|
|
1808
1810
|
let res: any
|
|
1809
1811
|
try {
|
|
1810
1812
|
res = await (this as any)[handler.groups.getMethod](baseEntity, { attribute: 'members.value', operator: 'eq', value: decodeURIComponent(id) }, ['id', 'displayName'], ctxPassThrough)
|
|
1811
|
-
logger.debug(`${gwName}[${pluginName}][${baseEntity}] "${handler.groups.getMethod}" result: ${res ? JSON.stringify(res) : ''}
|
|
1813
|
+
logger.debug(`${gwName}[${pluginName}][${baseEntity}] "${handler.groups.getMethod}" result: ${res ? JSON.stringify(res) : ''}`, { baseEntity })
|
|
1812
1814
|
} catch (err) { void 0 } // method may be implemented, but throwing error like groups not supported/implemented
|
|
1813
1815
|
currentGroups = []
|
|
1814
1816
|
if (res && res.Resources && Array.isArray(res.Resources) && res.Resources.length > 0) {
|
|
@@ -1889,7 +1891,7 @@ export class ScimGateway {
|
|
|
1889
1891
|
const id = ctx.routeObj.id ? decodeURIComponent(ctx.routeObj.id) : ctx.routeObj.id
|
|
1890
1892
|
const obj = ctx.request.body
|
|
1891
1893
|
|
|
1892
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [PUT ${handle[0].toUpperCase() + handle.slice(1)}] id=${id} body=${JSON.stringify(obj)}
|
|
1894
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [PUT ${handle[0].toUpperCase() + handle.slice(1)}] id=${id} body=${JSON.stringify(obj)}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
1893
1895
|
try {
|
|
1894
1896
|
if (!obj) throw new Error('missing body')
|
|
1895
1897
|
if (typeof obj !== 'object') throw new Error('body is not JSON')
|
|
@@ -1946,7 +1948,7 @@ export class ScimGateway {
|
|
|
1946
1948
|
|
|
1947
1949
|
const postBulkHandler = async (ctx: Context) => {
|
|
1948
1950
|
const baseEntity = ctx.routeObj.baseEntity
|
|
1949
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [Bulk Operations]
|
|
1951
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [Bulk Operations]`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
1950
1952
|
const bulkBody: SCIMBulkRequest = utils.copyObj(ctx.request.body)
|
|
1951
1953
|
try {
|
|
1952
1954
|
if (!bulkBody) throw new Error('missing body')
|
|
@@ -2098,7 +2100,7 @@ export class ScimGateway {
|
|
|
2098
2100
|
const postApiHandler = async (ctx: Context) => {
|
|
2099
2101
|
const baseEntity = ctx.routeObj.baseEntity
|
|
2100
2102
|
const obj = ctx.request.body
|
|
2101
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [POST ${ctx.routeObj.handle}]
|
|
2103
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [POST ${ctx.routeObj.handle}]`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
2102
2104
|
|
|
2103
2105
|
if (!obj) {
|
|
2104
2106
|
const err = new Error('missing body')
|
|
@@ -2107,7 +2109,7 @@ export class ScimGateway {
|
|
|
2107
2109
|
return
|
|
2108
2110
|
}
|
|
2109
2111
|
try {
|
|
2110
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling postApi and awaiting result
|
|
2112
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling postApi and awaiting result`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
2111
2113
|
let result = await this.postApi(baseEntity, obj, ctx.passThrough)
|
|
2112
2114
|
if (result) {
|
|
2113
2115
|
if (typeof result === 'object') result = { result: result }
|
|
@@ -2147,7 +2149,7 @@ export class ScimGateway {
|
|
|
2147
2149
|
const baseEntity = ctx.routeObj.baseEntity
|
|
2148
2150
|
const id = ctx.routeObj.id
|
|
2149
2151
|
const obj = ctx.request.body
|
|
2150
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [PUT ${ctx.routeObj.handle}] id=${id}
|
|
2152
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [PUT ${ctx.routeObj.handle}] id=${id}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
2151
2153
|
|
|
2152
2154
|
try {
|
|
2153
2155
|
if (!obj) throw new Error('missing body')
|
|
@@ -2159,7 +2161,7 @@ export class ScimGateway {
|
|
|
2159
2161
|
}
|
|
2160
2162
|
|
|
2161
2163
|
try {
|
|
2162
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling putApi and awaiting result
|
|
2164
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling putApi and awaiting result`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
2163
2165
|
let result = await this.putApi(baseEntity, id, obj, ctx.passThrough)
|
|
2164
2166
|
if (result) {
|
|
2165
2167
|
if (typeof result === 'object') result = { result }
|
|
@@ -2200,7 +2202,7 @@ export class ScimGateway {
|
|
|
2200
2202
|
const id = ctx.routeObj.id as string
|
|
2201
2203
|
const body = ctx.request.body
|
|
2202
2204
|
|
|
2203
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [PATCH ${handle} ] id=${id}
|
|
2205
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [PATCH ${handle} ] id=${id}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
2204
2206
|
|
|
2205
2207
|
if (!body) {
|
|
2206
2208
|
const err = new Error('missing body')
|
|
@@ -2209,7 +2211,7 @@ export class ScimGateway {
|
|
|
2209
2211
|
return
|
|
2210
2212
|
} else {
|
|
2211
2213
|
try {
|
|
2212
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling patchApi and awaiting result
|
|
2214
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling patchApi and awaiting result`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
2213
2215
|
let result = await this.patchApi(baseEntity, id, body, ctx.passThrough)
|
|
2214
2216
|
if (result) {
|
|
2215
2217
|
if (typeof result === 'object') result = { result }
|
|
@@ -2250,11 +2252,11 @@ export class ScimGateway {
|
|
|
2250
2252
|
const id = ctx.routeObj.id as string
|
|
2251
2253
|
const body = ctx.request.body
|
|
2252
2254
|
|
|
2253
|
-
if (id) logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [GET ${handle}] id=${id}
|
|
2255
|
+
if (id) logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [GET ${handle}] id=${id}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
2254
2256
|
else logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [GET ${handle}]`)
|
|
2255
2257
|
|
|
2256
2258
|
try {
|
|
2257
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling getApi and awaiting result
|
|
2259
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling getApi and awaiting result`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
2258
2260
|
let result = await this.getApi(baseEntity, id, ctx.query, body, ctx.passThrough)
|
|
2259
2261
|
if (result) {
|
|
2260
2262
|
if (typeof result === 'object') result = { result }
|
|
@@ -2289,10 +2291,10 @@ export class ScimGateway {
|
|
|
2289
2291
|
const deleteApiHandler = async (ctx: Context) => {
|
|
2290
2292
|
const baseEntity = ctx.routeObj.baseEntity
|
|
2291
2293
|
const id = ctx.routeObj.id
|
|
2292
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [DELETE ${ctx.routeObj.handle} ] id=${id}
|
|
2294
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] [DELETE ${ctx.routeObj.handle} ] id=${id}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
2293
2295
|
try {
|
|
2294
2296
|
if (!id || id.includes('/')) throw new Error('missing id')
|
|
2295
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling deleteApi and awaiting result
|
|
2297
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling deleteApi and awaiting result`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
2296
2298
|
let result = await this.deleteApi(baseEntity, id, ctx.passThrough)
|
|
2297
2299
|
if (result) {
|
|
2298
2300
|
if (typeof result === 'object') result = { result: result }
|
|
@@ -2334,7 +2336,7 @@ export class ScimGateway {
|
|
|
2334
2336
|
try {
|
|
2335
2337
|
const ob = { attribute: 'members.value', operator: 'eq', value: decodeURIComponent(id) }
|
|
2336
2338
|
const attributes = ['id', 'displayName']
|
|
2337
|
-
logger.debug(`${gwName}[${pluginName}][${baseEntity}] calling ${handler.groups.getMethod} and awaiting result - groups to be included
|
|
2339
|
+
logger.debug(`${gwName}[${pluginName}][${baseEntity}] calling ${handler.groups.getMethod} and awaiting result - groups to be included`, { baseEntity })
|
|
2338
2340
|
res = await (this as any)[handler.groups.getMethod](baseEntity, ob, attributes, ctxPassThrough)
|
|
2339
2341
|
} catch (err) { void 0 }
|
|
2340
2342
|
if (res && res.Resources && Array.isArray(res.Resources) && res.Resources.length > 0) {
|
|
@@ -2550,6 +2552,7 @@ export class ScimGateway {
|
|
|
2550
2552
|
} else if (!ctx.routeObj.handle) {
|
|
2551
2553
|
ctx.response.status = 404 // NOT_FOUND
|
|
2552
2554
|
} else if (!ipAllowList(ctx.ip)) {
|
|
2555
|
+
logger.debug(`${gwName}[${pluginName}] client ip ${ctx.ip} not in ipAllowList`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
2553
2556
|
ctx.response.status = 401
|
|
2554
2557
|
} else if (!await isAuthorized(ctx)) {
|
|
2555
2558
|
ctx.response.status = 401
|
|
@@ -2565,14 +2568,14 @@ export class ScimGateway {
|
|
|
2565
2568
|
const chainingBaseUrl = this.config.scimgateway.chainingBaseUrl // http(s)://<host>:<port>
|
|
2566
2569
|
if (!chainingBaseUrl) {
|
|
2567
2570
|
ctx.response.status = 500
|
|
2568
|
-
logger.error(`${gwName}[${pluginName}] onChainingHandler error: configuration scimgateway.chainingBaseUrl missing
|
|
2571
|
+
logger.error(`${gwName}[${pluginName}] onChainingHandler error: configuration scimgateway.chainingBaseUrl missing`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
2569
2572
|
return
|
|
2570
2573
|
}
|
|
2571
2574
|
try {
|
|
2572
2575
|
new URL(chainingBaseUrl)
|
|
2573
2576
|
} catch (err: any) {
|
|
2574
2577
|
ctx.response.status = 500
|
|
2575
|
-
logger.error(`${gwName}[${pluginName}] onChainingHandler error: configuration scimgateway.chainingBaseUrl must use correct syntax 'http(s)://host:port' error: ${err.message}
|
|
2578
|
+
logger.error(`${gwName}[${pluginName}] onChainingHandler error: configuration scimgateway.chainingBaseUrl must use correct syntax 'http(s)://host:port' error: ${err.message}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
2576
2579
|
return
|
|
2577
2580
|
}
|
|
2578
2581
|
try {
|
|
@@ -2597,7 +2600,7 @@ export class ScimGateway {
|
|
|
2597
2600
|
ctx.response.body = jBody.body ? JSON.stringify(jBody.body) : err.message
|
|
2598
2601
|
} catch (parseErr) {
|
|
2599
2602
|
ctx.response.status = 500
|
|
2600
|
-
logger.error(`${gwName}[${pluginName}] onChainingHandler error: ${err.message}
|
|
2603
|
+
logger.error(`${gwName}[${pluginName}] onChainingHandler error: ${err.message}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
2601
2604
|
}
|
|
2602
2605
|
}
|
|
2603
2606
|
}
|
|
@@ -2605,14 +2608,14 @@ export class ScimGateway {
|
|
|
2605
2608
|
const onPublisherHandler = async (ctx: Context) => {
|
|
2606
2609
|
if (!this.pub) {
|
|
2607
2610
|
ctx.response.status = 500
|
|
2608
|
-
logger.error(`${gwName}[${pluginName}] onPublisherHandler error: publisher not initialized
|
|
2611
|
+
logger.error(`${gwName}[${pluginName}] onPublisherHandler error: publisher not initialized`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
2609
2612
|
return
|
|
2610
2613
|
}
|
|
2611
2614
|
try {
|
|
2612
2615
|
ctx.response = await this.pub.publish({ ctx })
|
|
2613
2616
|
} catch (err: any) {
|
|
2614
2617
|
ctx.response.status = 500
|
|
2615
|
-
logger.error(`${gwName}[${pluginName}] onPublisherHandler error: ${err.message}
|
|
2618
|
+
logger.error(`${gwName}[${pluginName}] onPublisherHandler error: ${err.message}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
2616
2619
|
return
|
|
2617
2620
|
}
|
|
2618
2621
|
}
|
|
@@ -2732,7 +2735,7 @@ export class ScimGateway {
|
|
|
2732
2735
|
<script>
|
|
2733
2736
|
const stopBtn = document.getElementById('stopBtn')
|
|
2734
2737
|
const logElem = document.getElementById('log')
|
|
2735
|
-
let ws = new WebSocket('{{protocol}}//' + location.host +
|
|
2738
|
+
let ws = new WebSocket('{{protocol}}//' + location.host + location.pathname)
|
|
2736
2739
|
ws.onmessage = function(event) {
|
|
2737
2740
|
event.data.split('\\n').forEach(function(line) {
|
|
2738
2741
|
if (!line.trim()) return
|
|
@@ -2805,11 +2808,12 @@ export class ScimGateway {
|
|
|
2805
2808
|
return await onAfterHandle(ctx)
|
|
2806
2809
|
case 'GET logger': // no onAfterHandle
|
|
2807
2810
|
if (req.headers.get('upgrade')?.toLowerCase() === 'websocket') { // browser step 2, and other Bun ws(s) clients
|
|
2808
|
-
logger.info(`${gwName}[${pluginName}] remote logger connected from ip address ${ctx.ip}
|
|
2811
|
+
logger.info(`${gwName}[${pluginName}] remote logger connected from ip address ${ctx.ip}`, { baseEntity: ctx?.routeObj?.baseEntity })
|
|
2809
2812
|
return server.upgrade(req, { // after upgrade, the server will handle the WebSocket connection configured in Bun.serve()
|
|
2810
2813
|
data: { // passed to WebSocket server Bun open handler
|
|
2811
2814
|
headers: req.headers,
|
|
2812
2815
|
url: req.url,
|
|
2816
|
+
baseEntity: ctx?.routeObj?.baseEntity,
|
|
2813
2817
|
ip: ctx.ip,
|
|
2814
2818
|
nonce: this.Nonce.createItem(crypto.randomUUID()),
|
|
2815
2819
|
},
|
|
@@ -2882,7 +2886,7 @@ export class ScimGateway {
|
|
|
2882
2886
|
},
|
|
2883
2887
|
websocket: {
|
|
2884
2888
|
open: (ws) => {
|
|
2885
|
-
const data = ws.data as { headers: Headers, url: string, ip: string, nonce: string } || {}
|
|
2889
|
+
const data = ws.data as { headers: Headers, url: string, baseEntity: string, ip: string, nonce: string } || {}
|
|
2886
2890
|
let isAuthorized = false // client is already authenticated by initial http/https upgrade to websocket, anyhow passing data to be validated
|
|
2887
2891
|
if (data?.nonce && this.Nonce.isItemValid(data.nonce)) {
|
|
2888
2892
|
if (data.headers.has('authorization')) {
|
|
@@ -2890,7 +2894,7 @@ export class ScimGateway {
|
|
|
2890
2894
|
}
|
|
2891
2895
|
}
|
|
2892
2896
|
if (!isAuthorized) {
|
|
2893
|
-
logger.error(`${gwName}[${pluginName}] remote logger ip address ${data.ip} - WebSocket connection error: invalid nonce
|
|
2897
|
+
logger.error(`${gwName}[${pluginName}] remote logger ip address ${data.ip} - WebSocket connection error: invalid nonce`, { baseEntity: data.baseEntity })
|
|
2894
2898
|
ws.close(3000, 'Unauthorized')
|
|
2895
2899
|
return
|
|
2896
2900
|
}
|
|
@@ -2898,19 +2902,24 @@ export class ScimGateway {
|
|
|
2898
2902
|
const levelInt = logger.levelToInt(this.config?.scimgateway?.log?.loglevel?.push || 'info')
|
|
2899
2903
|
const sub = async (msgObj: Record<string, any>) => {
|
|
2900
2904
|
if (logger.levelToInt(msgObj.level) < levelInt) return
|
|
2905
|
+
if (data.baseEntity !== 'undefined') { // if using baseEntity e.g. <host>/company1/logger, only include corresponding baseEntity logentries
|
|
2906
|
+
if (data.baseEntity !== msgObj.baseEntity) return
|
|
2907
|
+
}
|
|
2901
2908
|
ws.send(`${JSON.stringify(msgObj)}`)
|
|
2902
2909
|
}
|
|
2903
2910
|
logger.subscribe(sub)
|
|
2904
2911
|
;(ws as any)._sub = sub
|
|
2912
|
+
;(ws as any)._baseEntity = data.baseEntity
|
|
2905
2913
|
;(ws as any)._ip = data.ip
|
|
2906
2914
|
},
|
|
2907
2915
|
close: (ws) => {
|
|
2908
2916
|
const sub = (ws as any)._sub
|
|
2917
|
+
const baseEntity = (ws as any)._baseEntity
|
|
2909
2918
|
const ip = (ws as any)._ip
|
|
2910
2919
|
if (sub) {
|
|
2911
2920
|
logger.unsubscribe(sub)
|
|
2912
2921
|
}
|
|
2913
|
-
logger.info(`${gwName}[${pluginName}] remote logger disconnected from ip address ${ip}
|
|
2922
|
+
logger.info(`${gwName}[${pluginName}] remote logger disconnected from ip address ${ip}`, { baseEntity })
|
|
2914
2923
|
},
|
|
2915
2924
|
message: () => {},
|
|
2916
2925
|
},
|
|
@@ -3185,28 +3194,28 @@ export class ScimGateway {
|
|
|
3185
3194
|
* logDebug logs debug message
|
|
3186
3195
|
**/
|
|
3187
3196
|
logDebug(baseEntity: string | undefined, msg: string) {
|
|
3188
|
-
this.logger.debug(`${this.pluginName}[${baseEntity}] ${msg}
|
|
3197
|
+
this.logger.debug(`${this.pluginName}[${baseEntity}] ${msg}`, { baseEntity })
|
|
3189
3198
|
}
|
|
3190
3199
|
|
|
3191
3200
|
/**
|
|
3192
3201
|
* logInfo logs info message
|
|
3193
3202
|
**/
|
|
3194
3203
|
logInfo(baseEntity: string | undefined, msg: string) {
|
|
3195
|
-
this.logger.info(`${this.pluginName}[${baseEntity}] ${msg}
|
|
3204
|
+
this.logger.info(`${this.pluginName}[${baseEntity}] ${msg}`, { baseEntity })
|
|
3196
3205
|
}
|
|
3197
3206
|
|
|
3198
3207
|
/**
|
|
3199
3208
|
* logWarn logs warning message
|
|
3200
3209
|
**/
|
|
3201
3210
|
logWarn(baseEntity: string | undefined, msg: string) {
|
|
3202
|
-
this.logger.warn(`${this.pluginName}[${baseEntity}] ${msg}
|
|
3211
|
+
this.logger.warn(`${this.pluginName}[${baseEntity}] ${msg}`, { baseEntity })
|
|
3203
3212
|
}
|
|
3204
3213
|
|
|
3205
3214
|
/**
|
|
3206
3215
|
* logError logs error message
|
|
3207
3216
|
**/
|
|
3208
3217
|
logError(baseEntity: string | undefined, msg: string) {
|
|
3209
|
-
this.logger.error(`${this.pluginName}[${baseEntity}] ${msg}
|
|
3218
|
+
this.logger.error(`${this.pluginName}[${baseEntity}] ${msg}`, { baseEntity })
|
|
3210
3219
|
}
|
|
3211
3220
|
|
|
3212
3221
|
/**
|
package/package.json
CHANGED