jelhub / scimgateway

Using SCIM protocol as a gateway for user provisioning to other endpoints
MIT License
176 stars 57 forks source link
gateway identity iga manager nodejs provisioning scim

SCIM Gateway

Build Status npm Versionnpm Downloads chat disqus GitHub forks


Author: Jarle Elshaug

Validated through IdP's:

Latest news:

Overview

With SCIM Gateway, user management is facilitated through the utilization of the REST-based SCIM 1.1 or 2.0 protocol. The gateway acts as a translator for incoming SCIM requests, seamlessly enabling the exposure of CRUD functionality (create, read, update, and delete user/group) towards destinations. This is achieved through the implementation of endpoint-specific protocols, ensuring precise and efficient provisioning with diverse endpoints.

SCIM Gateway is based on popular asynchronous event driven framework Bun or Node.js using TypeScript/JavaScript. It is cloud and firewall friendly. Runs on almost all operating systems, and may load balance between hosts (horizontal) and cpu's (vertical).

Following example plugins are included:

Installation

Install Bun

Bun is a prerequisite and must be installed on the server.

Note, Bun installs by default in the current user’s HOMEPATH\.bun. To install it elsewhere, set BUN_INSTALL=<install-path> as a global or system environment variable before installing. The installation will add Bun to the current user’s path, but consider adding it to the global or system path for easier access across all users.

Install SCIM Gateway

Open a command window (run as administrator)
Create your own package directory e.g. c:\my-scimgateway and install SCIM Gateway within this package.

mkdir c:\my-scimgateway
cd c:\my-scimgateway
bun init -y
bun install scimgateway
bun pm trust scimgateway

c:\my-scimgateway will now be <package-root>

index.ts, lib and config directories containing example plugins have been copied to your package from the original scimgateway package located under node_modules. Bun requires bun pm trust scimgateway for allowing postinstall copying these files.

If internet connection is blocked, we could install on another machine and copy the <package-root> folder.

Startup and verify default Loki plugin

bun c:\my-scimgateway

If using Node.js instead of Bun, scimgateway must be downloaded from github and startup: node --experimental-strip-types c:\my-scimgateway\index.ts

Start a browser (note, Edge do not pop-up logon dialog box when using http)

http://localhost:8880/ping
=> Health check with a "hello" response

http://localhost:8880/Users  
http://localhost:8880/Groups 
=> Logon using gwadmin/password and two users and groups should be listed  

http://localhost:8880/Users/bjensen
http://localhost:8880/Groups/Admins
or
http://localhost:8880/Users?filter=userName eq "bjensen"
http://localhost:8880/Groups?filter=displayName eq "Admins"
=> Lists all attributes for specified user/group

http://localhost:8880/Groups?filter=displayName eq "Admins"&excludedAttributes=members
http://localhost:8880/Groups?filter=members.value eq "bjensen"&attributes=id,displayName,members.value
http://localhost:8880/Users?filter=userName eq "bjensen"&attributes=userName,id,name.givenName
http://localhost:8880/Users?filter=meta.created ge "2010-01-01T00:00:00Z"&attributes=userName,name.familyName,meta.created
http://localhost:8880/Users?filter=emails.value co "@example.com"&attributes=userName,name.familyName,emails&sortBy=name.familyName&sortOrder=descending
=> Filtering and attribute examples

"Ctrl + c" to stop the SCIM Gateway

Tip, take a look at bun test scripts located in node_modules\scimgateway\test\lib

Upgrade SCIM Gateway

Not needed after a fresh install

The best and easiest way to upgrade is renaming existing scimgateway package folder, create a new one and do a fresh installation. After the installation we copy index.ts, config and lib folder (customized plugins) from previous installation to the new installation. You should also read the version history to see custom plugins needs to be updated.

Alternatives are:

Upgrade to latest minor version:

cd c:\my-scimgateway
bun install scimgateway

Note, always backup/copy c:\my-scimgateway before upgrading. Custom plugins and corresponding configuration files will not be affected.

To force a major upgrade (version x.*.* => y.*.*) that will brake compability with any existing custom plugins, we have to include the @latest suffix in the install command: bun install scimgateway@latest

Avoid (re-)adding the files created during postinstall

For production we do not need example plugins to be incuded by the postinstall job
Bun will by default exlude any postinstall jobs unless we have trusted the scimgateway package using the bun pm trust scimgateway that updates package.json { trustedDependencies: ["scimgateway"] }

For Node.js (and also Bun), we might set the property scimgateway_postinstall_skip = true in .npmrc or setting environment SCIMGATEWAY_POSTINSTALL_SKIP = true

Configuration

index.ts defines one or more plugins to be started by the const plugins setting.

// example starting all default plugins:
// const plugins = ['loki', 'scim', 'entra-id', 'ldap', 'mssql', 'api', 'mongodb', 'saphana', 'soap']

const plugins = ['ldap']

for (const plugin of plugins) {
  try {
    await import(`./lib/plugin-${plugin}.ts`)
  } catch (err: any) {
    console.error(`plugin-${plugin} startup error: ${err.message}`)
    console.log()
  }
}

Each endpoint plugin needs a TypeScript file (.ts) and a configuration file (.json). They both must have the same naming prefix. For SAP Hana endpoint we have:

lib\plugin-saphana.ts
config\plugin-saphana.json

Edit specific plugin configuration file according to your needs.
Below shows an example of config\plugin-saphana.json

{
  "scimgateway": {
    "port": 8884,
    "localhostonly": false,
    "payloadSize": null,
    "scim": {
      "version": "2.0",
      "skipTypeConvert" : false,
      "skipMetaLocation" false,
      "groupMemberOfUser": false
      "usePutSoftSync" : false
    },
    "log": {
      "loglevel": {
        "file": "debug",
        "console": "error"
      },
      "customMasking": []
    },
    "auth": {
      "basic": [
        {
          "username": "gwadmin",
          "password": "password",
          "readOnly": false,
          "baseEntities": []
        }
      ],
      "bearerToken": [
        {
          "token": null,
          "readOnly": false,
          "baseEntities": []
        }
      ],
      "bearerJwtAzure": [
        {
          "tenantIdGUID": null,
          "readOnly": false,
          "baseEntities": []
        }
      ],
      "bearerJwt": [
        {
          "secret": null,
          "publicKey": null,
          "options": {
            "issuer": null
           },
          "readOnly": false,
          "baseEntities": []
        }
      ],
      "bearerOAuth": [
        {
          "client_id": null,
          "client_secret": null,
          "readOnly": false,
          "baseEntities": []
        }
      ],
      "passThrough": {
         "enabled": false,
         "readOnly": false,
         "baseEntities": []
      }
    },
    "certificate": {
      "key": null,
      "cert": null,
      "ca": null,
      "pfx": {
        "bundle": null,
        "password": null
      }
    },
    "ipAllowList": [],
    "emailOnError": {
      "smtp": {
        "enabled": false,
        "host": null,
        "port": 587,
        "proxy": null,
        "authenticate": true,
        "username": null,
        "password": null,
        "sendInterval": 15,
        "to": null,
        "cc": null
      }
    },
    "stream": {
      "baseUrls": [],
      "certificate": {
        "ca": null
      },
      "subscriber": {
        "enabled": false,
        "entity": {
          "undefined": {
            "nats": {
              "tenant": null,
              "subject": null,
              "jwt": null,
              "secret": null
            },
            "deleteUserOnLastGroupRoleRemoval": false,
            "convertRolesToGroups": false,
            "generateUserPassword": false,
            "modifyOnly": false,
            "replaceDomains": []
          }
        }
      },
      "publisher": {
        "enabled": false,
        "entity": {
          "undefined": {
            "nats": {
              "tenant": null,
              "subject": null,
              "jwt": null,
              "secret": null
            }
          }
        }
      }
    }
  },
  "endpoint": {
    "host": "hostname",
    "port": 30015,
    "username": "username",
    "password": "password",
    "saml_provider": "saml_provider_name"
  }
}

Configuration file have two main JSON objects: scimgateway and endpoint

Definitions in scimgateway object have fixed attributes, but values can be modified. Sections not used/configured can be removed. This object is used by the core functionality of the SCIM Gateway.

Definitions in endpoint object are customized according to our plugin code. Plugin typically need this information for communicating with endpoint

Configuration notes

Manual startup

Gateway can be started from a command window running in administrative mode

3 ways to start:

bun c:\my-scimgateway

bun c:\my-scimgateway\index.ts

<package-root>bun .

Ctrl+c to stop

Automatic startup - Windows Task Scheduler

Start Windows Task Scheduler (taskschd.msc), right click on "Task Scheduler Library" and choose "Create Task"

General tab:  
-----------
Name = SCIM Gateway
User account = SYSTEM
Run with highest privileges

Triggers tab:
-------------
Begin the task = At startup

Actions tab:
------------
Action = Start a program
Program/script = <install path>\bun.exe
Arguments = c:\my-scimgateway

Settings - tab:
---------------
Stop the task if runs longer than = Disabled (greyed out)

Verification:

Running as a isolated virtual Docker container

On Linux systems we may also run SCIM Gateway as a Docker image (using docker-compose)

To list running containers information:
docker ps

To list available images:
docker images

To view the logs:
docker logs scimgateway

To execute command within your running container:
docker exec scimgateway <bash command>

To stop scimgateway:
docker-compose stop

To restart scimgateway:
docker-compose start

To debug running container (using Visual Studio Code):
docker-compose -f docker-compose.yml -f docker-compose-debug.yml up -d
Start Visual Studio Code and follow these debugging instructions

To upgrade scimgateway docker image (remove the old stuff before running docker-compose up --build):

docker rm scimgateway  
docker rm $(docker ps -a -q); docker rmi $(docker images -q -f "dangling=true")  

Entra ID as IdP using SCIM Gateway

Entra ID could do automatic user provisioning by synchronizing users towards SCIM Gateway, and gateway plugins will update endpoints.

Plugin configuration file must include SCIM Version "2.0" (scimgateway.scim.version) and either Bearer Token (scimgateway.auth.bearerToken[x].token) or Entra ID Tenant ID GUID (scimgateway.auth.bearerJwtAzure[x].tenantIdGUID) or both:

scimgateway: {
  "scim": {
    "version": "2.0",
    ...
  },
  ...
  "auth": {
    "bearerToken": [
      {
        "token": "shared-secret"
      }
    ],
    "bearerJwtAzure": [
      {
        "tenantIdGUID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
      }
    ]
  }
  ...
}

token configuration must correspond with "Secret Token" defined in Entra ID
tenantIdGUID configuration must correspond with Entra ID Tenant ID

In Azure Portal: Azure-Microsoft Entra ID-Enterprise Application-<My Application>-Provisioning-Secret Token
Note, when "Secret Token" is left blank, Azure will use JWT (tenantIdGUID)

Azure-Microsoft Entra ID-Overview-Tenant ID

User mappings attributes between AD and SCIM also needs to be configured

Azure-Microsoft Entra ID-Enterprise Application-<My Application>-Provisioning-Edit attribute mappings-Mappings

Entra ID default SCIM attribute mapping for USER must have:

userPrincipalName mapped to userName (matching precedence #1)  

Entra ID default SCIM attribute mapping for GROUP must have:

displayName mapped to displayName (matching precedence #1)  
members mapped to members  

Some notes related to Entra ID:

CA Identity Manager as IdP using SCIM Gateway

Using Symantec/Broadcom/CA Identity Manger, plugin configuration might have to use SCIM Version "1.1" (scimgateway.scim.version).

In the Provisioning Manager we have to use

Endpoint type = SCIM (DYN Endpoint)

or create our own custom endpoint type based on this one

SCIM endpoint configuration example for Loki plugin (plugin-loki)

Endpoint Name = Loki-8880  
User Name = gwadmin  
Password = password  
SCIM Authentication Method = HTTP Basic Authentication  
SCIM Based URL = http://localhost:8880  

or:  

SCIM Based URL = http://localhost:8880/<baseEntity>

Username, password and port must correspond with plugin configuration file. For "Loki" plugin it will be config\plugin-loki.json

"SCIM Based URL" refer to the FQDN (or localhost) having SCIM Gateway installed. Portnumber must be included. Use HTTPS instead of HTTP if SCIM Gateway configuration includes certificates.

"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:

http://localhost:8880/client-a
http://localhost:8880/client-b

Each baseEntity should then be defined in the plugin configuration file with custom attributes needed. Please see examples in plugin-soap.json

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.

Entra ID provisioning

Using plugin-entra-id we could do user provisioning towards Entra ID

For testing purposes we could get an Azure free account

Entra ID configuration

For some odd reasons Application needs to be member of "User administrator" for having privileges to manage office/mobile phone on users that is member of any administrator roles

Also note, enable/disable user (accountEnabled - through Graph API) will fail if user have an "Administrator" role other than above mentioned "User Administrator" e.g. "Group Administrator"/"Application Administrator". To be sure we can enable/disable all users, application needs to be member of "Global administrator" - 62e90394-69f5-4237-9190-012177145e10.

SCIM Gateway configuration

Edit index.ts
Set plugin to be started to entra-id

const plugins = ['entra-id']

Edit plugin-entra-id.json

Note, for Symantec/Broadcom/CA Provisioning we must use SCIM version 1.1

scimgateway: {
  "scim": {
    "version": "1.1"
  },

username and password used to connect the SCIM Gateway must be defined.

    "auth": {
      "basic": [
        {
          "username": "gwadmin",
          "password": "password",
          "readOnly": false,
          "baseEntities": []
        }
      ],

Update tenantIdGUID, clientID and clientSecret according to what you copied from the previous Entra ID configuration.

If using proxy, set proxy.host to "http://<FQDN-ProxyHost>:<port>" e.g "http://proxy.mycompany.com:3128"

"endpoint": {
  "entity": {
    "undefined": {
      "connection": {
        "baseUrls": [
          "not in use for Entra ID when tenantIdGUID is defined"
        ],
        "auth": {
          "type": "oauth",
          "options": {
            "tokenUrl": "oauth token_url - not in use when tenantIdGUID is defined",
            "tenantIdGUID": "Entra ID Tenant ID (GUID) or Primary domain name - only used by plugin-entra-id",
            "clientId": "oauth client_id - Entra ID: Application ID",
            "clientSecret": "oauth client_secret - Entra ID: generated application secret value"
          }
        },
        "proxy": {
          "host": null,
          "username": null,
          "password": null
        }
      }
    }
  },
  "map": {
    ...
  }
}

Note, clientSecret and any proxy.password will become encrypted in this file on the first Azure connection.

For multi-tenant or multi-endpoint support, we may add several entities:

"endpoint": {
  "entity": {
    "undefined": {
        ...
    },
    "client-a": {
        ...
    },
    "client-b": {
        ...
    }
  }
}

For additional details, see baseEntity description.

Note, we should normally use certificate (https) for communicating with SCIM Gateway unless we install gateway locally on the manager (e.g. on the CA Connector Server). When installed on the manager, we could use http://localhost:port or http://127.0.0.1:port which will not be passed down to the data link layer for transmission. We could then also set {"localhostonly": true}

Using Symantec/Broadcom/CA Provisioning

Create a new endpoint type "Azure - ScimGateway"

Note, metafile "Azure - ScimGateway.xml" is based on CA "Azure - WSL7" with some minor adjustments like using Microsoft Graph API attributes instead of Azure AD Graph attributes.

Provisioning Manager configuration

Endpoint type = Azure - ScimGateway (DYN Endpoint)

Endpoint configuration example:

Endpoint Name = AzureAD-8881  
User Name = gwadmin  
Password = password  
SCIM Authentication Method = HTTP Basic Authentication  
SCIM Based URL = http://localhost:8881  
or  
SCIM Based URL = http://localhost:8881/<baseEntity>  

For details, please see section "CA Identity Manager as IdP using SCIM Gateway"

SCIM Gateway REST API

Create = POST http://localhost:8880/Users  
(body contains the user information)

Update = PATCH http://localhost:8880/Users/<id>
(body contains the attributes to be updated)

Search/Read = GET http://localhost:8880/Users?userName eq 
"userID"&attributes=<comma separated list of scim-schema defined attributes>

Search/explore all users:
GET http://localhost:8880/Users?attributes=userName

Delete = DELETE http://localhost:8880/Users/<id>

Discovery:

GET http://localhost:8880/ServiceProviderConfigs
Specification compliance, authentication schemes, data models.

GET http://localhost:8880/Schemas
Introspect resources and attribute extensions.

Note:

API Gateway

SCIM Gateway also works as an API Gateway when using url /api or /<baseEntity>/api

Following methods for the none SCIM based api-plugin are supported:

    GET /api  
    GET /api?queries  
    GET /api/{id}  
    POST /api + body  
    PUT /api/{id} + body  
    PATCH /api/{id} + body  
    DELETE /api/{id}  

These methods can also be used in standard SCIM plugins
Please see example plugin: plugin-api.ts

How to build your own plugins

For JavaScript coding editor you may use Visual Studio Code

Preparation:

Now we are ready for custom coding by editing plugin-mine.ts 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).

  1. Turn off group functionality - getGroups to return empty response
    Please see plugin-saphana that do not use groups.
  2. getUsers (test provisioning retrieve accounts)
  3. createUser (test provisioning new account)
  4. deleteUser (test provisioning delete account)
  5. modifyUser (test provisioning modify account)
  6. Turn on group functionality - getGroups having logic for returning groups if groups are supported
  7. getGroups (test provisioning retrieve groups)
  8. modifyGroup (test provisioning modify group members)
  9. createGroup (test provisioning new group)
  10. deleteGroup (test provisioning delete account)

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)

CA Provisioning using default SCIM endpoint do not support SCIM Enterprise User Schema Extension (having attributes like employeeNumber, costCenter, organization, division, department and manager). If we need these or other attributes not found in CA Provisioning, we could define our own by using the free-text "type" definition in the multivalue entitlements or roles attribute. In the template entitlements definition, we could for example define type=Company and set value to %UCOMP%. Please see plugin-soap.ts using Company as a multivalue "type" definition.

Using CA Connector Xpress we could create a new SCIM endpoint type based on the original SCIM. We could then add/remove attributes and change from default assign "user to groups" to assign "groups to user". There are also other predefined endpoints based on the original SCIM. You may take a look at "ServiceNow - WSL7" and "Zendesk - WSL7".

For project setup:

How to change "user member of groups" to "group member of users"

Using Connector Xpress based on the original SCIM endpoint.

Delete defaults:
Group - Associations - with User Account
Group - Attributes - members
User Account - Attributes - Group Membership

Create new attribute:
User Account - Attributes: Groups - Flexi DN - Multivalue - groups

Create User - Group associations:
User Account - Accociations - Direct association with = Group
User Account - Accociations - with Group

Note, "Include a Reverse Association" - not needed if we don't need Group object functionality e.g list/add/remove group members

User Attribute = Physical Attribute = Groups
Match Group = By Attribute = ID

Objects Must Exist
Use DNs in Attribute = activated (toggled on)

Include a Reverse Association (if needed)
Group Attribute = Virtual Attribute = User Membership
Match User Account = By Attribute = User Name

Note, groups should be capability attribute (updated when account is synchronized with template):
advanced options - Synchronized = enabled (toggled on)

Methods

Plugins should have following initialization:

// start - mandatory plugin initialization
const ScimGateway: typeof import('scimgateway').ScimGateway = await (async () => {
  try {
    return (await import('scimgateway')).ScimGateway
  } catch (err) {
    const source = './scimgateway.ts'
    return (await import(source)).ScimGateway
  }
})()
const scimgateway = new ScimGateway()
const config = scimgateway.getConfig()
scimgateway.authPassThroughAllowed = false
// end - mandatory plugin initialization

If using REST, we could also include the HelperRest:

// start - mandatory plugin initialization
...
const HelperRest: typeof import('scimgateway').HelperRest = await (async () => {
  try {
    return (await import('scimgateway')).HelperRest
  } catch (err) {
    const source = './scimgateway.ts'
    return (await import(source)).HelperRest
  }
})()
...
// end - mandatory plugin initialization

Plugins should include following SCIM methods:

In addition following general API methods are available for use:

In code editor (e.g., Visual Studio Code), method details and documentation are shown by IntelliSense

License

MIT © Jarle Elshaug

Change log

v5.0.4

[Improved]

v5.0.3

[Fixed]

[Improved]

v5.0.2

[Improved]

v5.0.1

[Fixed]

v5.0.0

[MAJOR]

Major version v5.0.0 marks a shift to native TypeScript support and prioritizes Bun over Node.js.

Besides going from JavaScript to TypeScript, following can be mentioned:

How to migrate existing plugins:

v4.5.12

[Improved]

v4.5.11

[Improved]

[Fixed]

v4.5.10

[Fixed]

v4.5.9

[Improved]

v4.5.8

[Fixed]

Note, plugin-ldap now has following new configuration:

"ldap": {
  "isOpenLdap": false,
  ...
  "namingAttribute": {
    "user": [
      {
        "attribute": "CN",
        "mapTo": "userName"
      }
    ],
    "group": [
      {
        "attribute": "CN",
        "mapTo": "displayName"
      }
    ]
  },
  ...
}

isOpenLdap true/false decides whether or not OpenLDAP Foundation protocol should be used for national characters and special characters in DN. For Active Directory, default isOpenLdap=false should be used.

namingAttribute can now be linked to scim mapTo attribute and is not hardcoded like it was in previous version.

Previous userNamingAttr and groupNamingAttr shown below, is now deprecated

"ldap": {
  ...
  "userNamingAttr": "CN",
  "groupNamingAttr": "CN",
  ...
}

v4.5.7

[Fixed]

[Improved]

v4.5.6

[Improved]

v4.5.5

[Fixed]

v4.5.4

[Fixed]

v4.5.3

[Fixed]

[Improved]

v4.5.1

[Improved]

v4.5.0

[Improved]

v4.4.6

[Improved]

v4.4.5

[Fixed]

[Improved]

v4.4.4

[Improved]

Below is an example of nginx reverse proxy configuration supporting SCIM Gateway ipAllowList and correct meta.location response:

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;

v4.4.3

[Improved]

v4.4.2

[Improved]

v4.4.1

[Improved]

[Fixed]

v4.4.0

[Improved]

Note, module soap is not default included anymore. SOAP based plugins e.g., plugin-soap therefore needs npm install soap for including module in your package

v4.3.0

[Improved]

v4.2.17

[Fixed]

[Improved]

v4.2.15

[Improved]

v4.2.14

[Fixed]

v4.2.13

[Fixed]

v4.2.12

[Improved]

v4.2.11

[Improved]

Note, obsolete - see v4.2.15 comments

v4.2.10

[Fixed]

v4.2.9

[Fixed]

v4.2.8

[Fixed]

v4.2.7

[Improved]

[Fixed]

v4.2.6

[Fixed]

v4.2.5

[Fixed]

v4.2.4

[Improved]

v4.2.3

[Fixed]

v4.2.2

[Fixed]

v4.2.1

[Fixed]

v4.2.0

[Improved]

v4.1.15

[Improved]

v4.1.14

[Fixed]

v4.1.12

[Improved]

v4.1.11

[Fixed]

v4.1.10

[Improved]

[Fixed]

v4.1.9

[Fixed]

v4.1.8

[Fixed]

v4.1.7

Note, this version breaks compability with previous versions of plugin-azure-ad

[Improved]

v4.1.6

[Improved]

v4.1.5

[Improved]

SCIM Gateway related news:

v4.1.4

[Fixed]

v4.1.3

[Fixed]

[Improved]

v4.1.2

[Improved]

v4.1.1

[Improved]

v4.1.0

[Improved]

v4.0.1

[Improved]

v4.0.0

[MAJOR]

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

How to upgrade your custom plugins:

Replace: scimgateway.exploreUsers = async (baseEntity, attributes, startIndex, count) => {
With: scimgateway.getUsers = async (baseEntity, getObj, attributes) => {

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

In the very beginning, add:

  // mandatory if-else logic - start
  if (getObj.operator) {
    if (getObj.operator === 'eq' && ['id', 'userName', 'externalId'].includes(getObj.attribute)) {
      // mandatory - unique filtering - single unique user to be returned - correspond to getUser() in versions < 4.x.x
    } else if (getObj.operator === 'eq' && getObj.attribute === 'group.value') {
      // optional - only used when groups are member of users, not default behavior - correspond to getGroupUsers() in versions < 4.x.x
      throw new Error(`${action} error: not supporting groups member of user filtering: ${getObj.rawFilter}`)
    } else {
      // optional - simpel filtering
      throw new Error(`${action} error: not supporting simpel filtering: ${getObj.rawFilter}`)
    }
  } else if (getObj.rawFilter) {
    // optional - advanced filtering having and/or/not - use getObj.rawFilter
    throw new Error(`${action} error: not supporting advanced filtering: ${getObj.rawFilter}`)
  } else {
    // mandatory - no filtering (!getObj.operator && !getObj.rawFilter) - all users to be returned - correspond to exploreUsers() in versions < 4.x.x
  }
  // mandatory if-else logic - end

In the new getUsers() replacing exploreUsers() "as-is", we then need some logic in the last "else" statement listed above.
We also need to add logic from existing getGroup() and getGroupMembers()
Please have a look at provieded plugins to see different ways of doing this logic.

Replace: scimgateway.exploreGroups = async (baseEntity, attributes, startIndex, count) => {
With: scimgateway.getGroups = async (baseEntity, getObj, attributes) => {

In the very beginning, add:

  // mandatory if-else logic - start
  if (getObj.operator) {
    if (getObj.operator === 'eq' && ['id', 'displayName', 'externalId'].includes(getObj.attribute)) {
      // mandatory - unique filtering - single unique user to be returned - correspond to getUser() in versions < 4.x.x
    } else if (getObj.operator === 'eq' && getObj.attribute === 'members.value') {
      // mandatory - return all groups the user 'id' (getObj.value) is member of - correspond to getGroupMembers() in versions < 4.x.x
      // Resources = [{ id: <id-group>> , displayName: <displayName-group>, members [{value: <id-user>}] }]
    } else {
      // optional - simpel filtering
      throw new Error(`${action} error: not supporting simpel filtering: ${getObj.rawFilter}`)
    }
  } else if (getObj.rawFilter) {
    // optional - advanced filtering having and/or/not - use getObj.rawFilter
    throw new Error(`${action} error: not supporting advanced filtering: ${getObj.rawFilter}`)
  } else {
    // mandatory - no filtering (!getObj.operator && !getObj.rawFilter) - all groups to be returned - correspond to exploreGroups() in versions < 4.x.x
  }
  // mandatory if-else logic - end

In the new getGroups() replacing exploreGroups() "as-is", we then need some logic in the last "else" statement listed above.
We also need to add logic from existing getGroup() and getGroupMembers()
Please have a look at provieded plugins to see different ways of doing this logic.

Delete deprecated exploreUsers(), getUser(), getGroupUsers(), exploreGroups(), getGroup() and getGroupMembers()

v3.2.11

[Fixed]

v3.2.10

[Fixed]

[Improved]

v3.2.9

[Fixed]

v3.2.8

[Fixed]

v3.2.7

[Improved]

[Fixed]

v3.2.6

[Fixed]

v3.2.5

[Fixed]

[Improved]

v3.2.4

[Fixed]

v3.2.3

[Fixed]

v3.2.2

[Fixed]

[Improved]

v3.2.1

[Fixed]

[Improved]

v3.2.0

[Improved]

v3.1.0

[Improved]

v3.0.8

[Fixed]

v3.0.7

[Fixed]

v3.0.6

[Fixed]

v3.0.4

[Improved]

v3.0.3

[Fixed]

v3.0.2

[Fixed]

v3.0.1

[Improved]

v3.0.0

[MAJOR]

[UPGRADE]

Note, this is a major upgrade (^2.x.x => ^3.x.x) that will brake compatibility with any existing custom plugins. To force a major upgrade, suffix @latest must be include in the npm install command, but it's recommended to do a fresh install and copy any custom plugins instead of upgrading an existing package

Old syntax:

scimgateway.getUser = async (baseEntity, userName, attributes) => {
scimgateway.getGroup = async (baseEntity, displayName, attributes) => {
scimgateway.modifyGroupMembers = async (baseEntity, id, members) => {

New syntax:

scimgateway.getUser = async (baseEntity, getObj, attributes) => {
  const userName = getObj.identifier // gives v2.x compatibility

scimgateway.getGroup = async (baseEntity, getObj, attributes) => {
  const displayName = getObj.identifier // gives v2.x compatibility

scimgateway.modifyGroup = async (baseEntity, id, attrObj) => {
  // attrObj.members corresponds to members in deprecated modifyGroupMembers

getUser comments:
getObj = { filter: <filterAttribute>, identifier: <identifier> }
e.g: getObj = { filter: 'userName', identifier: 'bjensen'}
filter: userName and id must be supported

getGroup comments:
getObj = { filter: <filterAttribute>, identifier: <identifier> }
e.g: getObj = { filter: 'displayName', identifier: 'GroupA' }
filter: displayName and id must be supported

Please see provided example plugins

Using the new getObj parameter gives more flexibility in the way of lookup a user e.g:
http://localhost:8880/Users?filter=emails.value eq "jsmith@example.com"&attributes=userName,name.givenName
getObj = { filter: 'emails.value', identifier: 'jsmith@example.com'}
attributes = 'userName,name.givenName'

Configuration file, auth settings have changed and now using arrays allowing more than one user/object to be set. "readOnly": true can also be set for allowing read only access for a spesific user (does not apply to bearerJwtAzure).

New syntax is:

"auth": {
  "basic": [
    {
      "username": "gwadmin",
      "password": "password",
      "readOnly": false
    }
  ],
  "bearerToken": [
    {
      "token": null,
      "readOnly": false
    }
  ],
  "bearerJwtAzure": [
    {
      "tenantIdGUID": null
    }
  ],
  "bearerJwt": [
    {
      "secret": null,
      "publicKey": null,
      "options": {
        "issuer": null
      },
      "readOnly": false
    }
  ]
}

v2.1.13

[Fixed]

v2.1.11

[Fixed]

v2.1.10

[Improved]

v2.1.9

[Fixed]

Thanks to Luca Moretto

v2.1.8

[Fixed]

v2.1.7

[Fixed]

v2.1.6

[Fixed]

[Improved]

v2.1.4

[Fixed]

v2.1.3

[Fixed]

v2.1.2

[Fixed]

[Improved]

v2.1.1

[Fixed]

v2.1.0

[Improved]

[UPGRADE]

v2.0.2

[Fixed]

v2.0.0

[MAJOR]

[UPGRADE]

Note, this is a major upgrade (^1.x.x => ^2.x.x) and will brake compatibility with any existing custom plugins. To force a major upgrade, suffix @latest must be include in the npm install command, but it's recommended to do a fresh install and copy any custom plugins instead of upgrading an existing package

cd c:\my-scimgateway
npm install scimgateway@latest

Custom plugins needs some changes (please see included example plugins)

v1.0.20

[Fixed]

[UPGRADE]

v1.0.19

[Fixed]

v1.0.18

[Improved]

[UPGRADE]

v1.0.14

[Fixed]

v1.0.13

[Fixed]

[UPGRADE]

v1.0.12

[Fixed]

v1.0.11

[Fixed]

v1.0.10

[Fixed]

v1.0.9

[Improved]

v1.0.8

[Improved]

[UPGRADE]

v1.0.7

[Improved]

v1.0.6

[Fixed]

v1.0.5

[Improved]

[Fixed]

Thanks to ywchuang

v1.0.4

[Improved]

[Fixed]

v1.0.3

[Fixed]

v1.0.2

[Fixed]

v1.0.1

[Fixed]

v1.0.0

[Improved]

[UPGRADE]
Method getGroupMembers must be updated for all custom plugins

Replace:

scimgateway.on('getGroupMembers', function (baseEntity, id, attributes, startIndex, count, callback) {
...
let ret = {
'Resources' : [],
'totalResults' : null
}
...
ret.Resources.push(userGroup)
...
callback(null, ret)

With:

scimgateway.on('getGroupMembers', function (baseEntity ,id ,attributes, callback) {
...
let arrRet = []
...
arrRet.push(userGroup)
...
callback(null, arrRet)

v0.5.3

[Improved]

v0.5.2

[Improved]

[UPGRADE]

v0.4.6

[Improved]

v0.4.5

[Improved]

[UPGRADE]

v0.4.4

[Improved]

[UPGRADE]

v0.4.2

[Fixed]

v0.4.1

[Improved]

[Fixed]

v0.4.0

[Improved]

[UPGRADE]

v0.3.8

[Fixed]

v0.3.7

[Improved]

v0.3.6

[Improved]

[UPGRADE]

v0.3.5

[Fixed]

v0.3.4

[Improved]

[Fixed]

v0.3.3

[Fixed]

[UPGRADE]

v0.3.2

[Fixed]

v0.3.1

[Improved]

v0.3.0

[Improved]

[UPGRADE]

v0.2.2 - v0.2.8

[Doc]

v0.2.1

[Fixed]

v0.2.0

Initial version