scimgateway 5.0.7 → 5.0.8
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 +22 -15
- package/config/plugin-api.json +2 -2
- package/config/plugin-entra-id.json +2 -2
- package/config/plugin-ldap.json +2 -2
- package/config/plugin-loki.json +2 -2
- package/config/plugin-mongodb.json +2 -2
- package/config/plugin-mssql.json +2 -2
- package/config/plugin-saphana.json +2 -2
- package/config/plugin-scim.json +2 -2
- package/config/plugin-soap.json +2 -2
- package/lib/helper-rest.ts +4 -4
- package/lib/plugin-mssql.ts +30 -53
- package/lib/scimgateway.ts +23 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -258,8 +258,8 @@ Below shows an example of config\plugin-saphana.json
|
|
|
258
258
|
],
|
|
259
259
|
"bearerOAuth": [
|
|
260
260
|
{
|
|
261
|
-
"
|
|
262
|
-
"
|
|
261
|
+
"clientId": null,
|
|
262
|
+
"clientSecret": null,
|
|
263
263
|
"readOnly": false,
|
|
264
264
|
"baseEntities": []
|
|
265
265
|
}
|
|
@@ -398,7 +398,7 @@ Definitions in `endpoint` object are customized according to our plugin code. Pl
|
|
|
398
398
|
|
|
399
399
|
- **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.
|
|
400
400
|
|
|
401
|
-
- **auth.bearerOAuth** - Array of one or more Client Credentials OAuth configuration objects. **`
|
|
401
|
+
- **auth.bearerOAuth** - Array of one or more Client Credentials OAuth configuration objects. **`clientId`** and **`clientSecret`** are mandatory. clientSecret value will become encrypted when gateway is started. OAuth token request url is **/oauth/token** e.g. http://localhost:8880/oauth/token
|
|
402
402
|
|
|
403
403
|
- **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
|
|
404
404
|
|
|
@@ -462,18 +462,18 @@ Definitions in `endpoint` object are customized according to our plugin code. Pl
|
|
|
462
462
|
|
|
463
463
|
Configuration notes when using default configuration oauth and tenantIdGUID - Microsoft Exchange Online (ExO):
|
|
464
464
|
|
|
465
|
-
- Entra ID application must have application permissions
|
|
466
|
-
- To prevent the sending of emails from any defined mailboxes, an ExO
|
|
465
|
+
- Entra ID application must have application permissions `Mail.Send`
|
|
466
|
+
- To prevent the sending of emails from any defined mailboxes, an ExO `ApplicationAccessPolicy` must be defined through PowerShell.
|
|
467
467
|
|
|
468
468
|
First create a mail-enabled security-group that only includes those users (mailboxes) the application is allowed to send from
|
|
469
|
-
Note,
|
|
469
|
+
Note, `mail enabled security group` cannot be created from portal, only from admin or admin.exchange console
|
|
470
470
|
|
|
471
471
|
##Connect to Exchange
|
|
472
472
|
Install-Module -Name ExchangeOnlineManagement
|
|
473
473
|
Connect-ExchangeOnline
|
|
474
474
|
|
|
475
475
|
##Create ApplicationAccessPolicy
|
|
476
|
-
New-ApplicationAccessPolicy -AppId
|
|
476
|
+
New-ApplicationAccessPolicy -AppId <AppClientID> -PolicyScopeGroupId <MailEnabledSecurityGrpId> -AccessRight RestrictAccess -Description "Restrict app to specific mailboxes"
|
|
477
477
|
|
|
478
478
|
- **stream** - See [SCIM Stream](https://elshaug.xyz/docs/scim-stream) for configuration details
|
|
479
479
|
|
|
@@ -1111,6 +1111,15 @@ MIT © [Jarle Elshaug](https://www.elshaug.xyz)
|
|
|
1111
1111
|
|
|
1112
1112
|
## Change log
|
|
1113
1113
|
|
|
1114
|
+
### v5.0.8
|
|
1115
|
+
|
|
1116
|
+
[Fixed]
|
|
1117
|
+
|
|
1118
|
+
- Ensure Bun compatibility with Azure Reverse Proxy for large and long running response
|
|
1119
|
+
- HelperRest was not compatible with Node.js
|
|
1120
|
+
- plugin-mssql, some error handling should not throw an error
|
|
1121
|
+
- Configuration files updated according to the v5 configuration syntax of `scimgateway.auth.bearerOAuth` - `clientId/clientSecret` now replacing deprecated `client_id/client_secret`
|
|
1122
|
+
|
|
1114
1123
|
### v5.0.7
|
|
1115
1124
|
|
|
1116
1125
|
[Improved]
|
|
@@ -1155,9 +1164,7 @@ MIT © [Jarle Elshaug](https://www.elshaug.xyz)
|
|
|
1155
1164
|
|
|
1156
1165
|
|
|
1157
1166
|
**new configuration:**
|
|
1158
|
-
Using Microsoft Exchange Online and oauth authencation which also is default and recommended by Microsoft
|
|
1159
|
-
For other mail servers and options like SMTP AUTH (basic/oauth), please see configuration description
|
|
1160
|
-
Plugin may also send mail using method scimgateway.sendMail()
|
|
1167
|
+
Using Microsoft Exchange Online and oauth authencation which also is default and recommended by Microsoft. For other mail servers and options like SMTP AUTH (basic/oauth), please see configuration description. Plugin may also send mail using method scimgateway.sendMail()
|
|
1161
1168
|
|
|
1162
1169
|
{
|
|
1163
1170
|
"scimgateway": {
|
|
@@ -1184,18 +1191,18 @@ Plugin may also send mail using method scimgateway.sendMail()
|
|
|
1184
1191
|
|
|
1185
1192
|
Configuration notes when using oauth and tenantIdGUID - Microsoft Exchange Online (ExO):
|
|
1186
1193
|
|
|
1187
|
-
- Entra ID application must have application permissions
|
|
1188
|
-
- To prevent the sending of emails from any defined mailboxes, an ExO
|
|
1194
|
+
- Entra ID application must have application permissions `Mail.Send`
|
|
1195
|
+
- To prevent the sending of emails from any defined mailboxes, an ExO `ApplicationAccessPolicy` must be defined through PowerShell.
|
|
1189
1196
|
|
|
1190
1197
|
First create a mail-enabled security-group that only includes those users (mailboxes) the application is allowed to send from
|
|
1191
|
-
Note,
|
|
1198
|
+
Note, `mail enabled security group` cannot be created from portal, only from admin or admin.exchange console
|
|
1192
1199
|
|
|
1193
1200
|
##Connect to Exchange
|
|
1194
1201
|
Install-Module -Name ExchangeOnlineManagement
|
|
1195
1202
|
Connect-ExchangeOnline
|
|
1196
1203
|
|
|
1197
1204
|
##Create ApplicationAccessPolicy
|
|
1198
|
-
New-ApplicationAccessPolicy -AppId
|
|
1205
|
+
New-ApplicationAccessPolicy -AppId <AppClientID> -PolicyScopeGroupId <MailEnabledSecurityGrpId> -AccessRight RestrictAccess -Description "Restrict app to specific mailboxes"
|
|
1199
1206
|
|
|
1200
1207
|
|
|
1201
1208
|
### v5.0.5
|
|
@@ -1308,7 +1315,7 @@ Besides going from JavaScript to TypeScript, following can be mentioned:
|
|
|
1308
1315
|
|
|
1309
1316
|
* Use scimgateway.HelperRest() for REST functionlity, also supports Auth PassThrough
|
|
1310
1317
|
* scimgateway.endpointMapper() may be used for inbound/outbound attribute mappings
|
|
1311
|
-
* In general when using TypeScript, variables should be type
|
|
1318
|
+
* In general when using TypeScript, variables should be type-defined: `let isDone: boolean = false`, `catch (err: any)`, ...
|
|
1312
1319
|
|
|
1313
1320
|
### v4.5.12
|
|
1314
1321
|
|
package/config/plugin-api.json
CHANGED
package/config/plugin-ldap.json
CHANGED
package/config/plugin-loki.json
CHANGED
package/config/plugin-mssql.json
CHANGED
package/config/plugin-scim.json
CHANGED
package/config/plugin-soap.json
CHANGED
package/lib/helper-rest.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { Buffer } from 'node:buffer'
|
|
|
4
4
|
import fs from 'node:fs'
|
|
5
5
|
import querystring from 'querystring'
|
|
6
6
|
import * as utils from './utils.ts'
|
|
7
|
-
import ScimGateway from 'scimgateway'
|
|
7
|
+
// import type { ScimGateway } from 'scimgateway' // comment out for supporting Node.js, using type any and no IntelliSense
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* HelperRest includes function doRequest() for doing REST calls
|
|
@@ -13,12 +13,12 @@ export class HelperRest {
|
|
|
13
13
|
private lock = new utils.Lock()
|
|
14
14
|
private _serviceClient: Record<string, any> = {}
|
|
15
15
|
private config_entity: any
|
|
16
|
-
private scimgateway:
|
|
16
|
+
private scimgateway: any
|
|
17
17
|
private idleTimeout: number
|
|
18
18
|
private graphUrl = 'https://graph.microsoft.com/beta' // beta instead of 'v1.0' gives all user attributes when no $select
|
|
19
19
|
|
|
20
|
-
constructor(scimgateway:
|
|
21
|
-
if (!
|
|
20
|
+
constructor(scimgateway: any, optionalEntities?: Record<string, any>) {
|
|
21
|
+
if (!scimgateway || !scimgateway.gwName) throw new Error('HelperRest initialization error: argument scimgateway is not of type ScimGateway')
|
|
22
22
|
this.scimgateway = scimgateway
|
|
23
23
|
this.idleTimeout = (scimgateway as any)?.config?.scimgateway.idleTimeout || 120
|
|
24
24
|
this.idleTimeout = this.idleTimeout - 1
|
package/lib/plugin-mssql.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// Purpose: SQL user-provisioning
|
|
7
7
|
//
|
|
8
8
|
// Prereq:
|
|
9
|
-
// CREATE TABLE [
|
|
9
|
+
// CREATE TABLE [Users] (
|
|
10
10
|
// [UserID] VARCHAR(50) NOT NULL,
|
|
11
11
|
// [Enabled] VARCHAR(50) NULL,
|
|
12
12
|
// [Password] VARCHAR(50) NULL,
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
// PRIMARY KEY ([UserID])
|
|
20
20
|
// );
|
|
21
21
|
//
|
|
22
|
-
// CREATE TABLE [
|
|
22
|
+
// CREATE TABLE [Groups] (
|
|
23
23
|
// [GroupID] VARCHAR(50) NOT NULL,
|
|
24
24
|
// [Enabled] VARCHAR(50) NULL,
|
|
25
25
|
// CONSTRAINT [PK_Group]
|
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
// PRIMARY KEY ([GroupID],[UserID]),
|
|
34
34
|
// CONSTRAINT [FK_U2G_Group]
|
|
35
35
|
// FOREIGN KEY ([GroupID])
|
|
36
|
-
// REFERENCES [
|
|
36
|
+
// REFERENCES [Groups]([GroupID])
|
|
37
37
|
// ON DELETE CASCADE,
|
|
38
38
|
// CONSTRAINT [FK_U2G_Users]
|
|
39
39
|
// FOREIGN KEY ([UserID])
|
|
40
|
-
// REFERENCES [
|
|
40
|
+
// REFERENCES [Users]([UserID])
|
|
41
41
|
// ON DELETE CASCADE
|
|
42
42
|
// );
|
|
43
43
|
//
|
|
@@ -66,7 +66,7 @@ import { Connection, Request } from 'tedious'
|
|
|
66
66
|
const ScimGateway: typeof import('scimgateway').ScimGateway = await (async () => {
|
|
67
67
|
try {
|
|
68
68
|
return (await import('scimgateway')).ScimGateway
|
|
69
|
-
} catch (err) {
|
|
69
|
+
} catch (err: any) {
|
|
70
70
|
const source = './scimgateway.ts'
|
|
71
71
|
return (await import(source)).ScimGateway
|
|
72
72
|
}
|
|
@@ -113,17 +113,13 @@ scimgateway.getUsers = async (baseEntity, getObj, attributes, ctx) => {
|
|
|
113
113
|
if (!sqlQuery) throw new Error(`${action} error: mandatory if-else logic not fully implemented`)
|
|
114
114
|
|
|
115
115
|
try {
|
|
116
|
-
return await new Promise(async (resolve
|
|
116
|
+
return await new Promise(async (resolve) => {
|
|
117
117
|
const ret: any = { // itemsPerPage will be set by scimgateway
|
|
118
118
|
Resources: [],
|
|
119
119
|
totalResults: null,
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
const users: any[] = await query(sqlQuery, ctx).catch(
|
|
123
|
-
const e = new Error(`${action} error: ${err.message}`)
|
|
124
|
-
return reject(e)
|
|
125
|
-
})
|
|
126
|
-
|
|
122
|
+
const users: any[] = await query(sqlQuery, ctx).catch(err => scimgateway.logWarn(baseEntity, `${action} warning: ${err.message}`))
|
|
127
123
|
for (const user of users) {
|
|
128
124
|
const scimUser = {
|
|
129
125
|
id: user.UserID.value ? user.UserID.value : undefined,
|
|
@@ -155,7 +151,7 @@ scimgateway.createUser = async (baseEntity, userObj, ctx) => {
|
|
|
155
151
|
scimgateway.logDebug(baseEntity, `handling "${action}" userObj=${JSON.stringify(userObj)}`)
|
|
156
152
|
|
|
157
153
|
try {
|
|
158
|
-
return await new Promise(async (resolve
|
|
154
|
+
return await new Promise(async (resolve) => {
|
|
159
155
|
if (!userObj.name) userObj.name = {}
|
|
160
156
|
if (!userObj.emails) userObj.emails = { work: {} }
|
|
161
157
|
if (!userObj.phoneNumbers) userObj.phoneNumbers = { work: {} }
|
|
@@ -174,10 +170,7 @@ scimgateway.createUser = async (baseEntity, userObj, ctx) => {
|
|
|
174
170
|
const sqlQuery = `insert into [Users] (UserID, Enabled, Password, FirstName, MiddleName, LastName, Email, MobilePhone)
|
|
175
171
|
values (${insert.UserID}, ${insert.Enabled}, ${insert.Password}, ${insert.FirstName}, ${insert.MiddleName}, ${insert.LastName}, ${insert.Email}, ${insert.MobilePhone})`
|
|
176
172
|
|
|
177
|
-
await query(sqlQuery, ctx).catch(
|
|
178
|
-
const e = new Error(`${action} error: ${err.message}`)
|
|
179
|
-
return reject(e)
|
|
180
|
-
})
|
|
173
|
+
await query(sqlQuery, ctx).catch(err => scimgateway.logWarn(baseEntity, `${action} warning: ${err.message}`))
|
|
181
174
|
|
|
182
175
|
resolve(null)
|
|
183
176
|
}) // Promise
|
|
@@ -194,12 +187,9 @@ scimgateway.deleteUser = async (baseEntity, id, ctx) => {
|
|
|
194
187
|
scimgateway.logDebug(baseEntity, `handling "${action}" id=${id}`)
|
|
195
188
|
|
|
196
189
|
try {
|
|
197
|
-
return await new Promise(async (resolve
|
|
190
|
+
return await new Promise(async (resolve) => {
|
|
198
191
|
const sqlQuery = `delete from [Users] where UserID = '${id}'`
|
|
199
|
-
await query(sqlQuery, ctx).catch(
|
|
200
|
-
const e = new Error(`${action} error: ${err.message}`)
|
|
201
|
-
return reject(e)
|
|
202
|
-
})
|
|
192
|
+
await query(sqlQuery, ctx).catch(err => scimgateway.logWarn(baseEntity, `${action} warning: ${err.message}`))
|
|
203
193
|
|
|
204
194
|
resolve(null)
|
|
205
195
|
}) // Promise
|
|
@@ -216,7 +206,7 @@ scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
|
|
|
216
206
|
scimgateway.logDebug(baseEntity, `handling "${action}" id=${id} attrObj=${JSON.stringify(attrObj)}`)
|
|
217
207
|
|
|
218
208
|
try {
|
|
219
|
-
return await new Promise(async (resolve
|
|
209
|
+
return await new Promise(async (resolve) => {
|
|
220
210
|
if (!attrObj.name) attrObj.name = {}
|
|
221
211
|
if (!attrObj.emails) attrObj.emails = { work: {} }
|
|
222
212
|
if (!attrObj.phoneNumbers) attrObj.phoneNumbers = { work: {} }
|
|
@@ -252,10 +242,7 @@ scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
|
|
|
252
242
|
sql = sql.substr(0, sql.length - 1) // remove trailing ","
|
|
253
243
|
|
|
254
244
|
const sqlQuery = `update [Users] set ${sql} where UserID like '${id}'`
|
|
255
|
-
await query(sqlQuery, ctx).catch(
|
|
256
|
-
const e = new Error(`${action} error: ${err.message}`)
|
|
257
|
-
return reject(e)
|
|
258
|
-
})
|
|
245
|
+
await query(sqlQuery, ctx).catch(err => scimgateway.logWarn(baseEntity, `${action} warning: ${err.message}`))
|
|
259
246
|
|
|
260
247
|
resolve(null)
|
|
261
248
|
}) // Promise
|
|
@@ -296,16 +283,13 @@ scimgateway.getGroups = async (baseEntity, getObj, attributes, ctx) => {
|
|
|
296
283
|
if (!sqlQuery) throw new Error(`${action} error: mandatory if-else logic not fully implemented`)
|
|
297
284
|
|
|
298
285
|
try {
|
|
299
|
-
return await new Promise(async (resolve
|
|
286
|
+
return await new Promise(async (resolve) => {
|
|
300
287
|
const ret: any = { // itemsPerPage will be set by scimgateway
|
|
301
288
|
Resources: [],
|
|
302
289
|
totalResults: null,
|
|
303
290
|
}
|
|
304
291
|
|
|
305
|
-
const groups = await query(sqlQuery, ctx).catch(
|
|
306
|
-
const e = new Error(`${action} error: ${err.message}`)
|
|
307
|
-
return reject(e)
|
|
308
|
-
})
|
|
292
|
+
const groups: any[] = await query(sqlQuery, ctx).catch(err => scimgateway.logWarn(baseEntity, `${action} warning: ${err.message}`))
|
|
309
293
|
|
|
310
294
|
for (const group of groups) {
|
|
311
295
|
const scimGroup: Record<string, any> = {
|
|
@@ -316,7 +300,7 @@ scimgateway.getGroups = async (baseEntity, getObj, attributes, ctx) => {
|
|
|
316
300
|
}
|
|
317
301
|
|
|
318
302
|
const sqlQuery = `select UserID from [Users2Group] where GroupID = '${scimGroup.id}'`
|
|
319
|
-
const members = await query(sqlQuery, ctx).catch(
|
|
303
|
+
const members = await query(sqlQuery, ctx).catch(err => scimgateway.logWarn(baseEntity, `${action} warning: ${err.message}`))
|
|
320
304
|
for (const member of members) {
|
|
321
305
|
const scimMember = {
|
|
322
306
|
value: member.UserID.value,
|
|
@@ -343,21 +327,20 @@ scimgateway.createGroup = async (baseEntity, groupObj, ctx) => {
|
|
|
343
327
|
scimgateway.logDebug(baseEntity, `handling "${action}" groupObj=${JSON.stringify(groupObj)}`)
|
|
344
328
|
|
|
345
329
|
try {
|
|
346
|
-
return await new Promise(async (resolve
|
|
330
|
+
return await new Promise(async (resolve) => {
|
|
347
331
|
const insert = {
|
|
348
332
|
GroupID: `'${groupObj.displayName}'`,
|
|
349
333
|
Enabled: (groupObj.active) ? `'${groupObj.active}'` : '\'false\'',
|
|
350
334
|
}
|
|
351
335
|
|
|
352
336
|
const sqlQuery = `insert into [Groups] (GroupID, Enabled) values (${insert.GroupID}, ${insert.Enabled})`
|
|
353
|
-
await query(sqlQuery, ctx).catch(
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
})
|
|
337
|
+
await query(sqlQuery, ctx).catch(err => scimgateway.logWarn(baseEntity, `${action} warning: ${err.message}`))
|
|
338
|
+
|
|
339
|
+
if (Array.isArray(groupObj.members) && groupObj.members) {
|
|
340
|
+
for (const member of groupObj.members) {
|
|
341
|
+
const sqlQuery = `insert into [Users2Group] (UserID, GroupID) values ('${member.value}', ${insert.GroupID})`
|
|
342
|
+
await query(sqlQuery, ctx).catch(err => scimgateway.logWarn(baseEntity, `${action} warning: ${err.message}`))
|
|
343
|
+
}
|
|
361
344
|
}
|
|
362
345
|
|
|
363
346
|
resolve(null)
|
|
@@ -375,12 +358,9 @@ scimgateway.deleteGroup = async (baseEntity, id, ctx) => {
|
|
|
375
358
|
scimgateway.logDebug(baseEntity, `handling "${action}" id=${id}`)
|
|
376
359
|
|
|
377
360
|
try {
|
|
378
|
-
return await new Promise(async (resolve
|
|
361
|
+
return await new Promise(async (resolve) => {
|
|
379
362
|
const sqlQuery = `delete from [Groups] where GroupID = '${id}'`
|
|
380
|
-
await query(sqlQuery, ctx).catch(
|
|
381
|
-
const e = new Error(`${action} error: ${err.message}`)
|
|
382
|
-
return reject(e)
|
|
383
|
-
})
|
|
363
|
+
await query(sqlQuery, ctx).catch(err => scimgateway.logWarn(baseEntity, `${action} warning: ${err.message}`))
|
|
384
364
|
|
|
385
365
|
resolve(null)
|
|
386
366
|
}) // Promise
|
|
@@ -409,25 +389,22 @@ scimgateway.modifyGroup = async (baseEntity, id, attrObj, ctx) => {
|
|
|
409
389
|
// This BLINDLY inserts all user/groups and gracefully breaks on PK violation
|
|
410
390
|
// for each existing membership
|
|
411
391
|
if (Array.isArray(attrObj.members) && attrObj.members) {
|
|
412
|
-
attrObj.members
|
|
392
|
+
for (const member of attrObj.members) {
|
|
413
393
|
if (member.operation == 'delete') {
|
|
414
394
|
queries.push(`delete from [Users2Group] where GroupID='${id}' and UserID='${member.value}'`)
|
|
415
395
|
} else {
|
|
416
396
|
queries.push(`insert into [Users2Group] (UserID, GroupID) values ('${member.value}','${id}')`)
|
|
417
397
|
}
|
|
418
|
-
}
|
|
398
|
+
}
|
|
419
399
|
}
|
|
420
400
|
|
|
421
401
|
const sqlQuery = queries.join(';')
|
|
422
402
|
|
|
423
403
|
try {
|
|
424
|
-
return await new Promise(async (resolve
|
|
404
|
+
return await new Promise(async (resolve) => {
|
|
425
405
|
if (sqlQuery) {
|
|
426
406
|
scimgateway.logDebug(baseEntity, `sqlQuery: ${sqlQuery}`)
|
|
427
|
-
await query(sqlQuery, ctx).catch(
|
|
428
|
-
const e = new Error(`${action} error: ${err.message}`)
|
|
429
|
-
return reject(e)
|
|
430
|
-
})
|
|
407
|
+
await query(sqlQuery, ctx).catch(err => scimgateway.logWarn(baseEntity, `${action} warning: ${err.message}`))
|
|
431
408
|
}
|
|
432
409
|
|
|
433
410
|
resolve(null)
|
package/lib/scimgateway.ts
CHANGED
|
@@ -2367,13 +2367,25 @@ export class ScimGateway {
|
|
|
2367
2367
|
if (!ctx.response.body) ctx.response.body = 'NOT_FOUND'
|
|
2368
2368
|
break
|
|
2369
2369
|
}
|
|
2370
|
-
const
|
|
2371
|
-
if (
|
|
2370
|
+
const body = ctx.response.body
|
|
2371
|
+
if (body) {
|
|
2372
2372
|
try {
|
|
2373
|
-
JSON.parse(
|
|
2374
|
-
response.headers.set('content-type', 'application/scim+json; charset=utf-8')
|
|
2373
|
+
JSON.parse(body)
|
|
2374
|
+
ctx.response.headers.set('content-type', 'application/scim+json; charset=utf-8')
|
|
2375
2375
|
} catch (err) { void 0 }
|
|
2376
2376
|
}
|
|
2377
|
+
let response: Response
|
|
2378
|
+
if (typeof Bun !== 'undefined') {
|
|
2379
|
+
const stream = new ReadableStream({ // ensure Bun compatibility with Azure Reverse Proxy for large and long running response - header set by Bun: Transfer-Encoding: 'chunked'
|
|
2380
|
+
start(controller) {
|
|
2381
|
+
controller.enqueue(body)
|
|
2382
|
+
controller.close()
|
|
2383
|
+
},
|
|
2384
|
+
})
|
|
2385
|
+
response = new Response(body ? stream : undefined, { status: ctx.response.status, headers: ctx.response.headers })
|
|
2386
|
+
} else {
|
|
2387
|
+
response = new Response(body ? body : undefined, { status: ctx.response.status, headers: ctx.response.headers })
|
|
2388
|
+
}
|
|
2377
2389
|
logResult(ctx)
|
|
2378
2390
|
return response
|
|
2379
2391
|
}
|
|
@@ -2698,6 +2710,13 @@ export class ScimGateway {
|
|
|
2698
2710
|
this.logger.info(`${this.pluginName}[${baseEntity}] ${msg}`)
|
|
2699
2711
|
}
|
|
2700
2712
|
|
|
2713
|
+
/**
|
|
2714
|
+
* logWarn logs warning message
|
|
2715
|
+
**/
|
|
2716
|
+
logWarn(baseEntity: string | undefined, msg: string) {
|
|
2717
|
+
this.logger.warn(`${this.pluginName}[${baseEntity}] ${msg}`)
|
|
2718
|
+
}
|
|
2719
|
+
|
|
2701
2720
|
/**
|
|
2702
2721
|
* logError logs error message
|
|
2703
2722
|
**/
|
package/package.json
CHANGED