scimgateway 4.4.6 → 4.5.0
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 +21 -8
- package/config/plugin-api.json +13 -0
- package/config/plugin-entra-id.json +13 -0
- package/config/plugin-ldap.json +13 -0
- package/config/plugin-loki.json +13 -0
- package/config/plugin-mongodb.json +13 -0
- package/config/plugin-mssql.json +13 -0
- package/config/plugin-saphana.json +13 -0
- package/config/plugin-scim.json +13 -0
- package/config/plugin-soap.json +13 -0
- package/lib/plugin-api.js +1 -0
- package/lib/plugin-entra-id.js +1 -0
- package/lib/plugin-ldap.js +34 -34
- package/lib/plugin-loki.js +1 -1
- package/lib/plugin-scim.js +1 -0
- package/lib/scim-stream.js +3 -3
- package/lib/scimgateway.js +483 -276
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -16,6 +16,7 @@ Validated through IdP's:
|
|
|
16
16
|
|
|
17
17
|
Latest news:
|
|
18
18
|
|
|
19
|
+
- Supports stream publishing mode having [SCIM Stream](https://elshaug.xyz/docs/scim-stream) as a prerequisite. In this mode, standard incoming SCIM requests from your Identity Provider (IdP) or API are directed and published to the stream. Subsequently, one of the gateways subscribing to the channel utilized by the publisher will manage the SCIM request, and response back to the publisher. Using SCIM Stream we have `egress/outbound only traffic` and get loadbalancing/failover by adding more gateways subscribing to same channel.
|
|
19
20
|
- **BREAKING**: [SCIM Stream](https://elshaug.xyz/docs/scim-stream) is the modern way of user provisioning letting clients subscribe to messages instead of traditional IGA top-down provisioning. SCIM Gateway now offers enhanced functionality with support for message subscription and automated provisioning using SCIM Stream
|
|
20
21
|
- Authentication PassThrough letting plugin pass authentication directly to endpoint for avoid maintaining secrets at the gateway. Kubernetes health checks and shutdown handler support
|
|
21
22
|
- Supports OAuth Client Credentials authentication
|
|
@@ -33,7 +34,9 @@ Latest news:
|
|
|
33
34
|
|
|
34
35
|
## Overview
|
|
35
36
|
|
|
36
|
-
With SCIM Gateway, user management is facilitated through the utilization of the REST-based SCIM 1.1 or 2.0 protocol. The
|
|
37
|
+
With SCIM Gateway, user management is facilitated through the utilization of the REST-based SCIM 1.1 or 2.0 protocol. The gateway acts as a translator for incoming SCIM requests, seamlessly enabling the exposure of CRUD functionality (create, read, update, and delete user/group) towards destinations. This is achieved through the implementation of endpoint-specific protocols, ensuring precise and efficient provisioning with diverse endpoints.
|
|
38
|
+
|
|
39
|
+
Using [SCIM Stream](https://elshaug.xyz/docs/scim-stream), gateway may enable Pub/Sub allowing incoming SCIM requests to be published and processed by other gateways acting as subscribers. This extends beyond being Entra ID and HR subscriber for messages published by the SCIM Stream collector.
|
|
37
40
|
|
|
38
41
|

|
|
39
42
|
|
|
@@ -54,10 +57,10 @@ Same as plugin "Loki", but using external MongoDB
|
|
|
54
57
|
Shows how to implement a highly configurable multi tenant or multi endpoint solution through `baseEntity` in URL
|
|
55
58
|
|
|
56
59
|
* **SCIM** (REST Webservice)
|
|
57
|
-
Demonstrates user provisioning towards REST-Based endpoint (type SCIM)
|
|
58
|
-
Using plugin
|
|
60
|
+
Demonstrates user provisioning towards REST-Based endpoint (type SCIM)
|
|
61
|
+
Using plugin Loki as SCIM endpoint
|
|
59
62
|
Can be used as SCIM version-gateway e.g. 1.1=>2.0 or 2.0=>1.1
|
|
60
|
-
Can be used to chain several
|
|
63
|
+
Can be used to chain several gateways
|
|
61
64
|
|
|
62
65
|
|
|
63
66
|
* **Soap** (SOAP Webservice)
|
|
@@ -86,9 +89,9 @@ Using endpointMapper (like plugin-entra-id) for attribute flexibility
|
|
|
86
89
|
* **API** (REST Webservices)
|
|
87
90
|
Demonstrates API Gateway/plugin functionality using post/put/patch/get/delete
|
|
88
91
|
None SCIM plugin, becomes what you want it to become.
|
|
89
|
-
Methods
|
|
92
|
+
Methods included can also be used in standard SCIM plugins
|
|
90
93
|
Endpoint complexity could be put in this plugin, and client could instead communicate through Gateway using your own simplified REST specification.
|
|
91
|
-
One example of usage could be creation of tickets in ServiceDesk
|
|
94
|
+
One example of usage could be creation of tickets in ServiceDesk and also the other way, closing a ticket could automatically approve/reject corresponding workflow in IdP.
|
|
92
95
|
|
|
93
96
|
|
|
94
97
|
## Installation
|
|
@@ -384,13 +387,13 @@ Definitions in `endpoint` object are customized according to our plugin code. Pl
|
|
|
384
387
|
|
|
385
388
|
- **auth.bearerJwtAzure** - Array of one or more JWT used by Azure SyncFabric. **tenantIdGUID** must be set to Entra ID Tenant ID.
|
|
386
389
|
|
|
387
|
-
- **auth.bearerJwt** - Array of one or more standard JWT objects. Using **secret** or **publicKey** for signature verification. publicKey should be set to the filename of public key or certificate pem-file located in `<package-root>\config\certs
|
|
390
|
+
- **auth.bearerJwt** - Array of one or more standard JWT objects. Using **secret** or **publicKey** for signature verification. publicKey should be set to the filename of public key or certificate pem-file located in `<package-root>\config\certs` or absolute path being used. Clear text secret will become encrypted when gateway is started. **options.issuer** is mandatory. Other options may also be included according to jsonwebtoken npm package definition.
|
|
388
391
|
|
|
389
392
|
- **auth.bearerOAuth** - Array of one or more Client Credentials OAuth configuration objects. **`client_id`** and **`client_secret`** are mandatory. client_secret value will become encrypted when gateway is started. OAuth token request url is **/oauth/token** e.g. http://localhost:8880/oauth/token
|
|
390
393
|
|
|
391
394
|
- **auth.passThrough** - Setting **auth.passThrough.enabled=true** will bypass SCIM Gateway authentication. Gateway will instead pass ctx containing authentication header to the plugin. Plugin could then use this information for endpoint authentication and we don't have any password/token stored at the gateway. Note, this also requires plugin binary having `scimgateway.authPassThroughAllowed = true` and endpoint logic for handling/passing ctx.request.header.authorization
|
|
392
395
|
|
|
393
|
-
- **certificate** - If not using TLS certificate, set "key", "cert" and "ca" to **null**. When using TLS, "key" and "cert" have to be defined with the filename corresponding to the primary-key and public-certificate. Both files must be located in the `<package-root>\config\certs` directory e.g:
|
|
396
|
+
- **certificate** - If not using TLS certificate, set "key", "cert" and "ca" to **null**. When using TLS, "key" and "cert" have to be defined with the filename corresponding to the primary-key and public-certificate. Both files must be located in the `<package-root>\config\certs` directory unless absolute path being defined e.g:
|
|
394
397
|
|
|
395
398
|
"certificate": {
|
|
396
399
|
"key": "key.pem",
|
|
@@ -1147,6 +1150,16 @@ MIT © [Jarle Elshaug](https://www.elshaug.xyz)
|
|
|
1147
1150
|
|
|
1148
1151
|
## Change log
|
|
1149
1152
|
|
|
1153
|
+
### v4.5.0
|
|
1154
|
+
|
|
1155
|
+
[Improved]
|
|
1156
|
+
|
|
1157
|
+
- scim-stream, scimgateway now supports stream publishing mode having [SCIM Stream](https://elshaug.xyz/docs/scim-stream) as a prerequisite. In this mode, standard incoming SCIM requests from your Identity Provider (IdP) or API are directed and published to the stream. Subsequently, one of the gateways subscribing to the channel utilized by the publisher will manage the SCIM request, and response back to the publisher. Using SCIM Stream we have `egress/outbound only traffic` and get loadbalancing/failover by adding more gateways subscribing to same channel.
|
|
1158
|
+
- scim-stream, subscriber will do automatic retry until connected when plugin not able to connect to endpoint (offline endpoint)
|
|
1159
|
+
- plugin-ldap, modifyGroup now supports all attributes and not only add/remove members
|
|
1160
|
+
- certificate absolute path may be used in plugin configuration file instead of default relative path
|
|
1161
|
+
- dependencies bump
|
|
1162
|
+
|
|
1150
1163
|
### v4.4.6
|
|
1151
1164
|
|
|
1152
1165
|
[Improved]
|
package/config/plugin-api.json
CHANGED
|
@@ -116,6 +116,19 @@
|
|
|
116
116
|
"replaceDomains": []
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
+
},
|
|
120
|
+
"publisher": {
|
|
121
|
+
"enabled": false,
|
|
122
|
+
"entity": {
|
|
123
|
+
"undefined": {
|
|
124
|
+
"nats": {
|
|
125
|
+
"tenant": null,
|
|
126
|
+
"subject": null,
|
|
127
|
+
"jwt": null,
|
|
128
|
+
"secret": null
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
119
132
|
}
|
|
120
133
|
}
|
|
121
134
|
},
|
|
@@ -116,6 +116,19 @@
|
|
|
116
116
|
"replaceDomains": []
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
+
},
|
|
120
|
+
"publisher": {
|
|
121
|
+
"enabled": false,
|
|
122
|
+
"entity": {
|
|
123
|
+
"undefined": {
|
|
124
|
+
"nats": {
|
|
125
|
+
"tenant": null,
|
|
126
|
+
"subject": null,
|
|
127
|
+
"jwt": null,
|
|
128
|
+
"secret": null
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
119
132
|
}
|
|
120
133
|
}
|
|
121
134
|
},
|
package/config/plugin-ldap.json
CHANGED
|
@@ -116,6 +116,19 @@
|
|
|
116
116
|
"replaceDomains": []
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
+
},
|
|
120
|
+
"publisher": {
|
|
121
|
+
"enabled": false,
|
|
122
|
+
"entity": {
|
|
123
|
+
"undefined": {
|
|
124
|
+
"nats": {
|
|
125
|
+
"tenant": null,
|
|
126
|
+
"subject": null,
|
|
127
|
+
"jwt": null,
|
|
128
|
+
"secret": null
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
119
132
|
}
|
|
120
133
|
}
|
|
121
134
|
},
|
package/config/plugin-loki.json
CHANGED
|
@@ -116,6 +116,19 @@
|
|
|
116
116
|
"replaceDomains": []
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
+
},
|
|
120
|
+
"publisher": {
|
|
121
|
+
"enabled": false,
|
|
122
|
+
"entity": {
|
|
123
|
+
"undefined": {
|
|
124
|
+
"nats": {
|
|
125
|
+
"tenant": null,
|
|
126
|
+
"subject": null,
|
|
127
|
+
"jwt": null,
|
|
128
|
+
"secret": null
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
119
132
|
}
|
|
120
133
|
}
|
|
121
134
|
},
|
|
@@ -122,6 +122,19 @@
|
|
|
122
122
|
"replaceDomains": []
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
|
+
},
|
|
126
|
+
"publisher": {
|
|
127
|
+
"enabled": false,
|
|
128
|
+
"entity": {
|
|
129
|
+
"undefined": {
|
|
130
|
+
"nats": {
|
|
131
|
+
"tenant": null,
|
|
132
|
+
"subject": null,
|
|
133
|
+
"jwt": null,
|
|
134
|
+
"secret": null
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
125
138
|
}
|
|
126
139
|
}
|
|
127
140
|
},
|
package/config/plugin-mssql.json
CHANGED
|
@@ -116,6 +116,19 @@
|
|
|
116
116
|
"replaceDomains": []
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
+
},
|
|
120
|
+
"publisher": {
|
|
121
|
+
"enabled": false,
|
|
122
|
+
"entity": {
|
|
123
|
+
"undefined": {
|
|
124
|
+
"nats": {
|
|
125
|
+
"tenant": null,
|
|
126
|
+
"subject": null,
|
|
127
|
+
"jwt": null,
|
|
128
|
+
"secret": null
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
119
132
|
}
|
|
120
133
|
}
|
|
121
134
|
},
|
|
@@ -116,6 +116,19 @@
|
|
|
116
116
|
"replaceDomains": []
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
+
},
|
|
120
|
+
"publisher": {
|
|
121
|
+
"enabled": false,
|
|
122
|
+
"entity": {
|
|
123
|
+
"undefined": {
|
|
124
|
+
"nats": {
|
|
125
|
+
"tenant": null,
|
|
126
|
+
"subject": null,
|
|
127
|
+
"jwt": null,
|
|
128
|
+
"secret": null
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
119
132
|
}
|
|
120
133
|
}
|
|
121
134
|
},
|
package/config/plugin-scim.json
CHANGED
|
@@ -116,6 +116,19 @@
|
|
|
116
116
|
"replaceDomains": []
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
+
},
|
|
120
|
+
"publisher": {
|
|
121
|
+
"enabled": false,
|
|
122
|
+
"entity": {
|
|
123
|
+
"undefined": {
|
|
124
|
+
"nats": {
|
|
125
|
+
"tenant": null,
|
|
126
|
+
"subject": null,
|
|
127
|
+
"jwt": null,
|
|
128
|
+
"secret": null
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
119
132
|
}
|
|
120
133
|
}
|
|
121
134
|
},
|
package/config/plugin-soap.json
CHANGED
|
@@ -116,6 +116,19 @@
|
|
|
116
116
|
"replaceDomains": []
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
+
},
|
|
120
|
+
"publisher": {
|
|
121
|
+
"enabled": false,
|
|
122
|
+
"entity": {
|
|
123
|
+
"undefined": {
|
|
124
|
+
"nats": {
|
|
125
|
+
"tenant": null,
|
|
126
|
+
"subject": null,
|
|
127
|
+
"jwt": null,
|
|
128
|
+
"secret": null
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
119
132
|
}
|
|
120
133
|
}
|
|
121
134
|
},
|
package/lib/plugin-api.js
CHANGED
|
@@ -253,6 +253,7 @@ const getAccessToken = async (baseEntity, ctx) => {
|
|
|
253
253
|
grant_type: 'client_credentials',
|
|
254
254
|
client_id: username || config.entity[baseEntity].oauth.clientId,
|
|
255
255
|
client_secret: secret || scimgateway.getPassword(`endpoint.entity.${baseEntity}.oauth.clientSecret`, configFile),
|
|
256
|
+
scope: config.entity[baseEntity].oauth.scope || '',
|
|
256
257
|
resource: resource // "https://graph.microsoft.com"
|
|
257
258
|
}
|
|
258
259
|
options.headers = {
|
package/lib/plugin-entra-id.js
CHANGED
|
@@ -1069,6 +1069,7 @@ const getAccessToken = async (baseEntity, ctx) => {
|
|
|
1069
1069
|
grant_type: 'client_credentials',
|
|
1070
1070
|
client_id: username || config.entity[baseEntity].oauth.clientId,
|
|
1071
1071
|
client_secret: secret || scimgateway.getPassword(`endpoint.entity.${baseEntity}.oauth.clientSecret`, configFile),
|
|
1072
|
+
scope: config.entity[baseEntity].oauth.scope || '',
|
|
1072
1073
|
resource: resource // "https://graph.microsoft.com"
|
|
1073
1074
|
}
|
|
1074
1075
|
options.headers = {
|
package/lib/plugin-ldap.js
CHANGED
|
@@ -289,8 +289,7 @@ scimgateway.createUser = async (baseEntity, userObj, ctx) => {
|
|
|
289
289
|
if (!userBase) userBase = config.entity[baseEntity].ldap.userBase
|
|
290
290
|
|
|
291
291
|
// convert SCIM attributes to endpoint attributes according to config.map
|
|
292
|
-
const [endpointObj] = scimgateway.endpointMapper('outbound', userObj, config.map.user)
|
|
293
|
-
// if (err) throw new Error(`${action} error: ${err.message}`) // use above [endpointObj, err] to catch non supported attributes
|
|
292
|
+
const [endpointObj] = scimgateway.endpointMapper('outbound', userObj, config.map.user) // use [endpointObj, err] and if err, throw error to catch non supported attributes
|
|
294
293
|
|
|
295
294
|
// endpoint spesific attribute handling
|
|
296
295
|
if (endpointObj.sAMAccountName !== undefined) { // Active Directory
|
|
@@ -372,18 +371,16 @@ scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
|
|
|
372
371
|
delete attrObj.groups // make sure to be removed from attrObj
|
|
373
372
|
|
|
374
373
|
const [groupsAttr] = scimgateway.endpointMapper('outbound', 'groups.value', config.map.user)
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
body.add[groupsAttr] = []
|
|
379
|
-
body.remove[groupsAttr] = []
|
|
374
|
+
const grp = { add: { }, remove: { } }
|
|
375
|
+
grp.add[groupsAttr] = []
|
|
376
|
+
grp.remove[groupsAttr] = []
|
|
380
377
|
|
|
381
378
|
for (let i = 0; i < groups.length; i++) {
|
|
382
379
|
const el = groups[i]
|
|
383
380
|
if (el.operation && el.operation === 'delete') { // delete from users group attribute
|
|
384
|
-
|
|
381
|
+
grp.remove[groupsAttr].push(el.value)
|
|
385
382
|
} else { // add to users group attribute
|
|
386
|
-
|
|
383
|
+
grp.add[groupsAttr].push(el.value)
|
|
387
384
|
}
|
|
388
385
|
}
|
|
389
386
|
|
|
@@ -399,17 +396,17 @@ scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
|
|
|
399
396
|
} else base = id // dn
|
|
400
397
|
|
|
401
398
|
try {
|
|
402
|
-
if (
|
|
399
|
+
if (grp.add[groupsAttr].length > 0) {
|
|
403
400
|
const ldapOptions = {
|
|
404
401
|
operation: 'add',
|
|
405
|
-
modification:
|
|
402
|
+
modification: grp.add
|
|
406
403
|
}
|
|
407
404
|
await doRequest(baseEntity, method, base, ldapOptions, ctx)
|
|
408
405
|
}
|
|
409
|
-
if (
|
|
406
|
+
if (grp.remove[groupsAttr].length > 0) {
|
|
410
407
|
const ldapOptions = {
|
|
411
408
|
operation: 'delete',
|
|
412
|
-
modification:
|
|
409
|
+
modification: grp.remove
|
|
413
410
|
}
|
|
414
411
|
await doRequest(baseEntity, method, base, ldapOptions, ctx)
|
|
415
412
|
}
|
|
@@ -418,11 +415,10 @@ scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
|
|
|
418
415
|
}
|
|
419
416
|
}
|
|
420
417
|
|
|
421
|
-
if (
|
|
418
|
+
if (Object.keys(attrObj).length < 1) return null // only groups included
|
|
422
419
|
|
|
423
420
|
// convert SCIM attributes to endpoint attributes according to config.map
|
|
424
421
|
const [endpointObj] = scimgateway.endpointMapper('outbound', attrObj, config.map.user)
|
|
425
|
-
// if (err) throw new Error(`${action} error: ${err.message}`) // use above [endpointObj, err] to catch non supported attributes
|
|
426
422
|
|
|
427
423
|
// endpoint spesific attribute handling
|
|
428
424
|
if (endpointObj.userAccountControl !== undefined) { // SCIM "active" - Active Directory
|
|
@@ -527,7 +523,6 @@ scimgateway.getGroups = async (baseEntity, getObj, attributes, ctx) => {
|
|
|
527
523
|
}
|
|
528
524
|
|
|
529
525
|
const [attrs] = scimgateway.endpointMapper('outbound', attributes, config.map.group) // SCIM/CustomSCIM => endpoint attribute naming
|
|
530
|
-
|
|
531
526
|
const method = 'search'
|
|
532
527
|
const scope = 'sub'
|
|
533
528
|
let base = config.entity[baseEntity].ldap.groupBase
|
|
@@ -644,8 +639,7 @@ scimgateway.createGroup = async (baseEntity, groupObj, ctx) => {
|
|
|
644
639
|
if (!config.map.group) throw new Error(`${action} error: missing configuration endpoint.map.group`)
|
|
645
640
|
|
|
646
641
|
// convert SCIM attributes to endpoint attributes according to config.map
|
|
647
|
-
const [endpointObj
|
|
648
|
-
if (err) throw new Error(`${action} error: ${err.message}`)
|
|
642
|
+
const [endpointObj] = scimgateway.endpointMapper('outbound', groupObj, config.map.group)
|
|
649
643
|
|
|
650
644
|
// endpointObj.objectClass is mandatory and must must match your ldap schema
|
|
651
645
|
endpointObj.objectClass = config.entity[baseEntity].ldap.groupObjectClasses // Active Directory: ["group"]
|
|
@@ -700,21 +694,18 @@ scimgateway.modifyGroup = async (baseEntity, id, attrObj, ctx) => {
|
|
|
700
694
|
scimgateway.logger.debug(`${pluginName}[${baseEntity}] handling "${action}" id=${id} attrObj=${JSON.stringify(attrObj)}`)
|
|
701
695
|
|
|
702
696
|
if (!config.map.group) throw new Error(`${action} error: missing configuration endpoint.map.group`)
|
|
703
|
-
if (!attrObj.members) {
|
|
704
|
-
throw new Error(`${action} error: only supports modification of members`)
|
|
705
|
-
}
|
|
706
|
-
if (!Array.isArray(attrObj.members)) {
|
|
697
|
+
if (attrObj.members && !Array.isArray(attrObj.members)) {
|
|
707
698
|
throw new Error(`${action} error: ${JSON.stringify(attrObj)} - correct syntax is { "members": [...] }`)
|
|
708
699
|
}
|
|
709
700
|
|
|
710
|
-
const [memberAttr
|
|
711
|
-
if (
|
|
701
|
+
const [memberAttr] = scimgateway.endpointMapper('outbound', 'members.value', config.map.group)
|
|
702
|
+
if (!memberAttr && attrObj.members) throw new Error(`${action} error: missing attribute mapping configuration for group members`)
|
|
712
703
|
|
|
713
|
-
const
|
|
714
|
-
|
|
715
|
-
|
|
704
|
+
const grp = { add: { }, remove: { } }
|
|
705
|
+
grp.add[memberAttr] = []
|
|
706
|
+
grp.remove[memberAttr] = []
|
|
716
707
|
|
|
717
|
-
for (let i = 0; i < attrObj
|
|
708
|
+
for (let i = 0; i < attrObj?.members?.length; i++) {
|
|
718
709
|
const el = attrObj.members[i]
|
|
719
710
|
if (config.useSID_id || config.useGUID_id) {
|
|
720
711
|
const dn = await sidGuidToDn(baseEntity, el.value, ctx)
|
|
@@ -722,9 +713,9 @@ scimgateway.modifyGroup = async (baseEntity, id, attrObj, ctx) => {
|
|
|
722
713
|
el.value = dn
|
|
723
714
|
}
|
|
724
715
|
if (el.operation && el.operation === 'delete') { // delete member from group
|
|
725
|
-
|
|
716
|
+
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
|
|
726
717
|
} else { // add member to group
|
|
727
|
-
|
|
718
|
+
grp.add[memberAttr].push(el.value)
|
|
728
719
|
}
|
|
729
720
|
}
|
|
730
721
|
|
|
@@ -735,17 +726,26 @@ scimgateway.modifyGroup = async (baseEntity, id, attrObj, ctx) => {
|
|
|
735
726
|
else base = id // dn
|
|
736
727
|
|
|
737
728
|
try {
|
|
738
|
-
|
|
729
|
+
delete attrObj.members
|
|
730
|
+
const [endpointObj] = scimgateway.endpointMapper('outbound', attrObj, config.map.group)
|
|
731
|
+
if (Object.keys(endpointObj).length > 0) {
|
|
732
|
+
const ldapOptions = {
|
|
733
|
+
operation: 'replace',
|
|
734
|
+
modification: endpointObj
|
|
735
|
+
}
|
|
736
|
+
await doRequest(baseEntity, method, base, ldapOptions, ctx)
|
|
737
|
+
}
|
|
738
|
+
if (grp.add[memberAttr].length > 0) {
|
|
739
739
|
const ldapOptions = { // using ldap lookup (dn) instead of search
|
|
740
740
|
operation: 'add',
|
|
741
|
-
modification:
|
|
741
|
+
modification: grp.add
|
|
742
742
|
}
|
|
743
743
|
await doRequest(baseEntity, method, base, ldapOptions, ctx)
|
|
744
744
|
}
|
|
745
|
-
if (
|
|
745
|
+
if (grp.remove[memberAttr].length > 0) {
|
|
746
746
|
const ldapOptions = { // using ldap lookup (dn) instead of search
|
|
747
747
|
operation: 'delete',
|
|
748
|
-
modification:
|
|
748
|
+
modification: grp.remove
|
|
749
749
|
}
|
|
750
750
|
await doRequest(baseEntity, method, base, ldapOptions, ctx)
|
|
751
751
|
}
|
package/lib/plugin-loki.js
CHANGED
|
@@ -51,7 +51,7 @@ const validFilterOperators = ['eq', 'ne', 'aeq', 'dteq', 'gt', 'gte', 'lt', 'lte
|
|
|
51
51
|
|
|
52
52
|
const dbNames = []
|
|
53
53
|
for (const baseEntity in config.entity) {
|
|
54
|
-
let dbname =
|
|
54
|
+
let dbname = config.entity[baseEntity].dbname || 'loki.db'
|
|
55
55
|
if (dbNames.includes(dbname)) {
|
|
56
56
|
scimgateway.logger.error(`${pluginName}[${baseEntity}] initialization error: database '${dbname}' is already used by another baseEntity configuration`)
|
|
57
57
|
continue
|
package/lib/plugin-scim.js
CHANGED
|
@@ -587,6 +587,7 @@ const getAccessToken = async (baseEntity, ctx) => {
|
|
|
587
587
|
grant_type: 'client_credentials',
|
|
588
588
|
client_id: username || config.entity[baseEntity].oauth.clientId,
|
|
589
589
|
client_secret: secret || scimgateway.getPassword(`endpoint.entity.${baseEntity}.oauth.clientSecret`, configFile),
|
|
590
|
+
scope: config.entity[baseEntity].oauth.scope || '',
|
|
590
591
|
resource: resource // "https://graph.microsoft.com"
|
|
591
592
|
}
|
|
592
593
|
options.headers = {
|