scimgateway 3.2.11 → 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
@@ -16,10 +16,11 @@ Validated through IdP's:
16
16
 
17
17
  Latest news:
18
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
19
20
  - ipAllowList for restricting access to allowlisted IP addresses or subnets e.g. Azure AD IP-range
20
- - General LDAP plugin configured for Active Directory.
21
+ - General LDAP plugin configured for Active Directory
21
22
  - [PlugSSO](https://elshaug.xyz/docs/plugsso) using SCIM Gateway
22
- - 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
23
24
  - Codebase moved from callback of h... to the the promise(d) land of async/await
24
25
  - Supports configuration by environments and external files
25
26
  - Health monitoring through "/ping" URL, and option for error notifications by email
@@ -44,13 +45,17 @@ SCIM Gateway is based on the popular asynchronous event driven framework [Node.j
44
45
  **Following example plugins are included:**
45
46
 
46
47
  * **Loki** (NoSQL Document-Oriented Database)
47
- Gives a SCIM endpoint located on SCIM Gateway
48
+ SCIM Gateway becomes a standalone SCIM endpoint
48
49
  Demonstrates user provisioning towards document-oriented database
49
- 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)
50
51
  Default gives two predefined test users loaded using in-memory only (no persistence)
51
52
  Setting `{"persistence": true}` gives persistence file store (no test users)
52
53
  Example of a fully functional SCIM Gateway plugin
53
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
+
54
59
  * **RESTful** (REST Webservice)
55
60
  Demonstrates user provisioning towards REST-Based endpoint
56
61
  Using plugin "Loki" as a REST endpoint
@@ -58,7 +63,7 @@ Using plugin "Loki" as a REST endpoint
58
63
  * **Forwardinc** (SOAP Webservice)
59
64
  Demonstrates user provisioning towards SOAP-Based endpoint
60
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")
61
- 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
62
67
 
63
68
  * **MSSQL** (MSSQL Database)
64
69
  Demonstrates user provisioning towards MSSQL database
@@ -70,7 +75,7 @@ Demonstrates SAP HANA specific user provisioning
70
75
  Azure AD user provisioning including Azure license management (App Service plans) e.g. Office 365
71
76
  Using Microsoft Graph API
72
77
  Using customized SCIM attributes according to Microsoft Graph API
73
- 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
74
79
 
75
80
  * **LDAP** (Directory)
76
81
  Fully functional LDAP plugin
@@ -101,7 +106,7 @@ Create your own package directory e.g. C:\my-scimgateway and install SCIM Gatewa
101
106
  mkdir c:\my-scimgateway
102
107
  cd c:\my-scimgateway
103
108
  npm init -y
104
- npm install scimgateway --save
109
+ npm install scimgateway
105
110
 
106
111
  **c:\\my-scimgateway** will now be `<package-root>`
107
112
 
@@ -130,9 +135,12 @@ If internet connection is blocked, we could install on another machine and copy
130
135
  http://localhost:8880/Groups/Admins
131
136
  => Lists all attributes for specified user/group
132
137
 
138
+ http://localhost:8880/Groups?filter=displayName eq "Admins"&excludedAttributes=members
133
139
  http://localhost:8880/Users?filter=userName eq "bjensen"&attributes=userName,id,name.givenName
134
- http://localhost:8880/Users?filter=emails.value eq "bjensen@example.com"&attributes=userName,phoneNumbers
135
- => 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
+
136
144
 
137
145
  "Ctrl + c" to stop the SCIM Gateway
138
146
 
@@ -170,10 +178,11 @@ To force a major upgrade (version x.\*.\* => y.\*.\*) that will brake compabilit
170
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.
171
179
 
172
180
  const loki = require('./lib/plugin-loki')
181
+ // const mongodb = require('./lib/plugin-mongodb')
173
182
  // const restful = require('./lib/plugin-restful')
174
183
  // const forwardinc = require('./lib/plugin-forwardinc')
175
184
  // const mssql = require('./lib/plugin-mssql')
176
- // const saphana = require('./lib/plugin-saphana') // prereq: npm install hdb --save
185
+ // const saphana = require('./lib/plugin-saphana') // prereq: npm install hdb
177
186
  // const azureAD = require('./lib/plugin-azure-ad')
178
187
  // const ldap = require('./lib/plugin-ldap')
179
188
  // const api = require('./lib/plugin-api')
@@ -207,18 +216,22 @@ Below shows an example of config\plugin-saphana.json
207
216
  {
208
217
  "username": "gwadmin",
209
218
  "password": "password",
210
- "readOnly": false
219
+ "readOnly": false,
220
+ "baseEntities": []
211
221
  }
212
222
  ],
213
223
  "bearerToken": [
214
224
  {
215
225
  "token": null,
216
- "readOnly": false
226
+ "readOnly": false,
227
+ "baseEntities": []
217
228
  }
218
229
  ],
219
230
  "bearerJwtAzure": [
220
231
  {
221
- "tenantIdGUID": null
232
+ "tenantIdGUID": null,
233
+ "readOnly": false,
234
+ "baseEntities": []
222
235
  }
223
236
  ],
224
237
  "bearerJwt": [
@@ -228,7 +241,8 @@ Below shows an example of config\plugin-saphana.json
228
241
  "options": {
229
242
  "issuer": null
230
243
  },
231
- "readOnly": false
244
+ "readOnly": false,
245
+ "baseEntities": []
232
246
  }
233
247
  ]
234
248
  },
@@ -304,7 +318,10 @@ Definitions in `endpoint` object are customized according to our plugin code. Pl
304
318
 
305
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.
306
320
 
307
- - **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**
308
325
 
309
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.
310
327
 
@@ -524,7 +541,7 @@ docker-compose**
524
541
  mkdir /opt/my-scimgateway
525
542
  cd /opt/my-scimgateway
526
543
  npm init -y
527
- npm install scimgateway --save
544
+ npm install scimgateway
528
545
  cp ./config/docker/* .
529
546
 
530
547
  **docker-compose.yml** <== Here is where you would set the exposed port and environment
@@ -587,6 +604,71 @@ To upgrade scimgateway docker image (remove the old stuff before running docker-
587
604
  docker rm scimgateway
588
605
  docker rm $(docker ps -a -q); docker rmi $(docker images -q -f "dangling=true")
589
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
+
590
672
  ## CA Identity Manager as IdP using SCIM Gateway
591
673
 
592
674
  Using Symantec/Broadcom/CA Identity Manger, plugin configuration file must include **SCIM Version "1.1"** (scimgateway.scim.version).
@@ -616,82 +698,15 @@ Username, password and port must correspond with plugin configuration file. For
616
698
 
617
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:
618
700
 
619
- http://localhost:8880/clientA
620
- http://localhost:8880/clientB
701
+ http://localhost:8880/client-a
702
+ http://localhost:8880/client-b
621
703
 
622
704
  Each baseEntity should then be defined in the plugin configuration file with custom attributes needed. Please see examples in plugin-forwardinc.json
623
705
 
624
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.
625
707
 
626
- ## SCIM Gateway REST API
627
-
628
- Create = POST http://localhost:8880/Users
629
- (body contains the user information)
630
-
631
- Update = PATCH http://localhost:8880/Users/<id>
632
- (body contains the attributes to be updated)
633
-
634
- Search/Read = GET http://localhost:8880/Users?userName eq
635
- "userID"&attributes=<comma separated list of scim-schema defined attributes>
636
-
637
- Search/explore all users:
638
- GET http://localhost:8880/Users?attributes=userName
639
-
640
- Delete = DELETE http://localhost:8880/Users/<id>
641
-
642
- Discovery:
643
-
644
- GET http://localhost:8880/ServiceProviderConfigs
645
- Specification compliance, authentication schemes, data models.
646
-
647
- GET http://localhost:8880/Schemas
648
- Introspect resources and attribute extensions.
649
-
650
- Note:
651
-
652
- - userName (mandatory) = UserID
653
- - id (mandatory) = Unique id. Could be set to the same as UserID but don't have to.
654
-
655
- ## SAP Hana endpoint
656
-
657
- Get all users (explore):
658
- select USER_NAME from SYS.USERS where IS_SAML_ENABLED like 'TRUE';
659
-
660
- Get a specific user:
661
- select USER_NAME, USER_DEACTIVATED from SYS.USERS where USER_NAME like '<UserID>';
662
-
663
- Create User:
664
- CREATE USER <UserID> WITH IDENTITY '<UserID>' FOR SAML PROVIDER <SamlProvider>;
665
-
666
- Delete user:
667
- DROP USER <UserID>;
668
-
669
- Modify user (enable user):
670
- ALTER USER <UserID> ACTIVATE;
671
-
672
- Modify user (disable user):
673
- ALTER USER <UserID> DEACTIVATE;
674
-
675
- Postinstallation:
676
-
677
- cd c:\my-scimgateway
678
- npm install hdb --save
679
708
 
680
-
681
- Only SAML users will be explored and managed
682
-
683
- Supported template attributes:
684
-
685
- - User Name (UserID)
686
- - Suspended (Enabled/Disabled)
687
-
688
- 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.**
689
-
690
- SAP Hana converts UserID to uppercase. Provisioning use default lowercase. Provisioning template should therefore also convert to uppercase.
691
-
692
- User Name = %$$TOUPPER(%AC%)%
693
-
694
- ## Azure Active Directory endpoint
709
+ ## Azure Active Directory provisioning
695
710
  Using plugin-azure-ad we could do user provisioning towards Azure AD including license management e.g. O365
696
711
 
697
712
  For testing purposes we could get an Azure free account and in addition the free Office 365 for testing license management through Azure.
@@ -766,7 +781,8 @@ Note, for Symantec/Broadcom/CA Provisioning we have to use SCIM version 1.1
766
781
  {
767
782
  "username": "gwadmin",
768
783
  "password": "password",
769
- "readOnly": false
784
+ "readOnly": false,
785
+ "baseEntities": []
770
786
  }
771
787
  ],
772
788
 
@@ -798,10 +814,10 @@ For multi-tenant or multi-endpoint support, we may add several entities:
798
814
  "undefined": {
799
815
  ...
800
816
  },
801
- "clientA": {
817
+ "client-a": {
802
818
  ...
803
819
  },
804
- "clientB": {
820
+ "client-b": {
805
821
  ...
806
822
  }
807
823
  }
@@ -849,74 +865,39 @@ Endpoint configuration example:
849
865
 
850
866
  For details, please see section "CA Identity Manager as IdP using SCIM Gateway"
851
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>
852
883
 
853
- ## Azure Active Directory as IdP using SCIM Gateway
854
-
855
- Azure AD could do automatic user provisioning by synchronizing users towards SCIM Gateway, and gateway plugins will update endpoints.
856
-
857
- 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:
858
-
859
- scimgateway: {
860
- "scim": {
861
- "version": "2.0",
862
- ...
863
- },
864
- ...
865
- "auth": {
866
- "bearerToken": [
867
- {
868
- "token": "shared-secret"
869
- }
870
- ],
871
- "bearerJwtAzure": [
872
- {
873
- "tenantIdGUID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
874
- }
875
- ]
876
- }
877
- ...
878
- }
879
-
880
- `token` configuration must correspond with "Secret Token" defined in Azure AD
881
- `tenantIdGUID` configuration must correspond with Azure Active Directory Tenant ID
882
-
883
- In Azure Portal:
884
- `Azure-Azure Active Directory-Enterprise Application-<My Application>-Provisioning-Secret Token`
885
- Note, when "Secret Token" is left blank, Azure will use JWT (tenantIdGUID)
886
-
887
- `Azure-Azure Active Directory-Overview-Tenant ID`
888
-
889
- User mappings attributes between AD and SCIM also needs to be configured
890
-
891
- `Azure-Azure Active Directory-Enterprise Application-<My Application>-Provisioning-Edit attribute mappings-Mappings`
892
-
893
- Azure AD default SCIM attribute mapping for **USER** must have:
894
-
895
- userPrincipalName mapped to userName (matching precedence #1)
896
-
897
-
898
- Azure AD default SCIM attribute mapping for **GROUP** must have:
899
-
900
- displayName mapped to displayName (matching precedence #1)
901
- members mapped to members
902
-
903
-
904
-
905
- Some notes related to Azure AD:
906
-
907
- - Azure Active Directory SCIM [documentation](https://docs.microsoft.com/en-us/azure/active-directory/active-directory-scim-provisioning)
884
+ Discovery:
908
885
 
909
- - 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.
910
891
 
911
- - 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:
912
893
 
913
- - 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.
914
896
 
915
- - 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.
916
897
 
917
898
  ## API Gateway
918
899
 
919
- 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`
920
901
 
921
902
  Following methods for the none SCIM based api-plugin are supported:
922
903
 
@@ -928,7 +909,7 @@ Following methods for the none SCIM based api-plugin are supported:
928
909
  PATCH /api/{id} + body
929
910
  DELETE /api/{id}
930
911
 
931
-
912
+ These methods can also be used in standard SCIM plugins
932
913
  Please see example plugin: **plugin-api.js**
933
914
 
934
915
 
@@ -937,7 +918,7 @@ For JavaScript coding editor you may use [Visual Studio Code](https://code.visua
937
918
 
938
919
  Preparation:
939
920
 
940
- * 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)
941
922
  * Edit plugin-mine.json and define a unique port number for the gateway setting
942
923
  * Edit index.js and add a new line for starting your plugin e.g. `let mine = require('./lib/plugin-mine');`
943
924
  * Start SCIM Gateway and verify. If using CA Provisioning you could setup a SCIM endpoint using the port number you defined
@@ -945,20 +926,18 @@ Preparation:
945
926
  Now we are ready for custom coding by editing plugin-mine.js
946
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).
947
928
 
948
- 1. **Turn off group functionality** in getGroup, getGroupMembers, getGroupUsers and modifyGroupMembers
949
- Please see callback definitions in plugin-saphana that do not use groups.
950
- 2. **exploreUsers** (test provisioning explore users)
951
- 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)
952
932
  4. **createUser** (test provisioning new account)
953
933
  5. **deleteUser** (test provisioning delete account)
954
934
  6. **modifyUser** (test provisioning modify account)
955
- 7. **exploreGroups** (test provisioning explore groups)
956
- 8. **Turn on group functionality** (if supporting groups)
957
- 8. **getGroup** (test provisioning group list groups)
958
- 9. **getGroupMembers** (test provisioning retrieve account - group list groups)
959
- 10. **modifyGroupMembers** (test provisioning retrieve account - group add/remove groups)
960
- 11. **getGroupUsers** (if using "groups member of user")
961
- 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
+
962
941
 
963
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)
964
943
 
@@ -1028,9 +1007,9 @@ Plugins should have following initialization:
1028
1007
  // mandatory plugin initialization - end
1029
1008
 
1030
1009
 
1031
- ### exploreUsers
1010
+ ### getUsers
1032
1011
 
1033
- scimgateway.exploreUsers = async (baseEntity, attributes, startIndex, count) => {
1012
+ scimgateway.getUsers = async (baseEntity, getObj, attributes) => {
1034
1013
  let ret = {
1035
1014
  "Resources": [],
1036
1015
  "totalResults": null
@@ -1040,54 +1019,15 @@ Plugins should have following initialization:
1040
1019
  }
1041
1020
 
1042
1021
  * baseEntity = Optional for multi-tenant or multi-endpoint support (defined in base url e.g. `<baseurl>/client1` gives baseEntity=client1)
1043
- * startIndex = Pagination - The 1-based index of the first result in the current set of search results
1044
- * 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
1045
1028
  * ret:
1046
- ret.Resources = array filled with user objects containing user attributes where userName is mandatory e.g [{"userName":"bjensen"}, {"userName":"jsmith"}]
1047
- ret.totalResults = if supporting pagination, then attribute should be set to the total numbers of elements (users) at the endpoint, else set to null
1048
-
1049
- ### exploreGroups
1050
-
1051
- scimgateway.exploreGroups = async (baseEntity, attributes, startIndex, count) => {
1052
- let ret = {
1053
- "Resources": [],
1054
- "totalResults": null
1055
- }
1056
- ...
1057
- return ret
1058
- }
1059
-
1060
- * ret:
1061
- ret.Resources = array filled with group objects containing group attributes where displayName is mandatory e.g [{"displayName":"Admins"}, {"displayName":"Employees"}]
1062
- ret.totalResults = if supporting pagination attribute should be set to the total numbers of elements (groups) at the endpoint else set to null
1063
-
1064
- ### getUser
1065
-
1066
- scimgateway.getUser = async (baseEntity, getObj, attributes) => {
1067
- ...
1068
- return userObj
1069
- }
1070
-
1071
- * getObj = `{ filter: <filterAttribute>, identifier: <identifier> }`
1072
- e.g: getObj = { "filter": "userName", "identifier": "bjensen"}
1073
- filter: **userName** and **id** must be supported
1074
- * attributes = scim attributes to be returned. If no attributes defined, all should be returned.
1075
- * return userObj: userObj containing scim userattributes/values
1076
- eg:
1077
- {"id":"bjensen","name":{"formatted":"Ms. Barbara J Jensen III","familyName":"Jensen","givenName":"Barbara"}}
1078
-
1079
- Note, the value of the **id** attribute returned will be used by modifyUser and deleteUser
1080
-
1081
- ### createUser
1082
-
1083
- scimgateway.createUser = async (baseEntity, userObj) => {
1084
- ...
1085
- return null
1086
- }
1087
-
1088
- * userObj = user object containing userattributes according to scim standard
1089
- Note, multi-value attributes excluding user attribute 'groups' are customized from array to object based on type
1090
- * 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
1091
1031
 
1092
1032
  ### deleteUser
1093
1033
 
@@ -1112,73 +1052,28 @@ Note, multi-value attributes excluding user attribute 'groups' are customized fr
1112
1052
  Note, multi-value attributes excluding user attribute 'groups' are customized from array to object based on type
1113
1053
  * return null: null if OK, else throw error
1114
1054
 
1115
- ### getGroup
1116
-
1117
- scimgateway.getGroup = async (baseEntity, getObj, attributes) => {
1118
- ...
1119
- return retObj
1120
- }
1121
-
1122
-
1123
- * getObj = `{ filter: <filterAttribute>, identifier: <identifier> }`
1124
- e.g: getObj = { "filter": "displayName", "identifier": "GroupA" }
1125
- filter: **displayName** and **id** must be supported
1126
- * attributes = scim attributes to be returned. If no attributes defined, all should be returned.
1127
- * return retObj: retObj containing group displayName and id (+ members if using default "users are member of group")
1128
-
1129
- eg. using default "users are member of group":
1130
- {"displayName":"Admins","id":"Admins","members":[{"value":"bjensen","display":"bjensen"]}
1131
-
1132
- eg. using "groups are member of user":
1133
- {"displayName":"Admins","id":"Admins"}
1055
+ ### getGroups
1134
1056
 
1135
- If we do not support groups, callback(null, null)
1136
-
1137
- ### getGroupMembers
1138
-
1139
- scimgateway.getGroupMembers = async (baseEntity, id, attributes) => {
1140
- let arrRet = []
1141
- ...
1142
- return arrRet
1143
- }
1144
-
1145
-
1146
- 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.
1147
-
1148
- * id = user id (eg. bjensen)
1149
- * attributes = scim attributes to be returned as object in array
1150
- * arrRet = array containing the objects of id, displayName and members where members value only include current user id on the format:
1151
- { id: <id-group>> , displayName: <displayName-group>, members [{value: <id-user>}] }
1152
-
1153
- [
1154
- {"id": "Admins", "displayName: "Admins", "members": [{"value": "bjensen"}]},
1155
- {"id": "Employees", "displayName: "Employees", "members": [{"value": "bjensen"}]}
1156
- ]
1157
-
1158
- If "user member of groups" not supported, then return []
1159
-
1160
-
1161
-
1162
- ### getGroupUsers
1163
-
1164
- scimgateway.getGroupUsers = async (baseEntity, id, attributes) => {
1165
- let arrRet = []
1057
+ scimgateway.getGroups = async (baseEntity, getObj, attributes) => {
1058
+ let ret = {
1059
+ "Resources": [],
1060
+ "totalResults": null
1061
+ }
1166
1062
  ...
1167
- return arrRet
1168
- }
1169
-
1170
- 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
1171
-
1172
- * id = group id (eg. UserGroup-1)
1173
- * attributes = scim attributes to be returned as object in array
1174
- * arrRet = array containing the objects of userName and groups.value e.g:
1063
+ return ret
1064
+ }
1175
1065
 
1176
- [
1177
- {"userName", "bjensen": [{"value": "UserGroup-1"}]},
1178
- {"userName", "jsmith"}: [{"value": "UserGroup-1"}]}
1179
- ]
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
1180
1076
 
1181
- If "group member of users" not supported, then return []
1182
1077
 
1183
1078
  ### createGroup
1184
1079
  scimgateway.createGroup = async (baseEntity, groupObj) => {
@@ -1215,13 +1110,6 @@ eg: {"value":"bjensen"},{"operation":"delete","value":"jsmith"}
1215
1110
  If we do not support groups, then return null
1216
1111
 
1217
1112
 
1218
- ## Known limitations
1219
-
1220
- * SCIM filtering only supports operator 'eq' returning unique object only, example:
1221
- /Users?**filter**=userName **eq** "bjensen"&attributes=userName,id,name.givenName
1222
- /Users?**filter**=emails.value **eq** "bjensen@example.com"&attributes=userName,phoneNumbers
1223
-
1224
-
1225
1113
  ## License
1226
1114
 
1227
1115
  MIT © [Jarle Elshaug](https://www.elshaug.xyz)
@@ -1229,12 +1117,89 @@ MIT © [Jarle Elshaug](https://www.elshaug.xyz)
1229
1117
 
1230
1118
  ## Change log
1231
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
+
1232
1198
  ### v3.2.11
1233
1199
  [Fixed]
1234
1200
 
1235
1201
  - errorhandling related to running scimgateway as unikernel
1236
1202
 
1237
-
1238
1203
  ### v3.2.10
1239
1204
  [Fixed]
1240
1205