scimgateway 5.1.5 → 5.1.7
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 +215 -81
- package/bun.lock +58 -36
- package/lib/helper-rest.ts +85 -72
- package/lib/scimgateway.ts +14 -10
- package/package.json +10 -10
package/README.md
CHANGED
|
@@ -196,7 +196,8 @@ For Node.js (and also Bun), we might set the property `scimgateway_postinstall_s
|
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
|
|
199
|
-
Each endpoint plugin needs a TypeScript file (.ts) and a configuration file (.json).
|
|
199
|
+
Each endpoint plugin needs a TypeScript file (.ts) and a configuration file (.json).
|
|
200
|
+
**They both must have the same naming prefix**. For SAP Hana endpoint we have:
|
|
200
201
|
>lib\plugin-saphana.ts
|
|
201
202
|
>config\plugin-saphana.json
|
|
202
203
|
|
|
@@ -410,7 +411,7 @@ Definitions in `endpoint` object are customized according to our plugin code. Pl
|
|
|
410
411
|
"certificate": {
|
|
411
412
|
"key": "key.pem",
|
|
412
413
|
"cert": "cert.pem",
|
|
413
|
-
"ca":
|
|
414
|
+
"ca": "ca.pem" // if several: "ca": ["ca1.pem", "ca2.pem"]
|
|
414
415
|
}
|
|
415
416
|
|
|
416
417
|
Example of how to make a self signed certificate:
|
|
@@ -465,7 +466,7 @@ Definitions in `endpoint` object are customized according to our plugin code. Pl
|
|
|
465
466
|
|
|
466
467
|
- **endpoint** - Contains endpoint specific configuration according to customized **plugin code**.
|
|
467
468
|
|
|
468
|
-
|
|
469
|
+
### Configuration notes - general
|
|
469
470
|
|
|
470
471
|
- Custom Schemas, ServiceProviderConfig and ResourceType can be used if `./lib/scimdef-v2.json or scimdef-v1.json` exists. Original scimdef-v2.json/scimdef-v1.json can be copied from node_modules/scimgateway/lib to your plugin/lib and customized.
|
|
471
472
|
- Using reverse proxy and we want ipAllowList and correct meta.location response, following headers must be set by proxy: `X-Forwarded-For`, `X-Forwarded-Proto` and `X-Forwarded-Host`
|
|
@@ -521,88 +522,204 @@ Definitions in `endpoint` object are customized according to our plugin code. Pl
|
|
|
521
522
|
"plugin-soap.endpoint.password": "secret"
|
|
522
523
|
}
|
|
523
524
|
|
|
525
|
+
### Configuration notes - Email, using Microsoft Exchange Online (ExO)
|
|
524
526
|
|
|
525
|
-
-
|
|
526
|
-
|
|
527
|
-
- Entra ID application must have application permissions `Mail.Send`
|
|
528
|
-
- To prevent the sending of emails from any defined mailboxes, an ExO `ApplicationAccessPolicy` must be defined through PowerShell.
|
|
529
|
-
|
|
530
|
-
First create a mail-enabled security-group that only includes those users (mailboxes) the application is allowed to send from
|
|
531
|
-
Note, `mail enabled security group` cannot be created from portal, only from admin or admin.exchange console
|
|
532
|
-
|
|
533
|
-
##Connect to Exchange
|
|
534
|
-
Install-Module -Name ExchangeOnlineManagement
|
|
535
|
-
Connect-ExchangeOnline
|
|
536
|
-
|
|
537
|
-
##Create ApplicationAccessPolicy
|
|
538
|
-
New-ApplicationAccessPolicy -AppId <AppClientID> -PolicyScopeGroupId <MailEnabledSecurityGrpId> -AccessRight RestrictAccess -Description "Restrict app to specific mailboxes"
|
|
539
|
-
|
|
540
|
-
- Email, using Google Workspace Gmail
|
|
541
|
-
|
|
542
|
-
- https://console.cloud.google.com
|
|
543
|
-
- IAM & Admin > Service Accounts > Create Service Account
|
|
544
|
-
- Name=email-sender
|
|
545
|
-
- Create and Continue
|
|
546
|
-
- Grant this service account access to project - not needed
|
|
547
|
-
- Grant users access to this service - not needed
|
|
548
|
-
- IAM & Admin > Service Accounts > "email-sender" account > Keys
|
|
549
|
-
- Add Key > Create new key > JSON
|
|
550
|
-
- download json Service Account Key file, refere to configuration `email.auth.options.serviceAccountKeyFile`
|
|
551
|
-
|
|
552
|
-
- https://admin.google.com
|
|
553
|
-
- Security > Access and data control > API controls
|
|
554
|
-
- Manage Domain Wide Delegation > Add new
|
|
555
|
-
- Client ID = id of service account created
|
|
556
|
-
- OAuth scope = `https://www.googleapis.com/auth/gmail.send`
|
|
557
|
-
|
|
558
|
-
- https://admin.google.com
|
|
559
|
-
- Billing > Subscriptions - verify Google Workspace license
|
|
560
|
-
- Directory > Users > "user"
|
|
561
|
-
- Licenses > Edit > enable Google Workspace license
|
|
562
|
-
`email.emailOnError.from` mail address must have Google Workspace license
|
|
563
|
-
|
|
564
|
-
- Gateway chainging and chainingBaseUrl configuration
|
|
565
|
-
|
|
566
|
-
By configuring the `chainingBaseUrl`, it is possible to chain multiple gateways in sequence, such as `gateway1->gateway2->gateway3->endpoint`. In this setup, gateway behave much like a reverse proxy, validating authorization at each step unless PassThrough mode is enabled. Chaining is also supported in stream subscriber mode
|
|
527
|
+
- Entra ID application must have application permissions `Mail.Send`
|
|
528
|
+
- To prevent the sending of emails from any defined mailboxes, an ExO `ApplicationAccessPolicy` must be defined through PowerShell.
|
|
567
529
|
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
530
|
+
First create a mail-enabled security-group that only includes those users (mailboxes) the application is allowed to send from
|
|
531
|
+
Note, `mail enabled security group` cannot be created from portal, only from admin or admin.exchange console
|
|
532
|
+
|
|
533
|
+
##Connect to Exchange
|
|
534
|
+
Install-Module -Name ExchangeOnlineManagement
|
|
535
|
+
Connect-ExchangeOnline
|
|
536
|
+
|
|
537
|
+
##Create ApplicationAccessPolicy
|
|
538
|
+
New-ApplicationAccessPolicy -AppId <AppClientID> -PolicyScopeGroupId <MailEnabledSecurityGrpId> -AccessRight RestrictAccess -Description "Restrict app to specific mailboxes"
|
|
539
|
+
|
|
540
|
+
### Configuration notes - Email, using Google Workspace Gmail
|
|
541
|
+
|
|
542
|
+
- https://console.cloud.google.com
|
|
543
|
+
- IAM & Admin > Service Accounts > Create Service Account
|
|
544
|
+
- Name=email-sender
|
|
545
|
+
- Create and Continue
|
|
546
|
+
- Grant this service account access to project - not needed
|
|
547
|
+
- Grant users access to this service - not needed
|
|
548
|
+
- IAM & Admin > Service Accounts > "email-sender" account > Keys
|
|
549
|
+
- Add Key > Create new key > JSON
|
|
550
|
+
- download json Service Account Key file, refere to configuration `email.auth.options.serviceAccountKeyFile`
|
|
551
|
+
|
|
552
|
+
- https://admin.google.com
|
|
553
|
+
- Security > Access and data control > API controls
|
|
554
|
+
- Manage Domain Wide Delegation > Add new
|
|
555
|
+
- Client ID = id of service account created
|
|
556
|
+
- OAuth scope = `https://www.googleapis.com/auth/gmail.send`
|
|
557
|
+
|
|
558
|
+
- https://admin.google.com
|
|
559
|
+
- Billing > Subscriptions - verify Google Workspace license
|
|
560
|
+
- Directory > Users > "user"
|
|
561
|
+
- Licenses > Edit > enable Google Workspace license
|
|
562
|
+
`email.emailOnError.from` mail address must have Google Workspace license
|
|
563
|
+
|
|
564
|
+
### Configuration notes - Gateway chainging and chainingBaseUrl
|
|
565
|
+
|
|
566
|
+
By configuring the `chainingBaseUrl`, it is possible to chain multiple gateways in sequence, such as `gateway1->gateway2->gateway3->endpoint`. In this setup, gateway behave much like a reverse proxy, validating authorization at each step unless PassThrough mode is enabled. Chaining is also supported in stream subscriber mode
|
|
567
|
+
|
|
568
|
+
{
|
|
569
|
+
"scimgateway": {
|
|
570
|
+
...
|
|
571
|
+
"chainingBaseUrl": "https:\\gateway2:8880",
|
|
572
|
+
...
|
|
573
|
+
"auth": {
|
|
574
|
+
...
|
|
575
|
+
"passThrough": {
|
|
576
|
+
"enabled": false,
|
|
577
|
+
"readOnly": false,
|
|
578
|
+
"baseEntities": []
|
|
579
|
+
}
|
|
583
580
|
...
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
581
|
+
}
|
|
582
|
+
},
|
|
583
|
+
...
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
Using above configuration example on gateway1, incoming requests will be routed to `https:\\gateway2:8880`
|
|
588
|
+
|
|
589
|
+
The plugin and its associated authentication configuration can mirror the setup running on the final gateway. However, in chaining mode, the plugin binary is used solely for initializing and configuring the gateway. This allows for the use of a simplified `plugin-<name>.ts` binary containing only the essential mandatory components:
|
|
588
590
|
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
591
|
+
// start - mandatory plugin initialization
|
|
592
|
+
const ScimGateway: typeof import('scimgateway').ScimGateway = await (async () => {
|
|
593
|
+
try {
|
|
594
|
+
return (await import('scimgateway')).ScimGateway
|
|
595
|
+
} catch (err) {
|
|
596
|
+
const source = './scimgateway.ts'
|
|
597
|
+
return (await import(source)).ScimGateway
|
|
598
|
+
}
|
|
599
|
+
})()
|
|
600
|
+
const scimgateway = new ScimGateway()
|
|
601
|
+
const config = scimgateway.getConfig()
|
|
602
|
+
scimgateway.authPassThroughAllowed = false
|
|
603
|
+
// end - mandatory plugin initialization
|
|
604
|
+
|
|
605
|
+
Using `scimgateway.authPassThroughAllowed = true` and `plugin-<name>.json` configuration `scimgateway.auth.passThrough=true` enables Authentication PassTrhough
|
|
606
|
+
|
|
607
|
+
### Configuration notes - HelperRest used by plugins
|
|
608
|
+
For REST endpoints, plugins may use HelperRest to simplify authentication and communication
|
|
609
|
+
doRequest() executes REST request and return response
|
|
610
|
+
`doRequest(<baseEntity>, <method>, <path>, <body>, <ctx>, <options>)`
|
|
611
|
+
|
|
612
|
+
* baseEntity - 'undefined' if not used and must correspond with endpoint configuration that defines baseUrls and connection options.
|
|
613
|
+
* method - GET, PATCH, PUT, DELETE
|
|
614
|
+
* path - either full url or just the path that will be added to baseUrl. Using full url will override baseUrl. Using path is preferred because of auth caching logic and simplicity
|
|
615
|
+
* body - optional body to be used
|
|
616
|
+
* ctx - optional, passing authorization header if Auth PassThrough is enabled
|
|
617
|
+
* opt - optional, connection options that will extend/override any endpoint.entity.undefined.connection definitions
|
|
618
|
+
|
|
619
|
+
Configuration showing connection settings:
|
|
620
|
+
|
|
621
|
+
{
|
|
622
|
+
"scimgateway": {
|
|
623
|
+
...
|
|
624
|
+
}
|
|
625
|
+
"endpoint": {
|
|
626
|
+
"entity": {
|
|
627
|
+
"undefined": {
|
|
628
|
+
"connection": {
|
|
629
|
+
"baseUrls": [],
|
|
630
|
+
"auth": {
|
|
631
|
+
"type": "xxx",
|
|
632
|
+
"options": {
|
|
633
|
+
...
|
|
634
|
+
"jwtPayload": {},
|
|
635
|
+
"samlPayload": {},
|
|
636
|
+
"tls": {} // files located in ./config/certs
|
|
637
|
+
}
|
|
638
|
+
},
|
|
639
|
+
"options": {
|
|
640
|
+
"headers": {},
|
|
641
|
+
"tls": {} // files located in ./config/certs
|
|
642
|
+
},
|
|
643
|
+
"proxy": {}
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
* baseUrls - Endpoint URL. Several may be defined for failower. There are retry logic on connection failures
|
|
652
|
+
* auth.type - defines authentication being used: `basic`, `oauth`, `token`, `bearer`, `oauthSamlBearer` or `oauthJwtBearer`
|
|
653
|
+
* auth.options - for each valid type there are different options. tenantIdGUID is special for Entra ID and serviceAccountKeyFile is special for Google. Using these will simplify and reduce options to be included. Also note we do not need to include baseUrls when using tenantIdGUID/serviceAccountKeyFile as long as endpoint is Entra ID (Microsoft Graph) or Google.
|
|
654
|
+
|
|
655
|
+
Example using basic auth:
|
|
656
|
+
|
|
657
|
+
"connection": {
|
|
658
|
+
"baseUrls": [
|
|
659
|
+
"https://localhost:8880"
|
|
660
|
+
],
|
|
661
|
+
"auth": {
|
|
662
|
+
"type": "basic",
|
|
663
|
+
"options": {
|
|
664
|
+
"username": "gwadmin",
|
|
665
|
+
"password": "password"
|
|
666
|
+
}
|
|
667
|
+
},
|
|
668
|
+
"options": {
|
|
669
|
+
"tls": {
|
|
670
|
+
"rejectUnauthorized": false,
|
|
671
|
+
"ca": "ca.pem"
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
Example Entra ID (plugin-entra-id) using clientId/clientSecret:
|
|
677
|
+
|
|
678
|
+
"connection": {
|
|
679
|
+
"baseUrls": [],
|
|
680
|
+
"auth": {
|
|
681
|
+
"type": "oauth",
|
|
682
|
+
"options": {
|
|
683
|
+
"tenantIdGUID": "<tenantId>",
|
|
684
|
+
"clientId": "<clientId",
|
|
685
|
+
"clientSecret": "<clientSecret>"
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
Example Entra ID (plugin-entra-id) using certificate secret:
|
|
691
|
+
|
|
692
|
+
"connection": {
|
|
693
|
+
"baseUrls": [],
|
|
694
|
+
"auth": {
|
|
695
|
+
"type": "oauth",
|
|
696
|
+
"options": {
|
|
697
|
+
"tenantIdGUID": "<tenantId>",
|
|
698
|
+
"clientId": "<clientId",
|
|
699
|
+
"tls": {
|
|
700
|
+
"key": "key.pem",
|
|
701
|
+
"cert": "cert.pem"
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
Example using general OAuth:
|
|
708
|
+
|
|
709
|
+
"connection": {
|
|
710
|
+
"baseUrls": [<"endpointUrl">],
|
|
711
|
+
"auth": {
|
|
712
|
+
"type": "oauth",
|
|
713
|
+
"options": {
|
|
714
|
+
"tokenUrl": "<tokenUrl>"
|
|
715
|
+
"clientId": "<clientId",
|
|
716
|
+
"clientSecret": "<clientSecret>"
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
Please see code editor method HelperRest doRequest() IntelliSense for type and option details
|
|
604
722
|
|
|
605
|
-
Using `scimgateway.authPassThroughAllowed = true` and `plugin-<name>.json` configuration `scimgateway.auth.passThrough=true` enables Authentication PassTrhough
|
|
606
723
|
|
|
607
724
|
## Manual startup
|
|
608
725
|
|
|
@@ -1175,6 +1292,23 @@ MIT © [Jarle Elshaug](https://www.elshaug.xyz)
|
|
|
1175
1292
|
|
|
1176
1293
|
## Change log
|
|
1177
1294
|
|
|
1295
|
+
### v5.1.7
|
|
1296
|
+
|
|
1297
|
+
[Fixed]
|
|
1298
|
+
|
|
1299
|
+
- Using gateway certificate CA, the CA did not load correctly. It now also supports an array of multiple CAs.
|
|
1300
|
+
|
|
1301
|
+
[Improved]
|
|
1302
|
+
|
|
1303
|
+
- Dependencies bump
|
|
1304
|
+
|
|
1305
|
+
### v5.1.6
|
|
1306
|
+
|
|
1307
|
+
[Improved]
|
|
1308
|
+
|
|
1309
|
+
- HelperRest, payload/claims configuration now defined in auth.options.jwtPayload and auth.options.samlPayload. Previously all was defiend in auth.options
|
|
1310
|
+
- README configuration notes updated
|
|
1311
|
+
|
|
1178
1312
|
### v5.1.5
|
|
1179
1313
|
|
|
1180
1314
|
[Improved]
|
|
@@ -1205,7 +1339,7 @@ MIT © [Jarle Elshaug](https://www.elshaug.xyz)
|
|
|
1205
1339
|
"options": {
|
|
1206
1340
|
"tenantIdGUID": "Entra ID Tenant ID (GUID)",
|
|
1207
1341
|
"clientId": "<application clientId>",
|
|
1208
|
-
"
|
|
1342
|
+
"tls": { // files located in ./config/certs
|
|
1209
1343
|
"key": "key.pem",
|
|
1210
1344
|
"cert": "cert.pem"
|
|
1211
1345
|
}
|
package/bun.lock
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
"name": "scimgateway",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@ldapjs/asn1": "^2.0.0",
|
|
8
|
-
"@nats-io/jetstream": "^3.0.0-
|
|
9
|
-
"@nats-io/nats-core": "^3.0.0-
|
|
10
|
-
"@nats-io/transport-node": "^3.0.0-
|
|
8
|
+
"@nats-io/jetstream": "^3.0.0-37",
|
|
9
|
+
"@nats-io/nats-core": "^3.0.0-50",
|
|
10
|
+
"@nats-io/transport-node": "^3.0.0-35",
|
|
11
11
|
"@types/ldapjs": "^3.0.6",
|
|
12
12
|
"@types/lokijs": "^1.5.14",
|
|
13
13
|
"@types/tedious": "^4.0.14",
|
|
@@ -18,16 +18,16 @@
|
|
|
18
18
|
"jsonwebtoken": "^9.0.2",
|
|
19
19
|
"ldapjs": "^3.0.7",
|
|
20
20
|
"lokijs": "^1.5.12",
|
|
21
|
-
"mongodb": "^6.
|
|
21
|
+
"mongodb": "^6.13.0",
|
|
22
22
|
"node-machine-id": "1.1.12",
|
|
23
|
-
"nodemailer": "^6.
|
|
23
|
+
"nodemailer": "^6.10.0",
|
|
24
24
|
"passport": "^0.7.0",
|
|
25
25
|
"passport-azure-ad": "^4.3.5",
|
|
26
26
|
"saml": "^3.0.1",
|
|
27
27
|
"winston": "^3.17.0",
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@stylistic/eslint-plugin": "^
|
|
30
|
+
"@stylistic/eslint-plugin": "^3.1.0",
|
|
31
31
|
"@types/bun": "latest",
|
|
32
32
|
"@types/dot-object": "^2.1.6",
|
|
33
33
|
"@types/jsonwebtoken": "^9.0.6",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"@types/nodemailer": "^6.4.14",
|
|
36
36
|
"@types/passport": "^1.0.16",
|
|
37
37
|
"@types/passport-azure-ad": "^4.3.6",
|
|
38
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
39
|
-
"@typescript-eslint/parser": "^8.
|
|
40
|
-
"eslint": "^9.
|
|
38
|
+
"@typescript-eslint/eslint-plugin": "^8.23.0",
|
|
39
|
+
"@typescript-eslint/parser": "^8.23.0",
|
|
40
|
+
"eslint": "^9.20.0",
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"typescript": "^5.0.0",
|
|
@@ -53,17 +53,17 @@
|
|
|
53
53
|
|
|
54
54
|
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="],
|
|
55
55
|
|
|
56
|
-
"@eslint/config-array": ["@eslint/config-array@0.
|
|
56
|
+
"@eslint/config-array": ["@eslint/config-array@0.19.2", "", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w=="],
|
|
57
57
|
|
|
58
|
-
"@eslint/core": ["@eslint/core@0.
|
|
58
|
+
"@eslint/core": ["@eslint/core@0.11.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA=="],
|
|
59
59
|
|
|
60
|
-
"@eslint/eslintrc": ["@eslint/eslintrc@3.
|
|
60
|
+
"@eslint/eslintrc": ["@eslint/eslintrc@3.2.0", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w=="],
|
|
61
61
|
|
|
62
|
-
"@eslint/js": ["@eslint/js@9.
|
|
62
|
+
"@eslint/js": ["@eslint/js@9.20.0", "", {}, "sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ=="],
|
|
63
63
|
|
|
64
|
-
"@eslint/object-schema": ["@eslint/object-schema@2.1.
|
|
64
|
+
"@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="],
|
|
65
65
|
|
|
66
|
-
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.2.
|
|
66
|
+
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.2.5", "", { "dependencies": { "@eslint/core": "^0.10.0", "levn": "^0.4.1" } }, "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A=="],
|
|
67
67
|
|
|
68
68
|
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
|
|
69
69
|
|
|
@@ -91,15 +91,15 @@
|
|
|
91
91
|
|
|
92
92
|
"@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.1.9", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw=="],
|
|
93
93
|
|
|
94
|
-
"@nats-io/jetstream": ["@nats-io/jetstream@3.0.0-
|
|
94
|
+
"@nats-io/jetstream": ["@nats-io/jetstream@3.0.0-37", "", { "dependencies": { "@nats-io/nats-core": "3.0.0-50" } }, "sha512-hnYON3MrHWnEXAqGEoxoQ7TcGp7McqKPtZGKgga2I/R87c5QVOQOxDzP6y5YNiqO+y+nayGUXb3cM4qcYwLBMQ=="],
|
|
95
95
|
|
|
96
|
-
"@nats-io/nats-core": ["@nats-io/nats-core@3.0.0-
|
|
96
|
+
"@nats-io/nats-core": ["@nats-io/nats-core@3.0.0-50", "", { "dependencies": { "@nats-io/nkeys": "2.0.2", "@nats-io/nuid": "2.0.3" } }, "sha512-Kur1/yhzNrpcpu+OhsQ89k9Ge1woEWJd5FV3tpp0BtpRWMlIth3StBiADguynbKSQCkBAOUQ+C0kRnFW8zOIeg=="],
|
|
97
97
|
|
|
98
|
-
"@nats-io/nkeys": ["@nats-io/nkeys@2.0.
|
|
98
|
+
"@nats-io/nkeys": ["@nats-io/nkeys@2.0.2", "", { "dependencies": { "tweetnacl": "^1.0.3" } }, "sha512-0JTyVl9P+UJyjUBDWP9589TuUKXJQ8tDkVRgi02X/MMzW997+4FykirvZEkIe6ZAhiLIBN+NpN8ULMMt6mDrbA=="],
|
|
99
99
|
|
|
100
|
-
"@nats-io/nuid": ["@nats-io/nuid@2.0.
|
|
100
|
+
"@nats-io/nuid": ["@nats-io/nuid@2.0.3", "", {}, "sha512-TpA3HEBna/qMVudy+3HZr5M3mo/L1JPofpVT4t0HkFGkz2Cn9wrlrQC8tvR8Md5Oa9//GtGG26eN0qEWF5Vqew=="],
|
|
101
101
|
|
|
102
|
-
"@nats-io/transport-node": ["@nats-io/transport-node@3.0.0-
|
|
102
|
+
"@nats-io/transport-node": ["@nats-io/transport-node@3.0.0-35", "", { "dependencies": { "@nats-io/nats-core": "3.0.0-50", "@nats-io/nkeys": "2.0.2", "@nats-io/nuid": "2.0.3" } }, "sha512-Mx3y2/m7KAUFQtWx2MO0+kxw5JdtUOpdQMSTuAVYJbT8fXlAawH8It7CESoFaeJjhmQ58Li/gOAf+rDGJAOKGQ=="],
|
|
103
103
|
|
|
104
104
|
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
|
|
105
105
|
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
|
|
108
108
|
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
|
|
109
109
|
|
|
110
|
-
"@stylistic/eslint-plugin": ["@stylistic/eslint-plugin@
|
|
110
|
+
"@stylistic/eslint-plugin": ["@stylistic/eslint-plugin@3.1.0", "", { "dependencies": { "@typescript-eslint/utils": "^8.13.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "estraverse": "^5.3.0", "picomatch": "^4.0.2" }, "peerDependencies": { "eslint": ">=8.40.0" } }, "sha512-pA6VOrOqk0+S8toJYhQGv2MWpQQR0QpeUo9AhNkC49Y26nxBQ/nH1rta9bUU1rPw2fJ1zZEMV5oCX5AazT7J2g=="],
|
|
111
111
|
|
|
112
112
|
"@types/body-parser": ["@types/body-parser@1.19.5", "", { "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg=="],
|
|
113
113
|
|
|
@@ -161,21 +161,21 @@
|
|
|
161
161
|
|
|
162
162
|
"@types/ws": ["@types/ws@8.5.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA=="],
|
|
163
163
|
|
|
164
|
-
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.
|
|
164
|
+
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.23.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.23.0", "@typescript-eslint/type-utils": "8.23.0", "@typescript-eslint/utils": "8.23.0", "@typescript-eslint/visitor-keys": "8.23.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-vBz65tJgRrA1Q5gWlRfvoH+w943dq9K1p1yDBY2pc+a1nbBLZp7fB9+Hk8DaALUbzjqlMfgaqlVPT1REJdkt/w=="],
|
|
165
165
|
|
|
166
|
-
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.
|
|
166
|
+
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.23.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.23.0", "@typescript-eslint/types": "8.23.0", "@typescript-eslint/typescript-estree": "8.23.0", "@typescript-eslint/visitor-keys": "8.23.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-h2lUByouOXFAlMec2mILeELUbME5SZRN/7R9Cw2RD2lRQQY08MWMM+PmVVKKJNK1aIwqTo9t/0CvOxwPbRIE2Q=="],
|
|
167
167
|
|
|
168
|
-
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.
|
|
168
|
+
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.23.0", "", { "dependencies": { "@typescript-eslint/types": "8.23.0", "@typescript-eslint/visitor-keys": "8.23.0" } }, "sha512-OGqo7+dXHqI7Hfm+WqkZjKjsiRtFUQHPdGMXzk5mYXhJUedO7e/Y7i8AK3MyLMgZR93TX4bIzYrfyVjLC+0VSw=="],
|
|
169
169
|
|
|
170
|
-
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.
|
|
170
|
+
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.23.0", "", { "dependencies": { "@typescript-eslint/typescript-estree": "8.23.0", "@typescript-eslint/utils": "8.23.0", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-iIuLdYpQWZKbiH+RkCGc6iu+VwscP5rCtQ1lyQ7TYuKLrcZoeJVpcLiG8DliXVkUxirW/PWlmS+d6yD51L9jvA=="],
|
|
171
171
|
|
|
172
|
-
"@typescript-eslint/types": ["@typescript-eslint/types@8.
|
|
172
|
+
"@typescript-eslint/types": ["@typescript-eslint/types@8.23.0", "", {}, "sha512-1sK4ILJbCmZOTt9k4vkoulT6/y5CHJ1qUYxqpF1K/DBAd8+ZUL4LlSCxOssuH5m4rUaaN0uS0HlVPvd45zjduQ=="],
|
|
173
173
|
|
|
174
|
-
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.
|
|
174
|
+
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.23.0", "", { "dependencies": { "@typescript-eslint/types": "8.23.0", "@typescript-eslint/visitor-keys": "8.23.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "typescript": ">=4.8.4 <5.8.0" } }, "sha512-LcqzfipsB8RTvH8FX24W4UUFk1bl+0yTOf9ZA08XngFwMg4Kj8A+9hwz8Cr/ZS4KwHrmo9PJiLZkOt49vPnuvQ=="],
|
|
175
175
|
|
|
176
176
|
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.13.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "8.13.0", "@typescript-eslint/types": "8.13.0", "@typescript-eslint/typescript-estree": "8.13.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0" } }, "sha512-A1EeYOND6Uv250nybnLZapeXpYMl8tkzYUxqmoKAWnI4sei3ihf2XdZVd+vVOmHGcp3t+P7yRrNsyyiXTvShFQ=="],
|
|
177
177
|
|
|
178
|
-
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.
|
|
178
|
+
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.23.0", "", { "dependencies": { "@typescript-eslint/types": "8.23.0", "eslint-visitor-keys": "^4.2.0" } }, "sha512-oWWhcWDLwDfu++BGTZcmXWqpwtkwb5o7fxUIGksMQQDSdPW9prsSnfIOZMlsj4vBOSrcnjIUZMiIjODgGosFhQ=="],
|
|
179
179
|
|
|
180
180
|
"@xmldom/xmldom": ["@xmldom/xmldom@0.7.13", "", {}, "sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g=="],
|
|
181
181
|
|
|
@@ -241,7 +241,7 @@
|
|
|
241
241
|
|
|
242
242
|
"core-util-is": ["core-util-is@1.0.2", "", {}, "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="],
|
|
243
243
|
|
|
244
|
-
"cross-spawn": ["cross-spawn@7.0.
|
|
244
|
+
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
|
245
245
|
|
|
246
246
|
"debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="],
|
|
247
247
|
|
|
@@ -261,7 +261,7 @@
|
|
|
261
261
|
|
|
262
262
|
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
|
|
263
263
|
|
|
264
|
-
"eslint": ["eslint@9.
|
|
264
|
+
"eslint": ["eslint@9.20.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.19.0", "@eslint/core": "^0.11.0", "@eslint/eslintrc": "^3.2.0", "@eslint/js": "9.20.0", "@eslint/plugin-kit": "^0.2.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.1", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.2.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-aL4F8167Hg4IvsW89ejnpTwx+B/UQRzJPGgbIOl+4XqffWsahVVsLEWoZvnrVuwpWmnRd7XeXmQI1zlKcFDteA=="],
|
|
265
265
|
|
|
266
266
|
"eslint-scope": ["eslint-scope@8.2.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A=="],
|
|
267
267
|
|
|
@@ -411,7 +411,7 @@
|
|
|
411
411
|
|
|
412
412
|
"moment": ["moment@2.30.1", "", {}, "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how=="],
|
|
413
413
|
|
|
414
|
-
"mongodb": ["mongodb@6.
|
|
414
|
+
"mongodb": ["mongodb@6.13.0", "", { "dependencies": { "@mongodb-js/saslprep": "^1.1.9", "bson": "^6.10.1", "mongodb-connection-string-url": "^3.0.0" }, "peerDependencies": { "@aws-sdk/credential-providers": "^3.188.0", "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", "gcp-metadata": "^5.2.0", "kerberos": "^2.0.1", "mongodb-client-encryption": ">=6.0.0 <7", "snappy": "^7.2.2", "socks": "^2.7.1" }, "optionalPeers": ["@aws-sdk/credential-providers", "@mongodb-js/zstd", "gcp-metadata", "kerberos", "mongodb-client-encryption", "snappy", "socks"] }, "sha512-KeESYR5TEaFxOuwRqkOm3XOsMqCSkdeDMjaW5u2nuKfX7rqaofp7JQGoi7sVqQcNJTKuveNbzZtWMstb8ABP6Q=="],
|
|
415
415
|
|
|
416
416
|
"mongodb-connection-string-url": ["mongodb-connection-string-url@3.0.1", "", { "dependencies": { "@types/whatwg-url": "^11.0.2", "whatwg-url": "^13.0.0" } }, "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg=="],
|
|
417
417
|
|
|
@@ -431,7 +431,7 @@
|
|
|
431
431
|
|
|
432
432
|
"node-machine-id": ["node-machine-id@1.1.12", "", {}, "sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ=="],
|
|
433
433
|
|
|
434
|
-
"nodemailer": ["nodemailer@6.
|
|
434
|
+
"nodemailer": ["nodemailer@6.10.0", "", {}, "sha512-SQ3wZCExjeSatLE/HBaXS5vqUOQk6GtBdIIKxiFdmm01mOQZX/POJkO3SUX1wDiYcwUOJwT23scFSC9fY2H8IA=="],
|
|
435
435
|
|
|
436
436
|
"oauth": ["oauth@0.9.15", "", {}, "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA=="],
|
|
437
437
|
|
|
@@ -515,15 +515,13 @@
|
|
|
515
515
|
|
|
516
516
|
"text-hex": ["text-hex@1.0.0", "", {}, "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="],
|
|
517
517
|
|
|
518
|
-
"text-table": ["text-table@0.2.0", "", {}, "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="],
|
|
519
|
-
|
|
520
518
|
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
|
521
519
|
|
|
522
520
|
"tr46": ["tr46@4.1.1", "", { "dependencies": { "punycode": "^2.3.0" } }, "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw=="],
|
|
523
521
|
|
|
524
522
|
"triple-beam": ["triple-beam@1.4.1", "", {}, "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg=="],
|
|
525
523
|
|
|
526
|
-
"ts-api-utils": ["ts-api-utils@
|
|
524
|
+
"ts-api-utils": ["ts-api-utils@2.0.1", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w=="],
|
|
527
525
|
|
|
528
526
|
"tweetnacl": ["tweetnacl@1.0.3", "", {}, "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="],
|
|
529
527
|
|
|
@@ -575,13 +573,23 @@
|
|
|
575
573
|
|
|
576
574
|
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
|
|
577
575
|
|
|
576
|
+
"@eslint/plugin-kit/@eslint/core": ["@eslint/core@0.10.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw=="],
|
|
577
|
+
|
|
578
578
|
"@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="],
|
|
579
579
|
|
|
580
580
|
"@ldapjs/controls/@ldapjs/asn1": ["@ldapjs/asn1@1.2.0", "", {}, "sha512-KX/qQJ2xxzvO2/WOvr1UdQ+8P5dVvuOLk/C9b1bIkXxZss8BaR28njXdPgFCpj5aHaf1t8PmuVnea+N9YG9YMw=="],
|
|
581
581
|
|
|
582
|
+
"@typescript-eslint/eslint-plugin/@typescript-eslint/utils": ["@typescript-eslint/utils@8.23.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "8.23.0", "@typescript-eslint/types": "8.23.0", "@typescript-eslint/typescript-estree": "8.23.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-uB/+PSo6Exu02b5ZEiVtmY6RVYO7YU5xqgzTIVZwTHvvK3HsL8tZZHFaTLFtRG3CsV4A5mhOv+NZx5BlhXPyIA=="],
|
|
583
|
+
|
|
584
|
+
"@typescript-eslint/type-utils/@typescript-eslint/utils": ["@typescript-eslint/utils@8.23.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "8.23.0", "@typescript-eslint/types": "8.23.0", "@typescript-eslint/typescript-estree": "8.23.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-uB/+PSo6Exu02b5ZEiVtmY6RVYO7YU5xqgzTIVZwTHvvK3HsL8tZZHFaTLFtRG3CsV4A5mhOv+NZx5BlhXPyIA=="],
|
|
585
|
+
|
|
582
586
|
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
|
583
587
|
|
|
584
|
-
"@typescript-eslint/
|
|
588
|
+
"@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.13.0", "", { "dependencies": { "@typescript-eslint/types": "8.13.0", "@typescript-eslint/visitor-keys": "8.13.0" } }, "sha512-XsGWww0odcUT0gJoBZ1DeulY1+jkaHUciUq4jKNv4cpInbvvrtDoyBH9rE/n2V29wQJPk8iCH1wipra9BhmiMA=="],
|
|
589
|
+
|
|
590
|
+
"@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.13.0", "", {}, "sha512-4cyFErJetFLckcThRUFdReWJjVsPCqyBlJTi6IDEpc1GWCIIZRFxVppjWLIMcQhNGhdWJJRYFHpHoDWvMlDzng=="],
|
|
591
|
+
|
|
592
|
+
"@typescript-eslint/utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.13.0", "", { "dependencies": { "@typescript-eslint/types": "8.13.0", "@typescript-eslint/visitor-keys": "8.13.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^1.3.0" } }, "sha512-v7SCIGmVsRK2Cy/LTLGN22uea6SaUIlpBcO/gnMGT/7zPtxp90bphcGf4fyrCQl3ZtiBKqVTG32hb668oIYy1g=="],
|
|
585
593
|
|
|
586
594
|
"bun-types/@types/node": ["@types/node@20.12.14", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-scnD59RpYD91xngrQQLGkE+6UrHUPzeKZWhhjBSa3HSkwjbQc38+q3RoIVEwxQGRw3M+j5hpNAM+lgV3cVormg=="],
|
|
587
595
|
|
|
@@ -607,10 +615,24 @@
|
|
|
607
615
|
|
|
608
616
|
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
|
|
609
617
|
|
|
618
|
+
"@typescript-eslint/utils/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.13.0", "", { "dependencies": { "@typescript-eslint/types": "8.13.0", "eslint-visitor-keys": "^3.4.3" } }, "sha512-7N/+lztJqH4Mrf0lb10R/CbI1EaAMMGyF5y0oJvFoAhafwgiRA7TXyd8TFn8FC8k5y2dTsYogg238qavRGNnlw=="],
|
|
619
|
+
|
|
620
|
+
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.13.0", "", { "dependencies": { "@typescript-eslint/types": "8.13.0", "eslint-visitor-keys": "^3.4.3" } }, "sha512-7N/+lztJqH4Mrf0lb10R/CbI1EaAMMGyF5y0oJvFoAhafwgiRA7TXyd8TFn8FC8k5y2dTsYogg238qavRGNnlw=="],
|
|
621
|
+
|
|
622
|
+
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
|
623
|
+
|
|
624
|
+
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/ts-api-utils": ["ts-api-utils@1.4.0", "", { "peerDependencies": { "typescript": ">=4.2.0" } }, "sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ=="],
|
|
625
|
+
|
|
610
626
|
"bun-types/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
|
|
611
627
|
|
|
612
628
|
"color/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
|
|
613
629
|
|
|
614
630
|
"passport-azure-ad/https-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
|
|
631
|
+
|
|
632
|
+
"@typescript-eslint/utils/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
|
|
633
|
+
|
|
634
|
+
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
|
|
635
|
+
|
|
636
|
+
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
|
|
615
637
|
}
|
|
616
638
|
}
|
package/lib/helper-rest.ts
CHANGED
|
@@ -42,7 +42,7 @@ export class HelperRest {
|
|
|
42
42
|
if (this.config_entity[baseEntity]?.connection) {
|
|
43
43
|
connectionFound = true
|
|
44
44
|
const type = this.config_entity[baseEntity].connection?.auth?.type
|
|
45
|
-
if (type === 'oauthJwtBearer' || type === 'oauth') {
|
|
45
|
+
if (type === 'oauthJwtBearer' || type === 'oauth') {
|
|
46
46
|
// set default baseUrls for Entra ID and Google if not already defined
|
|
47
47
|
if (this.config_entity[baseEntity]?.connection?.auth?.options?.tenantIdGUID) { // Entra ID, setting baseUrls to graph
|
|
48
48
|
if (!this.config_entity[baseEntity].connection.baseUrls) {
|
|
@@ -83,29 +83,32 @@ export class HelperRest {
|
|
|
83
83
|
|
|
84
84
|
const action = 'getAccessToken'
|
|
85
85
|
|
|
86
|
+
const serviceAccountKeyFile = this.config_entity[baseEntity]?.connection?.auth?.options?.serviceAccountKeyFile
|
|
87
|
+
const tenantIdGUID = this.config_entity[baseEntity]?.connection?.auth?.options?.tenantIdGUID
|
|
86
88
|
let tokenUrl: string
|
|
87
|
-
let form:
|
|
89
|
+
let form: Record<string, any>
|
|
88
90
|
let resource = ''
|
|
89
91
|
|
|
92
|
+
try {
|
|
93
|
+
const urlObj = new URL(this.config_entity[baseEntity].connection.baseUrls[0])
|
|
94
|
+
resource = urlObj.origin
|
|
95
|
+
} catch (err) { void 0 }
|
|
96
|
+
if (tenantIdGUID) {
|
|
97
|
+
tokenUrl = `https://login.microsoftonline.com/${tenantIdGUID}/oauth2/v2.0/token`
|
|
98
|
+
if (resource) this.config_entity[baseEntity].connection.auth.options.scope = resource + '/.default' // "https://graph.microsoft.com/.default"
|
|
99
|
+
} else tokenUrl = this.config_entity[baseEntity].connection.auth.options.tokenUrl
|
|
100
|
+
|
|
90
101
|
try {
|
|
91
102
|
switch (this.config_entity[baseEntity]?.connection?.auth?.type) {
|
|
92
103
|
case 'oauth':
|
|
93
|
-
try {
|
|
94
|
-
const urlObj = new URL(this.config_entity[baseEntity].connection.baseUrls[0])
|
|
95
|
-
resource = urlObj.origin
|
|
96
|
-
} catch (err) { void 0 }
|
|
97
|
-
if (this.config_entity[baseEntity].connection.auth?.options?.tenantIdGUID) { // Azure
|
|
98
|
-
tokenUrl = `https://login.microsoftonline.com/${this.config_entity[baseEntity].connection.auth.options.tenantIdGUID}/oauth2/token`
|
|
99
|
-
} else {
|
|
100
|
-
tokenUrl = this.config_entity[baseEntity].connection.auth.options.tokenUrl
|
|
101
|
-
}
|
|
102
104
|
form = {
|
|
103
105
|
grant_type: 'client_credentials',
|
|
104
106
|
client_id: this.config_entity[baseEntity].connection.auth.options.clientId,
|
|
105
107
|
client_secret: this.config_entity[baseEntity].connection.auth.options.clientSecret,
|
|
106
|
-
scope: this.config_entity[baseEntity].connection.auth.options.scope || null,
|
|
107
|
-
resource: resource || null, // "https://graph.microsoft.com"
|
|
108
108
|
}
|
|
109
|
+
if (this.config_entity[baseEntity].connection.auth.options.scope) form.scope = this.config_entity[baseEntity].connection.auth.options.scope // required using Entra ID /oauth2/v2.0/token
|
|
110
|
+
if (this.config_entity[baseEntity].connection.auth.options.resource) resource = this.config_entity[baseEntity].connection.auth.options.resource // required using Entra ID /oauth2/token
|
|
111
|
+
|
|
109
112
|
break
|
|
110
113
|
|
|
111
114
|
case 'token':
|
|
@@ -119,23 +122,26 @@ export class HelperRest {
|
|
|
119
122
|
case 'oauthSamlBearer':
|
|
120
123
|
tokenUrl = this.config_entity[baseEntity].connection.auth.options.tokenUrl
|
|
121
124
|
const context = null
|
|
122
|
-
const cert = fs.readFileSync(this.config_entity[baseEntity].connection.auth.options.
|
|
123
|
-
const key = fs.readFileSync(this.config_entity[baseEntity].connection.auth.options.
|
|
124
|
-
|
|
125
|
-
const issuer = `scimgateway/${this.scimgateway.pluginName}`
|
|
126
|
-
const lifetime = 3600
|
|
127
|
-
const clientId = this.config_entity[baseEntity].connection.auth.options.clientId
|
|
128
|
-
const nameId = this.config_entity[baseEntity].connection.auth.options.userId
|
|
129
|
-
const userIdentifierFormat = 'userName'
|
|
125
|
+
const cert = fs.readFileSync(this.config_entity[baseEntity].connection.auth.options.tls.cert).toString()
|
|
126
|
+
const key = fs.readFileSync(this.config_entity[baseEntity].connection.auth.options.tls.key).toString()
|
|
127
|
+
|
|
130
128
|
const tokenEndpoint = tokenUrl
|
|
131
|
-
const audience = `scimgateway/${this.scimgateway.pluginName}`
|
|
132
129
|
const delay = 1
|
|
133
130
|
|
|
131
|
+
// mandatory: clientId, companyId and nameId
|
|
132
|
+
const clientId = this.config_entity[baseEntity].connection.auth.options.samlPayload.clientId
|
|
133
|
+
const companyId = this.config_entity[baseEntity].connection.auth.options.samlPayload.companyId
|
|
134
|
+
const nameId = this.config_entity[baseEntity].connection.auth.options.samlPayload.nameId
|
|
135
|
+
const userIdentifierFormat = this.config_entity[baseEntity].connection.auth.options.samlPayload.userIdentifierFormat || 'userName'
|
|
136
|
+
const lifetime = this.config_entity[baseEntity].connection.auth.options.samlPayload.lifetime || 3600
|
|
137
|
+
const issuer = this.config_entity[baseEntity].connection.auth.options.samlPayload.clientId || `https://scimgateway.${this.scimgateway.pluginName}.com`
|
|
138
|
+
const audience = this.config_entity[baseEntity].connection.auth.options.samlPayload.audience || `scimgateway/${this.scimgateway.pluginName}`
|
|
139
|
+
|
|
134
140
|
form = {
|
|
135
141
|
token_url: tokenUrl,
|
|
136
142
|
grant_type: 'urn:ietf:params:oauth:grant-type:saml2-bearer',
|
|
137
143
|
client_id: clientId,
|
|
138
|
-
company_id:
|
|
144
|
+
company_id: companyId,
|
|
139
145
|
assertion: await samlAssertion.run(context, cert, key, issuer, lifetime, clientId, nameId, userIdentifierFormat, tokenEndpoint, audience, delay),
|
|
140
146
|
}
|
|
141
147
|
break
|
|
@@ -143,25 +149,21 @@ export class HelperRest {
|
|
|
143
149
|
case 'oauthJwtBearer':
|
|
144
150
|
let jwtClaims: jsonwebtoken.JwtPayload | Record<string, any> = {}
|
|
145
151
|
let jwtOpts: jsonwebtoken.SignOptions = {}
|
|
146
|
-
const serviceAccountKeyFile = this.config_entity[baseEntity]?.connection?.auth?.options?.serviceAccountKeyFile
|
|
147
|
-
const tenantIdGUID = this.config_entity[baseEntity]?.connection?.auth?.options?.tenantIdGUID
|
|
148
152
|
|
|
149
|
-
if (tenantIdGUID) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
throw new Error(`auth type '${this.config_entity[baseEntity]?.connection?.auth?.type}' - missing options.certificate.key/cert configuration`)
|
|
153
|
+
if (tenantIdGUID) { // Microsoft Entra ID
|
|
154
|
+
if (!this.config_entity[baseEntity]?.connection?.auth?.options?.tls?.cert) {
|
|
155
|
+
throw new Error(`auth type '${this.config_entity[baseEntity]?.connection?.auth?.type}' - missing options.tls.key/cert configuration`)
|
|
153
156
|
}
|
|
154
|
-
|
|
155
|
-
let
|
|
156
|
-
let cert = this.config_entity[baseEntity]?.connection?.auth?.options?.certificate?._cert || ''
|
|
157
|
+
let privateKey = this.config_entity[baseEntity]?.connection?.auth?.options?.tls?._key || ''
|
|
158
|
+
let cert = this.config_entity[baseEntity]?.connection?.auth?.options?.tls?._cert || ''
|
|
157
159
|
if (!privateKey || !cert) {
|
|
158
|
-
privateKey = fs.readFileSync(this.config_entity[baseEntity].connection.auth.options.
|
|
159
|
-
cert = fs.readFileSync(this.config_entity[baseEntity].connection.auth.options.
|
|
160
|
-
if (privateKey) this.config_entity[baseEntity].connection.auth.options.
|
|
161
|
-
if (cert) this.config_entity[baseEntity].connection.auth.options.
|
|
160
|
+
privateKey = fs.readFileSync(this.config_entity[baseEntity].connection.auth.options.tls.key, 'utf-8') || ''
|
|
161
|
+
cert = fs.readFileSync(this.config_entity[baseEntity].connection.auth.options.tls.cert, 'utf-8') || ''
|
|
162
|
+
if (privateKey) this.config_entity[baseEntity].connection.auth.options.tls._key = privateKey
|
|
163
|
+
if (cert) this.config_entity[baseEntity].connection.auth.options.tls._cert = cert
|
|
162
164
|
}
|
|
163
165
|
if (!privateKey || !cert) {
|
|
164
|
-
throw new Error(`auth type '${this.config_entity[baseEntity]?.connection?.auth?.type}' - missing options.
|
|
166
|
+
throw new Error(`auth type '${this.config_entity[baseEntity]?.connection?.auth?.type}' - missing options.tls.key/cert file content`)
|
|
165
167
|
}
|
|
166
168
|
|
|
167
169
|
const jwtPayload: jsonwebtoken.JwtPayload = {
|
|
@@ -199,23 +201,16 @@ export class HelperRest {
|
|
|
199
201
|
}
|
|
200
202
|
*/
|
|
201
203
|
|
|
202
|
-
let scope = 'https://graph.microsoft.com/.default'
|
|
203
|
-
try {
|
|
204
|
-
const urlObj = new URL(this.config_entity[baseEntity].connection.baseUrls[0])
|
|
205
|
-
scope = urlObj.origin + '/.default' // for application exposed api's and included permissions use: api://${this.config_entity[baseEntity]?.connection?.auth?.options?.clientId}/.default
|
|
206
|
-
} catch (err) { void 0 }
|
|
207
|
-
|
|
208
204
|
form = {
|
|
209
|
-
scope,
|
|
210
205
|
grant_type: 'client_credentials',
|
|
206
|
+
scope: this.config_entity[baseEntity].connection.auth.options.scope, // "https://graph.microsoft.com/.default"
|
|
211
207
|
client_id: this.config_entity[baseEntity]?.connection?.auth?.options?.clientId,
|
|
212
208
|
client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
|
|
213
209
|
client_assertion: jsonwebtoken.sign(jwtClaims, privateKey, jwtOpts),
|
|
214
210
|
}
|
|
215
|
-
} else if (serviceAccountKeyFile) {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
const err = new Error(`auth type '${this.config_entity[baseEntity]?.connection?.auth?.type}' - using auth.options 'serviceAccountKeyFile' requires mandatory configuration entity.${baseEntity}.connection.auth.options.scope/subject`)
|
|
211
|
+
} else if (serviceAccountKeyFile) { // Google - using Service Account key json-file
|
|
212
|
+
if (!this.config_entity[baseEntity]?.connection?.auth?.options?.jwtPayload?.scope || !this.config_entity[baseEntity]?.connection?.auth?.options?.jwtPayload?.subject) {
|
|
213
|
+
const err = new Error(`auth type '${this.config_entity[baseEntity]?.connection?.auth?.type}' - using auth.options 'serviceAccountKeyFile' requires mandatory configuration entity.${baseEntity}.connection.auth.options.jwtPayload.scope/subject`)
|
|
219
214
|
throw err
|
|
220
215
|
}
|
|
221
216
|
let gkey: Record<string, any> = this.config_entity[baseEntity]?.connection?.auth?.options?._gkey
|
|
@@ -234,7 +229,7 @@ export class HelperRest {
|
|
|
234
229
|
tokenUrl = gkey.token_uri // https://oauth2.googleapis.com/token
|
|
235
230
|
const privateKey = gkey.private_key
|
|
236
231
|
const jwtPayload: jsonwebtoken.JwtPayload = {
|
|
237
|
-
sub: this.config_entity[baseEntity]?.connection?.auth?.options?.subject, //
|
|
232
|
+
sub: this.config_entity[baseEntity]?.connection?.auth?.options?.jwtPayload?.subject, // gmail sender mail-address: noreply@mycompany.com
|
|
238
233
|
iss: gkey.client_email, // service account email/user
|
|
239
234
|
aud: gkey.token_uri,
|
|
240
235
|
iat: Math.floor(Date.now() / 1000) - 60, // issued at
|
|
@@ -242,7 +237,7 @@ export class HelperRest {
|
|
|
242
237
|
}
|
|
243
238
|
jwtClaims = {
|
|
244
239
|
...jwtPayload,
|
|
245
|
-
scope: this.config_entity[baseEntity]?.connection?.auth?.options?.scope, // https://www.googleapis.com/auth/gmail.send
|
|
240
|
+
scope: this.config_entity[baseEntity]?.connection?.auth?.options?.jwtPayload?.scope, // https://www.googleapis.com/auth/gmail.send
|
|
246
241
|
}
|
|
247
242
|
jwtOpts = {
|
|
248
243
|
algorithm: 'RS256',
|
|
@@ -257,23 +252,23 @@ export class HelperRest {
|
|
|
257
252
|
assertion: jsonwebtoken.sign(jwtClaims, privateKey, jwtOpts),
|
|
258
253
|
}
|
|
259
254
|
} else {
|
|
260
|
-
// standard JWT - requires all configuation: tokenUrl,
|
|
255
|
+
// standard JWT - requires all configuation: tokenUrl, jwtPayload and tls.key
|
|
261
256
|
if (!this.config_entity[baseEntity]?.connection?.auth?.options?.tokenUrl
|
|
262
|
-
|| !this.config_entity[baseEntity]?.connection?.auth?.options?.
|
|
263
|
-
|| typeof this.config_entity[baseEntity]?.connection?.auth?.options?.
|
|
264
|
-
throw new Error(`auth.type '${this.config_entity[baseEntity]?.connection?.auth?.type}' (no tenantIdGUID/serviceAccountKeyFile using raw) - missing configuration entity.${baseEntity}.connection.auth.options.tokenUrl/
|
|
257
|
+
|| !this.config_entity[baseEntity]?.connection?.auth?.options?.jwtPayload
|
|
258
|
+
|| typeof this.config_entity[baseEntity]?.connection?.auth?.options?.jwtPayload !== 'object') {
|
|
259
|
+
throw new Error(`auth.type '${this.config_entity[baseEntity]?.connection?.auth?.type}' (no tenantIdGUID/serviceAccountKeyFile using raw) - missing configuration entity.${baseEntity}.connection.auth.options.tokenUrl/jwtPayload`)
|
|
265
260
|
}
|
|
266
|
-
if (!this.config_entity[baseEntity]?.connection?.auth?.options?.
|
|
267
|
-
throw new Error(`auth type '${this.config_entity[baseEntity]?.connection?.auth?.type}' (no tenantIdGUID/serviceAccountKeyFile using raw) - missing options.
|
|
261
|
+
if (!this.config_entity[baseEntity]?.connection?.auth?.options?.tls?.key) {
|
|
262
|
+
throw new Error(`auth type '${this.config_entity[baseEntity]?.connection?.auth?.type}' (no tenantIdGUID/serviceAccountKeyFile using raw) - missing options.tls.key configuration`)
|
|
268
263
|
}
|
|
269
264
|
tokenUrl = this.config_entity[baseEntity].connection.auth.options.tokenUrl
|
|
270
|
-
let privateKey = this.config_entity[baseEntity]?.connection?.auth?.options?.
|
|
265
|
+
let privateKey = this.config_entity[baseEntity]?.connection?.auth?.options?.tls?._key || ''
|
|
271
266
|
if (!privateKey) {
|
|
272
|
-
privateKey = fs.readFileSync(this.config_entity[baseEntity].connection.auth.options.
|
|
273
|
-
if (privateKey) this.config_entity[baseEntity].connection.auth.options.
|
|
267
|
+
privateKey = fs.readFileSync(this.config_entity[baseEntity].connection.auth.options.tls.key, 'utf-8') || ''
|
|
268
|
+
if (privateKey) this.config_entity[baseEntity].connection.auth.options.tls._key = privateKey
|
|
274
269
|
}
|
|
275
270
|
|
|
276
|
-
let jwtPayload = this.config_entity[baseEntity].connection.auth.options.
|
|
271
|
+
let jwtPayload = this.config_entity[baseEntity].connection.auth.options.jwtPayload
|
|
277
272
|
if (!jwtPayload.iat) jwtPayload.iat = Math.floor(Date.now() / 1000) - 60
|
|
278
273
|
if (!jwtPayload.exp) jwtPayload.exp = Math.floor(Date.now() / 1000) + 3600
|
|
279
274
|
|
|
@@ -419,6 +414,18 @@ export class HelperRest {
|
|
|
419
414
|
org = utils.extendObj(org, opt.connection)
|
|
420
415
|
}
|
|
421
416
|
|
|
417
|
+
// may use configuration type='oauth' and auto corrected to 'oauthJwtBearer'
|
|
418
|
+
if (this.config_entity[baseEntity]?.connection?.auth?.type == 'oauth') {
|
|
419
|
+
if (this.config_entity[baseEntity].connection.auth?.options?.tenantIdGUID) {
|
|
420
|
+
if (this.config_entity[baseEntity].connection.auth.options?.tls?.cert
|
|
421
|
+
&& this.config_entity[baseEntity].connection.auth.options?.tls?.key
|
|
422
|
+
&& this.config_entity[baseEntity].connection.auth.options.clientId
|
|
423
|
+
) this.config_entity[baseEntity].connection.auth.type = 'oauthJwtBearer'
|
|
424
|
+
} else if (this.config_entity[baseEntity]?.connection?.auth?.options?.serviceAccountKeyFile) {
|
|
425
|
+
this.config_entity[baseEntity].connection.auth.type = 'oauthJwtBearer'
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
422
429
|
switch (this.config_entity[baseEntity]?.connection?.auth?.type) {
|
|
423
430
|
case 'basic':
|
|
424
431
|
if (!this.config_entity[baseEntity]?.connection?.auth?.options?.username || !this.config_entity[baseEntity]?.connection?.auth?.options?.password) {
|
|
@@ -451,9 +458,9 @@ export class HelperRest {
|
|
|
451
458
|
param.options.headers['Authorization'] = 'Bearer ' + Buffer.from(this.config_entity[baseEntity].connection.auth.options.token).toString('base64')
|
|
452
459
|
break
|
|
453
460
|
case 'oauthSamlBearer':
|
|
454
|
-
if (!this.config_entity[baseEntity]?.connection?.auth?.options?.clientId || !this.config_entity[baseEntity]?.connection?.auth?.options?.companyId
|
|
455
|
-
|| !this.config_entity[baseEntity]?.connection?.auth?.options?.
|
|
456
|
-
const err = new Error(`auth.type 'oauthSamlBearer' - missing configuration entity.${baseEntity}.connection.auth.options
|
|
461
|
+
if (!this.config_entity[baseEntity]?.connection?.auth?.options?.samlPayload?.clientId || !this.config_entity[baseEntity]?.connection?.auth?.options?.samlPayload?.companyId
|
|
462
|
+
|| !this.config_entity[baseEntity]?.connection?.auth?.options?.tls?.key) {
|
|
463
|
+
const err = new Error(`auth.type 'oauthSamlBearer' - missing configuration entity.${baseEntity}.connection.auth.options.tls and/or options.samlPayload.clientId/companyId`)
|
|
457
464
|
throw err
|
|
458
465
|
}
|
|
459
466
|
param.accessToken = await this.getAccessToken(baseEntity, ctx)
|
|
@@ -462,7 +469,7 @@ export class HelperRest {
|
|
|
462
469
|
case 'oauthJwtBearer':
|
|
463
470
|
// auth.options.tenantIdGUID => Microsoft Entra ID
|
|
464
471
|
// auth.options.serviceAccountKeyFile => Google Service Account
|
|
465
|
-
// also support custom using tokenUrl/
|
|
472
|
+
// also support custom using tokenUrl/jwtPayload
|
|
466
473
|
param.accessToken = await this.getAccessToken(baseEntity, ctx)
|
|
467
474
|
param.options.headers['Authorization'] = `Bearer ${param.accessToken.access_token}`
|
|
468
475
|
break
|
|
@@ -764,7 +771,7 @@ export class HelperRest {
|
|
|
764
771
|
* ```
|
|
765
772
|
* type defines authentication being used
|
|
766
773
|
* if type not defined, no authentication used
|
|
767
|
-
* valid type is: `basic`, `oauth`, `token`, `bearer` or `
|
|
774
|
+
* valid type is: `basic`, `oauth`, `token`, `bearer`, `oauthSamlBearer` or `oauthJwtBearer`
|
|
768
775
|
*
|
|
769
776
|
* for each valid type there are different auth.options
|
|
770
777
|
*
|
|
@@ -815,10 +822,16 @@ export class HelperRest {
|
|
|
815
822
|
* {
|
|
816
823
|
* "options": {
|
|
817
824
|
* "tokenUrl": "<tokenUrl>",
|
|
818
|
-
* "
|
|
819
|
-
*
|
|
820
|
-
*
|
|
821
|
-
*
|
|
825
|
+
* "samlPayload": {
|
|
826
|
+
* "clientId": "<clientId>",
|
|
827
|
+
* "companyId": "<companyId>",
|
|
828
|
+
* "nameId": "<nameId>",
|
|
829
|
+
* "lifetime": "<optional>"
|
|
830
|
+
* "issuer": "<optional>",
|
|
831
|
+
* "userIdentifierFormat": "<optional>",
|
|
832
|
+
* "audience": "<optional>"
|
|
833
|
+
* },
|
|
834
|
+
* "tls": {
|
|
822
835
|
* "key": "<key-file-name>", // location: config/certs
|
|
823
836
|
* "cert": "<cert-file-name>", // location: config/certs
|
|
824
837
|
* }
|
|
@@ -833,7 +846,7 @@ export class HelperRest {
|
|
|
833
846
|
* "options": {
|
|
834
847
|
* "tenantIdGUID": "<Entra ID tenantIdGUID", // Entra ID authentication, if baseUrls not defined, baseUrls automatically set to [https://graph.microsoft.com/beta]
|
|
835
848
|
* "clientId": "<clientId>",
|
|
836
|
-
* "
|
|
849
|
+
* "tls": { // files located in ./config/certs
|
|
837
850
|
* "key": "key.pem",
|
|
838
851
|
* "cert": "cert.pem"
|
|
839
852
|
* }
|
|
@@ -853,10 +866,10 @@ export class HelperRest {
|
|
|
853
866
|
* {
|
|
854
867
|
* "options": {
|
|
855
868
|
* "tokenUrl": "<tokenUrl",
|
|
856
|
-
* "
|
|
869
|
+
* "tls": {
|
|
857
870
|
* "key": "<signing-key-file-name>" // key.pem file located in ./config/certs
|
|
858
871
|
* },
|
|
859
|
-
* "
|
|
872
|
+
* "jwtPayload": {
|
|
860
873
|
* "sub": "<subject>",
|
|
861
874
|
* "iss": "<issuer>",
|
|
862
875
|
* "aud": "<audience>",
|
package/lib/scimgateway.ts
CHANGED
|
@@ -2290,14 +2290,20 @@ export class ScimGateway {
|
|
|
2290
2290
|
hostname = 'localhost'
|
|
2291
2291
|
}
|
|
2292
2292
|
try {
|
|
2293
|
-
// using fs.readFileSync() instead of Bun.file() for nodejs
|
|
2293
|
+
// using fs.readFileSync() instead of Bun.file() for nodejs compatibility
|
|
2294
2294
|
if (this.config.scimgateway?.certificate?.key && this.config.scimgateway?.certificate?.cert) {
|
|
2295
2295
|
// TLS
|
|
2296
2296
|
tls.key = this.config.scimgateway.certificate.key ? fs.readFileSync(this.config.scimgateway.certificate.key) : undefined
|
|
2297
2297
|
tls.cert = this.config.scimgateway.certificate.cert ? fs.readFileSync(this.config.scimgateway.certificate.cert) : undefined
|
|
2298
|
-
|
|
2298
|
+
if (this.config.scimgateway?.certificate?.ca) {
|
|
2299
|
+
if (Array.isArray(this.config.scimgateway.certificate.ca)) {
|
|
2300
|
+
for (let i = 0; i < this.config.scimgateway.certificate.ca.length; i++) {
|
|
2301
|
+
this.config.scimgateway.certificate.ca[i] = fs.readFileSync(this.config.scimgateway.certificate.ca[i])
|
|
2302
|
+
}
|
|
2303
|
+
} else tls.ca = fs.readFileSync(this.config.scimgateway.certificate.ca)
|
|
2304
|
+
}
|
|
2299
2305
|
} else if (this.config.scimgateway?.certificate?.pfx && this.config.scimgateway?.certificate?.pfx?.bundle) {
|
|
2300
|
-
//
|
|
2306
|
+
// TODO: PFX/PKC#12 currently not supported by Bun
|
|
2301
2307
|
tls.pfx = this.config.scimgateway.certificate.pfx.bundle ? fs.readFileSync(this.config.scimgateway.certificate.pfx.bundle) : undefined
|
|
2302
2308
|
tls.passphrase = this.config.scimgateway.certificate.pfx.password ? utils.getSecret('scimgateway.certificate.pfx.password', this.configFile) : undefined
|
|
2303
2309
|
}
|
|
@@ -2538,12 +2544,12 @@ export class ScimGateway {
|
|
|
2538
2544
|
isMailLock = false
|
|
2539
2545
|
}, (this.config.scimgateway.email.emailOnError.sendInterval || 15) * 1000 * 60)
|
|
2540
2546
|
|
|
2541
|
-
const msgHtml = `<html><body><pre style="font-family: monospace; white-space: pre-wrap;">${msg}</pre><br/><p
|
|
2547
|
+
const msgHtml = `<html><body><pre style="font-family: monospace; white-space: pre-wrap;">${msg}</pre><br/><p>This is an automatically generated email - please do NOT reply to this email</p></body></html>`
|
|
2542
2548
|
const msgObj = {
|
|
2543
2549
|
from: this.config.scimgateway.email.emailOnError.from,
|
|
2544
2550
|
to: this.config.scimgateway.email.emailOnError.to,
|
|
2545
2551
|
cc: this.config.scimgateway.email.emailOnError.cc,
|
|
2546
|
-
subject: this.config.scimgateway.email.emailOnError.subject
|
|
2552
|
+
subject: this.config.scimgateway.email.emailOnError.subject || 'SCIM Gateway error message',
|
|
2547
2553
|
content: msgHtml,
|
|
2548
2554
|
}
|
|
2549
2555
|
this.sendMail(msgObj, true)
|
|
@@ -2870,9 +2876,7 @@ export class ScimGateway {
|
|
|
2870
2876
|
|
|
2871
2877
|
const path = `/users/${msgObj.from}/sendMail`
|
|
2872
2878
|
try {
|
|
2873
|
-
|
|
2874
|
-
await this.helperRest.doRequest('undefined', 'POST', path, emailMessage, null, { connection: { auth: { type: 'oauthJwtBearer' } } })
|
|
2875
|
-
} else await this.helperRest.doRequest('undefined', 'POST', path, emailMessage)
|
|
2879
|
+
await this.helperRest.doRequest('undefined', 'POST', path, emailMessage)
|
|
2876
2880
|
logger.debug(`${gwName}[${pluginName}] sendMail subject '${msgObj.subject}' sent to: ${msgObj.to}${(msgObj.cc) ? ',' + msgObj.cc : ''}`)
|
|
2877
2881
|
} catch (err: any) {
|
|
2878
2882
|
logger.error(`${gwName}[${pluginName}] sendMail subject '${msgObj.subject}' sending failed: ${err.message}`)
|
|
@@ -2894,7 +2898,7 @@ Content-Transfer-Encoding: quoted-printable
|
|
|
2894
2898
|
const emailMessage = { raw: encodedMessage }
|
|
2895
2899
|
const path = `/gmail/v1/users/${msgObj.from}/messages/send`
|
|
2896
2900
|
try { // using opt connection argument type=oauthJwtBearer and options scope/subject because we want to keep simplified email.auth.type=oauth and options serviceAccountKeyFile
|
|
2897
|
-
await this.helperRest.doRequest('undefined', 'POST', path, emailMessage, null, { connection: { auth: { type: 'oauthJwtBearer', options: { scope: 'https://www.googleapis.com/auth/gmail.send', subject: msgObj.from } } } })
|
|
2901
|
+
await this.helperRest.doRequest('undefined', 'POST', path, emailMessage, null, { connection: { auth: { type: 'oauthJwtBearer', options: { jwtPayload: { scope: 'https://www.googleapis.com/auth/gmail.send', subject: msgObj.from } } } } })
|
|
2898
2902
|
logger.debug(`${gwName}[${pluginName}] sendMail subject '${msgObj.subject}' sent to: ${msgObj.to}${(msgObj.cc) ? ',' + msgObj.cc : ''}`)
|
|
2899
2903
|
} catch (err: any) {
|
|
2900
2904
|
logger.error(`${gwName}[${pluginName}] sendMail subject '${msgObj.subject}' sending failed: ${err.message}`)
|
|
@@ -2981,7 +2985,7 @@ Content-Transfer-Encoding: quoted-printable
|
|
|
2981
2985
|
|
|
2982
2986
|
// certificate full path
|
|
2983
2987
|
if (key.includes('.certificate.') || key.includes('.tls.')) {
|
|
2984
|
-
if (key.endsWith('.key') || key.endsWith('.cert') || key.endsWith('.ca') || key.endsWith('.pfx.bundle')) {
|
|
2988
|
+
if (key.endsWith('.key') || key.endsWith('.cert') || key.endsWith('.ca') || key.includes('.ca[') || key.endsWith('.pfx.bundle')) {
|
|
2985
2989
|
let keyFile = path.join(this.configDir, '/certs/', dotConfig[key])
|
|
2986
2990
|
if (dotConfig[key].startsWith('/') || dotConfig[key].includes('\\')) {
|
|
2987
2991
|
keyFile = dotConfig[key]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scimgateway",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Using SCIM protocol as a gateway for user provisioning to other endpoints",
|
|
6
6
|
"author": "Jarle Elshaug <jarle.elshaug@gmail.com> (https://elshaug.xyz)",
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@ldapjs/asn1": "^2.0.0",
|
|
39
|
-
"@nats-io/jetstream": "^3.0.0-
|
|
40
|
-
"@nats-io/nats-core": "^3.0.0-
|
|
41
|
-
"@nats-io/transport-node": "^3.0.0-
|
|
39
|
+
"@nats-io/jetstream": "^3.0.0-37",
|
|
40
|
+
"@nats-io/nats-core": "^3.0.0-50",
|
|
41
|
+
"@nats-io/transport-node": "^3.0.0-35",
|
|
42
42
|
"@types/ldapjs": "^3.0.6",
|
|
43
43
|
"@types/lokijs": "^1.5.14",
|
|
44
44
|
"@types/tedious": "^4.0.14",
|
|
@@ -49,9 +49,9 @@
|
|
|
49
49
|
"jsonwebtoken": "^9.0.2",
|
|
50
50
|
"ldapjs": "^3.0.7",
|
|
51
51
|
"lokijs": "^1.5.12",
|
|
52
|
-
"mongodb": "^6.
|
|
52
|
+
"mongodb": "^6.13.0",
|
|
53
53
|
"node-machine-id": "1.1.12",
|
|
54
|
-
"nodemailer": "^6.
|
|
54
|
+
"nodemailer": "^6.10.0",
|
|
55
55
|
"passport": "^0.7.0",
|
|
56
56
|
"passport-azure-ad": "^4.3.5",
|
|
57
57
|
"saml": "^3.0.1",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"typescript": "^5.0.0"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@stylistic/eslint-plugin": "^
|
|
64
|
+
"@stylistic/eslint-plugin": "^3.1.0",
|
|
65
65
|
"@types/bun": "latest",
|
|
66
66
|
"@types/dot-object": "^2.1.6",
|
|
67
67
|
"@types/jsonwebtoken": "^9.0.6",
|
|
@@ -69,8 +69,8 @@
|
|
|
69
69
|
"@types/nodemailer": "^6.4.14",
|
|
70
70
|
"@types/passport": "^1.0.16",
|
|
71
71
|
"@types/passport-azure-ad": "^4.3.6",
|
|
72
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
73
|
-
"@typescript-eslint/parser": "^8.
|
|
74
|
-
"eslint": "^9.
|
|
72
|
+
"@typescript-eslint/eslint-plugin": "^8.23.0",
|
|
73
|
+
"@typescript-eslint/parser": "^8.23.0",
|
|
74
|
+
"eslint": "^9.20.0"
|
|
75
75
|
}
|
|
76
76
|
}
|