scimgateway 4.2.2 → 4.2.3

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
@@ -1165,6 +1165,12 @@ MIT © [Jarle Elshaug](https://www.elshaug.xyz)
1165
1165
 
1166
1166
  ## Change log
1167
1167
 
1168
+ ### v4.2.3
1169
+
1170
+ [Fixed]
1171
+
1172
+ - plugin-loki and plugin-mongodb, for multi-value attributes like emails,phoneNumbers,... that includes primary attribute, only one is allowed having primary value set to true in the multi-value set.
1173
+
1168
1174
  ### v4.2.2
1169
1175
 
1170
1176
  [Fixed]
@@ -267,27 +267,27 @@ scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
267
267
  const userObj = res[0]
268
268
 
269
269
  for (const key in attrObj) {
270
- if (Array.isArray(attrObj[key])) { // standard, not using type (e.g roles/groups)
271
- attrObj[key].forEach(el => {
272
- if (el.operation === 'delete') {
273
- userObj[key] = userObj[key].filter(e => {
274
- if (Object.prototype.hasOwnProperty.call(el, 'value') && el.value !== e.value) return true
275
- if (Object.prototype.hasOwnProperty.call(el, 'type') && el.type !== e.type) return true
276
- if (Object.prototype.hasOwnProperty.call(el, 'display') && el.display !== e.display) return true
277
- if (Object.prototype.hasOwnProperty.call(el, 'primary') && el.primary !== e.primary) return true
278
- return false
279
- })
280
- } else { // add
281
- if (!userObj[key]) userObj[key] = []
282
- if (Object.prototype.hasOwnProperty.call(el, 'primary')) {
283
- if (el.primary === true || (typeof el.primary === 'string' && el.primary.toLowerCase() === 'true')) {
284
- // delete any existing primary before adding
285
- const index = userObj[key].findIndex(e => e.primary === el.primary)
286
- if (index >= 0) userObj[key].splice(index, 1)
270
+ if (Array.isArray(attrObj[key])) { // standard, not using type (e.g roles/groups) or skipTypeConvert=true
271
+ const delArr = attrObj[key].filter(el => el.operation === 'delete')
272
+ const addArr = attrObj[key].filter(el => (!el.operation || el.operation !== 'delete'))
273
+ if (!userObj[key]) userObj[key] = []
274
+ // delete
275
+ userObj[key] = userObj[key].filter(el => {
276
+ if (delArr.findIndex(e => e.value === el.value) >= 0) return false
277
+ return true
278
+ })
279
+ // add
280
+ addArr.forEach(el => {
281
+ if (Object.prototype.hasOwnProperty.call(el, 'primary')) {
282
+ if (el.primary === true || (typeof el.primary === 'string' && el.primary.toLowerCase() === 'true')) {
283
+ const index = userObj[key].findIndex(e => e.primary === el.primary)
284
+ if (index >= 0) {
285
+ if (key === 'roles') userObj[key].splice(index, 1) // roles, delete existing role having primary attribute true (new role with primary will be added)
286
+ else userObj[key][index].primary = undefined // remove primary attribute, only one primary
287
287
  }
288
288
  }
289
- userObj[key].push(el)
290
289
  }
290
+ userObj[key].push(el)
291
291
  })
292
292
  } else if (scimgateway.isMultiValueTypes(key)) { // "type converted object" logic and original blank type having type "undefined"
293
293
  if (!attrObj[key]) delete userObj[key] // blank or null
@@ -300,6 +300,15 @@ scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
300
300
  if (userObj[key].length < 1) delete userObj[key]
301
301
  } else { // modify/create multivalue
302
302
  if (!userObj[key]) userObj[key] = []
303
+ if (attrObj[key][el].primary) { // remove any existing primary attribute, should only have one primary set
304
+ const primVal = attrObj[key][el].primary
305
+ if (primVal === true || (typeof primVal === 'string' && primVal.toLowerCase() === 'true')) {
306
+ const index = userObj[key].findIndex(e => e.primary === primVal)
307
+ if (index >= 0) {
308
+ userObj[key][index].primary = undefined
309
+ }
310
+ }
311
+ }
303
312
  const found = userObj[key].find((e, i) => {
304
313
  if (e.type === el || (!e.type && el === 'undefined')) {
305
314
  for (const k in attrObj[key][el]) {
@@ -353,27 +353,27 @@ scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
353
353
  let userObj = decodeDotDate(res[0])
354
354
 
355
355
  for (const key in attrObj) {
356
- if (Array.isArray(attrObj[key])) { // standard, not using type (e.g roles/groups)
357
- attrObj[key].forEach(el => {
358
- if (el.operation === 'delete') {
359
- userObj[key] = userObj[key].filter(e => {
360
- if (Object.prototype.hasOwnProperty.call(el, 'value') && el.value !== e.value) return true
361
- if (Object.prototype.hasOwnProperty.call(el, 'type') && el.type !== e.type) return true
362
- if (Object.prototype.hasOwnProperty.call(el, 'display') && el.display !== e.display) return true
363
- if (Object.prototype.hasOwnProperty.call(el, 'primary') && el.primary !== e.primary) return true
364
- return false
365
- })
366
- } else { // add
367
- if (!userObj[key]) userObj[key] = []
368
- if (Object.prototype.hasOwnProperty.call(el, 'primary')) {
369
- if (el.primary === true || (typeof el.primary === 'string' && el.primary.toLowerCase() === 'true')) {
370
- // delete any existing primary before adding
371
- const index = userObj[key].findIndex(e => e.primary === el.primary)
372
- if (index >= 0) userObj[key].splice(index, 1)
356
+ if (Array.isArray(attrObj[key])) { // standard, not using type (e.g roles/groups) or skipTypeConvert=true
357
+ const delArr = attrObj[key].filter(el => el.operation === 'delete')
358
+ const addArr = attrObj[key].filter(el => (!el.operation || el.operation !== 'delete'))
359
+ if (!userObj[key]) userObj[key] = []
360
+ // delete
361
+ userObj[key] = userObj[key].filter(el => {
362
+ if (delArr.findIndex(e => e.value === el.value) >= 0) return false
363
+ return true
364
+ })
365
+ // add
366
+ addArr.forEach(el => {
367
+ if (Object.prototype.hasOwnProperty.call(el, 'primary')) {
368
+ if (el.primary === true || (typeof el.primary === 'string' && el.primary.toLowerCase() === 'true')) {
369
+ const index = userObj[key].findIndex(e => e.primary === el.primary)
370
+ if (index >= 0) {
371
+ if (key === 'roles') userObj[key].splice(index, 1) // roles, delete existing role having primary attribute true (new role with primary will be added)
372
+ else userObj[key][index].primary = undefined // remove primary attribute, only one primary
373
373
  }
374
374
  }
375
- userObj[key].push(el)
376
375
  }
376
+ userObj[key].push(el)
377
377
  })
378
378
  } else if (scimgateway.isMultiValueTypes(key)) { // "type converted object" logic and original blank type having type "undefined"
379
379
  if (!attrObj[key]) delete userObj[key] // blank or null
@@ -386,6 +386,15 @@ scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
386
386
  if (userObj[key].length < 1) delete userObj[key]
387
387
  } else { // modify/create multivalue
388
388
  if (!userObj[key]) userObj[key] = []
389
+ if (attrObj[key][el].primary) { // remove any existing primary attribute, should only have one primary set
390
+ const primVal = attrObj[key][el].primary
391
+ if (primVal === true || (typeof primVal === 'string' && primVal.toLowerCase() === 'true')) {
392
+ const index = userObj[key].findIndex(e => e.primary === primVal)
393
+ if (index >= 0) {
394
+ userObj[key][index].primary = undefined
395
+ }
396
+ }
397
+ }
389
398
  const found = userObj[key].find((e, i) => {
390
399
  if (e.type === el || (!e.type && el === 'undefined')) {
391
400
  for (const k in attrObj[key][el]) {
@@ -2604,7 +2604,7 @@ const addSchemas = (data, type, isScimv2, location) => {
2604
2604
  return data
2605
2605
  }
2606
2606
 
2607
- // addPrimaryAttrs cheks for primary attributes and add them as standalone attributes
2607
+ // addPrimaryAttrs cheks for primary attributes (only for roles) and add them as standalone attributes
2608
2608
  // some IdP's may check for these e.g. Azure
2609
2609
  // e.g. {roles: [{value: "val1", primary: "True"}]}
2610
2610
  // gives:
@@ -2613,33 +2613,19 @@ const addSchemas = (data, type, isScimv2, location) => {
2613
2613
  // roles[primary eq "True"].primary: "True"}]
2614
2614
  // }
2615
2615
  const addPrimaryAttrs = (obj) => {
2616
+ const key = 'roles'
2616
2617
  if (!obj || typeof obj !== 'object') return obj
2617
- let arrObj
2618
- if (!Array.isArray(obj)) arrObj = [obj]
2619
- else {
2620
- if (obj.length < 1) return obj
2621
- arrObj = obj
2622
- }
2623
- let arrRet = []
2624
- arrRet = arrObj.map(obj => {
2625
- const o = utils.copyObj(obj)
2626
- for (const key in o) {
2627
- if (Array.isArray(o[key]) && key !== 'groups' && key !== 'members') {
2628
- // check for primary attribute
2629
- const index = o[key].findIndex(el => (el.primary === true || (typeof el.primary === 'string' && el.primary.toLowerCase() === 'true')))
2630
- if (index >= 0) {
2631
- const prim = o[key][index]
2632
- for (const k in prim) {
2633
- const primKey = `${key}[primary eq ${typeof prim.primary === 'string' ? `"${prim.primary}"` : prim.primary}].${k}` // roles[primary eq true].value / roles[primary eq "True"].value``
2634
- o[primKey] = prim[k] // { roles[primary eq true].value : "some-value" }
2635
- }
2636
- }
2637
- }
2618
+ if (!obj[key] || !Array.isArray(obj[key])) return obj
2619
+ const o = utils.copyObj(obj)
2620
+ const index = o[key].findIndex(el => (el.primary === true || (typeof el.primary === 'string' && el.primary.toLowerCase() === 'true')))
2621
+ if (index >= 0) {
2622
+ const prim = o[key][index]
2623
+ for (const k in prim) {
2624
+ const primKey = `${key}[primary eq ${typeof prim.primary === 'string' ? `"${prim.primary}"` : prim.primary}].${k}` // roles[primary eq true].value / roles[primary eq "True"].value``
2625
+ o[primKey] = prim[k] // { roles[primary eq true].value : "some-value" }
2638
2626
  }
2639
- return o
2640
- })
2641
- if (!Array.isArray(obj)) return arrRet[0]
2642
- return arrRet
2627
+ }
2628
+ return o
2643
2629
  }
2644
2630
 
2645
2631
  //
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scimgateway",
3
- "version": "4.2.2",
3
+ "version": "4.2.3",
4
4
  "description": "Using SCIM protocol as a gateway for user provisioning to other endpoints",
5
5
  "author": "Jarle Elshaug <jarle.elshaug@gmail.com> (https://elshaug.xyz)",
6
6
  "homepage": "https://elshaug.xyz",