scimgateway 4.5.11 → 4.5.12
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 +6 -0
- package/config/plugin-ldap.json +3 -2
- package/lib/plugin-ldap.js +110 -1
- package/lib/scimgateway.js +36 -36
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1163,6 +1163,12 @@ MIT © [Jarle Elshaug](https://www.elshaug.xyz)
|
|
|
1163
1163
|
|
|
1164
1164
|
## Change log
|
|
1165
1165
|
|
|
1166
|
+
### v4.5.12
|
|
1167
|
+
|
|
1168
|
+
[Improved]
|
|
1169
|
+
|
|
1170
|
+
- plugin-ldap, new configuration { allowModifyDN: true } allows DN being changed based on modified mapping or namingAttribute
|
|
1171
|
+
|
|
1166
1172
|
### v4.5.11
|
|
1167
1173
|
|
|
1168
1174
|
[Improved]
|
package/config/plugin-ldap.json
CHANGED
|
@@ -144,16 +144,17 @@
|
|
|
144
144
|
"groupBase": "OU=Groups,DC=test,DC=com",
|
|
145
145
|
"userFilter": null,
|
|
146
146
|
"groupFilter": null,
|
|
147
|
+
"allowModifyDN": false,
|
|
147
148
|
"namingAttribute": {
|
|
148
149
|
"user": [
|
|
149
150
|
{
|
|
150
|
-
"attribute": "
|
|
151
|
+
"attribute": "cn",
|
|
151
152
|
"mapTo": "userName"
|
|
152
153
|
}
|
|
153
154
|
],
|
|
154
155
|
"group": [
|
|
155
156
|
{
|
|
156
|
-
"attribute": "
|
|
157
|
+
"attribute": "cn",
|
|
157
158
|
"mapTo": "displayName"
|
|
158
159
|
}
|
|
159
160
|
]
|
package/lib/plugin-ldap.js
CHANGED
|
@@ -35,6 +35,8 @@
|
|
|
35
35
|
// be used for national characters and special characters in DN.
|
|
36
36
|
// For Active Directory, default isOpenLdap=false should be used
|
|
37
37
|
//
|
|
38
|
+
// Configuration allowModifyDN=true allows DN being changed based on modified mapping or namingAttribute
|
|
39
|
+
//
|
|
38
40
|
// Attributes according to map definition in the configuration file plugin-ldap.json:
|
|
39
41
|
//
|
|
40
42
|
// GlobalUser Template Scim Endpoint
|
|
@@ -466,7 +468,41 @@ scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
|
|
|
466
468
|
}
|
|
467
469
|
|
|
468
470
|
try {
|
|
471
|
+
const newDN = checkIfNewDN(baseEntity, base, 'user', attrObj, endpointObj)
|
|
469
472
|
await doRequest(baseEntity, method, base, ldapOptions, ctx)
|
|
473
|
+
if (newDN && config.entity[baseEntity].ldap.allowModifyDN) {
|
|
474
|
+
// modify DN
|
|
475
|
+
await doRequest(baseEntity, 'modifyDN', base, { modification: { newDN } }, ctx)
|
|
476
|
+
// clean up zoombie group members and use the new user DN incase not handled by ldap server
|
|
477
|
+
const [memberAttr] = scimgateway.endpointMapper('outbound', 'members.value', config.map.group)
|
|
478
|
+
if (memberAttr) {
|
|
479
|
+
const grp = { add: {}, remove: {} }
|
|
480
|
+
grp.add[memberAttr] = []
|
|
481
|
+
grp.remove[memberAttr] = []
|
|
482
|
+
let r
|
|
483
|
+
try {
|
|
484
|
+
const ob = { attribute: 'members.value', operator: 'eq', value: base } // base is old DN
|
|
485
|
+
const attributes = ['id', 'displayName']
|
|
486
|
+
r = await scimgateway.getGroups(baseEntity, ob, attributes, ctx)
|
|
487
|
+
} catch (err) { } // ignore errors incase method not implemented
|
|
488
|
+
if (r && r.Resources && Array.isArray(r.Resources) && r.Resources.length > 0) {
|
|
489
|
+
for (let i = 0; i < r.Resources.length; i++) {
|
|
490
|
+
if (!r.Resources[i].id) continue
|
|
491
|
+
const grpId = decodeURIComponent(r.Resources[i].id)
|
|
492
|
+
grp.remove[memberAttr] = [base]
|
|
493
|
+
grp.add[memberAttr] = [newDN]
|
|
494
|
+
await Promise.all([
|
|
495
|
+
doRequest(baseEntity, method, grpId, { operation: 'add', modification: grp.add }, ctx),
|
|
496
|
+
doRequest(baseEntity, method, grpId, { operation: 'delete', modification: grp.remove }, ctx)
|
|
497
|
+
])
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
// return full user object to avoid scimgateway doing same getUser() using original id/dn that now will fail
|
|
501
|
+
const getObj = { attribute: 'id', operator: 'eq', value: newDN }
|
|
502
|
+
const res = await scimgateway.getUsers(baseEntity, getObj, [], ctx)
|
|
503
|
+
return res
|
|
504
|
+
}
|
|
505
|
+
}
|
|
470
506
|
return null
|
|
471
507
|
} catch (err) {
|
|
472
508
|
throw new Error(`${action} error: ${err.message}`)
|
|
@@ -740,6 +776,8 @@ scimgateway.modifyGroup = async (baseEntity, id, attrObj, ctx) => {
|
|
|
740
776
|
try {
|
|
741
777
|
delete attrObj.members
|
|
742
778
|
const [endpointObj] = scimgateway.endpointMapper('outbound', attrObj, config.map.group)
|
|
779
|
+
const newDN = checkIfNewDN(baseEntity, base, 'group', attrObj, endpointObj)
|
|
780
|
+
|
|
743
781
|
if (Object.keys(endpointObj).length > 0) {
|
|
744
782
|
const ldapOptions = {
|
|
745
783
|
operation: 'replace',
|
|
@@ -761,6 +799,12 @@ scimgateway.modifyGroup = async (baseEntity, id, attrObj, ctx) => {
|
|
|
761
799
|
}
|
|
762
800
|
await doRequest(baseEntity, method, base, ldapOptions, ctx)
|
|
763
801
|
}
|
|
802
|
+
if (newDN && config.entity[baseEntity].ldap.allowModifyDN) {
|
|
803
|
+
await doRequest(baseEntity, 'modifyDN', base, { modification: { newDN } }, ctx)
|
|
804
|
+
const getObj = { attribute: 'id', operator: 'eq', value: newDN }
|
|
805
|
+
const res = await scimgateway.getGroups(baseEntity, getObj, [], ctx)
|
|
806
|
+
return res // return full group object to avoid scimgateway doing same getUser() using original id/dn that now will fail
|
|
807
|
+
}
|
|
764
808
|
return null
|
|
765
809
|
} catch (err) {
|
|
766
810
|
throw new Error(`${action} error: ${err.message}`)
|
|
@@ -1044,7 +1088,7 @@ const getMemberOfGroups = async (baseEntity, id, ctx) => {
|
|
|
1044
1088
|
// using Active Directory (none OpenLDAP), DN should not be escaped, but DN retrieved from AD is character escaped
|
|
1045
1089
|
//
|
|
1046
1090
|
const ldapEscDn = (isOpenLdap, str) => {
|
|
1047
|
-
if (
|
|
1091
|
+
if (typeof str !== 'string' || str.length < 1) return str
|
|
1048
1092
|
|
|
1049
1093
|
if (!isOpenLdap && str.indexOf('\\') > 0) {
|
|
1050
1094
|
const conv = str.replace(/\\([0-9A-Fa-f]{2})/g, (_, hex) => {
|
|
@@ -1200,6 +1244,10 @@ const berDecodeDn = (dn) => {
|
|
|
1200
1244
|
}
|
|
1201
1245
|
}
|
|
1202
1246
|
if (decoded.length > 0) {
|
|
1247
|
+
// convert any extended ascii to utf8
|
|
1248
|
+
const isoBytes = Uint8Array.from(decoded, c => c.charCodeAt(0))
|
|
1249
|
+
decoded = new TextDecoder('utf-8').decode(isoBytes)
|
|
1250
|
+
decoded = decoded.replace(/,/g, '\\,')
|
|
1203
1251
|
a.splice(0, 1) // remove element 0 from array
|
|
1204
1252
|
return `${arr[0]}${decoded},${a.join(',')}` // OU=users,OU=abc
|
|
1205
1253
|
}
|
|
@@ -1224,6 +1272,51 @@ const getNamingAttribute = (baseEntity, type) => {
|
|
|
1224
1272
|
return [arr[0].attribute, arr[0].mapTo]
|
|
1225
1273
|
}
|
|
1226
1274
|
|
|
1275
|
+
const checkIfNewDN = (baseEntity, base, type, obj, endpointObj) => {
|
|
1276
|
+
if (typeof obj !== 'object' || Object.keys(obj).length < 1) return ''
|
|
1277
|
+
if (typeof endpointObj !== 'object' || Object.keys(endpointObj).length < 1) return ''
|
|
1278
|
+
|
|
1279
|
+
const namingAttr = base.split('=')[0] // cn
|
|
1280
|
+
let scimAttr = ''
|
|
1281
|
+
if (endpointObj[namingAttr]) { // naming attribute can't be modified, have to use modifyDN()
|
|
1282
|
+
delete endpointObj[namingAttr] // modifying original ldapOptions
|
|
1283
|
+
if (config.map[type] && config.map[type][namingAttr]) {
|
|
1284
|
+
scimAttr = config.map[type][namingAttr].mapTo
|
|
1285
|
+
}
|
|
1286
|
+
if (!config.entity[baseEntity].ldap.allowModifyDN) {
|
|
1287
|
+
throw new Error(`changing ldap Naming Attribute ${namingAttr}/${scimAttr} requires configuration ldap.allowModifyDN=true`)
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
if (!scimAttr) { // check if namingAttr is defined as namingAttribute configuration having linked scimAttr
|
|
1291
|
+
const [nAttr, sAttr] = getNamingAttribute(baseEntity, type) // ['cn', 'userName']
|
|
1292
|
+
if (namingAttr === nAttr) scimAttr = sAttr
|
|
1293
|
+
}
|
|
1294
|
+
if (!scimAttr) return ''
|
|
1295
|
+
// find and return the new DN
|
|
1296
|
+
let newNamingValue
|
|
1297
|
+
const arr = scimAttr.split('.')
|
|
1298
|
+
if (arr.length < 2) {
|
|
1299
|
+
if (obj[scimAttr]) newNamingValue = obj[scimAttr]
|
|
1300
|
+
} else {
|
|
1301
|
+
if (obj[arr[0]] && obj[arr[0]][arr[1]]) newNamingValue = obj[arr[0]][arr[1]]
|
|
1302
|
+
}
|
|
1303
|
+
if (!newNamingValue) return ''
|
|
1304
|
+
const re = '^([a-zA-Z]+=)(.*?)(?=,[a-zA-Z]+=|$)(.*)$'
|
|
1305
|
+
const rePattern = new RegExp(re, 'i')
|
|
1306
|
+
const a = base.match(rePattern)
|
|
1307
|
+
/*
|
|
1308
|
+
a[1] 'CN='
|
|
1309
|
+
a[2] '<value>'
|
|
1310
|
+
a[3] '<rest> e.g.,: ,OU=mycompany,OU=com'
|
|
1311
|
+
*/
|
|
1312
|
+
if (a.length !== 4) return ''
|
|
1313
|
+
if (a[1].toLowerCase() !== namingAttr.toLowerCase() + '=') return ''
|
|
1314
|
+
if (a[2] === newNamingValue) return ''
|
|
1315
|
+
let newDN = a[1] + newNamingValue + a[3]
|
|
1316
|
+
newDN = ldapEscDn(config.entity[baseEntity].ldap.isOpenLdap, newDN)
|
|
1317
|
+
return newDN
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1227
1320
|
//
|
|
1228
1321
|
// getCtxAuth returns username/secret from ctx header when using Auth PassThrough
|
|
1229
1322
|
//
|
|
@@ -1418,6 +1511,22 @@ const doRequest = async (baseEntity, method, base, options, ctx) => {
|
|
|
1418
1511
|
})
|
|
1419
1512
|
break
|
|
1420
1513
|
|
|
1514
|
+
case 'modifyDN':
|
|
1515
|
+
result = await new Promise((resolve, reject) => {
|
|
1516
|
+
let dn = base
|
|
1517
|
+
if (Object.prototype.toString.call(dn) === '[object LdapDn]') dn = base.toString() // needed for client.modifyDN...
|
|
1518
|
+
let newDN = options?.modification?.newDN
|
|
1519
|
+
if (!newDN) return reject(new Error('modifyDN() missing newDN'))
|
|
1520
|
+
if (Object.prototype.toString.call(newDN) === '[object LdapDn]') newDN = newDN.toString()
|
|
1521
|
+
client.modifyDN(dn, newDN, (err) => {
|
|
1522
|
+
if (err) {
|
|
1523
|
+
return reject(err)
|
|
1524
|
+
}
|
|
1525
|
+
resolve()
|
|
1526
|
+
})
|
|
1527
|
+
})
|
|
1528
|
+
break
|
|
1529
|
+
|
|
1421
1530
|
case 'add':
|
|
1422
1531
|
result = await new Promise((resolve, reject) => {
|
|
1423
1532
|
client.add(base, options, (err) => {
|
package/lib/scimgateway.js
CHANGED
|
@@ -274,7 +274,7 @@ const ScimGateway = function () {
|
|
|
274
274
|
if (!fs.existsSync(configDir + '/wsdls')) fs.mkdirSync(configDir + '/wsdls')
|
|
275
275
|
if (!fs.existsSync(configDir + '/certs')) fs.mkdirSync(configDir + '/certs')
|
|
276
276
|
if (!fs.existsSync(configDir + '/schemas')) fs.mkdirSync(configDir + '/schemas')
|
|
277
|
-
} catch (err) {}
|
|
277
|
+
} catch (err) { }
|
|
278
278
|
|
|
279
279
|
let isScimv2 = false
|
|
280
280
|
if (config.scim.version === '2.0' || config.scim.version === 2) {
|
|
@@ -1488,6 +1488,7 @@ const ScimGateway = function () {
|
|
|
1488
1488
|
}
|
|
1489
1489
|
}
|
|
1490
1490
|
try {
|
|
1491
|
+
let res
|
|
1491
1492
|
if (config.stream.publisher.enabled) {
|
|
1492
1493
|
let streamObj = {
|
|
1493
1494
|
handle: handle.modifyMethod,
|
|
@@ -1508,14 +1509,14 @@ const ScimGateway = function () {
|
|
|
1508
1509
|
}
|
|
1509
1510
|
}
|
|
1510
1511
|
logger.debug(`${gwName}[${pluginName}][${ctx?.params?.baseEntity}] publishing "${handle.modifyMethod}" to SCIM Stream and awaiting result`)
|
|
1511
|
-
await this.publish(streamObj)
|
|
1512
|
+
res = await this.publish(streamObj)
|
|
1512
1513
|
} else {
|
|
1513
1514
|
if (Array.isArray(scimdata.members) && scimdata.members.length === 0 && handle.modifyMethod === 'modifyGroup') {
|
|
1514
1515
|
ctx.request.body = scimdata
|
|
1515
|
-
await replaceUsrGrp(ctx, config.scim.usePutSoftSync)
|
|
1516
|
+
res = await replaceUsrGrp(ctx, config.scim.usePutSoftSync)
|
|
1516
1517
|
} else {
|
|
1517
1518
|
logger.debug(`${gwName}[${pluginName}][${ctx?.params?.baseEntity}] calling "${handle.modifyMethod}" and awaiting result`)
|
|
1518
|
-
await this[handle.modifyMethod](ctx.params.baseEntity, id, scimdata, ctx.passThrough)
|
|
1519
|
+
res = await this[handle.modifyMethod](ctx.params.baseEntity, id, scimdata, ctx.passThrough)
|
|
1519
1520
|
}
|
|
1520
1521
|
}
|
|
1521
1522
|
|
|
@@ -1545,28 +1546,27 @@ const ScimGateway = function () {
|
|
|
1545
1546
|
}
|
|
1546
1547
|
}
|
|
1547
1548
|
|
|
1548
|
-
// include full object in response
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1549
|
+
if (!res) { // include full object in response, TODO: include groups
|
|
1550
|
+
if (handle.getMethod !== handler.users.getMethod && handle.getMethod !== handler.groups.getMethod && !config.stream.publisher.enabled) { // getUsers or getGroups not implemented
|
|
1551
|
+
ctx.status = 204
|
|
1552
|
+
return
|
|
1553
|
+
}
|
|
1554
|
+
const ob = { attribute: 'id', operator: 'eq', value: id }
|
|
1555
|
+
const attributes = ctx.query.attributes ? ctx.query.attributes.split(',').map(item => item.trim()) : []
|
|
1556
|
+
if (config.stream.publisher.enabled) {
|
|
1557
|
+
const streamObj = {
|
|
1558
|
+
handle: handle.getMethod,
|
|
1559
|
+
baseEntity: ctx.params.baseEntity,
|
|
1560
|
+
obj: ob,
|
|
1561
|
+
attributes,
|
|
1562
|
+
ctxPassThrough: ctx.passThrough
|
|
1563
|
+
}
|
|
1564
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.params?.baseEntity}] publishing "${handle.getMethod}" to SCIM Stream and awaiting result`)
|
|
1565
|
+
res = await this.publish(streamObj)
|
|
1566
|
+
} else {
|
|
1567
|
+
logger.debug(`${gwName}[${pluginName}][${ctx?.params?.baseEntity}] calling "${handle.getMethod}" and awaiting result`)
|
|
1568
|
+
res = await this[handle.getMethod](ctx.params.baseEntity, ob, attributes, ctx.passThrough)
|
|
1564
1569
|
}
|
|
1565
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.params?.baseEntity}] publishing "${handle.getMethod}" to SCIM Stream and awaiting result`)
|
|
1566
|
-
res = await this.publish(streamObj)
|
|
1567
|
-
} else {
|
|
1568
|
-
logger.debug(`${gwName}[${pluginName}][${ctx?.params?.baseEntity}] calling "${handle.getMethod}" and awaiting result`)
|
|
1569
|
-
res = await this[handle.getMethod](ctx.params.baseEntity, ob, attributes, ctx.passThrough)
|
|
1570
1570
|
}
|
|
1571
1571
|
|
|
1572
1572
|
scimdata = {
|
|
@@ -1686,7 +1686,7 @@ const ScimGateway = function () {
|
|
|
1686
1686
|
let res
|
|
1687
1687
|
try {
|
|
1688
1688
|
res = await this[handler.groups.getMethod](ctx.params.baseEntity, { attribute: 'members.value', operator: 'eq', value: decodeURIComponent(id) }, ['id', 'displayName'], ctx.passThrough)
|
|
1689
|
-
} catch (err) {} // method may be implemented but throwing error like groups not supported/implemented
|
|
1689
|
+
} catch (err) { } // method may be implemented but throwing error like groups not supported/implemented
|
|
1690
1690
|
currentGroups = []
|
|
1691
1691
|
if (res && res.Resources && Array.isArray(res.Resources) && res.Resources.length > 0) {
|
|
1692
1692
|
for (let i = 0; i < res.Resources.length; i++) {
|
|
@@ -1763,7 +1763,7 @@ const ScimGateway = function () {
|
|
|
1763
1763
|
this.replaceUsrGrp = replaceUsrGrp
|
|
1764
1764
|
|
|
1765
1765
|
router.put([`/(|scim/)(!${undefined}|Users|Groups|servicePlans)/:id`,
|
|
1766
|
-
|
|
1766
|
+
`/:baseEntity/(|scim/)(!${undefined}|Users|Groups|servicePlans)/:id`], async (ctx) => {
|
|
1767
1767
|
const originalUrl = ctx.request.originalUrl
|
|
1768
1768
|
if (config.stream.publisher.enabled) {
|
|
1769
1769
|
const streamObj = {
|
|
@@ -2085,7 +2085,7 @@ const ScimGateway = function () {
|
|
|
2085
2085
|
const attributes = ['id', 'displayName']
|
|
2086
2086
|
logger.debug(`${gwName}[${pluginName}][${baseEntity}] calling "${handler.groups.getMethod}" and awaiting result - groups to be included`)
|
|
2087
2087
|
res = await this[handler.groups.getMethod](baseEntity, ob, attributes, ctxPassThrough)
|
|
2088
|
-
} catch (err) {} // ignore errors
|
|
2088
|
+
} catch (err) { } // ignore errors
|
|
2089
2089
|
if (res && res.Resources && Array.isArray(res.Resources) && res.Resources.length > 0) {
|
|
2090
2090
|
for (let i = 0; i < res.Resources.length; i++) {
|
|
2091
2091
|
if (!res.Resources[i].id) continue
|
|
@@ -2121,7 +2121,7 @@ const ScimGateway = function () {
|
|
|
2121
2121
|
if (config.localhostonly === true) {
|
|
2122
2122
|
logger.info(`${gwName}[${pluginName}] denying other clients than localhost (127.0.0.1)`)
|
|
2123
2123
|
if (config.certificate && config.certificate.key && config.certificate.cert) {
|
|
2124
|
-
|
|
2124
|
+
// SSL
|
|
2125
2125
|
let keyFile = path.join(configDir, '/certs/', config.certificate.key)
|
|
2126
2126
|
if (config.certificate.key.startsWith('/') || config.certificate.key.includes('\\')) {
|
|
2127
2127
|
keyFile = config.certificate.key
|
|
@@ -2136,7 +2136,7 @@ const ScimGateway = function () {
|
|
|
2136
2136
|
}, app.callback()).listen(config.port, 'localhost')
|
|
2137
2137
|
logger.info(`${gwName}[${pluginName}] now listening SCIM ${config.scim.version} on TLS port ${config.port}...${config.stream.subscriber.enabled ? '' : '\n'}`)
|
|
2138
2138
|
} else if (config.certificate && config.certificate.pfx && config.certificate.pfx.bundle) {
|
|
2139
|
-
|
|
2139
|
+
// SSL using PFX / PKCS#12
|
|
2140
2140
|
let pfxFile = path.join(configDir, '/certs/', config.certificate.pfx.bundle)
|
|
2141
2141
|
if (config.certificate.pfx.bundle.startsWith('/') || config.certificate.pfx.bundle.includes('\\')) {
|
|
2142
2142
|
pfxFile = config.certificate.pfx.bundle
|
|
@@ -2147,14 +2147,14 @@ const ScimGateway = function () {
|
|
|
2147
2147
|
}, app.callback()).listen(config.port, 'localhost')
|
|
2148
2148
|
logger.info(`${gwName}[${pluginName}] now listening SCIM ${config.scim.version} on TLS port ${config.port}...${config.stream.subscriber.enabled ? '' : '\n'}`)
|
|
2149
2149
|
} else {
|
|
2150
|
-
|
|
2150
|
+
// none SSL
|
|
2151
2151
|
server = http.createServer(app.callback()).listen(config.port, 'localhost')
|
|
2152
2152
|
logger.info(`${gwName}[${pluginName}] now listening SCIM ${config.scim.version} on port ${config.port}...${config.stream.subscriber.enabled ? '' : '\n'}`)
|
|
2153
2153
|
}
|
|
2154
2154
|
} else {
|
|
2155
2155
|
logger.info(`${gwName}[${pluginName}] accepting requests from all clients`)
|
|
2156
2156
|
if (config.certificate && config.certificate.key && config.certificate.cert) {
|
|
2157
|
-
|
|
2157
|
+
// SSL self signed cert e.g: openssl req -nodes -newkey rsa:2048 -x509 -sha256 -days 3650 -keyout key.pem -out cert.pem -subj "/O=NodeJS/OU=Testing/CN=<FQDN>"
|
|
2158
2158
|
let keyFile = path.join(configDir, '/certs/', config.certificate.key)
|
|
2159
2159
|
if (config.certificate.key.startsWith('/') || config.certificate.key.includes('\\')) {
|
|
2160
2160
|
keyFile = config.certificate.key
|
|
@@ -2177,7 +2177,7 @@ const ScimGateway = function () {
|
|
|
2177
2177
|
}, app.callback()).listen(config.port)
|
|
2178
2178
|
logger.info(`${gwName}[${pluginName}] now listening SCIM ${config.scim.version} on TLS port ${config.port}...${config.stream.subscriber.enabled ? '' : '\n'}`)
|
|
2179
2179
|
} else if (config.certificate && config.certificate.pfx && config.certificate.pfx.bundle) {
|
|
2180
|
-
|
|
2180
|
+
// SSL using PFX / PKCS#12
|
|
2181
2181
|
let pfxFile = path.join(configDir, '/certs/', config.certificate.pfx.bundle)
|
|
2182
2182
|
if (config.certificate.pfx.bundle.startsWith('/') || config.certificate.pfx.bundle.includes('\\')) {
|
|
2183
2183
|
pfxFile = config.certificate.pfx.bundle
|
|
@@ -2188,7 +2188,7 @@ const ScimGateway = function () {
|
|
|
2188
2188
|
}, app.callback()).listen(config.port)
|
|
2189
2189
|
logger.info(`${gwName}[${pluginName}] now listening SCIM ${config.scim.version} on TLS port ${config.port}...${config.stream.subscriber.enabled ? '' : '\n'}`)
|
|
2190
2190
|
} else {
|
|
2191
|
-
|
|
2191
|
+
// none SSL
|
|
2192
2192
|
server = http.createServer(app.callback()).listen(config.port)
|
|
2193
2193
|
logger.info(`${gwName}[${pluginName}] now listening SCIM ${config.scim.version} on port ${config.port}...${config.stream.subscriber.enabled ? '' : '\n'}`)
|
|
2194
2194
|
}
|
|
@@ -2707,7 +2707,7 @@ ScimGateway.prototype.endpointMapper = function endpointMapper (direction, parse
|
|
|
2707
2707
|
if (complexObj[attr]) {
|
|
2708
2708
|
found = true
|
|
2709
2709
|
resArr.push(keyNotDot)
|
|
2710
|
-
|
|
2710
|
+
// don't break - check for multiple complex definitions
|
|
2711
2711
|
}
|
|
2712
2712
|
}
|
|
2713
2713
|
}
|
|
@@ -3191,7 +3191,7 @@ ScimGateway.prototype.convertedScim20 = function convertedScim20 (obj) {
|
|
|
3191
3191
|
} else if (typeof el.value === 'string' && el.value.substring(0, 1) === '{') { // "value": [{"value":"{\"id\":\"c20e145e-5459-4a6c-a074-b942bbd4cfe1\",\"value\":\"admin\",\"displayName\":\"Administrator\"}"}}]
|
|
3192
3192
|
try {
|
|
3193
3193
|
element.value[i] = JSON.parse(el.value)
|
|
3194
|
-
} catch (err) {}
|
|
3194
|
+
} catch (err) { }
|
|
3195
3195
|
}
|
|
3196
3196
|
}
|
|
3197
3197
|
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scimgateway",
|
|
3
|
-
"version": "4.5.
|
|
3
|
+
"version": "4.5.12",
|
|
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",
|