scimgateway 6.0.0 → 6.0.1

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 CHANGED
@@ -1484,6 +1484,13 @@ MIT © [Jarle Elshaug](https://www.elshaug.xyz)
1484
1484
 
1485
1485
  ## Change log
1486
1486
 
1487
+
1488
+ ### v6.0.1
1489
+
1490
+ [Fixed]
1491
+ - plugin-ldap, failed when the RDN value contained the character '=' e.g., `CN=Firstname \= Lastname,CN=Users,DC=my-company,DC=com`
1492
+ - GET using filter failed when filter value contained the character '%' e.g., `GET /Users?filter=userName eq "my % name"`
1493
+
1487
1494
  ### v6.0.0
1488
1495
 
1489
1496
  **[MAJOR]**
package/lib/plugin-api.ts CHANGED
@@ -55,7 +55,7 @@ const helper = new HelperRest(scimgateway)
55
55
  //
56
56
  scimgateway.postApi = async (baseEntity, body, ctx) => {
57
57
  const action = 'postApi'
58
- scimgateway.logDebug(baseEntity, `handling ${action} body=${JSON.stringify(body)}`)
58
+ scimgateway.logDebug(baseEntity, `handling ${action} body=${JSON.stringify(body)} passThrough=${ctx ? 'true' : 'false'}`)
59
59
 
60
60
  if ((typeof (body) !== 'object') || (Object.keys(body).length === 0)) {
61
61
  throw new Error('unsupported POST syntax')
@@ -81,7 +81,7 @@ scimgateway.postApi = async (baseEntity, body, ctx) => {
81
81
  //
82
82
  scimgateway.putApi = async (baseEntity, id, body, ctx) => {
83
83
  const action = 'putApi'
84
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id} body=${JSON.stringify(body)}`)
84
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} body=${JSON.stringify(body)} passThrough=${ctx ? 'true' : 'false'}`)
85
85
 
86
86
  if ((typeof (body) !== 'object') || (Object.keys(body).length === 0)) {
87
87
  throw new Error('unsupported PUT syntax')
@@ -108,7 +108,7 @@ scimgateway.putApi = async (baseEntity, id, body, ctx) => {
108
108
  //
109
109
  scimgateway.patchApi = async (baseEntity, id, body, ctx) => {
110
110
  const action = 'patchApi'
111
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id} body=${JSON.stringify(body)}`)
111
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} body=${JSON.stringify(body)} passThrough=${ctx ? 'true' : 'false'}`)
112
112
 
113
113
  if ((typeof (body) !== 'object') || (Object.keys(body).length === 0)) {
114
114
  throw new Error('unsupported PATCH syntax')
@@ -135,7 +135,7 @@ scimgateway.patchApi = async (baseEntity, id, body, ctx) => {
135
135
  //
136
136
  scimgateway.getApi = async (baseEntity, id, query, ctx) => {
137
137
  const action = 'getApi'
138
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id} apiQuery=${JSON.stringify(query)}}`)
138
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} apiQuery=${JSON.stringify(query)}} passThrough=${ctx ? 'true' : 'false'}`)
139
139
 
140
140
  const method = 'GET'
141
141
  let path = '/products'
@@ -162,7 +162,7 @@ scimgateway.getApi = async (baseEntity, id, query, ctx) => {
162
162
  //
163
163
  scimgateway.deleteApi = async (baseEntity, id, ctx) => {
164
164
  const action = 'deleteApi'
165
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id}`)
165
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} passThrough=${ctx ? 'true' : 'false'}`)
166
166
 
167
167
  const method = 'DELETE'
168
168
  const path = `/products/${id}`
@@ -212,9 +212,9 @@ const deletePublicApi = async (baseEntity: string, id: string | undefined, body:
212
212
  return { delete: { id, body } }
213
213
  }
214
214
 
215
- scimgateway.publicApi = async (baseEntity, method, id, query, body) => {
215
+ scimgateway.publicApi = async (baseEntity, method, id, query, body, ctx) => {
216
216
  const action = 'publicApi'
217
- scimgateway.logDebug(baseEntity, `handling ${action} method=${method} id=${id} query=${query ? JSON.stringify(query) : query} body=${JSON.stringify(body)}`)
217
+ scimgateway.logDebug(baseEntity, `handling ${action} method=${method} id=${id} query=${query ? JSON.stringify(query) : query} body=${JSON.stringify(body)} passThrough=${ctx ? 'true' : 'false'}`)
218
218
 
219
219
  switch (method) {
220
220
  case 'GET':
@@ -140,7 +140,7 @@ scimgateway.getUsers = async (baseEntity, getObj, attributes, ctx) => {
140
140
  // scimgateway will automatically filter response according to the attributes list
141
141
  //
142
142
  const action = 'getUsers'
143
- scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes}`)
143
+ scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes} passThrough=${ctx ? 'true' : 'false'}`)
144
144
 
145
145
  const ret: any = {
146
146
  Resources: [],
@@ -207,7 +207,7 @@ scimgateway.getUsers = async (baseEntity, getObj, attributes, ctx) => {
207
207
  // =================================================
208
208
  scimgateway.createUser = async (baseEntity, userObj, ctx) => {
209
209
  const action = 'createUser'
210
- scimgateway.logDebug(baseEntity, `handling ${action} userObj=${JSON.stringify(userObj)}`)
210
+ scimgateway.logDebug(baseEntity, `handling ${action} userObj=${JSON.stringify(userObj)} passThrough=${ctx ? 'true' : 'false'}`)
211
211
 
212
212
  const addonObj: Record<string, any> = {}
213
213
  if (userObj.servicePlan) {
@@ -241,7 +241,7 @@ scimgateway.createUser = async (baseEntity, userObj, ctx) => {
241
241
  // =================================================
242
242
  scimgateway.deleteUser = async (baseEntity, id, ctx) => {
243
243
  const action = 'deleteUser'
244
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id}`)
244
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} passThrough=${ctx ? 'true' : 'false'}`)
245
245
  const method = 'DELETE'
246
246
  const path = `/Users/${id}`
247
247
  const body = null
@@ -258,7 +258,7 @@ scimgateway.deleteUser = async (baseEntity, id, ctx) => {
258
258
  // =================================================
259
259
  scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
260
260
  const action = 'modifyUser'
261
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)}`)
261
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)} passThrough=${ctx ? 'true' : 'false'}`)
262
262
 
263
263
  if (attrObj.servicePlan) delete attrObj.servicePlan // use license management through groups
264
264
  const [parsedAttrObj] = scimgateway.endpointMapper('outbound', attrObj, config.map.user) // SCIM/CustomSCIM => endpoint attribute standard
@@ -340,7 +340,7 @@ scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
340
340
  // =================================================
341
341
  scimgateway.getGroups = async (baseEntity, getObj, attributes, ctx) => {
342
342
  const action = 'getGroups'
343
- scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes}`)
343
+ scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes} passThrough=${ctx ? 'true' : 'false'}`)
344
344
 
345
345
  const ret: any = {
346
346
  Resources: [],
@@ -444,7 +444,7 @@ scimgateway.getGroups = async (baseEntity, getObj, attributes, ctx) => {
444
444
  // =================================================
445
445
  scimgateway.createGroup = async (baseEntity, groupObj, ctx) => {
446
446
  const action = 'createGroup'
447
- scimgateway.logDebug(baseEntity, `handling ${action} groupObj=${JSON.stringify(groupObj)}`)
447
+ scimgateway.logDebug(baseEntity, `handling ${action} groupObj=${JSON.stringify(groupObj)} passThrough=${ctx ? 'true' : 'false'}`)
448
448
  const body: any = { displayName: groupObj.displayName }
449
449
  body.mailNickName = groupObj.displayName
450
450
  body.mailEnabled = false
@@ -469,9 +469,9 @@ scimgateway.createGroup = async (baseEntity, groupObj, ctx) => {
469
469
  // =================================================
470
470
  // deleteGroup
471
471
  // =================================================
472
- scimgateway.deleteGroup = async (baseEntity, id) => {
472
+ scimgateway.deleteGroup = async (baseEntity, id, ctx) => {
473
473
  const action = 'deleteGroup'
474
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id}`)
474
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} passThrough=${ctx ? 'true' : 'false'}`)
475
475
  throw new Error(`${action} error: ${action} is not supported`)
476
476
  }
477
477
 
@@ -480,7 +480,7 @@ scimgateway.deleteGroup = async (baseEntity, id) => {
480
480
  // =================================================
481
481
  scimgateway.modifyGroup = async (baseEntity, id, attrObj, ctx) => {
482
482
  const action = 'modifyGroup'
483
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)}`)
483
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)} passThrough=${ctx ? 'true' : 'false'}`)
484
484
 
485
485
  if (!attrObj.members) {
486
486
  throw new Error(`${action} error: only supports modification of members`)
@@ -559,7 +559,7 @@ scimgateway.getServicePlans = async (baseEntity, getObj, attributes, ctx) => {
559
559
  // scimgateway will automatically filter response according to the attributes list
560
560
  //
561
561
  const action = 'getServicePlans'
562
- scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes}`)
562
+ scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes} passThrough=${ctx ? 'true' : 'false'}`)
563
563
 
564
564
  const ret: any = {
565
565
  Resources: [],
@@ -1,5 +1,5 @@
1
1
  // =================================================================================
2
- // File: plugin-ldap.js
2
+ // File: plugin-ldap.ts
3
3
  //
4
4
  // Author: Jarle Elshaug
5
5
  //
@@ -123,7 +123,7 @@ scimgateway.getUsers = async (baseEntity, getObj, attributes, ctx) => {
123
123
  // scimgateway will automatically filter response according to the attributes list
124
124
  //
125
125
  const action = 'getUsers'
126
- scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes}`)
126
+ scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes} passThrough=${ctx ? 'true' : 'false'}`)
127
127
  if (!config.entity[baseEntity]) throw new Error(`unsupported baseEntity: ${baseEntity}`)
128
128
 
129
129
  const result: any = {
@@ -272,7 +272,7 @@ scimgateway.getUsers = async (baseEntity, getObj, attributes, ctx) => {
272
272
  // =================================================
273
273
  scimgateway.createUser = async (baseEntity, userObj, ctx) => {
274
274
  const action = 'createUser'
275
- scimgateway.logDebug(baseEntity, `handling ${action} userObj=${JSON.stringify(userObj)}`)
275
+ scimgateway.logDebug(baseEntity, `handling ${action} userObj=${JSON.stringify(userObj)} passThrough=${ctx ? 'true' : 'false'}`)
276
276
 
277
277
  let userBase = null
278
278
  if (userObj.entitlements && userObj.entitlements.userbase) { // override default userBase (type userbase will be lowercase)
@@ -338,7 +338,7 @@ scimgateway.createUser = async (baseEntity, userObj, ctx) => {
338
338
  // =================================================
339
339
  scimgateway.deleteUser = async (baseEntity, id, ctx) => {
340
340
  const action = 'deleteUser'
341
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id}`)
341
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} passThrough=${ctx ? 'true' : 'false'}`)
342
342
 
343
343
  const method = 'del'
344
344
  let base
@@ -365,7 +365,7 @@ scimgateway.deleteUser = async (baseEntity, id, ctx) => {
365
365
  // =================================================
366
366
  scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
367
367
  const action = 'modifyUser'
368
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)}`)
368
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)} passThrough=${ctx ? 'true' : 'false'}`)
369
369
 
370
370
  // groups must be handled separate - using group member of user and not user member of group
371
371
  if (attrObj.groups) { // not supported by AD - will fail (not allowing updating users memberOf attribute, must update group instead of user)
@@ -539,7 +539,7 @@ scimgateway.getGroups = async (baseEntity, getObj, attributes, ctx) => {
539
539
  // scimgateway will automatically filter response according to the attributes list
540
540
  //
541
541
  const action = 'getGroups'
542
- scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes}`)
542
+ scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes} passThrough=${ctx ? 'true' : 'false'}`)
543
543
  if (!config.entity[baseEntity]) throw new Error(`unsupported baseEntity: ${baseEntity}`)
544
544
 
545
545
  const result: any = {
@@ -683,7 +683,7 @@ scimgateway.getGroups = async (baseEntity, getObj, attributes, ctx) => {
683
683
  // =================================================
684
684
  scimgateway.createGroup = async (baseEntity, groupObj, ctx) => {
685
685
  const action = 'createGroup'
686
- scimgateway.logDebug(baseEntity, `handling ${action} groupObj=${JSON.stringify(groupObj)}`)
686
+ scimgateway.logDebug(baseEntity, `handling ${action} groupObj=${JSON.stringify(groupObj)} passThrough=${ctx ? 'true' : 'false'}`)
687
687
 
688
688
  if (!config.map.group) throw new Error(`${action} error: missing configuration endpoint.map.group`)
689
689
  const groupBase = config.entity[baseEntity].ldap.groupBase
@@ -723,7 +723,7 @@ scimgateway.createGroup = async (baseEntity, groupObj, ctx) => {
723
723
  // =================================================
724
724
  scimgateway.deleteGroup = async (baseEntity, id, ctx) => {
725
725
  const action = 'deleteGroup'
726
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id}`)
726
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} passThrough=${ctx ? 'true' : 'false'}`)
727
727
 
728
728
  if (!config.map.group) throw new Error(`${action} error: missing configuration endpoint.map.group`)
729
729
  const method = 'del'
@@ -751,7 +751,7 @@ scimgateway.deleteGroup = async (baseEntity, id, ctx) => {
751
751
  // =================================================
752
752
  scimgateway.modifyGroup = async (baseEntity, id, attrObj, ctx) => {
753
753
  const action = 'modifyGroup'
754
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)}`)
754
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)} passThrough=${ctx ? 'true' : 'false'}`)
755
755
 
756
756
  if (!config.map.group) throw new Error(`${action} error: missing configuration endpoint.map.group`)
757
757
  if (attrObj.members && !Array.isArray(attrObj.members)) {
@@ -772,6 +772,8 @@ scimgateway.modifyGroup = async (baseEntity, id, attrObj, ctx) => {
772
772
  if (!dn) throw new Error(`${action} error: sidGuidToDn() did not return any objectGUID value for dn=${el.value}`)
773
773
  el.value = dn
774
774
  }
775
+ const dnObj = ldapEscDn(config.entity[baseEntity].ldap.isOpenLdap, el.value)
776
+ el.value = dnObj.toString()
775
777
  if (el.operation && el.operation === 'delete') { // delete member from group
776
778
  grp.remove[memberAttr].push(el.value) // endpointMapper returns URI encoded id because some IdP's don't encode id used in GET url e.g. Symantec/Broadcom/CA
777
779
  } else { // add member to group
@@ -1098,8 +1100,8 @@ const getMemberOfGroups = async (baseEntity: string, id: string, ctx: any) => {
1098
1100
  // using OpenLDAP, DN must be escaped - national characters and special ldap characters
1099
1101
  // using Active Directory (none OpenLDAP), DN should not be escaped, but DN retrieved from AD is character escaped
1100
1102
  //
1101
- const ldapEscDn = (isOpenLdap: any, str: string) => {
1102
- if (typeof str !== 'string' || str.length < 1) return str
1103
+ const ldapEscDn = (isOpenLdap: any, str: string): ldap.DN => {
1104
+ if (typeof str !== 'string' || str.length < 1) return new ldap.DN()
1103
1105
 
1104
1106
  if (!isOpenLdap && str.indexOf('\\') > 0) {
1105
1107
  const conv = str.replace(/\\([0-9A-Fa-f]{2})/g, (_, hex) => {
@@ -1127,6 +1129,10 @@ const ldapEscDn = (isOpenLdap: any, str: string) => {
1127
1129
  continue
1128
1130
  }
1129
1131
  const a = arr[i].split('=')
1132
+ while (a.length > 2) { // 'uid=Firstname \= Lastname'
1133
+ a[1] += '=' + a[2]
1134
+ a.splice(2, 1)
1135
+ }
1130
1136
  if (a.length < 2 && i > 0) { // value having comma and content
1131
1137
  if (arr[i - 1].charAt(arr[i - 1].length - 1) === '\\') {
1132
1138
  arr[i - 1] = arr[i - 1].substring(0, arr[i - 1].length - 1)
@@ -1142,17 +1148,18 @@ const ldapEscDn = (isOpenLdap: any, str: string) => {
1142
1148
  }
1143
1149
  if (i > 0) break // only escape logic on first, assume sub OU's are correct
1144
1150
  }
1145
- if (isOpenLdap) {
1146
- str = arr.join(',')
1147
- return str
1148
- }
1149
- // Using dn object and BER encoding
1150
- // e.g., Active Directory to avoid internal ldapjs OpenLDAP validating and string escaping logic
1151
+
1152
+ // Using dn object instead of string to ensure all escaping will be OK e.g. 'uid=test \= test,dc=example,dc=com'
1153
+ // For non OpenLdap e.g., Active Directory, we must include BER encoding
1151
1154
  const dn = new ldap.DN()
1152
1155
  for (let i = 0; i < arr.length; i++) {
1153
1156
  const a = arr[i].split('=') // cn=Kürt
1157
+ while (a.length > 2) {
1158
+ a[1] += '=' + a[2]
1159
+ a.splice(2, 1)
1160
+ }
1154
1161
  if (a.length === 2) {
1155
- if (i === 0) {
1162
+ if (i === 0 && !isOpenLdap) {
1156
1163
  const ua = new Uint8Array(Buffer.from(a[1], 'utf-8'))
1157
1164
  const buf = Buffer.from(new Uint8Array([4, ua.length, ...ua]))
1158
1165
  const rdn: any = {}
@@ -1328,8 +1335,7 @@ const checkIfNewDN = (baseEntity: string, base: any, type: string, obj: any, end
1328
1335
  if (a[1].toLowerCase() !== namingAttr.toLowerCase() + '=') return ''
1329
1336
  if (a[2] === newNamingValue) return ''
1330
1337
  let newDN = a[1] + newNamingValue + a[3]
1331
- newDN = ldapEscDn(config.entity[baseEntity].ldap.isOpenLdap, newDN)
1332
- return newDN
1338
+ return ldapEscDn(config.entity[baseEntity].ldap.isOpenLdap, newDN)
1333
1339
  }
1334
1340
 
1335
1341
  //
@@ -1422,7 +1428,7 @@ const doRequest = async (baseEntity: string, method: string, base: any, options:
1422
1428
  if (!config.entity[baseEntity]) throw new Error(`unsupported baseEntity: ${baseEntity}`)
1423
1429
  let result: any = null
1424
1430
  let client: any = null
1425
- base = ldapEscDn(config.entity[baseEntity].ldap.isOpenLdap, base)
1431
+ const dnObj = ldapEscDn(config.entity[baseEntity].ldap.isOpenLdap, base)
1426
1432
 
1427
1433
  // support having different upn-domain on IdP and target
1428
1434
  if (options.modification && options.modification.userPrincipalName && config.map.user.userPrincipalName && config.map.user.userPrincipalName.mapDomain) {
@@ -1441,7 +1447,7 @@ const doRequest = async (baseEntity: string, method: string, base: any, options:
1441
1447
  result = await new Promise((resolve, reject) => {
1442
1448
  const results: any = []
1443
1449
 
1444
- client.search(base, options, (err: any, search: any) => {
1450
+ client.search(dnObj, options, (err: any, search: any) => {
1445
1451
  if (err) {
1446
1452
  return reject(err)
1447
1453
  }
@@ -1510,7 +1516,7 @@ const doRequest = async (baseEntity: string, method: string, base: any, options:
1510
1516
 
1511
1517
  case 'modify':
1512
1518
  result = await new Promise((resolve: any, reject: any) => {
1513
- const dn = base
1519
+ const dn = dnObj
1514
1520
  const changes: any = []
1515
1521
  for (const key in options.modification) {
1516
1522
  const mod: any = {}
@@ -1549,8 +1555,7 @@ const doRequest = async (baseEntity: string, method: string, base: any, options:
1549
1555
 
1550
1556
  case 'modifyDN':
1551
1557
  result = await new Promise((resolve: any, reject: any) => {
1552
- let dn = base
1553
- if (Object.prototype.toString.call(dn) === '[object LdapDn]') dn = base.toString() // needed for client.modifyDN...
1558
+ let dn = dnObj.toString() // needed for client.modifyDN...
1554
1559
  let newDN = options?.modification?.newDN
1555
1560
  if (!newDN) return reject(new Error('modifyDN() missing newDN'))
1556
1561
  if (Object.prototype.toString.call(newDN) === '[object LdapDn]') newDN = newDN.toString()
@@ -1565,7 +1570,7 @@ const doRequest = async (baseEntity: string, method: string, base: any, options:
1565
1570
 
1566
1571
  case 'add':
1567
1572
  result = await new Promise((resolve: any, reject: any) => {
1568
- client.add(base, options, (err: any) => {
1573
+ client.add(dnObj, options, (err: any) => {
1569
1574
  if (err) {
1570
1575
  return reject(err)
1571
1576
  }
@@ -1576,7 +1581,7 @@ const doRequest = async (baseEntity: string, method: string, base: any, options:
1576
1581
 
1577
1582
  case 'del':
1578
1583
  result = await new Promise((resolve: any, reject: any) => {
1579
- client.del(base, (err: any) => {
1584
+ client.del(dnObj, (err: any) => {
1580
1585
  if (err) {
1581
1586
  return reject(err)
1582
1587
  }
@@ -1593,7 +1598,7 @@ const doRequest = async (baseEntity: string, method: string, base: any, options:
1593
1598
  if (options.filter && typeof options.filter === 'object') {
1594
1599
  options.filter = options.filter.toString()
1595
1600
  }
1596
- scimgateway.logDebug(baseEntity, `doRequest method=${method} base=${berDecodeDn(base)} ldapOptions=${JSON.stringify(options)} Error Response = ${err.message}`)
1601
+ scimgateway.logDebug(baseEntity, `doRequest method=${method} base=${berDecodeDn(dnObj)} ldapOptions=${JSON.stringify(options)} Error Response = ${err.message}`)
1597
1602
  if (client) {
1598
1603
  try {
1599
1604
  client.destroy()
@@ -1605,7 +1610,7 @@ const doRequest = async (baseEntity: string, method: string, base: any, options:
1605
1610
  if (options.filter && typeof options.filter === 'object') {
1606
1611
  options.filter = options.filter.toString()
1607
1612
  }
1608
- scimgateway.logDebug(baseEntity, `doRequest method=${method} base=${berDecodeDn(base)} ldapOptions=${JSON.stringify(options)} Response=${JSON.stringify(result)}`)
1613
+ scimgateway.logDebug(baseEntity, `doRequest method=${method} base=${berDecodeDn(dnObj)} ldapOptions=${JSON.stringify(options)} Response=${JSON.stringify(result)}`)
1609
1614
  return result
1610
1615
  } // doRequest
1611
1616
 
@@ -104,9 +104,9 @@ for (const baseEntity in config.entity) {
104
104
  // =================================================
105
105
  // getUsers
106
106
  // =================================================
107
- scimgateway.getUsers = async (baseEntity, getObj, attributes) => {
107
+ scimgateway.getUsers = async (baseEntity, getObj, attributes, ctx) => {
108
108
  const action = 'getUsers'
109
- scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes}`)
109
+ scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes} passThrough=${ctx ? 'true' : 'false'}`)
110
110
 
111
111
  if (!config.entity[baseEntity]) throw new Error(`unsupported baseEntity=${baseEntity}`)
112
112
  const users = config.entity[baseEntity].users
@@ -232,9 +232,9 @@ scimgateway.getUsers = async (baseEntity, getObj, attributes) => {
232
232
  // =================================================
233
233
  // createUser
234
234
  // =================================================
235
- scimgateway.createUser = async (baseEntity, userObj) => {
235
+ scimgateway.createUser = async (baseEntity, userObj, ctx) => {
236
236
  const action = 'createUser'
237
- scimgateway.logDebug(baseEntity, `handling ${action} userObj=${JSON.stringify(userObj)}`)
237
+ scimgateway.logDebug(baseEntity, `handling ${action} userObj=${JSON.stringify(userObj)} passThrough=${ctx ? 'true' : 'false'}`)
238
238
 
239
239
  if (!config.entity[baseEntity]) throw new Error(`unsupported baseEntity=${baseEntity}`)
240
240
  const users = config.entity[baseEntity].users
@@ -271,9 +271,9 @@ scimgateway.createUser = async (baseEntity, userObj) => {
271
271
  // =================================================
272
272
  // deleteUser
273
273
  // =================================================
274
- scimgateway.deleteUser = async (baseEntity, id) => {
274
+ scimgateway.deleteUser = async (baseEntity, id, ctx) => {
275
275
  const action = 'deleteUser'
276
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id}`)
276
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} passThrough=${ctx ? 'true' : 'false'}`)
277
277
 
278
278
  if (!config.entity[baseEntity]) throw new Error(`unsupported baseEntity=${baseEntity}`)
279
279
  const users = config.entity[baseEntity].users
@@ -287,9 +287,9 @@ scimgateway.deleteUser = async (baseEntity, id) => {
287
287
  // =================================================
288
288
  // modifyUser
289
289
  // =================================================
290
- scimgateway.modifyUser = async (baseEntity, id, attrObj) => {
290
+ scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
291
291
  const action = 'modifyUser'
292
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)}`)
292
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)} passThrough=${ctx ? 'true' : 'false'}`)
293
293
 
294
294
  if (!config.entity[baseEntity]) throw new Error(`unsupported baseEntity=${baseEntity}`)
295
295
  const users = config.entity[baseEntity].users
@@ -408,9 +408,9 @@ scimgateway.modifyUser = async (baseEntity, id, attrObj) => {
408
408
  // =================================================
409
409
  // getGroups
410
410
  // =================================================
411
- scimgateway.getGroups = async (baseEntity, getObj, attributes) => {
411
+ scimgateway.getGroups = async (baseEntity, getObj, attributes, ctx) => {
412
412
  const action = 'getGroups'
413
- scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes}`)
413
+ scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes} passThrough=${ctx ? 'true' : 'false'}`)
414
414
 
415
415
  if (!config.entity[baseEntity]) throw new Error(`unsupported baseEntity=${baseEntity}`)
416
416
  const groups = config.entity[baseEntity].groups
@@ -502,7 +502,7 @@ scimgateway.getGroups = async (baseEntity, getObj, attributes) => {
502
502
  // =================================================
503
503
  scimgateway.createGroup = async (baseEntity, groupObj, ctx) => {
504
504
  const action = 'createGroup'
505
- scimgateway.logDebug(baseEntity, `handling ${action} groupObj=${JSON.stringify(groupObj)}`)
505
+ scimgateway.logDebug(baseEntity, `handling ${action} groupObj=${JSON.stringify(groupObj)} passThrough=${ctx ? 'true' : 'false'}`)
506
506
 
507
507
  if (!config.entity[baseEntity]) throw new Error(`unsupported baseEntity=${baseEntity}`)
508
508
  const groups = config.entity[baseEntity].groups
@@ -540,9 +540,9 @@ scimgateway.createGroup = async (baseEntity, groupObj, ctx) => {
540
540
  // =================================================
541
541
  // deleteGroup
542
542
  // =================================================
543
- scimgateway.deleteGroup = async (baseEntity, id) => {
543
+ scimgateway.deleteGroup = async (baseEntity, id, ctx) => {
544
544
  const action = 'deleteGroup'
545
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id}`)
545
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} passThrough=${ctx ? 'true' : 'false'}`)
546
546
 
547
547
  if (!config.entity[baseEntity]) throw new Error(`unsupported baseEntity=${baseEntity}`)
548
548
  const groups = config.entity[baseEntity].groups
@@ -558,7 +558,7 @@ scimgateway.deleteGroup = async (baseEntity, id) => {
558
558
  // =================================================
559
559
  scimgateway.modifyGroup = async (baseEntity, id, attrObj, ctx) => {
560
560
  const action = 'modifyGroup'
561
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)}`)
561
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)} passThrough=${ctx ? 'true' : 'false'}`)
562
562
 
563
563
  if (!config.entity[baseEntity]) throw new Error(`unsupported baseEntity=${baseEntity}`)
564
564
  const groups = config.entity[baseEntity].groups
@@ -158,7 +158,7 @@ async function loadHandler(baseEntity: string, ctx: undefined | Record<string, a
158
158
  // =================================================
159
159
  scimgateway.getUsers = async (baseEntity, getObj, attributes, ctx) => {
160
160
  const action = 'getUsers'
161
- scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes}`)
161
+ scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes} passThrough=${ctx ? 'true' : 'false'}`)
162
162
 
163
163
  const clientIdentifier = await loadHandler(baseEntity, ctx) // includes Auth PassThrough logic and loaded only once
164
164
 
@@ -258,7 +258,7 @@ scimgateway.getUsers = async (baseEntity, getObj, attributes, ctx) => {
258
258
  // =================================================
259
259
  scimgateway.createUser = async (baseEntity, userObj, ctx) => {
260
260
  const action = 'createUser'
261
- scimgateway.logDebug(baseEntity, `handling ${action} userObj=${JSON.stringify(userObj)}`)
261
+ scimgateway.logDebug(baseEntity, `handling ${action} userObj=${JSON.stringify(userObj)} passThrough=${ctx ? 'true' : 'false'}`)
262
262
 
263
263
  const clientIdentifier = await loadHandler(baseEntity, ctx) // includes Auth PassThrough logic and loaded only once
264
264
 
@@ -307,7 +307,7 @@ scimgateway.createUser = async (baseEntity, userObj, ctx) => {
307
307
  // =================================================
308
308
  scimgateway.deleteUser = async (baseEntity, id, ctx) => {
309
309
  const action = 'deleteUser'
310
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id}`)
310
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} passThrough=${ctx ? 'true' : 'false'}`)
311
311
 
312
312
  const clientIdentifier = await loadHandler(baseEntity, ctx) // includes Auth PassThrough logic and loaded only once
313
313
 
@@ -336,7 +336,7 @@ scimgateway.deleteUser = async (baseEntity, id, ctx) => {
336
336
  // =================================================
337
337
  scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
338
338
  const action = 'modifyUser'
339
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)}`)
339
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)} passThrough=${ctx ? 'true' : 'false'}`)
340
340
 
341
341
  const clientIdentifier = await loadHandler(baseEntity, ctx) // includes Auth PassThrough logic and loaded only once
342
342
 
@@ -490,7 +490,7 @@ scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
490
490
  // =================================================
491
491
  scimgateway.getGroups = async (baseEntity, getObj, attributes, ctx) => {
492
492
  const action = 'getGroups'
493
- scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes}`)
493
+ scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes} passThrough=${ctx ? 'true' : 'false'}`)
494
494
 
495
495
  const clientIdentifier = await loadHandler(baseEntity, ctx) // includes Auth PassThrough logic and loaded only once
496
496
 
@@ -586,7 +586,7 @@ scimgateway.getGroups = async (baseEntity, getObj, attributes, ctx) => {
586
586
  // =================================================
587
587
  scimgateway.createGroup = async (baseEntity, groupObj, ctx) => {
588
588
  const action = 'createGroup'
589
- scimgateway.logDebug(baseEntity, `handling ${action} groupObj=${JSON.stringify(groupObj)}`)
589
+ scimgateway.logDebug(baseEntity, `handling ${action} groupObj=${JSON.stringify(groupObj)} passThrough=${ctx ? 'true' : 'false'}`)
590
590
 
591
591
  const clientIdentifier = await loadHandler(baseEntity, ctx) // includes Auth PassThrough logic and loaded only once
592
592
 
@@ -638,7 +638,7 @@ scimgateway.createGroup = async (baseEntity, groupObj, ctx) => {
638
638
  // =================================================
639
639
  scimgateway.deleteGroup = async (baseEntity, id, ctx) => {
640
640
  const action = 'deleteGroup'
641
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id}`)
641
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} passThrough=${ctx ? 'true' : 'false'}`)
642
642
 
643
643
  const clientIdentifier = await loadHandler(baseEntity, ctx) // includes Auth PassThrough logic and loaded only once
644
644
 
@@ -667,7 +667,7 @@ scimgateway.deleteGroup = async (baseEntity, id, ctx) => {
667
667
  // =================================================
668
668
  scimgateway.modifyGroup = async (baseEntity, id, attrObj, ctx) => {
669
669
  const action = 'modifyGroup'
670
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)}`)
670
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)} passThrough=${ctx ? 'true' : 'false'}`)
671
671
 
672
672
  const clientIdentifier = await loadHandler(baseEntity, ctx) // includes Auth PassThrough logic and loaded only once
673
673
 
@@ -83,7 +83,7 @@ if (config?.connection?.authentication?.options?.password) {
83
83
  // =================================================
84
84
  scimgateway.getUsers = async (baseEntity, getObj, attributes, ctx) => {
85
85
  const action = 'getUsers'
86
- scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes}`)
86
+ scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes} passThrough=${ctx ? 'true' : 'false'}`)
87
87
 
88
88
  let sqlQuery
89
89
 
@@ -147,7 +147,7 @@ scimgateway.getUsers = async (baseEntity, getObj, attributes, ctx) => {
147
147
  // =================================================
148
148
  scimgateway.createUser = async (baseEntity, userObj, ctx) => {
149
149
  const action = 'createUser'
150
- scimgateway.logDebug(baseEntity, `handling ${action} userObj=${JSON.stringify(userObj)}`)
150
+ scimgateway.logDebug(baseEntity, `handling ${action} userObj=${JSON.stringify(userObj)} passThrough=${ctx ? 'true' : 'false'}`)
151
151
 
152
152
  try {
153
153
  return await new Promise(async (resolve) => {
@@ -183,7 +183,7 @@ scimgateway.createUser = async (baseEntity, userObj, ctx) => {
183
183
  // =================================================
184
184
  scimgateway.deleteUser = async (baseEntity, id, ctx) => {
185
185
  const action = 'deleteUser'
186
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id}`)
186
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} passThrough=${ctx ? 'true' : 'false'}`)
187
187
 
188
188
  try {
189
189
  return await new Promise(async (resolve) => {
@@ -202,7 +202,7 @@ scimgateway.deleteUser = async (baseEntity, id, ctx) => {
202
202
  // =================================================
203
203
  scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
204
204
  const action = 'modifyUser'
205
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)}`)
205
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)} passThrough=${ctx ? 'true' : 'false'}`)
206
206
 
207
207
  try {
208
208
  return await new Promise(async (resolve) => {
@@ -255,7 +255,7 @@ scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
255
255
  // =================================================
256
256
  scimgateway.getGroups = async (baseEntity, getObj, attributes, ctx) => {
257
257
  const action = 'getGroups'
258
- scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes}`)
258
+ scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes} passThrough=${ctx ? 'true' : 'false'}`)
259
259
 
260
260
  let sqlQuery
261
261
 
@@ -324,7 +324,7 @@ scimgateway.getGroups = async (baseEntity, getObj, attributes, ctx) => {
324
324
  // =================================================
325
325
  scimgateway.createGroup = async (baseEntity, groupObj, ctx) => {
326
326
  const action = 'createGroup'
327
- scimgateway.logDebug(baseEntity, `handling ${action} groupObj=${JSON.stringify(groupObj)}`)
327
+ scimgateway.logDebug(baseEntity, `handling ${action} groupObj=${JSON.stringify(groupObj)} passThrough=${ctx ? 'true' : 'false'}`)
328
328
 
329
329
  try {
330
330
  return await new Promise(async (resolve) => {
@@ -355,7 +355,7 @@ scimgateway.createGroup = async (baseEntity, groupObj, ctx) => {
355
355
  // =================================================
356
356
  scimgateway.deleteGroup = async (baseEntity, id, ctx) => {
357
357
  const action = 'deleteGroup'
358
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id}`)
358
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} passThrough=${ctx ? 'true' : 'false'}`)
359
359
 
360
360
  try {
361
361
  return await new Promise(async (resolve) => {
@@ -374,7 +374,7 @@ scimgateway.deleteGroup = async (baseEntity, id, ctx) => {
374
374
  // =================================================
375
375
  scimgateway.modifyGroup = async (baseEntity, id, attrObj, ctx) => {
376
376
  const action = 'modifyGroup'
377
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)}`)
377
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)} passThrough=${ctx ? 'true' : 'false'}`)
378
378
 
379
379
  let sql = ''
380
380
 
@@ -50,9 +50,9 @@ const hdbClient = hdb.createClient({
50
50
  // =================================================
51
51
  // getUsers
52
52
  // =================================================
53
- scimgateway.getUsers = async (baseEntity, getObj, attributes) => {
53
+ scimgateway.getUsers = async (baseEntity, getObj, attributes, ctx) => {
54
54
  const action = 'getUsers'
55
- scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes}`)
55
+ scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes} passThrough=${ctx ? 'true' : 'false'}`)
56
56
 
57
57
  let sqlQuery
58
58
 
@@ -118,9 +118,9 @@ scimgateway.getUsers = async (baseEntity, getObj, attributes) => {
118
118
  // =================================================
119
119
  // createUser
120
120
  // =================================================
121
- scimgateway.createUser = async (baseEntity, userObj) => {
121
+ scimgateway.createUser = async (baseEntity, userObj, ctx) => {
122
122
  const action = 'createUser'
123
- scimgateway.logDebug(baseEntity, `handling ${action} userObj=${JSON.stringify(userObj)}`)
123
+ scimgateway.logDebug(baseEntity, `handling ${action} userObj=${JSON.stringify(userObj)} passThrough=${ctx ? 'true' : 'false'}`)
124
124
 
125
125
  try {
126
126
  return await new Promise((resolve, reject) => {
@@ -159,9 +159,9 @@ scimgateway.createUser = async (baseEntity, userObj) => {
159
159
  // =================================================
160
160
  // deleteUser
161
161
  // =================================================
162
- scimgateway.deleteUser = async (baseEntity, id) => {
162
+ scimgateway.deleteUser = async (baseEntity, id, ctx) => {
163
163
  const action = 'deleteUser'
164
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id}`)
164
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} passThrough=${ctx ? 'true' : 'false'}`)
165
165
 
166
166
  try {
167
167
  return await new Promise((resolve, reject) => {
@@ -189,9 +189,9 @@ scimgateway.deleteUser = async (baseEntity, id) => {
189
189
  // =================================================
190
190
  // modifyUser
191
191
  // =================================================
192
- scimgateway.modifyUser = async (baseEntity, id, attrObj) => {
192
+ scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
193
193
  const action = 'modifyUser'
194
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)}`)
194
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)} passThrough=${ctx ? 'true' : 'false'}`)
195
195
 
196
196
  try {
197
197
  return await new Promise((resolve, reject) => {
@@ -225,9 +225,9 @@ scimgateway.modifyUser = async (baseEntity, id, attrObj) => {
225
225
  // =================================================
226
226
  // getGroups
227
227
  // =================================================
228
- scimgateway.getGroups = async (baseEntity, getObj, attributes) => {
228
+ scimgateway.getGroups = async (baseEntity, getObj, attributes, ctx) => {
229
229
  const action = 'getGroups'
230
- scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes}`)
230
+ scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes} passThrough=${ctx ? 'true' : 'false'}`)
231
231
 
232
232
  // mandatory if-else logic - start
233
233
  if (getObj.operator) {
@@ -252,27 +252,27 @@ scimgateway.getGroups = async (baseEntity, getObj, attributes) => {
252
252
  // =================================================
253
253
  // createGroup
254
254
  // =================================================
255
- scimgateway.createGroup = async (baseEntity, groupObj) => {
255
+ scimgateway.createGroup = async (baseEntity, groupObj, ctx) => {
256
256
  const action = 'createGroup'
257
- scimgateway.logDebug(baseEntity, `handling ${action} groupObj=${JSON.stringify(groupObj)}`)
257
+ scimgateway.logDebug(baseEntity, `handling ${action} groupObj=${JSON.stringify(groupObj)} passThrough=${ctx ? 'true' : 'false'}`)
258
258
  throw new Error(`${action} error: ${action} is not supported`)
259
259
  }
260
260
 
261
261
  // =================================================
262
262
  // deleteGroup
263
263
  // =================================================
264
- scimgateway.deleteGroup = async (baseEntity, id) => {
264
+ scimgateway.deleteGroup = async (baseEntity, id, ctx) => {
265
265
  const action = 'deleteGroup'
266
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id}`)
266
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} passThrough=${ctx ? 'true' : 'false'}`)
267
267
  throw new Error(`${action} error: ${action} is not supported`)
268
268
  }
269
269
 
270
270
  // =================================================
271
271
  // modifyGroup
272
272
  // =================================================
273
- scimgateway.modifyGroup = async (baseEntity, id, attrObj) => {
273
+ scimgateway.modifyGroup = async (baseEntity, id, attrObj, ctx) => {
274
274
  const action = 'modifyGroup'
275
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)}`)
275
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)} passThrough=${ctx ? 'true' : 'false'}`)
276
276
  throw new Error(`${action} error: ${action} is not supported`)
277
277
  }
278
278
 
@@ -56,7 +56,7 @@ const helper = new HelperRest(scimgateway)
56
56
  // =================================================
57
57
  scimgateway.getUsers = async (baseEntity, getObj, attributes, ctx) => {
58
58
  const action = 'getUsers'
59
- scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes}`)
59
+ scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes} passThrough=${ctx ? 'true' : 'false'}`)
60
60
 
61
61
  const method = 'GET'
62
62
  let path
@@ -156,7 +156,7 @@ scimgateway.getUsers = async (baseEntity, getObj, attributes, ctx) => {
156
156
  // =================================================
157
157
  scimgateway.createUser = async (baseEntity, userObj, ctx) => {
158
158
  const action = 'createUser'
159
- scimgateway.logDebug(baseEntity, `handling ${action} userObj=${JSON.stringify(userObj)}`)
159
+ scimgateway.logDebug(baseEntity, `handling ${action} userObj=${JSON.stringify(userObj)} passThrough=${ctx ? 'true' : 'false'}`)
160
160
 
161
161
  if (!userObj.name) userObj.name = {}
162
162
  if (!userObj.emails) userObj.emails = { work: {} }
@@ -203,7 +203,7 @@ scimgateway.createUser = async (baseEntity, userObj, ctx) => {
203
203
  // =================================================
204
204
  scimgateway.deleteUser = async (baseEntity, id, ctx) => {
205
205
  const action = 'deleteUser'
206
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id}`)
206
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} passThrough=${ctx ? 'true' : 'false'}`)
207
207
 
208
208
  const method = 'DELETE'
209
209
  const path = `/Users/${id}`
@@ -225,7 +225,7 @@ scimgateway.deleteUser = async (baseEntity, id, ctx) => {
225
225
  // =================================================
226
226
  scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
227
227
  const action = 'modifyUser'
228
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)}`)
228
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)} passThrough=${ctx ? 'true' : 'false'}`)
229
229
 
230
230
  if (!attrObj.name) attrObj.name = {}
231
231
  if (!attrObj.emails) attrObj.emails = {}
@@ -308,7 +308,7 @@ scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
308
308
  // =================================================
309
309
  scimgateway.getGroups = async (baseEntity, getObj, attributes, ctx) => {
310
310
  const action = 'getGroups'
311
- scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes}`)
311
+ scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes} passThrough=${ctx ? 'true' : 'false'}`)
312
312
 
313
313
  const method = 'GET'
314
314
  let path
@@ -388,7 +388,7 @@ scimgateway.getGroups = async (baseEntity, getObj, attributes, ctx) => {
388
388
  // =================================================
389
389
  scimgateway.createGroup = async (baseEntity, groupObj, ctx) => {
390
390
  const action = 'createGroup'
391
- scimgateway.logDebug(baseEntity, `handling ${action} groupObj=${JSON.stringify(groupObj)}`)
391
+ scimgateway.logDebug(baseEntity, `handling ${action} groupObj=${JSON.stringify(groupObj)} passThrough=${ctx ? 'true' : 'false'}`)
392
392
 
393
393
  const method = 'POST'
394
394
  const path = '/Groups'
@@ -410,7 +410,7 @@ scimgateway.createGroup = async (baseEntity, groupObj, ctx) => {
410
410
  // =================================================
411
411
  scimgateway.deleteGroup = async (baseEntity, id, ctx) => {
412
412
  const action = 'deleteGroup'
413
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id}`)
413
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} passThrough=${ctx ? 'true' : 'false'}`)
414
414
 
415
415
  const method = 'DELETE'
416
416
  const path = `/Groups/${id}`
@@ -432,7 +432,7 @@ scimgateway.deleteGroup = async (baseEntity, id, ctx) => {
432
432
  // =================================================
433
433
  scimgateway.modifyGroup = async (baseEntity, id, attrObj, ctx) => {
434
434
  const action = 'modifyGroup'
435
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)}`)
435
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)} passThrough=${ctx ? 'true' : 'false'}`)
436
436
 
437
437
  if (!attrObj.members) {
438
438
  throw new Error(`${action} error: only supports modification of members`)
@@ -58,7 +58,7 @@ if (!scimgateway.authPassThroughAllowed) {
58
58
  // =================================================
59
59
  scimgateway.getUsers = async (baseEntity, getObj, attributes, ctx) => {
60
60
  const action = 'getUsers'
61
- scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes}`)
61
+ scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes} passThrough=${ctx ? 'true' : 'false'}`)
62
62
 
63
63
  let soapRequest
64
64
  let soapAction
@@ -169,7 +169,7 @@ scimgateway.getUsers = async (baseEntity, getObj, attributes, ctx) => {
169
169
  // =================================================
170
170
  scimgateway.createUser = async (baseEntity, userObj, ctx) => {
171
171
  const action = 'createUser'
172
- scimgateway.logDebug(baseEntity, `handling ${action} userObj=${JSON.stringify(userObj)}`)
172
+ scimgateway.logDebug(baseEntity, `handling ${action} userObj=${JSON.stringify(userObj)} passThrough=${ctx ? 'true' : 'false'}`)
173
173
  try {
174
174
  if (!userObj.name) userObj.name = {}
175
175
  if (!userObj.emails) userObj.emails = { work: {} }
@@ -213,7 +213,7 @@ scimgateway.createUser = async (baseEntity, userObj, ctx) => {
213
213
  // =================================================
214
214
  scimgateway.deleteUser = async (baseEntity, id, ctx) => {
215
215
  const action = 'deleteUser'
216
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id}`)
216
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} passThrough=${ctx ? 'true' : 'false'}`)
217
217
  try {
218
218
  const serviceClient = await getServiceClient(baseEntity, action, ctx)
219
219
 
@@ -240,7 +240,7 @@ scimgateway.deleteUser = async (baseEntity, id, ctx) => {
240
240
  // =================================================
241
241
  scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
242
242
  const action = 'modifyUser'
243
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)}`)
243
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)} passThrough=${ctx ? 'true' : 'false'}`)
244
244
  try {
245
245
  // forwardinc modify user will blank all attributes not included in soap request...
246
246
  // We therefore need to to retrieve all user attributes from forwardinc and merge with updated attributes.
@@ -309,7 +309,7 @@ scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
309
309
  // =================================================
310
310
  scimgateway.getGroups = async (baseEntity, getObj, attributes, ctx) => {
311
311
  const action = 'getGroups'
312
- scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes}`)
312
+ scimgateway.logDebug(baseEntity, `handling ${action} getObj=${getObj ? JSON.stringify(getObj) : ''} attributes=${attributes} passThrough=${ctx ? 'true' : 'false'}`)
313
313
 
314
314
  let soapRequest
315
315
  let soapAction
@@ -401,9 +401,9 @@ scimgateway.getGroups = async (baseEntity, getObj, attributes, ctx) => {
401
401
  // =================================================
402
402
  // createGroup
403
403
  // =================================================
404
- scimgateway.createGroup = async (baseEntity, groupObj) => {
404
+ scimgateway.createGroup = async (baseEntity, groupObj, ctx) => {
405
405
  const action = 'createGroup'
406
- scimgateway.logDebug(baseEntity, `handling ${action} groupObj=${JSON.stringify(groupObj)}`)
406
+ scimgateway.logDebug(baseEntity, `handling ${action} groupObj=${JSON.stringify(groupObj)} passThrough=${ctx ? 'true' : 'false'}`)
407
407
  // groupObj.displayName contains the group to be created
408
408
  // if supporting create group, we need some endpoint logic here
409
409
  throw new Error(`${action} error: ${action} is not supported`)
@@ -412,9 +412,9 @@ scimgateway.createGroup = async (baseEntity, groupObj) => {
412
412
  // =================================================
413
413
  // deleteGroup
414
414
  // =================================================
415
- scimgateway.deleteGroup = async (baseEntity, id) => {
415
+ scimgateway.deleteGroup = async (baseEntity, id, ctx) => {
416
416
  const action = 'deleteGroup'
417
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id}`)
417
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} passThrough=${ctx ? 'true' : 'false'}`)
418
418
  // if supporting delete group, we need some endpoint logic here
419
419
  throw new Error(`${action} error: ${action} is not supported`)
420
420
  }
@@ -424,7 +424,7 @@ scimgateway.deleteGroup = async (baseEntity, id) => {
424
424
  // =================================================
425
425
  scimgateway.modifyGroup = async (baseEntity, id, attrObj, ctx) => {
426
426
  const action = 'modifyGroup'
427
- scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)}`)
427
+ scimgateway.logDebug(baseEntity, `handling ${action} id=${id} attrObj=${JSON.stringify(attrObj)} passThrough=${ctx ? 'true' : 'false'}`)
428
428
 
429
429
  if (!attrObj.members) {
430
430
  throw new Error(`${action} error: only supports modification of members`)
@@ -314,7 +314,7 @@ export class ScimGateway {
314
314
  * PATCH http://localhost:8890/pub/api/100
315
315
  * body = {"title":"BMW X3"}
316
316
  */
317
- publicApi!: (baseEntity: string, method: string, id: string | undefined, query: Record<string, any> | undefined, apiObj: any) => any
317
+ publicApi!: (baseEntity: string, method: string, id: string | undefined, query: Record<string, any> | undefined, apiObj: any, ctx?: undefined | Record<string, any>) => any
318
318
 
319
319
  constructor() {
320
320
  const funcHandler: any = {}
@@ -1279,7 +1279,12 @@ export class ScimGateway {
1279
1279
  if (arrFilter.length === 3 || (arrFilter.length > 2 && arrFilter[2].startsWith('"') && arrFilter[arrFilter.length - 1].endsWith('"'))) {
1280
1280
  getObj.attribute = arrFilter[0] // userName
1281
1281
  getObj.operator = arrFilter[1].toLowerCase() // eq
1282
- getObj.value = decodeURIComponent(arrFilter.slice(2).join(' ').replace(/"/g, '')) // bjensen
1282
+ const value = arrFilter.slice(2).join(' ').replace(/"/g, '')
1283
+ try {
1284
+ getObj.value = decodeURIComponent(value) // bjensen
1285
+ } catch (err) { // e.g., character '%' in string - 'name%test'
1286
+ getObj.value = value
1287
+ }
1283
1288
  }
1284
1289
  }
1285
1290
 
@@ -2443,7 +2448,7 @@ export class ScimGateway {
2443
2448
  return
2444
2449
  }
2445
2450
  const handle = ctx.routeObj.handle
2446
- const baseEntity = ctx.routeObj.baseEntity
2451
+ const baseEntity = ctx.routeObj.baseEntity = 'undefined'
2447
2452
  const method = ctx.request.method
2448
2453
  const id = ctx.routeObj.id || undefined
2449
2454
  const query = Object.keys(ctx.query).length > 0 ? ctx.query : undefined
@@ -2453,7 +2458,7 @@ export class ScimGateway {
2453
2458
 
2454
2459
  try {
2455
2460
  logger.debug(`${gwName}[${pluginName}][${ctx?.routeObj?.baseEntity}] calling publicApi and awaiting result`, { baseEntity: ctx?.routeObj?.baseEntity })
2456
- let result = await this.publicApi(baseEntity, method, id, query, body)
2461
+ let result = await this.publicApi(baseEntity, method, id, query, body, ctx.passThrough)
2457
2462
  if (result) {
2458
2463
  if (typeof result === 'string') {
2459
2464
  const r = result.trim()
@@ -2475,8 +2480,10 @@ export class ScimGateway {
2475
2480
  } catch (err: any) {
2476
2481
  const [e, statusCode] = utilsScim.jsonErr('1.1', pluginName, 500, err)
2477
2482
  ctx.response.status = statusCode
2478
- ctx.response.body = JSON.stringify(e)
2479
- ctx.response.headers.set('content-type', 'application/json; charset=utf-8')
2483
+ if (err.message) { // may use err.name (xxx#<code>) and no message to avoid returning standard error formatted body e.g., const err=new Error(); err.name=err.name +='#404'; throw err
2484
+ ctx.response.body = JSON.stringify(e)
2485
+ ctx.response.headers.set('content-type', 'application/json; charset=utf-8')
2486
+ }
2480
2487
  }
2481
2488
  }
2482
2489
  funcHandler.publicApiHandler = publicApiHandler
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scimgateway",
3
- "version": "6.0.0",
3
+ "version": "6.0.1",
4
4
  "type": "module",
5
5
  "description": "Using SCIM protocol as a gateway for user provisioning to other endpoints",
6
6
  "author": "Jarle Elshaug <jarle.elshaug@gmail.com> (https://elshaug.xyz)",