scimgateway 4.1.8 → 4.1.10

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
@@ -206,6 +206,7 @@ Below shows an example of config\plugin-saphana.json
206
206
  "scimgateway": {
207
207
  "port": 8884,
208
208
  "localhostonly": false,
209
+ "payloadSize": null,
209
210
  "scim": {
210
211
  "version": "2.0",
211
212
  "customSchema": null,
@@ -307,6 +308,8 @@ Definitions in `endpoint` object are customized according to our plugin code. Pl
307
308
 
308
309
  - **localhostonly** - true or false. False means gateway accepts incoming requests from all clients. True means traffic from only localhost (127.0.0.1) is accepted (gateway must then be installed on the CA Connector Server).
309
310
 
311
+ - **payloadSize** - if not defined, default "1mb" will be used. There are cases which large groups could exceed default size and you may want to increase by setting your own size
312
+
310
313
  - **scim.version** - "1.1" or "2.0". Default is "2.0". For Symantec/Broadcom/CA Identity Manager "1.1" should be used.
311
314
 
312
315
  - **scim.customSchema** - filename of JSON file located in `<package-root>\config\schemas` containing custom schema attributes, see configuration notes
@@ -1143,6 +1146,24 @@ MIT © [Jarle Elshaug](https://www.elshaug.xyz)
1143
1146
 
1144
1147
  ## Change log
1145
1148
 
1149
+ ### v4.1.10
1150
+
1151
+ [Added]
1152
+
1153
+ - new plugin configuration `payloadSize`. If not defined, default "1mb" will be used. There are cases which large groups could exceed default size and you may want to increase by setting your own size e.g. "5mb"
1154
+ **Thanks to Sam Murphy**
1155
+
1156
+ [Fixed]
1157
+
1158
+ - using `GET /Users`, scimgateway automatically adds groups if not included by plugin. This operation calls plugin getGroups having attributes=['members.value', 'id', 'displayName']. Now, `members.value` is excluded. This attribute was in use and could cause unneeded load when having many group members.
1159
+
1160
+ ### v4.1.9
1161
+
1162
+ [Fixed]
1163
+
1164
+ - plugin-azure-ad.json configuration file introduced in v.4.1.7 was missing passwordProfile attribute mappings
1165
+ - Symantec/Broadcom/CA ConnectorXpress configuration file `config\resources\Azure - ScimGateway.xml` now using standard text on manager attribute instead of selection dialogbox.
1166
+
1146
1167
  ### v4.1.8
1147
1168
 
1148
1169
  [Fixed]
@@ -2,6 +2,7 @@
2
2
  "scimgateway": {
3
3
  "port": 8890,
4
4
  "localhostonly": false,
5
+ "payloadSize": null,
5
6
  "scim": {
6
7
  "version": "2.0",
7
8
  "customSchema": null,
@@ -86,9 +87,7 @@
86
87
  "endpoint": {
87
88
  "entity": {
88
89
  "undefined": {
89
- "baseUrls": [
90
- "http://fakerestapi.azurewebsites.net"
91
- ],
90
+ "baseUrls": ["http://fakerestapi.azurewebsites.net"],
92
91
  "username": "endpointuser",
93
92
  "password": "password",
94
93
  "proxy": {
@@ -99,4 +98,4 @@
99
98
  }
100
99
  }
101
100
  }
102
- }
101
+ }
@@ -2,6 +2,7 @@
2
2
  "scimgateway": {
3
3
  "port": 8881,
4
4
  "localhostonly": false,
5
+ "payloadSize": null,
5
6
  "scim": {
6
7
  "version": "1.1",
7
8
  "customSchema": null,
@@ -210,6 +211,14 @@
210
211
  "mapTo": "passwordPolicies",
211
212
  "type": "string"
212
213
  },
214
+ "passwordProfile.forceChangePasswordNextSignIn": {
215
+ "mapTo": "passwordProfile.forceChangePasswordNextSignIn",
216
+ "type": "string"
217
+ },
218
+ "passwordProfile.password": {
219
+ "mapTo": "passwordProfile.password",
220
+ "type": "string"
221
+ },
213
222
  "servicePlan": {
214
223
  "mapTo": "servicePlan.value",
215
224
  "type": "array"
@@ -251,4 +260,4 @@
251
260
  }
252
261
  }
253
262
  }
254
- }
263
+ }
@@ -2,6 +2,7 @@
2
2
  "scimgateway": {
3
3
  "port": 8882,
4
4
  "localhostonly": false,
5
+ "payloadSize": null,
5
6
  "scim": {
6
7
  "version": "2.0",
7
8
  "customSchema": null,
@@ -145,4 +146,4 @@
145
146
  }
146
147
  }
147
148
  }
148
- }
149
+ }
@@ -2,6 +2,7 @@
2
2
  "scimgateway": {
3
3
  "port": 8883,
4
4
  "localhostonly": false,
5
+ "payloadSize": null,
5
6
  "scim": {
6
7
  "version": "2.0",
7
8
  "customSchema": null,
@@ -86,10 +87,7 @@
86
87
  "endpoint": {
87
88
  "entity": {
88
89
  "undefined": {
89
- "baseUrls": [
90
- "ldaps://dc1.test.com:636",
91
- "ldaps://dc2.test.com:636"
92
- ],
90
+ "baseUrls": ["ldaps://dc1.test.com:636", "ldaps://dc2.test.com:636"],
93
91
  "username": "CN=Administrator,CN=Users,DC=test,DC=com",
94
92
  "password": "password",
95
93
  "ldap": {
@@ -105,10 +103,7 @@
105
103
  "organizationalPerson",
106
104
  "top"
107
105
  ],
108
- "groupObjectClasses": [
109
- "group",
110
- "top"
111
- ]
106
+ "groupObjectClasses": ["group", "top"]
112
107
  }
113
108
  }
114
109
  },
@@ -223,4 +218,4 @@
223
218
  }
224
219
  }
225
220
  }
226
- }
221
+ }
@@ -2,6 +2,7 @@
2
2
  "scimgateway": {
3
3
  "port": 8880,
4
4
  "localhostonly": false,
5
+ "payloadSize": null,
5
6
  "scim": {
6
7
  "version": "2.0",
7
8
  "customSchema": null,
@@ -87,4 +88,4 @@
87
88
  "dbname": "loki.db",
88
89
  "persistence": false
89
90
  }
90
- }
91
+ }
@@ -2,6 +2,7 @@
2
2
  "scimgateway": {
3
3
  "port": 8885,
4
4
  "localhostonly": false,
5
+ "payloadSize": null,
5
6
  "scim": {
6
7
  "version": "2.0",
7
8
  "customSchema": null,
@@ -107,4 +108,4 @@
107
108
  }
108
109
  }
109
110
  }
110
- }
111
+ }
@@ -2,6 +2,7 @@
2
2
  "scimgateway": {
3
3
  "port": 8888,
4
4
  "localhostonly": false,
5
+ "payloadSize": null,
5
6
  "scim": {
6
7
  "version": "2.0",
7
8
  "customSchema": null,
@@ -103,4 +104,4 @@
103
104
  }
104
105
  }
105
106
  }
106
- }
107
+ }
@@ -2,6 +2,7 @@
2
2
  "scimgateway": {
3
3
  "port": 8884,
4
4
  "localhostonly": false,
5
+ "payloadSize": null,
5
6
  "scim": {
6
7
  "version": "2.0",
7
8
  "customSchema": null,
@@ -90,4 +91,4 @@
90
91
  "password": "password",
91
92
  "saml_provider": "saml_provider_name"
92
93
  }
93
- }
94
+ }
@@ -2,6 +2,7 @@
2
2
  "scimgateway": {
3
3
  "port": 8886,
4
4
  "localhostonly": false,
5
+ "payloadSize": null,
5
6
  "scim": {
6
7
  "version": "2.0",
7
8
  "customSchema": null,
@@ -86,9 +87,7 @@
86
87
  "endpoint": {
87
88
  "entity": {
88
89
  "undefined": {
89
- "baseUrls": [
90
- "http://localhost:8880"
91
- ],
90
+ "baseUrls": ["http://localhost:8880"],
92
91
  "scimVersion": "2.0",
93
92
  "username": "gwadmin",
94
93
  "password": "password",
@@ -99,9 +98,7 @@
99
98
  }
100
99
  },
101
100
  "clientA": {
102
- "baseUrls": [
103
- "http://localhost:8880"
104
- ],
101
+ "baseUrls": ["http://localhost:8880"],
105
102
  "scimVersion": "2.0",
106
103
  "username": "gwadmin",
107
104
  "password": "password",
@@ -113,4 +110,4 @@
113
110
  }
114
111
  }
115
112
  }
116
- }
113
+ }
@@ -3326,16 +3326,16 @@ function init(FieldContext)
3326
3326
  <property name="eTDYN-str-multi-11">
3327
3327
  <doc></doc>
3328
3328
  <value default="false">
3329
- <flexiStrValue type="DN"></flexiStrValue>
3329
+ <strValue></strValue>
3330
3330
  </value>
3331
3331
  <metadata name="displayName">
3332
3332
  <value>
3333
- <strValue>Manager Id</strValue>
3333
+ <strValue>Manager UPN</strValue>
3334
3334
  </value>
3335
3335
  </metadata>
3336
3336
  <metadata name="beanPropertyName">
3337
3337
  <value>
3338
- <strValue>managermanagerId</strValue>
3338
+ <strValue>managerId</strValue>
3339
3339
  </value>
3340
3340
  </metadata>
3341
3341
  <metadata name="isRequired">
@@ -3348,26 +3348,6 @@ function init(FieldContext)
3348
3348
  <strValue>manager.managerId</strValue>
3349
3349
  </value>
3350
3350
  </metadata>
3351
- <metadata name="DNTestExists">
3352
- <value>
3353
- <boolValue>true</boolValue>
3354
- </value>
3355
- </metadata>
3356
- <metadata name="assocRefObjectClass">
3357
- <value>
3358
- <strValue>eTDYNAccount</strValue>
3359
- </value>
3360
- </metadata>
3361
- <metadata name="assocRefKeyAttr">
3362
- <value>
3363
- <strValue>id</strValue>
3364
- </value>
3365
- </metadata>
3366
- <metadata name="DNLdapObjectClass">
3367
- <value>
3368
- <strValue>eTDYNAccount</strValue>
3369
- </value>
3370
- </metadata>
3371
3351
  </property>
3372
3352
  <property name="eTDYN-str-multi-29">
3373
3353
  <doc>Proxy Addresses</doc>
@@ -4906,16 +4886,16 @@ function init(FieldContext)
4906
4886
  </property>
4907
4887
  <property name="eTDYN-str-multi-11">
4908
4888
  <value>
4909
- <flexiStrValue type="DN"></flexiStrValue>
4889
+ <strValue></strValue>
4910
4890
  </value>
4911
4891
  <metadata name="displayName">
4912
4892
  <value>
4913
- <strValue>Manager Id</strValue>
4893
+ <strValue>Manager UPN</strValue>
4914
4894
  </value>
4915
4895
  </metadata>
4916
4896
  <metadata name="beanPropertyName">
4917
4897
  <value>
4918
- <strValue>managermanagerId</strValue>
4898
+ <strValue>managerId</strValue>
4919
4899
  </value>
4920
4900
  </metadata>
4921
4901
  <metadata name="isRequired">
@@ -4923,21 +4903,6 @@ function init(FieldContext)
4923
4903
  <boolValue>false</boolValue>
4924
4904
  </value>
4925
4905
  </metadata>
4926
- <metadata name="assocRefObjectClass">
4927
- <value>
4928
- <strValue>eTDYNAccount</strValue>
4929
- </value>
4930
- </metadata>
4931
- <metadata name="assocRefKeyAttr">
4932
- <value>
4933
- <strValue>id</strValue>
4934
- </value>
4935
- </metadata>
4936
- <metadata name="DNLdapObjectClass">
4937
- <value>
4938
- <strValue>eTDYNAccount</strValue>
4939
- </value>
4940
- </metadata>
4941
4906
  </property>
4942
4907
  <property name="eTDYN-str-multi-29">
4943
4908
  <value>
@@ -4962,11 +4927,6 @@ function init(FieldContext)
4962
4927
  <boolValue>false</boolValue>
4963
4928
  </value>
4964
4929
  </metadata>
4965
- <metadata name="isReadOnly">
4966
- <value>
4967
- <boolValue>true</boolValue>
4968
- </value>
4969
- </metadata>
4970
4930
  <metadata name="writableBy">
4971
4931
  <value>
4972
4932
  <strValue></strValue>
@@ -1199,7 +1199,7 @@ const getUser = async (baseEntity, uid, attributes) => { // uid = id, userName (
1199
1199
  (async () => {
1200
1200
  // const [attrs] = scimgateway.endpointMapper('outbound', attributes, config.map.user) // SCIM/CustomSCIM => endpoint attribute standard
1201
1201
  const method = 'GET'
1202
- const path = `/users/${querystring.escape(uid)}?$expand=manager($select=id)` // /beta returns all attributes or use: ?$select=${attrs.join()}
1202
+ const path = `/users/${querystring.escape(uid)}?$expand=manager($select=userPrincipalName)` // beta returns all attributes or use: ?$select=${attrs.join()}
1203
1203
  const body = null
1204
1204
  try {
1205
1205
  const response = await doRequest(baseEntity, method, path, body)
@@ -1210,7 +1210,7 @@ const getUser = async (baseEntity, uid, attributes) => { // uid = id, userName (
1210
1210
  }
1211
1211
 
1212
1212
  let managerId
1213
- if (userObj.manager && userObj.manager.id) managerId = userObj.manager.id
1213
+ if (userObj.manager && userObj.manager.userPrincipalName) managerId = userObj.manager.userPrincipalName
1214
1214
  delete userObj.manager
1215
1215
  if (managerId) userObj.manager = managerId
1216
1216
 
@@ -578,7 +578,8 @@ const ScimGateway = function () {
578
578
  app.use(bodyParser({ // parsed body store in ctx.request.body
579
579
  enableTypes: ['json', 'form'],
580
580
  extendTypes: { json: ['application/scim+json', 'text/plain'] },
581
- formTypes: { form: ['application/x-www-form-urlencoded'] }
581
+ formTypes: { form: ['application/x-www-form-urlencoded'] },
582
+ jsonLimit: (!config.payloadSize) ? undefined : config.payloadSize // default '1mb'
582
583
  }))
583
584
  app.use(ipAllowList)
584
585
  app.use(auth) // authentication before routes
@@ -787,7 +788,7 @@ const ScimGateway = function () {
787
788
  logger.debug(`${gwName}[${pluginName}] calling "${handler.groups.getMethod}" and awaiting result - groups to be included`)
788
789
  let res
789
790
  try {
790
- res = await this[handler.groups.getMethod](ctx.params.baseEntity, { attribute: 'members.value', operator: 'eq', value: getObj.value }, ['members.value', 'id', 'displayName'])
791
+ res = await this[handler.groups.getMethod](ctx.params.baseEntity, { attribute: 'members.value', operator: 'eq', value: getObj.value }, ['id', 'displayName'])
791
792
  } catch (err) {} // method may be implemented but throwing error like groups not supported/implemented
792
793
  if (res && res.Resources && Array.isArray(res.Resources) && res.Resources.length > 0) {
793
794
  userObj.groups = []
@@ -798,7 +799,7 @@ const ScimGateway = function () {
798
799
  if (res.Resources[i].displayName) el.display = res.Resources[i].displayName
799
800
  if (isScimv2) el.type = 'direct'
800
801
  else el.type = { value: 'direct' }
801
- if (el.value) userObj.groups.push(el) // { "value": "Admins", "display": "Admins", "type": "direct"}
802
+ userObj.groups.push(el) // { "value": "Admins", "display": "Admins", "type": "direct"}
802
803
  }
803
804
  }
804
805
  }
@@ -991,7 +992,7 @@ const ScimGateway = function () {
991
992
  logger.debug(`${gwName}[${pluginName}] calling "${handler.groups.getMethod}" and awaiting result - groups to be included`)
992
993
  let res
993
994
  try {
994
- res = await this[handler.groups.getMethod](ctx.params.baseEntity, { attribute: 'members.value', operator: 'eq', value: decodeURIComponent(userObj.id) }, ['members.value', 'id', 'displayName']) // await scimgateway.getUserGroups(baseEntity, userObj.id, 'members.value,displayName')
995
+ res = await this[handler.groups.getMethod](ctx.params.baseEntity, { attribute: 'members.value', operator: 'eq', value: decodeURIComponent(userObj.id) }, ['id', 'displayName']) // await scimgateway.getUserGroups(baseEntity, userObj.id, 'members.value,displayName')
995
996
  } catch (err) {} // method may be implemented but throwing error like groups not supported/implemented
996
997
  if (res && res.Resources && Array.isArray(res.Resources) && res.Resources.length > 0) {
997
998
  userObj.groups = []
@@ -1002,7 +1003,7 @@ const ScimGateway = function () {
1002
1003
  if (res.Resources[i].displayName) el.display = res.Resources[i].displayName
1003
1004
  if (isScimv2) el.type = 'direct'
1004
1005
  else el.type = { value: 'direct' }
1005
- if (el.value) userObj.groups.push(el) // { "value": "Admins", "display": "Admins", "type": "direct"}
1006
+ userObj.groups.push(el) // { "value": "Admins", "display": "Admins", "type": "direct"}
1006
1007
  }
1007
1008
  }
1008
1009
  }
package/lib/utils.js CHANGED
@@ -388,3 +388,22 @@ module.exports.fsExistsSync = function (f) {
388
388
  return false
389
389
  }
390
390
  }
391
+
392
+ // createRandomPassword creates a random password, syntax:
393
+ // utils.createRandomPassword(12) => 12 characters, lower, upper and special
394
+ // utils.createRandomPassword(12, utils.createRandomPassword.alphaLower)
395
+ // https://gist.github.com/6174/6062387
396
+ module.exports.createRandomPassword = (function () {
397
+ const gen = (min, max) => max++ && [...Array(max - min)].map((s, i) => String.fromCharCode(min + i))
398
+ const sets = {
399
+ num: gen(48, 57),
400
+ alphaLower: gen(97, 122),
401
+ alphaUpper: gen(65, 90),
402
+ special: [...'~!@#$%^&*()_+-=[]{}|;:\'",./<>?']
403
+ }
404
+ function * iter (len, set) {
405
+ if (set.length < 1) { set = Object.values(sets).flat() }
406
+ for (let i = 0; i < len; i++) { yield set[Math.random() * set.length | 0] }
407
+ }
408
+ return Object.assign((len, ...set) => [...iter(len, set.flat())].join(''), sets)
409
+ }())
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scimgateway",
3
- "version": "4.1.8",
3
+ "version": "4.1.10",
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",