scimgateway 3.2.8 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # SCIM Gateway
2
2
 
3
- [![Build Status](https://travis-ci.com/jelhub/scimgateway.svg)](https://travis-ci.com/jelhub/scimgateway) [![npm Version](https://img.shields.io/npm/v/scimgateway.svg?style=flat-square&label=latest)](https://www.npmjs.com/package/scimgateway)[![npm Downloads](https://img.shields.io/npm/dt/scimgateway.svg?style=flat-square)](https://www.npmjs.com/package/scimgateway) [![chat disqus](https://jelhub.github.io/images/chat.svg)](https://elshaug.xyz/docs/scimgateway#disqus_thread) [![GitHub forks](https://img.shields.io/github/forks/jelhub/scimgateway.svg?style=social&label=Fork)](https://github.com/jelhub/scimgateway)
3
+ [![Build Status](https://app.travis-ci.com/jelhub/scimgateway.svg?branch=master)](https://app.travis-ci.com/github/jelhub/scimgateway) [![npm Version](https://img.shields.io/npm/v/scimgateway.svg?style=flat-square&label=latest)](https://www.npmjs.com/package/scimgateway)[![npm Downloads](https://img.shields.io/npm/dt/scimgateway.svg?style=flat-square)](https://www.npmjs.com/package/scimgateway) [![chat disqus](https://jelhub.github.io/images/chat.svg)](https://elshaug.xyz/docs/scimgateway#disqus_thread) [![GitHub forks](https://img.shields.io/github/forks/jelhub/scimgateway.svg?style=social&label=Fork)](https://github.com/jelhub/scimgateway)
4
4
 
5
5
  ---
6
6
  Author: Jarle Elshaug
@@ -12,13 +12,15 @@ Validated through IdP's:
12
12
  - OneLogin
13
13
  - Okta
14
14
  - Omada
15
+ - SailPoint/IdentityNow
15
16
 
16
17
  Latest news:
17
18
 
19
+ - New major version v4.0.0. getUsers() and getGroups() replacing some deprecated methods. No limitations on filtering/sorting. Admin user access can be limited to specific baseEntities. New MongoDB plugin
18
20
  - ipAllowList for restricting access to allowlisted IP addresses or subnets e.g. Azure AD IP-range
19
- - General LDAP plugin configured for Active Directory.
21
+ - General LDAP plugin configured for Active Directory
20
22
  - [PlugSSO](https://elshaug.xyz/docs/plugsso) using SCIM Gateway
21
- - getUser/getGroup having more flexibility. Auth configuration allowing more than one admin user including option for readOnly
23
+ - Authentication configuration allowing more than one admin user including option for readOnly
22
24
  - Codebase moved from callback of h... to the the promise(d) land of async/await
23
25
  - Supports configuration by environments and external files
24
26
  - Health monitoring through "/ping" URL, and option for error notifications by email
@@ -28,7 +30,7 @@ Latest news:
28
30
 
29
31
  ## Overview
30
32
 
31
- With SCIM Gateway we could do user management by using REST based [SCIM](http://www.simplecloud.info/) 1.1 or 2.0 protocol. Gateway will translate incoming SCIM requests and expose CRUD functionality (create, read, update and delete user/group) towards destinations using endpoint specific protocols. Gateway do not require SCIM to be used, it's also an API Gateway that could be used for other things than user provisioning.
33
+ With SCIM Gateway we could do user management by using REST based [SCIM](http://www.simplecloud.info/) 1.1 or 2.0 protocol. Gateway will translate incoming SCIM requests and expose CRUD functionality (create, read, update and delete user/group) towards destinations using endpoint specific protocols. In other words, none SCIM-endpoints will become SCIM-endpoints. Gateway do not require SCIM to be used, it's also an API Gateway that could be used for other things than user provisioning.
32
34
 
33
35
  SCIM Gateway is a standalone product, however this document shows how the gateway could be used by products like Symatec/Broadcom/CA Identity Manager.
34
36
 
@@ -43,13 +45,17 @@ SCIM Gateway is based on the popular asynchronous event driven framework [Node.j
43
45
  **Following example plugins are included:**
44
46
 
45
47
  * **Loki** (NoSQL Document-Oriented Database)
46
- Gives a SCIM endpoint located on SCIM Gateway
48
+ SCIM Gateway becomes a standalone SCIM endpoint
47
49
  Demonstrates user provisioning towards document-oriented database
48
- Using [LokiJS](http://lokijs.org) for a fast, in-memory document-oriented database (much like MongoDB/PouchDB)
50
+ Using [LokiJS](https://github.com/techfort/LokiJS) for a fast, in-memory document-oriented database (much like MongoDB/PouchDB)
49
51
  Default gives two predefined test users loaded using in-memory only (no persistence)
50
52
  Setting `{"persistence": true}` gives persistence file store (no test users)
51
53
  Example of a fully functional SCIM Gateway plugin
52
54
 
55
+ * **MongoDB** (NoSQL Document-Oriented Database)
56
+ Same as plugin "Loki" but using MongoDB
57
+ Shows how to implement a highly configurable multi tenant or multi endpoint solution through `baseEntity` in URL
58
+
53
59
  * **RESTful** (REST Webservice)
54
60
  Demonstrates user provisioning towards REST-Based endpoint
55
61
  Using plugin "Loki" as a REST endpoint
@@ -57,7 +63,7 @@ Using plugin "Loki" as a REST endpoint
57
63
  * **Forwardinc** (SOAP Webservice)
58
64
  Demonstrates user provisioning towards SOAP-Based endpoint
59
65
  Using endpoint Forwardinc that comes with Broadcom/CA IM SDK (SDKWS) - [wiki.ca.com](https://docops.ca.com/ca-identity-manager/12-6-8/EN/programming/connector-programming-reference/sdk-sample-connectors/sdkws-sdk-web-services-connector/sdkws-sample-connector-build-requirements "wiki.ca.com")
60
- Shows how to implement a highly configurable multi tenant or multi endpoint solution using `baseEntity` parameter
66
+ Shows how to implement a highly configurable multi tenant or multi endpoint solution through `baseEntity` in URL
61
67
 
62
68
  * **MSSQL** (MSSQL Database)
63
69
  Demonstrates user provisioning towards MSSQL database
@@ -69,7 +75,7 @@ Demonstrates SAP HANA specific user provisioning
69
75
  Azure AD user provisioning including Azure license management (App Service plans) e.g. Office 365
70
76
  Using Microsoft Graph API
71
77
  Using customized SCIM attributes according to Microsoft Graph API
72
- Includes CA ConnectorXpress metafile for creating CA IM "Azure - ScimGateway" endpoint type
78
+ Includes Symantec/Broadcom/CA ConnectorXpress metafile for creating provisioning "Azure - ScimGateway" endpoint type
73
79
 
74
80
  * **LDAP** (Directory)
75
81
  Fully functional LDAP plugin
@@ -100,16 +106,13 @@ Create your own package directory e.g. C:\my-scimgateway and install SCIM Gatewa
100
106
  mkdir c:\my-scimgateway
101
107
  cd c:\my-scimgateway
102
108
  npm init -y
103
- npm install scimgateway --save
104
-
105
- Please **ignore any error messages** unless soap WSSecurityCert functionality is needed in your custom plugin code. Module soap installation of optional dependency 'ursa' that also includes 'node-gyp' then needs misc. prerequisites to bee manually installed.
106
-
109
+ npm install scimgateway
107
110
 
108
111
  **c:\\my-scimgateway** will now be `<package-root>`
109
112
 
110
113
  index.js, lib and config directories containing example plugins have been copied to your package from the original scimgateway package located under node_modules.
111
114
 
112
- If internet connection is blocked, we could install on another machine and copy the scimgateway folder.
115
+ If internet connection is blocked, we could install on another machine and copy the `<package-root>` folder.
113
116
 
114
117
 
115
118
  #### Startup and verify default Loki plugin
@@ -132,9 +135,12 @@ If internet connection is blocked, we could install on another machine and copy
132
135
  http://localhost:8880/Groups/Admins
133
136
  => Lists all attributes for specified user/group
134
137
 
138
+ http://localhost:8880/Groups?filter=displayName eq "Admins"&excludedAttributes=members
135
139
  http://localhost:8880/Users?filter=userName eq "bjensen"&attributes=userName,id,name.givenName
136
- http://localhost:8880/Users?filter=emails.value eq "bjensen@example.com"&attributes=userName,phoneNumbers
137
- => Filtering supporting operator 'eq' returning unique object with attributes specified
140
+ http://localhost:8880/Users?filter=meta.created gte "2010-01-01T00:00:00Z"&attributes=userName,name.familyName,meta.created
141
+ http://localhost:8880/Users?filter=emails.value co "@example.com"&attributes=userName,name.familyName,emails&sortBy=name.familyName&sortOrder=descending
142
+ => Filtering examples
143
+
138
144
 
139
145
  "Ctrl + c" to stop the SCIM Gateway
140
146
 
@@ -172,10 +178,11 @@ To force a major upgrade (version x.\*.\* => y.\*.\*) that will brake compabilit
172
178
  **index.js** defines one or more plugins to be started. We could comment out those we do not need. Default configuration only starts the loki plugin.
173
179
 
174
180
  const loki = require('./lib/plugin-loki')
181
+ // const mongodb = require('./lib/plugin-mongodb')
175
182
  // const restful = require('./lib/plugin-restful')
176
183
  // const forwardinc = require('./lib/plugin-forwardinc')
177
184
  // const mssql = require('./lib/plugin-mssql')
178
- // const saphana = require('./lib/plugin-saphana') // prereq: npm install hdb --save
185
+ // const saphana = require('./lib/plugin-saphana') // prereq: npm install hdb
179
186
  // const azureAD = require('./lib/plugin-azure-ad')
180
187
  // const ldap = require('./lib/plugin-ldap')
181
188
  // const api = require('./lib/plugin-api')
@@ -209,18 +216,22 @@ Below shows an example of config\plugin-saphana.json
209
216
  {
210
217
  "username": "gwadmin",
211
218
  "password": "password",
212
- "readOnly": false
219
+ "readOnly": false,
220
+ "baseEntities": []
213
221
  }
214
222
  ],
215
223
  "bearerToken": [
216
224
  {
217
225
  "token": null,
218
- "readOnly": false
226
+ "readOnly": false,
227
+ "baseEntities": []
219
228
  }
220
229
  ],
221
230
  "bearerJwtAzure": [
222
231
  {
223
- "tenantIdGUID": null
232
+ "tenantIdGUID": null,
233
+ "readOnly": false,
234
+ "baseEntities": []
224
235
  }
225
236
  ],
226
237
  "bearerJwt": [
@@ -230,7 +241,8 @@ Below shows an example of config\plugin-saphana.json
230
241
  "options": {
231
242
  "issuer": null
232
243
  },
233
- "readOnly": false
244
+ "readOnly": false,
245
+ "baseEntities": []
234
246
  }
235
247
  ]
236
248
  },
@@ -306,7 +318,10 @@ Definitions in `endpoint` object are customized according to our plugin code. Pl
306
318
 
307
319
  - **log.customMasking** - array of attributes to be masked e.g. `"customMasking": ["SSN", "weight"]`. By default SCIM Gateway includes masking of some standard attributes like password.
308
320
 
309
- - **auth** - Contains one or more authentication/authorization methods used by clients for accessing gateway. **Methods are disabled by setting corresponding attributes to null or remove methods not used**. Methods having user/object set to `"readOnly": true` gives read only access (only allowing `GET` requests for corresponding admin user).
321
+ - **auth** - Contains one or more authentication/authorization methods used by clients for accessing gateway - may also include:
322
+ - **auth.xx.readOnly** - true/false, true gives read only access - only allowing `GET` requests for corresponding admin user
323
+ - **auth.xx.baseEntities** - array containing one or more `baseEntity` allowed for this user e.g. ["client-a"] - empty array allowing all.
324
+ **Methods are disabled by setting corresponding admin user to null or remove methods not used**
310
325
 
311
326
  - **auth.basic** - Array of one ore more basic authentication objects - Basic Authentication with **username**/**password**. Note, we set a clear text password that will become encrypted when gateway is started.
312
327
 
@@ -362,11 +377,6 @@ Definitions in `endpoint` object are customized according to our plugin code. Pl
362
377
  - **emailOnError.smtp.sendInterval** - Mail notifications on error are deferred until sendInterval **minutes** have passed since the last notification. Default 15 minutes
363
378
  - **emailOnError.smtp.to** - Comma separated list of recipients email addresses e.g: "someone@example.com"
364
379
  - **emailOnError.smtp.cc** - Comma separated list of cc email addresses
365
- - **actions** - Pre and post actions onAddGroups/onRemoveGroups. Needed logic to be defined in plugin method `pre_post_Action`
366
- - **actions.preAction.onAddGroups** - Array of groups e.g. ["Admins", "Employees"]
367
- - **actions.preAction.onRemoveGroups** - Array of groups e.g. ["Admins", "Employees"]
368
- - **actions.postAction.onAddGroups** - Array of groups e.g. ["Admins", "Employees"]
369
- - **actions.postAction.onRemoveGroups** - Array of groups e.g. ["Admins", "Employees"]
370
380
 
371
381
  - **endpoint** - Contains endpoint specific configuration according to our **plugin code**.
372
382
 
@@ -531,7 +541,7 @@ docker-compose**
531
541
  mkdir /opt/my-scimgateway
532
542
  cd /opt/my-scimgateway
533
543
  npm init -y
534
- npm install scimgateway --save
544
+ npm install scimgateway
535
545
  cp ./config/docker/* .
536
546
 
537
547
  **docker-compose.yml** <== Here is where you would set the exposed port and environment
@@ -594,6 +604,71 @@ To upgrade scimgateway docker image (remove the old stuff before running docker-
594
604
  docker rm scimgateway
595
605
  docker rm $(docker ps -a -q); docker rmi $(docker images -q -f "dangling=true")
596
606
 
607
+ ## Azure Active Directory as IdP using SCIM Gateway
608
+
609
+ Azure AD could do automatic user provisioning by synchronizing users towards SCIM Gateway, and gateway plugins will update endpoints.
610
+
611
+ Plugin configuration file must include **SCIM Version "2.0"** (scimgateway.scim.version) and either **Bearer Token** (scimgateway.auth.bearerToken[x].token) or **Azure Tenant ID GUID** (scimgateway.auth.bearerJwtAzure[x].tenantIdGUID) or both:
612
+
613
+ scimgateway: {
614
+ "scim": {
615
+ "version": "2.0",
616
+ ...
617
+ },
618
+ ...
619
+ "auth": {
620
+ "bearerToken": [
621
+ {
622
+ "token": "shared-secret"
623
+ }
624
+ ],
625
+ "bearerJwtAzure": [
626
+ {
627
+ "tenantIdGUID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
628
+ }
629
+ ]
630
+ }
631
+ ...
632
+ }
633
+
634
+ `token` configuration must correspond with "Secret Token" defined in Azure AD
635
+ `tenantIdGUID` configuration must correspond with Azure Active Directory Tenant ID
636
+
637
+ In Azure Portal:
638
+ `Azure-Azure Active Directory-Enterprise Application-<My Application>-Provisioning-Secret Token`
639
+ Note, when "Secret Token" is left blank, Azure will use JWT (tenantIdGUID)
640
+
641
+ `Azure-Azure Active Directory-Overview-Tenant ID`
642
+
643
+ User mappings attributes between AD and SCIM also needs to be configured
644
+
645
+ `Azure-Azure Active Directory-Enterprise Application-<My Application>-Provisioning-Edit attribute mappings-Mappings`
646
+
647
+ Azure AD default SCIM attribute mapping for **USER** must have:
648
+
649
+ userPrincipalName mapped to userName (matching precedence #1)
650
+
651
+
652
+ Azure AD default SCIM attribute mapping for **GROUP** must have:
653
+
654
+ displayName mapped to displayName (matching precedence #1)
655
+ members mapped to members
656
+
657
+
658
+
659
+ Some notes related to Azure AD:
660
+
661
+ - Azure Active Directory SCIM [documentation](https://docs.microsoft.com/en-us/azure/active-directory/active-directory-scim-provisioning)
662
+
663
+ - For using OAuth/JWT credentials, Azure configuration "Secret Token" (bearer token) should be blank. Plugin configuration must then include bearerJwtAzure.tenantIdGUID. Click "Test Connection" in Azure to verify
664
+
665
+ - Azure AD do a regular check for a "none" existing user/group. This check seems to be a "keep alive" to verify connection.
666
+
667
+ - Azure AD first checks if user/group exists, if not exist they will be created (no explore of all users like CA Identity Manager)
668
+
669
+ - Deleting a user in Azure AD sends a modify user `{"active":"False"}` which means user should be disabled. This logic is default set in attribute mappings expression rule `Switch([IsSoftDeleted], , "False", "True", "True", "False")`. Standard SCIM "DELETE" method seems not to be used.
670
+
671
+
597
672
  ## CA Identity Manager as IdP using SCIM Gateway
598
673
 
599
674
  Using Symantec/Broadcom/CA Identity Manger, plugin configuration file must include **SCIM Version "1.1"** (scimgateway.scim.version).
@@ -623,82 +698,15 @@ Username, password and port must correspond with plugin configuration file. For
623
698
 
624
699
  "baseEntity" is optional. This is a parameter used for multi tenant or multi endpoint solutions. We could create several endpoints having same base url with unique baseEntity. e.g:
625
700
 
626
- http://localhost:8880/clientA
627
- http://localhost:8880/clientB
701
+ http://localhost:8880/client-a
702
+ http://localhost:8880/client-b
628
703
 
629
704
  Each baseEntity should then be defined in the plugin configuration file with custom attributes needed. Please see examples in plugin-forwardinc.json
630
705
 
631
706
  IM 12.6 SP7 (and above) also supports pagination for SCIM endpoint (data transferred in bulks - endpoint explore of users). Loki plugin supports pagination. Other plugin may ignore this setting.
632
707
 
633
- ## SCIM Gateway REST API
634
-
635
- Create = POST http://localhost:8880/Users
636
- (body contains the user information)
637
-
638
- Update = PATCH http://localhost:8880/Users/<id>
639
- (body contains the attributes to be updated)
640
-
641
- Search/Read = GET http://localhost:8880/Users?userName eq
642
- "userID"&attributes=<comma separated list of scim-schema defined attributes>
643
-
644
- Search/explore all users:
645
- GET http://localhost:8880/Users?attributes=userName
646
-
647
- Delete = DELETE http://localhost:8880/Users/<id>
648
-
649
- Discovery:
650
-
651
- GET http://localhost:8880/ServiceProviderConfigs
652
- Specification compliance, authentication schemes, data models.
653
-
654
- GET http://localhost:8880/Schemas
655
- Introspect resources and attribute extensions.
656
-
657
- Note:
658
-
659
- - userName (mandatory) = UserID
660
- - id (mandatory) = Unique id. Could be set to the same as UserID but don't have to.
661
-
662
- ## SAP Hana endpoint
663
-
664
- Get all users (explore):
665
- select USER_NAME from SYS.USERS where IS_SAML_ENABLED like 'TRUE';
666
-
667
- Get a specific user:
668
- select USER_NAME, USER_DEACTIVATED from SYS.USERS where USER_NAME like '<UserID>';
669
-
670
- Create User:
671
- CREATE USER <UserID> WITH IDENTITY '<UserID>' FOR SAML PROVIDER <SamlProvider>;
672
-
673
- Delete user:
674
- DROP USER <UserID>;
675
-
676
- Modify user (enable user):
677
- ALTER USER <UserID> ACTIVATE;
678
-
679
- Modify user (disable user):
680
- ALTER USER <UserID> DEACTIVATE;
681
-
682
- Postinstallation:
683
-
684
- cd c:\my-scimgateway
685
- npm install hdb --save
686
-
687
-
688
- Only SAML users will be explored and managed
689
-
690
- Supported template attributes:
691
708
 
692
- - User Name (UserID)
693
- - Suspended (Enabled/Disabled)
694
-
695
- Currently no other attributes needed. Trying to update other attributes will then give an error message. **The SCIM Provisioning template should therefore not include any other global user attribute references.**
696
-
697
- SAP Hana converts UserID to uppercase. Provisioning use default lowercase. Provisioning template should therefore also convert to uppercase.
698
-
699
- User Name = %$$TOUPPER(%AC%)%
700
-
701
- ## Azure Active Directory endpoint
709
+ ## Azure Active Directory provisioning
702
710
  Using plugin-azure-ad we could do user provisioning towards Azure AD including license management e.g. O365
703
711
 
704
712
  For testing purposes we could get an Azure free account and in addition the free Office 365 for testing license management through Azure.
@@ -773,7 +781,8 @@ Note, for Symantec/Broadcom/CA Provisioning we have to use SCIM version 1.1
773
781
  {
774
782
  "username": "gwadmin",
775
783
  "password": "password",
776
- "readOnly": false
784
+ "readOnly": false,
785
+ "baseEntities": []
777
786
  }
778
787
  ],
779
788
 
@@ -805,10 +814,10 @@ For multi-tenant or multi-endpoint support, we may add several entities:
805
814
  "undefined": {
806
815
  ...
807
816
  },
808
- "clientA": {
817
+ "client-a": {
809
818
  ...
810
819
  },
811
- "clientB": {
820
+ "client-b": {
812
821
  ...
813
822
  }
814
823
  }
@@ -856,74 +865,39 @@ Endpoint configuration example:
856
865
 
857
866
  For details, please see section "CA Identity Manager as IdP using SCIM Gateway"
858
867
 
868
+ ## SCIM Gateway REST API
869
+
870
+ Create = POST http://localhost:8880/Users
871
+ (body contains the user information)
872
+
873
+ Update = PATCH http://localhost:8880/Users/<id>
874
+ (body contains the attributes to be updated)
875
+
876
+ Search/Read = GET http://localhost:8880/Users?userName eq
877
+ "userID"&attributes=<comma separated list of scim-schema defined attributes>
878
+
879
+ Search/explore all users:
880
+ GET http://localhost:8880/Users?attributes=userName
881
+
882
+ Delete = DELETE http://localhost:8880/Users/<id>
859
883
 
860
- ## Azure Active Directory as IdP using SCIM Gateway
861
-
862
- Azure AD could do automatic user provisioning by synchronizing users towards SCIM Gateway, and gateway plugins will update endpoints.
863
-
864
- Plugin configuration file must include **SCIM Version "2.0"** (scimgateway.scim.version) and either **Bearer Token** (scimgateway.auth.bearerToken[x].token) or **Azure Tenant ID GUID** (scimgateway.auth.bearerJwtAzure[x].tenantIdGUID) or both:
865
-
866
- scimgateway: {
867
- "scim": {
868
- "version": "2.0",
869
- ...
870
- },
871
- ...
872
- "auth": {
873
- "bearerToken": [
874
- {
875
- "token": "shared-secret"
876
- }
877
- ],
878
- "bearerJwtAzure": [
879
- {
880
- "tenantIdGUID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
881
- }
882
- ]
883
- }
884
- ...
885
- }
886
-
887
- `token` configuration must correspond with "Secret Token" defined in Azure AD
888
- `tenantIdGUID` configuration must correspond with Azure Active Directory Tenant ID
889
-
890
- In Azure Portal:
891
- `Azure-Azure Active Directory-Enterprise Application-<My Application>-Provisioning-Secret Token`
892
- Note, when "Secret Token" is left blank, Azure will use JWT (tenantIdGUID)
893
-
894
- `Azure-Azure Active Directory-Overview-Tenant ID`
895
-
896
- User mappings attributes between AD and SCIM also needs to be configured
897
-
898
- `Azure-Azure Active Directory-Enterprise Application-<My Application>-Provisioning-Edit attribute mappings-Mappings`
899
-
900
- Azure AD default SCIM attribute mapping for **USER** must have:
901
-
902
- userPrincipalName mapped to userName (matching precedence #1)
903
-
904
-
905
- Azure AD default SCIM attribute mapping for **GROUP** must have:
906
-
907
- displayName mapped to displayName (matching precedence #1)
908
- members mapped to members
909
-
910
-
911
-
912
- Some notes related to Azure AD:
913
-
914
- - Azure Active Directory SCIM [documentation](https://docs.microsoft.com/en-us/azure/active-directory/active-directory-scim-provisioning)
884
+ Discovery:
915
885
 
916
- - For using OAuth/JWT credentials, Azure configuration "Secret Token" (bearer token) should be blank. Plugin configuration must then include bearerJwtAzure.tenantIdGUID. Click "Test Connection" in Azure to verify
886
+ GET http://localhost:8880/ServiceProviderConfigs
887
+ Specification compliance, authentication schemes, data models.
888
+
889
+ GET http://localhost:8880/Schemas
890
+ Introspect resources and attribute extensions.
917
891
 
918
- - Azure AD do a regular check for a "none" existing user/group. This check seems to be a "keep alive" to verify connection.
892
+ Note:
919
893
 
920
- - Azure AD first checks if user/group exists, if not exist they will be created (no explore of all users like CA Identity Manager)
894
+ - userName (mandatory) = UserID
895
+ - id (mandatory) = Unique id. Could be set to the same as UserID but don't have to.
921
896
 
922
- - Deleting a user in Azure AD sends a modify user `{"active":"False"}` which means user should be disabled. This logic is default set in attribute mappings expression rule `Switch([IsSoftDeleted], , "False", "True", "True", "False")`. Standard SCIM "DELETE" method seems not to be used.
923
897
 
924
898
  ## API Gateway
925
899
 
926
- Gateway also works as an API Gateway when using url `/api` or `/<baseEntity>/api`
900
+ SCIM Gateway also works as an API Gateway when using url `/api` or `/<baseEntity>/api`
927
901
 
928
902
  Following methods for the none SCIM based api-plugin are supported:
929
903
 
@@ -935,7 +909,7 @@ Following methods for the none SCIM based api-plugin are supported:
935
909
  PATCH /api/{id} + body
936
910
  DELETE /api/{id}
937
911
 
938
-
912
+ These methods can also be used in standard SCIM plugins
939
913
  Please see example plugin: **plugin-api.js**
940
914
 
941
915
 
@@ -944,7 +918,7 @@ For JavaScript coding editor you may use [Visual Studio Code](https://code.visua
944
918
 
945
919
  Preparation:
946
920
 
947
- * Copy "best matching" example plugin e.g. `lib\plugin-loki.js` and `config\plugin-loki.json` and rename both copies to your plugin name prefix e.g. plugin-mine.js and plugin-mine.json (for SOAP Webservice endpoint we might use plugin-forwardinc as a template)
921
+ * Copy "best matching" example plugin e.g. `lib\plugin-mssql.js` and `config\plugin-mssql.json` and rename both copies to your plugin name prefix e.g. plugin-mine.js and plugin-mine.json (for SOAP Webservice endpoint we might use plugin-forwardinc as a template)
948
922
  * Edit plugin-mine.json and define a unique port number for the gateway setting
949
923
  * Edit index.js and add a new line for starting your plugin e.g. `let mine = require('./lib/plugin-mine');`
950
924
  * Start SCIM Gateway and verify. If using CA Provisioning you could setup a SCIM endpoint using the port number you defined
@@ -952,20 +926,18 @@ Preparation:
952
926
  Now we are ready for custom coding by editing plugin-mine.js
953
927
  Coding should be done step by step and each step should be verified and tested before starting the next (they are all highlighted by comments in existing code).
954
928
 
955
- 1. **Turn off group functionality** in getGroup, getGroupMembers, getGroupUsers and modifyGroupMembers
956
- Please see callback definitions in plugin-saphana that do not use groups.
957
- 2. **exploreUsers** (test provisioning explore users)
958
- 3. **getUser** (test provisioning retrieve account)
929
+ 1. **Turn off group functionality** - getGroups to return empty response
930
+ Please see plugin-saphana that do not use groups.
931
+ 2. **getUsers** (test provisioning retrieve accounts)
959
932
  4. **createUser** (test provisioning new account)
960
933
  5. **deleteUser** (test provisioning delete account)
961
934
  6. **modifyUser** (test provisioning modify account)
962
- 7. **exploreGroups** (test provisioning explore groups)
963
- 8. **Turn on group functionality** (if supporting groups)
964
- 8. **getGroup** (test provisioning group list groups)
965
- 9. **getGroupMembers** (test provisioning retrieve account - group list groups)
966
- 10. **modifyGroupMembers** (test provisioning retrieve account - group add/remove groups)
967
- 11. **getGroupUsers** (if using "groups member of user")
968
- 12. **createGroup** (test provisioning new group)
935
+ 7. **Turn on group functionality** - getGroups having logic for returning groups if groups are supported
936
+ 7. **getGroups** (test provisioning retrieve groups)
937
+ 8. **modifyGroup** (test provisioning modify group members)
938
+ 12. **createGroup** (test provisioning new group)
939
+ 13. **deleteGroup** (test provisioning delete account)
940
+
969
941
 
970
942
  Template used by CA Provisioning role should only include endpoint supported attributes defined in our plugin. Template should therefore have no links to global user for none supported attributes (e.g. remove %UT% from "Job Title" if our endpoint/code do not support title)
971
943
 
@@ -1035,9 +1007,9 @@ Plugins should have following initialization:
1035
1007
  // mandatory plugin initialization - end
1036
1008
 
1037
1009
 
1038
- ### exploreUsers
1010
+ ### getUsers
1039
1011
 
1040
- scimgateway.exploreUsers = async (baseEntity, attributes, startIndex, count) => {
1012
+ scimgateway.getUsers = async (baseEntity, getObj, attributes) => {
1041
1013
  let ret = {
1042
1014
  "Resources": [],
1043
1015
  "totalResults": null
@@ -1047,54 +1019,15 @@ Plugins should have following initialization:
1047
1019
  }
1048
1020
 
1049
1021
  * baseEntity = Optional for multi-tenant or multi-endpoint support (defined in base url e.g. `<baseurl>/client1` gives baseEntity=client1)
1050
- * startIndex = Pagination - The 1-based index of the first result in the current set of search results
1051
- * count = Pagination - Number of elements to be returned in the current set of search results
1022
+ * getObj = { attribute: <>, operator: <>, value: <>, rawFilter: <>, startIndex: <>, count: <> }
1023
+ * attribute, operator and value are set when using "simpel filtering", e.g. getObj.attribute='userName', getObj.operator='eq' and getObj.value='bjensen', but not for advanced filtering having and/or/not
1024
+ * rawFilter is always set when filtering is used
1025
+ * startIndex = Pagination - The 1-based index of the first result in the current set of search results
1026
+ * count = Pagination - Number of elements to be returned in the current set of search results
1027
+ * attributes = array of attributes to be returned - if empty, all supported attributes should be returned
1052
1028
  * ret:
1053
- ret.Resources = array filled with user objects containing user attributes where userName is mandatory e.g [{"userName":"bjensen"}, {"userName":"jsmith"}]
1054
- ret.totalResults = if supporting pagination, then attribute should be set to the total numbers of elements (users) at the endpoint, else set to null
1055
-
1056
- ### exploreGroups
1057
-
1058
- scimgateway.exploreGroups = async (baseEntity, attributes, startIndex, count) => {
1059
- let ret = {
1060
- "Resources": [],
1061
- "totalResults": null
1062
- }
1063
- ...
1064
- return ret
1065
- }
1066
-
1067
- * ret:
1068
- ret.Resources = array filled with group objects containing group attributes where displayName is mandatory e.g [{"displayName":"Admins"}, {"displayName":"Employees"}]
1069
- ret.totalResults = if supporting pagination attribute should be set to the total numbers of elements (groups) at the endpoint else set to null
1070
-
1071
- ### getUser
1072
-
1073
- scimgateway.getUser = async (baseEntity, getObj, attributes) => {
1074
- ...
1075
- return userObj
1076
- }
1077
-
1078
- * getObj = `{ filter: <filterAttribute>, identifier: <identifier> }`
1079
- e.g: getObj = { "filter": "userName", "identifier": "bjensen"}
1080
- filter: **userName** and **id** must be supported
1081
- * attributes = scim attributes to be returned. If no attributes defined, all should be returned.
1082
- * return userObj: userObj containing scim userattributes/values
1083
- eg:
1084
- {"id":"bjensen","name":{"formatted":"Ms. Barbara J Jensen III","familyName":"Jensen","givenName":"Barbara"}}
1085
-
1086
- Note, the value of the **id** attribute returned will be used by modifyUser and deleteUser
1087
-
1088
- ### createUser
1089
-
1090
- scimgateway.createUser = async (baseEntity, userObj) => {
1091
- ...
1092
- return null
1093
- }
1094
-
1095
- * userObj = user object containing userattributes according to scim standard
1096
- Note, multi-value attributes excluding user attribute 'groups' are customized from array to object based on type
1097
- * return null: null if OK, else throw error
1029
+ ret.Resources = array filled with user objects according to getObj/attributes, we could normally include all attributes having id and userName as mandatory e.g [{"id": "bjensen", "userName": "bjensen"}, {"id":"jsmith", "userName":"jsmith"}]
1030
+ ret.totalResults = if supporting pagination, then it should be set to the total numbers of elements (users), else set to null
1098
1031
 
1099
1032
  ### deleteUser
1100
1033
 
@@ -1119,73 +1052,28 @@ Note, multi-value attributes excluding user attribute 'groups' are customized fr
1119
1052
  Note, multi-value attributes excluding user attribute 'groups' are customized from array to object based on type
1120
1053
  * return null: null if OK, else throw error
1121
1054
 
1122
- ### getGroup
1123
-
1124
- scimgateway.getGroup = async (baseEntity, getObj, attributes) => {
1125
- ...
1126
- return retObj
1127
- }
1128
-
1129
-
1130
- * getObj = `{ filter: <filterAttribute>, identifier: <identifier> }`
1131
- e.g: getObj = { "filter": "displayName", "identifier": "GroupA" }
1132
- filter: **displayName** and **id** must be supported
1133
- * attributes = scim attributes to be returned. If no attributes defined, all should be returned.
1134
- * return retObj: retObj containing group displayName and id (+ members if using default "users are member of group")
1135
-
1136
- eg. using default "users are member of group":
1137
- {"displayName":"Admins","id":"Admins","members":[{"value":"bjensen","display":"bjensen"]}
1138
-
1139
- eg. using "groups are member of user":
1140
- {"displayName":"Admins","id":"Admins"}
1141
-
1142
- If we do not support groups, callback(null, null)
1143
-
1144
- ### getGroupMembers
1145
-
1146
- scimgateway.getGroupMembers = async (baseEntity, id, attributes) => {
1147
- let arrRet = []
1148
- ...
1149
- return arrRet
1150
- }
1151
-
1152
-
1153
- Retrieve all groups for user id WHEN **"user member of groups"**. This setting is default SCIM behaviour. This means Group having multivalue attribute members containing id of users.
1154
-
1155
- * id = user id (eg. bjensen)
1156
- * attributes = scim attributes to be returned as object in array
1157
- * arrRet = array containing the objects of id, displayName and members where members value only include current user id on the format:
1158
- { id: <id-group>> , displayName: <displayName-group>, members [{value: <id-user>}] }
1159
-
1160
- [
1161
- {"id": "Admins", "displayName: "Admins", "members": [{"value": "bjensen"}]},
1162
- {"id": "Employees", "displayName: "Employees", "members": [{"value": "bjensen"}]}
1163
- ]
1055
+ ### getGroups
1164
1056
 
1165
- If "user member of groups" not supported, then return []
1166
-
1167
-
1168
-
1169
- ### getGroupUsers
1170
-
1171
- scimgateway.getGroupUsers = async (baseEntity, id, attributes) => {
1172
- let arrRet = []
1057
+ scimgateway.getGroups = async (baseEntity, getObj, attributes) => {
1058
+ let ret = {
1059
+ "Resources": [],
1060
+ "totalResults": null
1061
+ }
1173
1062
  ...
1174
- return arrRet
1175
- }
1176
-
1177
- Retrieve all users for a spesific group id WHEN **"group member of users"**. This means user having multivalue attribute groups having value set to group id
1178
-
1179
- * id = group id (eg. UserGroup-1)
1180
- * attributes = scim attributes to be returned as object in array
1181
- * arrRet = array containing the objects of userName and groups.value e.g:
1063
+ return ret
1064
+ }
1182
1065
 
1183
- [
1184
- {"userName", "bjensen": [{"value": "UserGroup-1"}]},
1185
- {"userName", "jsmith"}: [{"value": "UserGroup-1"}]}
1186
- ]
1066
+ * baseEntity = Optional for multi-tenant or multi-endpoint support (defined in base url e.g. `<baseurl>/client1` gives baseEntity=client1)
1067
+ * getObj = { attribute: <>, operator: <>, value: <>, rawFilter: <>, startIndex: <>, count: <> }
1068
+ * attribute, operator and value are set when using "simpel filtering", e.g. getObj.attribute='displayName', getObj.operator='eq' and getObj.value='Admins', but not for advanced filtering having and/or/not
1069
+ * rawFilter is always set when filtering is used
1070
+ * startIndex = Pagination - The 1-based index of the first result in the current set of search results
1071
+ * count = Pagination - Number of elements to be returned in the current set of search results
1072
+ * attributes = array of attributes to be returned - if empty, all supported attributes should be returned
1073
+ * ret:
1074
+ ret.Resources = array filled with group objects according to getObj/attributes, we could normally include all attributes having id, displayName and members as mandatory e.g [{"id":"Admins", "displayName":"Admins", members":[{"value":"bjensen"}]}, {"id":"Employees", "displayName":"Employees"}, "members":[{"value":"jsmith","display":"John Smith"}]]
1075
+ ret.totalResults = if supporting pagination, then it should be set to the total numbers of elements (users), else set to null
1187
1076
 
1188
- If "group member of users" not supported, then return []
1189
1077
 
1190
1078
  ### createGroup
1191
1079
  scimgateway.createGroup = async (baseEntity, groupObj) => {
@@ -1222,15 +1110,6 @@ eg: {"value":"bjensen"},{"operation":"delete","value":"jsmith"}
1222
1110
  If we do not support groups, then return null
1223
1111
 
1224
1112
 
1225
- ## Known limitations
1226
-
1227
- * Installation gives error messages related to the module soap optional dependency to 'ursa' that also includes 'node-gyp'. These error messages can be ignored unless soap WSSecurityCert functionality is needed in custom plugin code.
1228
-
1229
- * SCIM filtering only supports operator 'eq' returning unique object only, example:
1230
- /Users?**filter**=userName **eq** "bjensen"&attributes=userName,id,name.givenName
1231
- /Users?**filter**=emails.value **eq** "bjensen@example.com"&attributes=userName,phoneNumbers
1232
-
1233
-
1234
1113
  ## License
1235
1114
 
1236
1115
  MIT © [Jarle Elshaug](https://www.elshaug.xyz)
@@ -1238,6 +1117,102 @@ MIT © [Jarle Elshaug](https://www.elshaug.xyz)
1238
1117
 
1239
1118
  ## Change log
1240
1119
 
1120
+ ### v4.0.0
1121
+ **[MAJOR]**
1122
+
1123
+ - New `getUsers()` replacing deprecated exploreUsers(), getUser() and getGroupUsers()
1124
+ - New `getGroups()` replacing deprecated exploreGroups(), getGroup() and getGroupMembers()
1125
+ - Fully filter and sort support
1126
+ - Authentication configuration may now include a baseEntities array containing one or more `baseEntity` allowed for corresponding admin user
1127
+ - New plugin-mongodb, **thanks to Filipe Ribeiro and Miguel Ferreira (KEEP SOLUTIONS)**
1128
+
1129
+ Note, using this major version **require existing custom plugins to be upgraded**. If you do not want to upgrade your custom plugins, the old version have to be installed using: `npm install scimgateway@3.2.11`
1130
+
1131
+ How to upgrade your custom plugins:
1132
+
1133
+ Replace: scimgateway.exploreUsers = async (baseEntity, attributes, startIndex, count) => {
1134
+ With: scimgateway.getUsers = async (baseEntity, getObj, attributes) => {
1135
+
1136
+ See comments in provided plugins regarding the new `getObj`. Also note that `attributes` is now an array and not a comma separated string like previous versions
1137
+
1138
+ In the very beginning, add:
1139
+
1140
+ // mandatory if-else logic - start
1141
+ if (getObj.operator) {
1142
+ if (getObj.operator === 'eq' && ['id', 'userName', 'externalId'].includes(getObj.attribute)) {
1143
+ // mandatory - unique filtering - single unique user to be returned - correspond to getUser() in versions < 4.x.x
1144
+ } else if (getObj.operator === 'eq' && getObj.attribute === 'group.value') {
1145
+ // optional - only used when groups are member of users, not default behavior - correspond to getGroupUsers() in versions < 4.x.x
1146
+ throw new Error(`${action} error: not supporting groups member of user filtering: ${getObj.rawFilter}`)
1147
+ } else {
1148
+ // optional - simpel filtering
1149
+ throw new Error(`${action} error: not supporting simpel filtering: ${getObj.rawFilter}`)
1150
+ }
1151
+ } else if (getObj.rawFilter) {
1152
+ // optional - advanced filtering having and/or/not - use getObj.rawFilter
1153
+ throw new Error(`${action} error: not supporting advanced filtering: ${getObj.rawFilter}`)
1154
+ } else {
1155
+ // mandatory - no filtering (!getObj.operator && !getObj.rawFilter) - all users to be returned - correspond to exploreUsers() in versions < 4.x.x
1156
+ }
1157
+ // mandatory if-else logic - end
1158
+
1159
+
1160
+ In the new getUsers() replacing exploreUsers() "as-is", we then need some logic in the last "else" statement listed above.
1161
+ We also need to add logic from existing getGroup() and getGroupMembers()
1162
+ **Please have a look at provieded plugins to see different ways of doing this logic.**
1163
+
1164
+
1165
+ Replace: scimgateway.exploreGroups = async (baseEntity, attributes, startIndex, count) => {
1166
+ With: scimgateway.getGroups = async (baseEntity, getObj, attributes) => {
1167
+
1168
+ In the very beginning, add:
1169
+
1170
+ // mandatory if-else logic - start
1171
+ if (getObj.operator) {
1172
+ if (getObj.operator === 'eq' && ['id', 'displayName', 'externalId'].includes(getObj.attribute)) {
1173
+ // mandatory - unique filtering - single unique user to be returned - correspond to getUser() in versions < 4.x.x
1174
+ } else if (getObj.operator === 'eq' && getObj.attribute === 'members.value') {
1175
+ // mandatory - return all groups the user 'id' (getObj.value) is member of - correspond to getGroupMembers() in versions < 4.x.x
1176
+ // Resources = [{ id: <id-group>> , displayName: <displayName-group>, members [{value: <id-user>}] }]
1177
+ } else {
1178
+ // optional - simpel filtering
1179
+ throw new Error(`${action} error: not supporting simpel filtering: ${getObj.rawFilter}`)
1180
+ }
1181
+ } else if (getObj.rawFilter) {
1182
+ // optional - advanced filtering having and/or/not - use getObj.rawFilter
1183
+ throw new Error(`${action} error: not supporting advanced filtering: ${getObj.rawFilter}`)
1184
+ } else {
1185
+ // mandatory - no filtering (!getObj.operator && !getObj.rawFilter) - all groups to be returned - correspond to exploreGroups() in versions < 4.x.x
1186
+ }
1187
+ // mandatory if-else logic - end
1188
+
1189
+
1190
+ In the new getGroups() replacing exploreGroups() "as-is", we then need some logic in the last "else" statement listed above.
1191
+ We also need to add logic from existing getGroup() and getGroupMembers()
1192
+ **Please have a look at provieded plugins to see different ways of doing this logic.**
1193
+
1194
+
1195
+ Delete deprecated exploreUsers(), getUser(), getGroupUsers(), exploreGroups(), getGroup() and getGroupMembers()
1196
+
1197
+
1198
+ ### v3.2.11
1199
+ [Fixed]
1200
+
1201
+ - errorhandling related to running scimgateway as unikernel
1202
+
1203
+ ### v3.2.10
1204
+ [Fixed]
1205
+
1206
+ - for SCIM 2.0 exploreUsers/exploreGroups now includes schemas/resourceType on each object in the Resources response. This may be required by som IdP's.
1207
+
1208
+ [Added]
1209
+ - Dependencies bump
1210
+
1211
+ ### v3.2.9
1212
+ [Fixed]
1213
+
1214
+ - plugin-loki pagination fix
1215
+
1241
1216
  ### v3.2.8
1242
1217
  [Fixed]
1243
1218