npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

scimgateway

v5.0.4

Published

Using SCIM protocol as a gateway for user provisioning to other endpoints

Downloads

5,540

Readme

SCIM Gateway

Build Status npm Versionnpm Downloads chat disqus GitHub forks


Author: Jarle Elshaug

Validated through IdP's:

  • Symantec/Broadcom/CA Identity Manager
  • Microsoft Entra ID
  • One Identity Manager/OneLogin
  • Okta
  • Omada
  • SailPoint/IdentityNow

Latest news:

  • Major version v5.0.0 marks a shift to native TypeScript support and prioritizes Bun over Node.js. This upgrade requires some modifications to existing plugins.
  • BREAKING: SCIM Stream is the modern way of user provisioning letting clients subscribe to messages instead of traditional IGA top-down provisioning. SCIM Gateway now offers enhanced functionality with support for message subscription and automated provisioning using SCIM Stream
  • Authentication PassThrough letting plugin pass authentication directly to endpoint for avoid maintaining secrets at the gateway. Kubernetes health checks and shutdown handler support
  • Supports OAuth Client Credentials authentication
  • Major version v4.0.0 getUsers() and getGroups() replacing some deprecated methods. No limitations on filtering/sorting. Admin user access can be linked to specific baseEntities. New MongoDB plugin
  • ipAllowList for restricting access to allowlisted IP addresses or subnets e.g. Azure IP-range
  • General LDAP plugin configured for Active Directory
  • PlugSSO using SCIM Gateway
  • Each authentication configuration allowing more than one admin user including option for readOnly
  • Codebase moved from callback of h... to the the promise(d) land of async/await
  • Supports configuration by environments and external files
  • Health monitoring through "/ping" URL, and option for error notifications by email
  • Entra ID user provisioning including license management e.g. Office 365, installed and configured within minutes!
  • Includes API Gateway for none SCIM/provisioning - becomes what you want it to become
  • Running SCIM Gateway as a Docker container

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:

  • Loki (NoSQL Document-Oriented Database)
    SCIM Gateway becomes a standalone SCIM endpoint
    Demonstrates user provisioning towards document-oriented database
    Using LokiJS for a fast, in-memory document-oriented database (much like MongoDB/PouchDB)
    Default gives two predefined test users loaded using in-memory only (no persistence)
    Configuration {"persistence": true} gives persistence file store (no test users)
    Example of a fully functional SCIM Gateway plugin

  • MongoDB (NoSQL Document-Oriented Database)
    Same as plugin "Loki", but using external MongoDB
    Shows how to implement a highly configurable multi tenant or multi endpoint solution through baseEntity in URL

  • SCIM (REST Webservice)
    Demonstrates user provisioning towards REST-Based endpoint (type SCIM)
    Using plugin Loki as SCIM endpoint
    Can be used as SCIM version-gateway e.g. 1.1=>2.0 or 2.0=>1.1
    Can be used to chain several gateways

  • Soap (SOAP Webservice)
    Demonstrates user provisioning towards SOAP-Based endpoint
    Example WSDLs are included
    Using endpoint "Forwardinc" as an example (comes with Symantec/Broadcom/CA IM SDK - SDKWS)
    Shows how to implement a highly configurable multi tenant or multi endpoint solution through baseEntity in URL

  • MSSQL (MSSQL Database)
    Demonstrates user provisioning towards MSSQL database

  • SAP HANA (SAP HANA Database)
    Demonstrates SAP HANA specific user provisioning

  • Entra ID (REST Webservices)
    Entra ID user provisioning including license management (App Service plans) e.g. Office 365
    Using Microsoft Graph API
    Using customized SCIM attributes according to Microsoft Graph API
    Includes Symantec/Broadcom/CA ConnectorXpress metafile for creating provisioning "Azure - ScimGateway" endpoint type

  • LDAP (Directory)
    Fully functional LDAP plugin
    Pre-configured for Microsoft Active Directory
    Using endpointMapper (like plugin-entra-id) for attribute mapping flexibility

  • API (REST Webservices)
    Demonstrates API Gateway/plugin functionality using post/put/patch/get/delete
    None SCIM plugin, becomes what you want it to become.
    Methods included can also be used in standard SCIM plugins
    Endpoint complexity could be put in this plugin, and client could instead communicate through Gateway using your own simplified REST specification.
    One example of usage could be creation of tickets in ServiceDesk and also the other way, closing a ticket could automatically approve/reject corresponding workflow in IdP.

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

  • port - Gateway will listen on this port number. Clients (e.g. Provisioning Server) will be using this port number for communicating with the gateway.

  • localhostonly - true or false. False means gateway accepts incoming requests from all clients. True means traffic from only localhost (127.0.0.1) is accepted.

  • payloadSize - if not defined, default "1mb" will be used. There are cases which large groups could exceed default size and you may want to increase by setting your own size

  • scim.version - "1.1" or "2.0". Default is "2.0".

  • scim.skipTypeConvert - true or false, default false. Multivalue attributes supporting types e.g. emails, phoneNumbers, ims, photos, addresses, entitlements and x509Certificates (but not roles, groups and members) will be become "type converted objects" when sent to modifyUser and createUser. This for simplicity of checking attributes included and also for the endpointMapper method (used by plugin-ldap and plugin-entra-id), e.g.:

      "emails": {
        "work": {"value": "[email protected]", "type": "work"},
        "home": {"value": "", "type": "home", "operation": "delete"},
        "undefined": {"value": "[email protected]"}
      }  
    
      skipTypeConvert set to true gives attribute "as-is": array, allow duplicate types including blank, but values to be deleted have been marked with "operation": "delete"
    
      "emails": [
        {"value": "[email protected]", "type": "work"},
        {"value": "john.smith.org", "type": "home", "operation": "delete"},
        {"value": "[email protected]"}
      ]  
  • scim.skipMetaLocation - true or false, default false. If set to true, meta.location which contains protocol and hostname from request-url, will be excluded from response e.g. "{...,meta":{"location":"https://my-company.com/<...>"}}. If using reverse proxy and not including headers X-Forwarded-Proto and X-Forwarded-Host, originator will be the proxy and we might not want to expose internal protocol and hostname being used by the proxy request.

  • scim."groupMemberOfUser - true or false, default false. If body contains groups and groupMemberOfUser=true, groups attribute will remain at user object (groups are member of user) instead of default user member of groups that will use modifyGroup method for maintaining group members.

  • scim.usePutSoftSync - true or false, default false. PUT /Users/bjensen will replace the user bjensen with body content. If set to true, only PUT body content will be replaced. Any additional existing user attributes and groups supported by plugin will remain as-is.

  • log.loglevel.file - off, error, info, or debug. Output to plugin-logfile e.g. logs\plugin-saphana.log

  • log.loglevel.console - off, error, info, or debug. Output to stdout and errors to stderr.

  • 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.

  • auth - Contains one or more authentication/authorization methods used by clients for accessing gateway - may also include:

    • auth.xx.readOnly - true/false, true gives read only access - only allowing GET requests for corresponding admin user
    • auth.xx.baseEntities - array containing one or more baseEntity allowed for this user e.g. ["client-a"] - empty array allowing all.
      Methods are disabled by setting corresponding admin user to null or remove methods not used
  • 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.

  • auth.bearerToken - Array of one or more bearer token objects - Shared token/secret (supported by Entra ID). Clear text value will become encrypted when gateway is started.

  • auth.bearerJwtAzure - Array of one or more JWT used by Azure SyncFabric. tenantIdGUID must be set to Entra ID Tenant ID.

  • auth.bearerJwt - Array of one or more standard JWT objects. Using secret or publicKey for signature verification. publicKey should be set to the filename of public key or certificate pem-file located in <package-root>\config\certs or absolute path being used. Clear text secret will become encrypted when gateway is started. options.issuer is mandatory. Other options may also be included according to jsonwebtoken npm package definition.

  • auth.bearerOAuth - Array of one or more Client Credentials OAuth configuration objects. client_id and client_secret are mandatory. client_secret value will become encrypted when gateway is started. OAuth token request url is /oauth/token e.g. http://localhost:8880/oauth/token

  • auth.passThrough - Setting auth.passThrough.enabled=true will bypass SCIM Gateway authentication. Gateway will instead pass ctx containing authentication header to the plugin. Plugin could then use this information for endpoint authentication and we don't have any password/token stored at the gateway. Note, this also requires plugin binary having scimgateway.authPassThroughAllowed = true and endpoint logic for handling/passing ctx.request.header.authorization

  • certificate - If not using TLS certificate, set "key", "cert" and "ca" to null. When using TLS, "key" and "cert" have to be defined with the filename corresponding to the primary-key and public-certificate. Both files must be located in the <package-root>\config\certs directory unless absolute path being defined e.g:

      "certificate": {
        "key": "key.pem",
        "cert": "cert.pem",
        "ca": null
      }  

    Example of how to make a self signed certificate:

      openssl req -nodes -newkey rsa:2048 -x509 -sha256 -days 3650 -keyout key.pem -out cert.pem -subj "/O=Testing/OU=SCIM Gateway/CN=<FQDN>" -config "<path>\openssl.cnf"

    <FQDN> is Fully Qualified Domain Name of the host having SCIM Gateway installed

    Note, when using Symantec/Broadcom/CA Provisioning, the "certificate authority - CA" also have to be imported on the Connector Server. For self-signed certificate CA and the certificate (public key) is the same.

    PFX / PKCS#12 bundle can be used instead of key/cert/ca e.g:

      "pfx": {
        "bundle": "certbundle.pfx",
        "password": "password"
      }

    Note, we should normally use certificate (https) for communicating with SCIM Gateway unless we install ScimGatway 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}

  • ipAllowList - Array of one or more IPv4/IPv6 subnets (CIDR) allowed for incoming traffic. E.g. using Entra ID as IdP, we would like to restrict access to IP addresses used by Azure. Azure IP-range can be downloaded from: https://azureipranges.azurewebsites.net, enter AzureActiveDirectory in the search list and select JSON download. Copy the "addressPrefixes" array content and paste into ipAllowList array. CIDR single IP-host syntax is a.b.c.d/32. Note, front-end HTTP proxy or a load balancer must include client IP-address in the X-Forwarded-For header. Configuration example:

      "ipAllowList": [
        "13.64.151.161/32",
        "13.66.141.64/27",
        ...
        "2603:1056:2000::/48",
        "2603:1057:2::/48"
      ]
  • emailOnError - Contains configuration for sending error notifications by email. Note, only the first error will be sent until sendInterval have passed

  • emailOnError.smtp.enabled - true or false, value set to true will enable email notifications

  • emailOnError.smtp.host - Mailserver e.g. "smtp.office365.com"

  • emailOnError.smtp.port - Port used by mailserver e.g. 587, 25 or 465

  • emailOnError.smtp.proxy - If using mailproxy e.g. "http://proxy-host:1234"

  • emailOnError.smtp.authenticate - true or false, set to true will use username/password authentication

  • emailOnError.smtp.username - Mail account for authentication and also the sender of the email, e.g. "[email protected]"

  • emailOnError.smtp.password - Mail account password

  • emailOnError.smtp.sendInterval - Mail notifications on error are deferred until sendInterval minutes have passed since the last notification. Default 15 minutes

  • emailOnError.smtp.to - Comma separated list of recipients email addresses e.g: "[email protected]"

  • emailOnError.smtp.cc - Comma separated list of cc email addresses

  • stream - See SCIM Stream for configuration details

  • endpoint - Contains endpoint specific configuration according to our plugin code.

Configuration notes

  • Custom Schemas, ServiceProviderConfig and ResourceType can be used if ./lib/scimdef-v2.json or scimdef-v1.json exists. Original scimdef-v2.json/scimdef-v1.json can be copied from node_modules/scimgateway/lib to your plugin/lib and customized.

  • Using reverse proxy and we want ipAllowList and correct meta.location response, following headers must be set by proxy: X-Forwarded-For, X-Forwarded-Proto and X-Forwarded-Host

  • Setting environment variable SEED with some random characters will override default password seeding logic. This also allow copying configuration file with encrypted secrets from one machine to another.

  • All configuration can be set based on environment variables. Syntax will then be "process.env.<ENVIRONMENT>" where <ENVIRONMENT> is the environment variable used. E.g. scimgateway.port could have value "process.env.PORT", then using environment variable PORT.

  • All configuration values can be moved to a single external file having JSON dot notation content with plugin name as parent JSON object. Syntax in original configuration file used by the gateway will then be "process.file.<path>" where <path> is the file used. E.g. key endpoint.password could have value "process.file./var/run/vault/secrets.json"

  • All configuration values can be moved to multiple external files, each file containing one single value. Syntax in original configuration file used by the gateway will then be "process.text.<path>" where <path> is the file which contains raw (UTF-8) character value. E.g. key endpoint.password could have value "process.text./var/run/vault/endpoint.password".

    Example:

      {
        "scimgateway": {
          ...
          "port": "process.env.PORT",
          ...
          "loglevel": {
            "file": "process.env.LOG_LEVEL_FILE",
            ...
          "auth": {
            "basic": [
              {
                "username": "process.file./var/run/vault/secrets.json",
                "password": "process.file./var/run/vault/secrets.json"
              },
              ...
            ],
            "bearerJwt": [
               "secret": "process.text./var/run/vault/jwt.secret",
               "publicKey": "process.text./var/run/vault/jwt.pub",
      		 ...
      	  ],
            ...
          },
        "endpoint": {
          ...
          "username": "process.file./var/run/vault/secrets.json",
          "password": "process.file./var/run/vault/secrets.json",
          ...
        }
      }  

    jwt.secret file content example:

      thisIsSecret

    secrets.json file content example for plugin-soap:

      {
        "plugin-soap.scimgateway.auth.basic[0].username": "gwadmin",
        "plugin-soap.scimgateway.auth.basic[0].password": "password",
        "plugin-soap.endpoint.username": "superuser",
        "plugin-soap.endpoint.password": "secret"
      }  

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:

  • Right click task - Run, verify process node.exe (SCIM Gateway) can be found in the task manager (not the same as task scheduler). Also verify logfiles <pakage-root>\logs
  • Right click task - End, verify process node.exe have been terminated and disappeared from task manager
  • Reboot server and verify SCIM Gateway have been automatically started

Running as a isolated virtual Docker container

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

  • Docker Pre-requisites:
    docker-ce
    docker-compose
  • Install SCIM Gateway within your own package and copy provided docker files:

      mkdir /opt/my-scimgateway  
      cd /opt/my-scimgateway  
      bun init -y  
      bun install scimgateway  
      bun pm trust scimgateway  
      cp ./config/docker/* .  

    docker-compose.yml <== Here is where you would set the exposed port and environment
    Dockerfile <== Main dockerfile
    DataDockerfile <== Handles volume mapping
    docker-compose-debug.yml <== Debugging

  • Create a scimgateway user on your Linux VM.

      adduser scimgateway
  • Create a directory on your VM host for the scimgateway configs:

      mkdir /home/scimgateway/config
  • Copy your updated configuration file e.g. /opt/my-scimgateway/config/plugin-loki.json to /home/scimgateway/config. Use scp to perform the copy.

    NOTE: /home/scimgateway/config is where all important configuration and loki datastore will reside outside of the running docker container. If you upgrade scimgateway you won't lose your configurations and data.

  • Build docker images and start it up

      docker-compose up --build -d

    NOTE: Add the -d flag to run the command above detached.

    Be sure to confirm that port 8880 is available with a simple http request

    If using default plugin-loki and we have configured {"persistence": true}, we could confirm scimgateway created loki.db:

      su scimgateway  
      cd /home/scimgateway/config  
      ls loki.db  

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:

  • Entra ID SCIM documentation

  • For using OAuth/JWT credentials, Entra ID configuration "Secret Token" (bearer token) should be blank. Plugin configuration must then include bearerJwtAzure.tenantIdGUID. Click "Test Connection" in Azure to verify

  • Entra ID do a regular check for a "non" existing user/group. This check seems to be a "keep alive" to verify connection.

  • Entra ID first checks if user/group exists, if not exist they will be created (no explore of all users like CA Identity Manager)

  • Deleting a user in Entra ID 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.

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

  • Logon to Azure as global administrator
  • Microsoft Entra ID - App registrations
    • Click "New registration"
    • Name = SCIM Gateway Inbound
    • Select: Accounts in this organizational directory only
    • Click "Register"
    • Overview:
      • Copy "Application (client) ID"
      • Copy "Directory (tentant) ID"
    • Certificates & secrets:
      • Click "New client secret"
      • Description = SCIM Gateway Inbound secret#1
      • Select an appropriate "Expires"
      • Click "Add"
      • Copy "Value" of the new secret that was created
    • API permissions: - Add a permission - Microsoft Graph - Application permissions
      • Optionally remove any defaults included e.g. User.Read
      • Click "Add a permission"
      • Microsoft Graph
      • Application permissions
      • Directory - Directory.ReadWriteAll
      • Organization - Organization.ReadWrite.All
      • Click "Add permissions"
        Note, we also have to go to Enterprise application to grant these consents
  • Microsoft Entra ID - Enterprise applications - SCIM Gateway Inbound
    • Permissions:
      • Click "Grant admin consent for [tenant name]"
      • In the logon dialog, logon as global administrator
      • In permissions request dialog, click "Accept"
      • Click "Refresh", directory and organization permissions are now listed and OK

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.

  • Microsoft Entra ID - Roles and administration
    • Click on role "User administrator"
    • Click "Add assignments"
    • Search: SCIM Gateway Inbound (application name)
    • Select the application that shows up and click "Add"

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"

  • Start SCIM Gateway
    • Using plugin-entra-id: const plugins = ['entra-id'] in index.ts
    • username, password and port defined in plugin-entra-id.json must also be known
  • Start ConnectorXpress
  • Setup Data Sources
    • Add
    • Layer7 (this is SCIM)
    • Name = SCIM Gateway-8881
    • Base URL = http://localhost:8881 (SCIM Gateway installed locally on Connector Server)
  • Add the new "Azure - ScimGateway" endpoint type
    • Metadata - Import - "my-scimgateway\node_modules\scimgateway\config\resources\Azure - ScimGateway.xml"
    • Select the datasource we created - SCIM Gateway-8881
    • Enter password for the user defined in datasource (e.g. gwadmin/password)
    • On the right - expand Provisioning Servers - your server - and logon
    • Right Click "Endpoint Types", Create New Endpoint Type
      • You may use default name "Azure - ScimGateway" and click "OK" to create endpoint

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:

  • userName (mandatory) = UserID
  • id (mandatory) = Unique id. Could be set to the same as UserID but don't have to.

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:

  • Copy "best matching" example plugin e.g. lib\plugin-mssql.ts and config\plugin-mssql.json and rename both copies to your plugin name prefix e.g. plugin-mine.ts and plugin-mine.json (for SOAP Webservice endpoint we might use plugin-soap as a template)
  • Edit plugin-mine.json and define a unique port number for the gateway setting
  • Edit index.ts and include your plugin in the startup e.g. const plugins = ['mine']');
  • Start SCIM Gateway and verify. If using CA Provisioning you could setup a SCIM endpoint using the port number you defined

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:

  • Datasource = Layer7 (CA API) - this is SCIM
  • Layer7 Base URL = SCIM Gateway url and port (SCIM Base URL)
  • Authentication = Basic Authentication
    (connect using gwadmin/password defined in plugin config-file)

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:

  • scimgateway.getUsers()
  • scimgateway.createUser()
  • scimgateway.deleteUser()
  • scimgateway.modifyUser()
  • scimgateway.getGroups()
  • scimgateway.createGroup()
  • scimgateway.deleteGroup()
  • scimgateway.modifyGroup()

In addition following general API methods are available for use:

  • scimgateway.postApi()
  • scimgateway.putApi()
  • scimgateway.patchApi()
  • scimgateway.getApi()
  • scimgateway.deleteApi()

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]

  • minor type definition cosmetics

v5.0.3

[Fixed]

  • unauthorized connection when using configuration bearerJwtAzure

[Improved]

  • minor type definition cosmetics

v5.0.2

[Improved]

  • minor cosmetics readme updates

v5.0.1

[Fixed]

  • postinstall did not update index.ts when default bun index.ts did exist

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:

  • Code editor now having IntelliSense showing available methods and documentation details for scimgateway methods

  • index.ts having new logic for starting plugins e.g.: const plugins = ['ldap'] for starting plugin-ldap

  • If using Node.js: node must be version >= 22.6.0, scimgateway must be downloaded from github (because stripping types is currently unsupported for files under node_modules) and startup argument --experimental-strip-types e.g.; node --experimental-strip-types index.ts

  • Plugins can use scimgateway.HelperRest() for REST functionality. Previously this logic was included in each plugin that used REST.

      // 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  

    Note, HelperRest use fetch which is not fully supported by Node.js regarding TLS.
    For TLS and Node.js, environment must instead be used and set before started, e.g.,:
    export NODE_EXTRA_CA_CERTS=/package-path/config/certs/ca.pem
    or export NODE_TLS_REJECT_UNAUTHORIZED=0

  • Configuration secrets (password, secret, token, client_secret, ... ) defined in the endpoint section of the configuration file, will automatically be encrypted/decrypted. If there are secrets not handled by the automated encryption/decryption, we may use scimgateway.getSecret(). In the old version, corresponding method was named scimgateway.getPassword().

  • kubernetes configuration and logic have been removed. Kubernetes can use default /ping url for healthchecks, and graceful shutdown is taken care of the gateway

  • In case using custom schemas defined in lib/scimdef-v1/v2.js, these files have now changed to scimdef-v1/v2.json

  • config/docker/Dockerfile now using Bun

  • plugin-entra, modify licenses/servicePlans is not included anymore, only listing. For license management we instead use groups.

  • plugin-ldap, for LDAPS/TLS and Bun, we must use environments e.g.:
    export NODE_EXTRA_CA_CERTS=/package-path/config/certs/ca.pem
    or export NODE_TLS_REJECT_UNAUTHORIZED=0

How to migrate existing plugins:

  • Remove old index.js, use the new index.ts and update const plugins = ['xxx'] to include your plugin name(s)

  • Rename plugin-xxx.js to plugin-xxx.ts

  • import must be used instead of require for loading modules e.g.:
    const Loki = require('lokijs') => import Loki from 'lokijs'

  • Use the new mandatory settings:

      // 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
  • Use the new config object (mentioned above) which contains the scimgatway.endpoint configuration having automated encryption/decryption of any attributes named password, secret, client_secret, token and APIKey

  • The old scimgateway.getPassword() is not normally not needed because of scimgateway automated config logic. If needed, use the new scimgateway.getSecret().

  • Use the new logging syntax:

      replace: scimgateway.logger.debug(`${pluginName}[${baseEntity}] xxx`)  
      with: scimgateway.logDebug(baseEntity, `xxx`)
  • Use scimgateway.HelperRest() for REST functionlity, also supports Auth PassThrough

  • scimgateway.endpointMapper() may be used for inbound/outbound attribute mappings

  • In general when using TypeScript, variables should be type defined: let isDone: boolean = false, catch (err: any), ...

v4.5.12

[Improved]

  • plugin-ldap, new configuration { allowModifyDN: true } allows DN being changed based on modified mapping or namingAttribute

v4.5.11

[Improved]

  • deleteUser will try to revoke user from groups before deleting user
  • advanced or-filter (e.g., used by One Identity Manager) will be chunked and handled by scimgateway as separate calls to plugin
  • baseEntity now included in scimgateway log entries like plugin log entries

[Fixed]

  • plugin-ldap, using OpenLDAP - configuration { "isOpenLdap": true } and adding an already existing group member returned 500 Error instead of 200 OK.

  • plugin-ldap, using OpenLDAP in combination with endpoint user mapping "type":"array" and "typeInbound":"string" for handling comma separated SCIM string mapping towards an endpoint array/multivalue attribute, did not return correct sort order of the comma separated string when using OpenLDAP. Mapping example:

      "<endpointAttr>": {
        "mapTo": "<scimAttr>",
        "type": "array",
        "typeInbound": "string"
      },

v4.5.10

[Fixed]

  • PUT changes introduced in v4.5.7 had incorrect check of configuration groupMemberOfUser (default not set)

v4.5.9

[Improved]

  • Dependencies bump

v4.5.8

[Fixed]

  • plugin-ldap failed when using national special characters and some other LDAP special characters in DN

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]

  • PUT changes introduced in v4.4.6 did not handle PUT /Groups correctly

[Improved]

  • configuration scim.usePutGroupMemberOfUser replaced by scim.groupMemberOfUser
  • misc cosmetics

v4.5.6

[Improved]

  • plugin-ldap preserve multivalue-attribute order on modify. Do not apply to groups/members.

v4.5.5

[Fixed]

  • PUT /Groups/xxx failed on final group lookup and returned error
  • endpointMapper failed to correctly map customExtensions in certain use cases

v4.5.4

[Fixed]

  • Delete User missing url-decoding of id e.g. using ldap-dn as id

v4.5.3

[Fixed]

  • plugin-api configuration file having new credentials for dummy-json testing

[Improved]

  • Dependencies bump

  • plugin-loki and plugin-mongodb, minor improvements for handling raw mulitivalue updates when not using default skipTypeConvert=false

  • endpointMapper supporting comma separated string to be converted to array, e.g.:
    SCIM otherMails = "[email protected],[email protected],[email protected]"

    endpointMapper configuration for endpoint attribute emails of type array:

    "map": { "user": { "emails": { "mapTo": "otherMails", "type": "array", "typeInbound": "string" }, ...

v4.5.1

[Improved]

  • scim-stream, client reconnect improvements

v4.5.0

[Improved]

  • scim-stream, scimgateway now supports stream publishing mode having SCIM Stream as a prerequisite. In this mode, standard incoming SCIM requests from your Identity Provider (IdP) or API are directed and published to the stream. Subsequently, one of the gateways subscribing to the channel utilized by the publisher will manage the SCIM request, and response back to the publisher. Using SCIM Stream we have egress/outbound only traffic and get loadbalancing/failover by adding more gateways subscribing to same channel.
  • scim-stream, subscriber will do automatic retry until connected when plugin not able to connect to endpoint (offline endpoint)
  • plugin-ldap, modifyGroup now supports all attributes and not only add/remove members
  • certificate absolute path may be used in plugin configuration file instead of default relative path
  • dependencies bump

v4.4.6

[Improved]

  • Some PUT logic redesign. More granularity on mulitvalues, instead of including all elements, now only those that differ are sent to modifyUser.

v4.4.5

[Fixed]

  • PATCH group members=[] should remove all members
  • scim-stream modify user fix

[Improved]

  • plugin-entra-id, plugin-scim and plugin-api having updated REST endpoint helpers-template that includes tokenAuth (now used by plugin-api). Auth PassTrhough also supported for oauth/tokenAuth endpoint
  • PUT improvements

v4.4.4

[Improved]

  • New configuration: scim.skipMetaLocation
    true or false, default false. If set to true, meta.location which contains protocol and hostname from request-url, will be excluded from response e.g. "{...,meta":{"location":"https://my-company.com/<...>"}}. If using reverse proxy and not including headers X-Forwarded-Proto and X-Forwarded-Host, originator will be the proxy and we might not want to expose internal protocol and hostname being used by the proxy request.

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]

  • Dependencies bump

v4.4.2

[Improved]

  • scim-stream subscriber configuration have been changed:
    old: "convertRolesToGroups": false
    new: "skipConvertRolesToGroups": false
    This means convert roles to groups is default behavior unless skipConvertRolesToGroups=true

v4.4.1

[Improved]

  • scim-stream subscriber using latest api and some additional recovery logic
    Prerequisite: SCIM Stream version > v1.0.0

[Fixed]

  • plugin-loki was missing async await and could cause problems in some stress test use cases

v4.4.0

[Improved]

  • SCIM Gateway now offers enhanced functionality with support for message subscription and automated provisioning using SCIM Stream
  • plugin-entra-id, plugin-scim and plugin-api having updated REST endpoint helpers-template to address and resolve endpoint throttling

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]

  • configuration scimgateway.scim.port can now be set to 0 or removed for deactivating listener
  • configuration cimgateway.scim.usePutSoftSync set to true now includes additional logic that do not change existing user attributes not included in PUT body content
  • createUser/createGroup no longer return id if id have not been returned by plugin or by getUser filtering on userName. Previously userName was returned as id when missing plugin logic.
  • plugin-ldap supporting simpel filtering
  • plugin-loki using baseEntity configuration for supporting multi loki endpoints
  • plugin-azure-ad renamed to plugin-entra-id
  • plugin-entra-id and plugin-scim now using an updated default REST helpers-template that gives more flexible endpoint authentication support like OAuth, Basic, Bearer, custom-headers, no-auth,...
  • Dependencies bump

v4.2.17

[Fixed]

  • plugin-loki incorrect unique filtering

[Improved]

  • Dependencies bump

v4.2.15

[Improved]

  • Plugin can set error statusCode returned by scimgateway through error object key err.name. This can be done by adding suffix #code to err.name where code is HTTP status code e.g., err.name += '#401'. This can be useful for auth.PassThrough and other scenarios like createUser where user already exist (409) and modifyUser where user does not exist (404)

    This change replace statusCode logic introduced in v4.2.11

v4.2.14

[Fixed]

  • PUT now returning 404 instead of 500 when trying to update a user/group that does not exist

v4.2.13

[Fixed]

  • /ping now excluded from info logs. If we want ping logging, use something else than lowercase e.g., /Ping or /PING

v4.2.12

[Improved]

  • Schemas, ServiceProviderConfig and ResourceType can be customized if lib/scimdef-v2.js (or scimdef-v1.js) exists. Original scimdef-v2.js/scimdef-v1.js can be copied from node_modules/scimgateway/lib to your plugin/lib and customized.

v4.2.11

[Improved]

Note, obsolete - see v4.2.15 comments

  • Plugin can set error statusCode returned by scimgateway through error message. Error message must then contain string "statusCode":xxx where xxx is HTTP status code e.g., 401. Plugin using REST will have statusCode automatically included in error message thrown by plugin. This could be useful for auth.PassThrough.

v4.2.10

[Fixed]

  • plugin-ldap broken after dependencies bump of ldapjs (from 2.x.x to 3.x.x) in version 4.2.7

v4.2.9

[Fixed]

  • installation require nodejs >= v.16.0.0 due to previous dependencies bump

v4.2.8

[Fixed]

  • PUT did not allow group name to be modified

v4.2.7

[Improved]

  • new plugin configuration scim.usePutGroupMemberOfUser can be set to true or false, default false. PUT /Users/<user> will replace user with body content. If body contains groups and usePutGroupMemberOfUser=true, groups will be set on user object (groups are member of user) instead of default user member of groups
  • plugin-forwardinc renamed to plugin-soap
  • Dependencies bump

[Fixed]

  • plugin-azure-ad fixed some issues introduced in v4.2.4
  • plugin-mongodb fixed some issues introduced in v4.2.4

v4.2.6

[Fixed]

  • cosmetics related to 401 error handling introduced in v4.2.4

v4.2.5

[Fixed]

  • travis test build cosmetics

v4.2.4

[Improved]

  • provided plugins now supports Auth PassThrough. See helpers methods like getClientIdentifier(), getCtxAuth() and changes in doRequest() and getServiceClient(). In general, PassThrough is supported for both basic and bearer auth. Password/secret/client_secret are then not needed in configuration file. Username may still be needed in configuration file depended on how logic is implemented (ref. mongodb/mssql) and what auth beeing used (basic/bearer). Plugin scim, api and azure-ad are all REST plugins having the same helpers (but, some minor differences to azure-ad using OAuth and the getAccessToken() method)

v4.2.3

[Fixed]

  • plugin-loki and plugin-mongodb, for multi-value attributes like emails,phoneNumbers,... that includes primary attribute, only one is allowed having primary value set to true in the multi-value set.

v4.2.2

[Fixed]

v4.2.1

[Fixed]

  • plugin-azure-ad createUser failed when manager was included
  • plugin-ldap slow when not using group/groupBase configuration

v4.2.0

[Improved]

  • Kubernetes health checks and shutdown handler support

    Plugin configuration prerequisite: kubernetes.enabled=true

      "kubernetes": {
        "enabled": true,
        "shutdownTimeout": 15000,
        "forceExitTimeout": 1000
      }

    Thanks to Kevin Osborn

v4.1.15

[Improved]

  • Authentication PassThrough for passing the authentication directly to plugin without being processed by scimgateway. Plugin can then pass this authentication to endpoint for avoid maintaining secrets at the gateway.

    Plugin configuration prerequisites: auth.passThrough.enabled=true

      "auth": {
         ...
         "passThrough": {
           "enabled": true,
           "readOnly": false,