Git Product home page Git Product logo

scimgateway's Introduction

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
  • OneLogin
  • Okta
  • Omada
  • SailPoint/IdentityNow

Latest news:

  • 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. Using SCIM Stream we have egress/outbound only traffic and get loadbalancing/failover by adding more gateways subscribing to the same channel.
  • 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.

Using SCIM Stream, gateway may enable Pub/Sub allowing incoming SCIM requests to be published and processed by other gateways acting as subscribers. This extends beyond being Entra ID and HR subscriber for messages published by the SCIM Stream collector.

SCIM Gateway is based on the popular asynchronous event driven framework Node.js using JavaScript. It is cloud and firewall friendly using REST webservices. 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
    Excample 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 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 Node.js

Node.js is a prerequisite and have to be installed on the server.

Download the windows installer (.msi 64-bit) and install using default options.

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
npm init -y
npm install scimgateway

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

index.js, lib and config directories containing example plugins have been copied to your package from the original scimgateway package located under node_modules.

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

Startup and verify default Loki plugin

node c:\my-scimgateway

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

For more functionality using browser (post/patch/delete) a REST extension/add-on is needed.

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

Upgrade SCIM Gateway

Not needed after a fresh install

Check if newer versions are available:

cd c:\my-scimgateway
npm outdated

Lists current, wanted and latest version. No output on screen means we are running the latest version.

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 you copy index.js, config and lib folder (your customized plugins) from your previous installation to the new installation. You should also read the version history to see if your custom plugins needs to be updated.

Alternatives are:

Upgrade to latest minor version:

cd c:\my-scimgateway
npm 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: npm install scimgateway@latest

Avoid (re-)adding the files created during postinstall

When maintaining a set of modifications it useful to disable the postinstall operations to keep your changes intact by setting the property scimgateway_postinstall_skip = true in .npmrc or by setting environment SCIMGATEWAY_POSTINSTALL_SKIP = true

Configuration

index.js defines one or more plugins to be started. We could comment out those we do not need. Default configuration only starts the loki plugin.

const loki = require('./lib/plugin-loki')
// const mongodb = require('./lib/plugin-mongodb')
// const scim = require('./lib/plugin-scim')
// const soap = require('./lib/plugin-soap') // prereq: npm install soap
// const mssql = require('./lib/plugin-mssql')
// const saphana = require('./lib/plugin-saphana') // prereq: npm install hdb
// const entra = require('./lib/plugin-entra-id')
// const ldap = require('./lib/plugin-ldap')
// const api = require('./lib/plugin-api')

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

lib\plugin-saphana.js
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,
      "usePutSoftSync" : false,
      "usePutGroupMemberOfUser": 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
      }
    },
    "kubernetes": {
      "enabled": false,
      "shutdownTimeout": 15000,
      "forceExitTimeout": 1000
    },
    "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.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.

  • scim."usePutGroupMemberOfUser - true or false, default false. PUT /Users/<user> will replace the 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

  • 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

  • kubernetes - Enable Kubernetes support for healthchecks and graceful shutdown.

  • kubernetes.enabled - true or false, true will enable Kubernets health checks and shutdown handler

  • kubernetes.shutdownTimeout - Number of milliseconds to wait before shutting down (default 15000).

  • kubernetes.forceExitTimeout - Number of milliseconds before forceful exiting (default 1000).

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

  • 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 now be started from a command window running in administrative mode

3 ways to start:

node c:\my-scimgateway

node c:\my-scimgateway\index.js

<package-root>node .

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 = c:\Program Files\nodejs\node.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  
      npm init -y  
      npm install 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 including license management e.g. O365

For testing purposes we could get an Azure free account and in addition the free Office 365 for testing license management through Azure.

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.js
Uncomment startup of plugin-entra-id, other plugins could be comment out if not needed

const entra = require('./lib/plugin-entra-id')

Edit plugin-entra-id.json

Note, for Symantec/Broadcom/CA Provisioning we have to 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": {
      "tenantIdGUID": "DomainName or DirectoryID (GUID)",
      "clientId": "Application ID",
      "clientSecret": "Generated application key value",
      "proxy": {
        "host": null,
        "username": null,
        "password": null
      }
    }
  }
}

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
    • "const entra" must be uncomment in index.js
    • 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.js

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.js and config\plugin-mssql.json and rename both copies to your plugin name prefix e.g. plugin-mine.js and plugin-mine.json (for SOAP Webservice endpoint we might use plugin-soap as a template)
  • Edit plugin-mine.json and define a unique port number for the gateway setting
  • Edit index.js and add a new line for starting your plugin e.g. let mine = require('./lib/plugin-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.js 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.js 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:

// mandatory plugin initialization - start
const path = require('path')
let ScimGateway = null
try {
  ScimGateway = require('scimgateway')
} catch (err) {
  ScimGateway = require('./scimgateway')
}
let scimgateway = new ScimGateway()
let pluginName = path.basename(__filename, '.js')
let configDir = path.join(__dirname, '..', 'config')
let configFile = path.join(`${configDir}`, `${pluginName}.json`)
let config = require(configFile).endpoint
let validScimAttr = [] // empty array - all attrbutes are supported by endpoint
// add any external config process.env and process.file
config = scimgateway.processExtConfig(pluginName, config)
scimgateway.authPassThroughAllowed = false
// mandatory plugin initialization - end

getUsers

scimgateway.getUsers = async (baseEntity, getObj, attributes, ctx) => {
    let ret = {
        "Resources": [],
        "totalResults": null
    }
	...
	return ret
}  
  • baseEntity = Optional for multi-tenant or multi-endpoint support (defined in base url e.g. <baseurl>/client1 gives baseEntity=client1)
  • getObj = { attribute: <>, operator: <>, value: <>, rawFilter: <>, startIndex: <>, count: <> }
    • attribute, operator and value are set when using "simpel filtering", e.g. getObj.attribute='userName', getObj.operator='eq' and getObj.value='bjensen', but not for advanced filtering having and/or/not
    • rawFilter is always set when filtering is used
    • startIndex = Pagination - The 1-based index of the first result in the current set of search results
    • count = Pagination - Number of elements to be returned in the current set of search results
  • attributes = array of attributes to be returned - if empty, all supported attributes should be returned
  • ret:
    ret.Resources = array filled with user objects according to getObj/attributes, we could normally include all attributes having id and userName as mandatory e.g [{"id": "bjensen", "userName": "bjensen"}, {"id":"jsmith", "userName":"jsmith"}]
    ret.totalResults = if supporting pagination, then it should be set to the total numbers of elements (users), else set to null

createUser

scimgateway.createUser = async (baseEntity, userObj, ctx) => {
	...
    return { "id": uniqueID }
})
  • userObj = user object containing userattributes according to scim standard
    userObj.userName contains the unique naming at IdP
  • return the created user object or minimum the id generated { "id": uniqueID }, null is also accepted else throw error

deleteUser

scimgateway.deleteUser = async (baseEntity, id, ctx) => {
	...
	return null
} 
  • id = user id to be deleted
  • return null: null if OK, else throw error

modifyUser

scimgateway.modifyUser = async (baseEntity, id, attrObj, ctx) => {
	...
	return null
} 
  • id = user id
  • attrObj = object containing userattributes to be modified according to scim standard
    Note, multi-value attributes excluding user attribute 'groups' are customized from array to object based on type
  • return null: null if OK, else throw error

getGroups

scimgateway.getGroups = async (baseEntity, getObj, attributes, ctx) => {
    let ret = {
        "Resources": [],
        "totalResults": null
    }
	...
	return ret
}  
  • baseEntity = Optional for multi-tenant or multi-endpoint support (defined in base url e.g. <baseurl>/client1 gives baseEntity=client1)
  • getObj = { attribute: <>, operator: <>, value: <>, rawFilter: <>, startIndex: <>, count: <> }
    • attribute, operator and value are set when using "simpel filtering", e.g. getObj.attribute='displayName', getObj.operator='eq' and getObj.value='Admins', but not for advanced filtering having and/or/not
    • rawFilter is always set when filtering is used
    • startIndex = Pagination - The 1-based index of the first result in the current set of search results
    • count = Pagination - Number of elements to be returned in the current set of search results
  • attributes = array of attributes to be returned - if empty, all supported attributes should be returned
  • ret:
    ret.Resources = array filled with group objects according to getObj/attributes, we could normally include all attributes having id, displayName and members as mandatory e.g [{"id":"Admins", "displayName":"Admins", members":[{"value":"bjensen"}]}, {"id":"Employees", "displayName":"Employees"}, "members":[{"value":"jsmith","display":"John Smith"}]]
    ret.totalResults = if supporting pagination, then it should be set to the total numbers of elements (users), else set to null

createGroup

scimgateway.createGroup = async (baseEntity, groupObj, ctx) => {
	...
    return { "id": uniqueID }
})
  • groupObj = group object containing groupattributes according to scim standard
    groupObj.displayName contains the group name to be created
  • return the created group object or minimum the id generated { "id": uniqueID }, null is also accepted else throw error

deleteGroup

scimgateway.deleteGroup = async (baseEntity, id, ctx) => {
	...
    return null
}
  • id = group name (eg. Admins) to be deleted
  • return null: null if OK, else throw error

modifyGroup

scimgateway.modifyGroup = async (baseEntity, id, attrObj, ctx) => {
	...
    return null
}
  • id = group name (eg. Admins)
  • attrObj = object containing groupattributes to be modified according to scim standard
    attrObj.members (must be supported) = array of objects containing groupmembers modifications
    eg: {"value":"bjensen"},{"operation":"delete","value":"jsmith"}
    (adding bjensen and deliting jsmith from group)
  • return null: null if OK, else throw error
    If we do not support groups, then return null

License

MIT © Jarle Elshaug

Change log

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,
           "baseEntities": []
         }
         ...
       }
    

    Plugin binary prerequisites:

      scimgateway.authPassThroughAllowed = true
      // also need endpoint logic for handling/passing ctx.request.header.authorization
    

    For upgrading existing custom plugins, above mention prerequisites needs to be included and in addition all plugin methods must include the ctx parameter e.g.:

      scimgateway.getUsers = async (baseEntity, getObj, attributes, ctx)
      // tip, see provided example plugins
    

    Thanks to Kevin Osborn

v4.1.14

[Fixed]

  • Do not create logs directory or log-file when configuration log.loglevel.file not defined or set to "off". This fix will allow SCIM Gateway to run on systems having read-only disk like Google Cloud App Engine Standard

v4.1.12

[Improved]

  • Dependencies bump

v4.1.11

[Fixed]

  • basic auth logon dialog should not show up when not configured

v4.1.10

[Improved]

  • new plugin configuration 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 e.g. "5mb"
    Thanks to Sam Murphy

[Fixed]

  • using GET /Users, scimgateway automatically adds groups if not included by plugin. This operation calls plugin getGroups having attributes=['members.value', 'id', 'displayName']. Now, members.value is excluded. This attribute was in use and could cause unneeded load when having many group members.

v4.1.9

[Fixed]

  • plugin-azure-ad.json configuration file introduced in v.4.1.7 was missing passwordProfile attribute mappings
  • Symantec/Broadcom/CA ConnectorXpress configuration file config\resources\Azure - ScimGateway.xml now using standard text on manager attribute instead of selection dialogbox.

v4.1.8

[Fixed]

  • endpointMap and Symantec/Broadcom/CA ConnectorXpress configuration file config\resources\Azure - ScimGateway.xml introduced in v.4.1.7 had some missing logic

v4.1.7

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

[Improved]

  • endpointMap moved from scimgateway to plugin-azure-ad
  • plugin-azure-ad.json configuration file now includes attribute mapping giving flexibility to add or customize AAD-SCIM attribute mappings
  • Symantec/Broadcom/CA ConnectorXpress configuration file config\resources\Azure - ScimGateway.xml for defining the Azure endpoint, have been updated with some new attributes according to plugin-azure-ad.json attribute mappings

v4.1.6

[Improved]

  • Dependencies bump

v4.1.5

[Improved]

SCIM Gateway related news:

  • SCIM Stream is the modern way of user provisioning letting clients subscribe to messages instead of traditional IGA top-down provisioning. SCIM Stream includes SCIM Stream Gateway, the next generation SCIM Gateway that supports message subscription and automated provisioning

v4.1.4

[Fixed]

  • TypeConvert logic for multivalue attribute addresses did not correctly catch duplicate entries
  • PUT (Replace User) configuration scim.usePutSoftsync=true will also prevent removing any existing roles that are not included in body.roles ref. v4.1.3

v4.1.3

[Fixed]

  • createUser response did not include the id that was returned by plugin

[Improved]

  • PUT (Replace User) now includes group handling. Using configuration scim.usePutSoftsync=true will prevent removing any existing groups that are not included in body.groups

    Example:

      PUT /Users/bjensen
      {
        ...
        "groups": [
          {"value":"Employees","display":"Employees"},
          {"value":"Admins","display":"Admins"}
         ],
        ...
      }
    

v4.1.2

[Improved]

  • endpointMapper supporting one to many mappings using a comma separated list of attributes in the mapTo

    Configuration example:

      "map": {
        "user": {
          "PersonnelNumber": {
            "mapTo": "id,userName",
            "type": "string"
          },
          ...
        }
      }
    

v4.1.1

[Improved]

  • plugin-ldap support userFilter/groupFilter configuration for restricting scope

    Configuration example:

      {
        ...
        "userFilter": "(memberOf=CN=grp1,OU=Groups,DC=test,DC=com)(!(memberOf=CN=Domain Admins,CN=Users,DC=test,DC=com))",
        "groupFilter": "(!(cn=grp2))",
        ...
      }
    

v4.1.0

[Improved]

  • Supporting OAuth Client Credentials authentication

    Configuration example:

      "bearerOAuth": [
        {
          "client_id": "my_client_id",
          "client_secret": "my_client_secret",
          "readOnly": false,
          "baseEntities": []
        }
      ]
    

    In example above, client using SCIM Gateway must have OAuth configuration:

      client_id = my_client_id
      client_secret = my_client_secret
      token request url = http(s)://<host>:<port>/oauth/token
    

v4.0.1

[Improved]

  • create user/group supporting externalId

  • plugin-restful renamed to plugin-scim

  • plugin-ldap having improved SID/GUID support for Active Directory, also supporting domain map of userPrincipalName e.g. Azure AD => Active Directory

      "userPrincipalName": {
         "mapTo": "userName",
         "type": "string",
         "mapDomain": {
           "inbound": "test.onmicrosoft.com",
           "outbound": "my-company.com"
      }
    
  • postinstall copying example plugins may be skipped by setting the property scimgateway_postinstall_skip = true in .npmrc or by setting environment SCIMGATEWAY_POSTINSTALL_SKIP = true

  • Secrets now also support key-value storage. The key defined in plugin configuration have syntax process.text.<path> where <path> is the file which contains raw (UTF-8) character value. E.g. configuration endpoint.password could have value process.text./var/run/vault/endpoint.password, and the corresponding file contains the secret. Thanks to Raymond Augé

v4.0.0

[MAJOR]

  • New getUsers() replacing deprecated exploreUsers(), getUser() and getGroupUsers()
  • New getGroups() replacing deprecated exploreGroups(), getGroup() and getGroupMembers()
  • Fully filter and sort support
  • Authentication configuration may now include a baseEntities array containing one or more baseEntity allowed for corresponding admin user
  • New plugin-mongodb, thanks to Filipe Ribeiro and Miguel Ferreira (KEEP SOLUTIONS)

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 [email protected]

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]

  • errorhandling related to running scimgateway as unikernel

v3.2.10

[Fixed]

  • for SCIM 2.0 exploreUsers/exploreGroups now includes schemas/resourceType on each object in the Resources response. This may be required by som IdP's.

[Improved]

  • Dependencies bump

v3.2.9

[Fixed]

  • plugin-loki pagination fix

v3.2.8

[Fixed]

  • plugin-ldap objectGUID introduced in v.3.2.7 had some missing logic

v3.2.7

[Improved]

  • plugin-ldap supports using Active Directory objectGUID instead of dn mapped to id
    configuration example:

      "objectGUID": {
        "mapTo": "id",
        "type": "string"
      }
    

[Fixed]

  • Return 500 on GET handler error instead of 404
    Thanks to Nipun Dayanath
  • createUser/createRole response now includes id retrieved by getUser/getRole instead of using posted userName/displayName value

v3.2.6

[Fixed]

  • bearerJwt authentication missing public key handling
  • plugin-azure-ad getGroup did not return all members when group had more than 100 members (Azure page size is 100). getGroup now using paging

v3.2.5

[Fixed]

  • default "type converted object" logic may fail on requests that includes a mix of type and blank type. Now blank type will be converted to type "undefined", and all types must be unique within the same request. "type converted object" logic can be turned off by configuration scim.skipTypeConvert = true
  • plugin-loki supporting type = "undefined"

[Improved]

  • new configuration scim.skipTypeConvert allowing overriding the default behaviour "type converted object" when set to true. See attribute list for details

  • scimgateway.isMultivalue used by plugin-loki have been changed, and custom plugins using this method must be updated

      old syntax:
      scimgateway.isMultivalue('User', key)
    
      new syntax:
      scimgateway.isMultiValueTypes(key) 
    

v3.2.4

[Fixed]

  • plugin-loki some code cleanup

v3.2.3

[Fixed]

  • PUT was not according to the SCIM specification
  • plugin-mssql broken after dependencies bump v3.1.0
  • plugin-loki getUser using find instead of findOne to ensure returning unique user

v3.2.2

[Fixed]

  • plugins missing logic for handling the virtual readOnly user attribute groups (when "user member of groups") e.g. GET /Users/bjensen should return all user attributes including the virtual groups attribute. Now this user attribute will be automatically handled by scimgateway if not included in the plugin response.
  • Pre and post actions onAddGroups/onRemoveGroups introduced in v.3.2.0 has been withdrawn

[Improved]

  • scimgateway will do plugin response filtering according to requested attributes/excludedAttributes

v3.2.1

[Fixed]

  • plugin-azure-ad updating businessPhones (Office phone) broken after v3.2.0
  • plugin-azure-ad listing groups for user did also include Azure roles
  • SCIM v2.0 none core schema attributes handling
  • response not always including correct schemas

[Improved]

  • roles now using array instead of objects based on type. Note, this may break your custom plugins if roles logic are in use

v3.2.0

[Improved]

  • ipAllowList for restricting access to allowlisted IP addresses or subnets e.g. Azure AD IP-range
    Configuration example:

      "ipAllowList": [
        "13.66.60.119/32",
        "13.66.143.220/30",
        ...
        "2603:1056:2000::/48",
        "2603:1057:2::/48"
      ]
    
  • Example plugins now configured for SCIM v2.0 instead of v1.1

    New configuration:

      "scim": {
          "version": "2.0"
      }
    

    Old configuration:

      "scim": {
          "version": "1.1"
      }
    

v3.1.0

[Improved]

  • plugin-ldap a general LDAP plugin pre-configured for Microsoft Active Directory. Using endpointMapper logic (like plugin-azure-ad) for attribute flexibility
  • Pre and post actions onAddGroups/onRemoveGroups can be configured and needed logic to be defined in plugin method pre_post_Action
  • Dependencies bump

v3.0.8

[Fixed]

  • plugin-azure-ad delete account fails in v3.x

v3.0.7

[Fixed]

  • Using proxy configuration broken in v3.x

v3.0.6

[Fixed]

  • Dependencies bump

v3.0.4

[Improved]

  • Pagination request having startIndex but no count, now sets count to default 200 and may be overridden by plugin.

v3.0.3

[Fixed]

  • GET /Users?startIndex=1&count=100 with no attributes filter included did not work

v3.0.2

[Fixed]

  • SCIM v2.0 PUT did not work.

v3.0.1

[Improved]

  • getApi supports body (apiObj).

    Old syntax:

      scimgateway.getApi = async (baseEntity, id, apiQuery) => {
    

    New syntax:

      scimgateway.getApi = async (baseEntity, id, apiQuery, apiObj) => {
    

v3.0.0

[MAJOR]

  • getUser/getGroup now using parameter getObj giving more flexibility
  • deprecated modifyGroupMembers - now using modifyGroup
  • deprecated configuration scimgateway.scim.customUniqueAttrMapping - replaced by getObj logic
  • loglevel=off turns of logging
  • Auth methods allowing more than one user/object including option for readOnly
  • Includes latest versions of module dependencies

[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 "[email protected]"&attributes=userName,name.givenName
getObj = { filter: 'emails.value', identifier: '[email protected]'}
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]

  • Plugin configuration referring to an external configuration file using an array did not work.

v2.1.11

[Fixed]

  • Log masking of xml (SOAP) messages.

v2.1.10

[Improved]

  • Log masking of custom defined attributes.
    customMasking may include an array of attributes to be masked
    e.g. "customMasking": ["SSN", "weight"]

  • Note, configurationfiles must be changed (old syntax still supported)
    old syntax:

      "loglevel": {
        "file": "debug",
        "console": "error"
      },
    

    new syntax:

      "log": {
        "loglevel": {
          "file": "debug",
          "console": "error"
        },
        "customMasking": []
      },
    

    By default SCIM Gateway includes masking of standard attributes like password

v2.1.9

[Fixed]

  • AAD as IdP broken after content-type validation introduced in v2.1.7
  • AAD as IdP, none gallery app support
  • Incorrect SCIM 2.0 multivalue converting
  • plugin-saphana not correctly ported to v2.x

Thanks to Luca Moretto

v2.1.8

[Fixed]

  • plugin-mssql not correctly ported to v2.x, and some config syntax for this plugin have also changed in newer releases of dependencies.

v2.1.7

[Fixed]

  • Validates content-type when body is included
  • Case insensitive log-masking
  • Plugins now don't using deprecated url.parse
  • Misc cosmetics e.g. using const instead of let when not reassigned

v2.1.6

[Fixed]

  • plugin-azure-ad did not return correct error code (err.name = 'DuplicateKeyError') when failing on creating a duplicate user

[Improved]

  • Includes latest versions of module dependencies

v2.1.4

[Fixed]

  • Incorrect SCIM 2.0 error handling after v2.1.0
  • For duplicate key error, setting err.name = 'DuplicateKeyError' now gives correct status code 409 instead of defult 500 (see plugin-loki.js)

v2.1.3

[Fixed]

  • Standardized the API Gateway response (not SCIM related)
  • Not allowing plugins to return password
  • Colorize option now automatically turned off when using stdout/stderr redirect (configuration file loglevel.colorize is not needed)

v2.1.2

[Fixed]

  • SCIM 2.0 may use Operations.value as array and none array (issue #16)

[Improved]

  • Option for replacing mandatory userName/displayName attribute by configuring customUniqueAttrMapping
  • Includes latest versions of module dependencies

v2.1.1

[Fixed]

  • SCIM 2.0 may use Operations.value or Operation.value[] for PATCH syntax of the name object (issue #14)
  • plugin-loki failed to modify a none existing object, e.g name object not included in Create User

v2.1.0

[Improved]

  • Custom schema attributes can be added by plugin configuration scim.customSchema having value set to filename of a JSON schema-file located in <package-root>/config/schemas

[UPGRADE]

  • Configurationfiles for custom plugins should be changed
    old syntax:

      "scimversion": "1.1",  
    

    new syntax:

      "scim": {
        "version": "1.1",
        "customSchema": null
      },
    

Note, "1.1" is default, if using "2.0" the new syntax must be used.

v2.0.2

[Fixed]

  • SCIM 2.0 incorrect response for user not found
  • Did not mask logentries ending with newline

v2.0.0

[MAJOR]

  • Codebase moved from callback to async/await
  • Koa replacing Express
  • Some log enhancements
  • Deprecated cipher methods have been replaced
  • Plugin restful (REST) and
  • forwardinc (SOAP) includes failover logic based on endpoints defined in array baseUrls/baseServiceEndpoints.

[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)

  • scimgateway.on(xxx, function (..., callback) replaced with scimgateway.xxx = async (...) returning a result or throwing an error
  • Rest and SOAP using doRequest method having endpoint failover logic through array baseUrls/baseServiceEndpoints defined in corresponding plugin configuration file.
  • Additional argument attributes included in exploreUsers and exploreGroups method
  • Proxy configuration includes option for user/password
  • Encrypted passwords in configuration files needs to be reset to clear text passwords

v1.0.20

[Fixed]

  • HTTP status code 200 and totalResults set to value of 0 when using SCIM 2.0 filter user/group and no resulted user/group found. SCIM 1.1 still using status code 404.

[UPGRADE]

  • For custom plugins to be compliant with SCIM 2.0, the getUser and getGroup methods needs to be updated. If user/group not found then return callback(null, null) instead of callback(err)

v1.0.19

[Fixed]

  • Fix related to external configuration (ref. v1.0.18) when running multiple plugins

v1.0.18

[Improved]

  • Includes latest versions of module dependencies
  • Loglevel configuration for file and console now separated
  • Loglevel colorize option (value false could be useful when redirecting console output)
  • All configuration can be set based on environment variables
  • All configuration can be set based on correspondig json-content in external file (supports also dot notation)

[UPGRADE]

  • Configurationfiles for custom plugins should be changed
    old syntax:

      loglevel: "debug"
    

    new syntax:

      "loglevel": {
        "file": "debug",
        "console": "error",
        "colorize": true
      }
    

v1.0.14

[Fixed]

  • Some multiValued attributes not correctly handled (e.g. addresses)

v1.0.13

[Fixed]

  • plugin-azure-ad: New version of "Azure - ScimGateway.xml" fixing CA IM RoleDefGenerator problem (related to creating and importing screens in CA IM)

[UPGRADE]

  • Use CA ConnectorXpress, import "Azure - ScimGateway.xml" and deploy/redeploy endpoint

v1.0.12

[Fixed]

  • Incorrect logging of Express stream messages (type info) when running multiple plugins

v1.0.11

[Fixed]

  • plugin-azure-ad: proxy configuration did not work

v1.0.10

[Fixed]

  • An issue with pagination fixed

v1.0.9

[Improved]

  • Cosmetics, changed emailOnError logic - now emitted by logger

v1.0.8

[Improved]

  • Support health monitoring using the "/ping" URL with a "hello" response, e.g. http://localhost:8880/ping. Useful for frontend load balancing/failover functionality
  • Option for error notifications by email

[UPGRADE]

  • Configuration files for custom plugins must include the emailOnError object for enabling error notifications by email. Please see the syntax in provided example plugins and details described in the "Configuration" section of this document.

v1.0.7

[Improved]

  • Docker now using node v.9.10.0 instead of v.6.9.2
  • Minor log cosmetics

v1.0.6

[Fixed]

  • Azure AD plugin, failed to create user when licenses (app Service plans) was included

v1.0.5

[Improved]

  • Supporting GET /Users, GET /Groups, PUT method and delete groups
  • After more than 3 invalid auth attempts, response will be delayed to prevent brute force

[Fixed]

  • Some minor compliance fixes

Thanks to ywchuang

v1.0.4

[Improved]

  • Plugin for Azure AD now supports paging for retrieving users and groups. Any existing metafile used by CA ConnectorXpress ("Azure - ScimGateway.xml") must be re-deployed.

[Fixed]

  • Don't use deprecated existsSync in postinstallation

v1.0.3

[Fixed]

  • Undefined root url not handled correctly after v1.0.0

v1.0.2

[Fixed]

  • License and group defined as capability attributes in metafile used by CA ConnectorXpress regarding plugin-azure-ad

v1.0.1

[Fixed]

  • Mocha test script did not terminate after upgrading from 3.x to 4.x of Mocha

v1.0.0

[Improved]

  • New plugin-azure-ad.js for Azure AD user provisioning including Azure license management e.g. Office 365
  • Includes latest versions of module dependencies
  • Module hdb (for SapHana) and saml is not included by default anymore and therefore have to be manually installed if needed.

[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]

  • Includes api gateway/plugin for general none provisioning
    • GET /api
    • GET /api?queries
    • GET /api/{id}
    • POST /api + body
    • PUT /api/{id} + body
    • PATCH /api/{id} + body
    • DELETE /api/{id}
  • plugin-api.js demonstrates api functionallity (becomes what you want it to become)

v0.5.2

[Improved]

  • One or more of following authentication/authorization methods are accepted:
    • Basic Authentication
    • Bearer token - shared secret
    • Bearer token - Standard JSON Web Token (JWT)
    • Bearer token - Azure JSON Web Token (JWT)

[UPGRADE]

  • Configuration files for custom plugins config/plugin-xxx.json needs to be updated regarding the new scimgateway.auth section:
    • Copy scimgateway.auth section from one of the example plugins
    • Copy existing scimgateway.username value to new auth.basic.username value
    • Copy existing scimgateway.password value to new auth.basic.username value
    • Copy existing scimgateway.oauth.accesstoken value to new auth.bearer.token value
    • Delete scimgateway.username
    • Delete scimgateway.password
    • Delete scimgateway.oauth

v0.4.6

[Improved]

  • Document updated on how to run SCIM Gateway as a Docker container
  • config\docker includes docker configuration examples
    Thanks to Charley Watson and Jeffrey Gilbert

v0.4.5

[Improved]

  • Environment variable SEED overrides default password seeding
  • Setting SCIM Gateway port to "process.env.XXX" lets environment variable XXX define the port
  • Don't validate config-file port number for numeric value (Azure AD - iisnode using a name pipe for communication)

[UPGRADE]

  • Configuration files for custom plugins config/plugin-xxx.json needs to be updated:
    • Encrypted passwords needs to be reset to clear text passwords
    • Start SCIM Gateway and passwords will become encrypted

v0.4.4

[Improved]

  • NoSQL Document-Oriented Database plugin: plugin-loki
    This plugin now replace previous plugin-testmode
    Thanks to Jeffrey Gilbert
  • Minor code/comment reorganizations in provided plugins
  • Minor adjustments to multi-value logic introduced in v0.4.0

[UPGRADE]

  • Delete depricated lib/plugin-testmode.js and config/plugin-testmode.json
  • Edit index.js, replace tesmode with loki

v0.4.2

[Fixed]

  • plugin-restful minor adjustments to multivalue and cleared attributes logic introduced in v0.4.0

v0.4.1

[Improved]

  • Mocha test scripts for automated testing of plugin-testmode
  • Automated tests run on Travis-ci.org (click on build badge)
  • Thanks to Jeffrey Gilbert

[Fixed]

  • Minor adjustments to multi-value logic introduced in v0.4.0

v0.4.0

[Improved]

  • Not using the SCIM standard for handling multivalue attributes and cleared attributes. Changed from array to object based on type. This simplifies plugin-coding for multivalue attributes like emails, phoneNumbers, entitlements, ...
  • Module dependencies updated to latest versions

[UPGRADE]

  • Custom plugins using multivalue attributes needs to be updated regarding methods createUser and modifyUser. Please see example plugins for details.

v0.3.8

[Fixed]

  • Minor changes related to SCIM specification

v0.3.7

[Improved]

  • PFX / PKCS#12 certificate bundle is supported

v0.3.6

[Improved]

  • SCIM Gateway used by Microsoft Azure Active Directory is supported
  • SCIM version 2.0 is supported
  • Create group is supported

[UPGRADE]

  • For custom plugins to support create group, they needs to be updated regarding listener method scimgateway.on('createGroup',... Please see example plugins for details.

v0.3.5

[Fixed]

  • plugin-mssql not included in postinstall

v0.3.4

[Improved]

  • MSSQL example plugin: plugin-mssql
  • Changed multivalue logic in example plugins, now using scimgateway.getArrayObject

[Fixed]

  • Minor changes related to SCIM specification

v0.3.3

[Fixed]

  • Logic for handling incorrect pagination request to avoid endless loop conditions (there is a pagination bug in CA Identity Manager v.14)
  • Pagination now supported on getGroupMembers

[UPGRADE]

  • Custom plugins needs to be updated regarding listener method scimgateway.on('getGroupMembers',... New arguments have been added "startIndex" and "count". Also a new return variable "ret". Please see example plugins for details.

v0.3.2

[Fixed]

  • Minor changes related to SCIM specification

v0.3.1

[Improved]

  • REST Webservices example plugin: plugin-restful

v0.3.0

[Improved]

  • Preferred installation method changed from "global" to "local"
  • <Base URL>/[baseEntity] for multi tenant or multi endpoint flexibility
  • plugin-forwardinc includes examples of baseEntity, custom soap header and signed saml assertion
  • Support groups defined on user object "group member of user"
  • New module dependendcies included: saml, async and callsite

[UPGRADE]

  • Use "fresh" install and restore any custom plugins. Custom plugins needs to be updated. Listener method names have changed and method must include "baseEntity" - please see example plugins.

v0.2.2 - v0.2.8

[Doc]

  • Minor readme changes and version bumps

v0.2.1

[Fixed]

  • plugin-forwardinc explore of empty endpoint

v0.2.0

Initial version

scimgateway's People

Contributors

dependabot[bot] avatar jelhub avatar osbornk avatar rotty3000 avatar sammurphydev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

scimgateway's Issues

loki plugin getUser response is not SCIM compliant

Hi jelhub

I am using loki plugin and doing filter request as following :
https://domain/Users?filter=userName+eq+%22bjensen1%22

It works fine when user is found, but when user is not found, its sending 404 response instead of 200 with empty array.
Azure AD expects following response when user is not found :

{
	"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
	"totalResults": 0,
	"Resources": [],
	"startIndex": 1,
	"itemsPerPage": 20
}

Can you please explain regarding this.

Thanks & Regards

Sending token to backend

Our IDP will be sending a token to SCIM Gateway. In the handlers (createUser, updateUser, etc.) we want access to this token since it will then be used to communicate with our back end.

But the handler API is

scimgateway.createUser = async (baseEntity, userObj)

instead of

scimgateway.createUser = async (ctx, userObj)

Is there any other way of accessing the token of the original request to SCIM Gateway?

Fetching users returns users groups with all the groups members in them

When fetching user (/Users), the groups' attribute is returned containing a list of all the groups the user is part of. Then each of those groups within the users returns a list of all their members.
(Not representative of a complete response, here is an example of how the payload is currently structured)

{
  "id": "fbc56952-0c46-4c00-80b3-fc48fbef8eaa",
  "groups": [
    {
      "value": "383e9f70-a1af-4e26-b068-d2454aca0260",
      "members": [
        {
          "value": "fbc56952-0c46-4c00-80b3-fc48fbef8eaa"
        },
        {
          "value": "b6ccf7e6-ac9e-4db8-b81c-b0167d431a95"
        }
      ]
    }
  ]
}

This can create large responses when the user belongs to many groups with many users (in my case, 120MB for a single user).

I propose changing https://github.com/jelhub/scimgateway/blob/master/lib/scimgateway.js#L791 to remove the members.value. This could be breaking for people relying on it, or it could be hidden behind a feature flag.

Doing this is within the SCIM Schema specification. As outlined in section 4.1.2 https://www.rfc-editor.org/rfc/rfc7643#section-4.1.2, under the heading of groups,

SCIM service provider exposes a "Group" resource, the "value" sub-attribute MUST be the "id", and the "$ref" sub-attribute must be the URI of the corresponding "Group" resources to which the user belongs.

This, in my eyes, would mean that members is at least an optional attribute to return on the user response payload. This is further backed up by the full user representation listed here https://www.rfc-editor.org/rfc/rfc7643#section-8.2. While the specification refers to a non-normative example, it provides an insight into what the specification authors were expecting as part of the standard.

Let me know what you think. I've already implemented the change on my fork (without the feature flag). So happy to carry this forward to a PR if you agree with the above.

Cheers,
Sam

Can I use multiple plugins?

  • Looking at the current implementation, every plugin needs a config file that describes the standard scimgateway configuration.
  • If I want to use multiple plugins in the same gateway application, how can I do that?
  • It will contain scimgateway config. for each plugin which can create problems.

LDAP: custom attribute only visible in result during CREATE

Hi,

I have created an 'initials' attribute in a custom schema.

The attribute mapped to LDAP attribute in ldap-config.json.

    },
    "initials": {
      "mapTo": "name.initials",
      "type": "string"
    },

Custom attribute in <customschema.json>

[
{
"name":"User",
"attributes":[
{
"name":"name.initials",
"type":"string",
"multiValued":false,
"description":"initials",
"readOnly":false,
"required":false,
"mutability": "readWrite",
"returned": "default",
"uniqueness": "none",
"caseExact":false
}

  ]

},
{
"name":"Group",
"attributes":[

  ]

}
]

When a user is created the attribute is visible in the output and is correctly written to ldap

"name": {
    "formatted": "John Doe",
    "familyName": "Doe",
    "givenName": "John",
    "initials": "J"

But all GET operations regarding the USER or USERS does not show this specific custom attribute in the request.

I understand that the custom attributes are imported in the core schema during startup. Am I doing something wrong or could this be a bug or by design? Is it possible to configure that a custom attribute will be shown in the GET results?

Latest version of SCIM Gateway is being used for testing.

Thank you for your work!

Michael

Question: Resource (User/Group) ID substitution in scim gateway

Hi,

We are looking at using scimgateway to expose SCIM 2.0 interface, and are building a custom plugin to integrate with our own identity service backend. We have a question around a piece of code we came across as we develop our plugin.

When we create a user record in our plugin, our plugin returns the full user object (including the ID) of the newly created user in the response. However, this piece of code substitute our id with the userName - jsonBody.id = jsonBody.userName. And do another GET on the same object using the userName field.

https://github.com/jelhub/scimgateway/blob/master/lib/scimgateway.js#L1094-L1101

If userName doesn't exist on the return object, it would do the same with externalId field.

Any reasons the scimgateway needs to:

  1. substitute the id returned by the plugin with either userName or externalId and
  2. re-retrieve the same object using a different filter

While the plugin returns full user object.

We are just wondering if there's a usecase that scimgateway is catering for that we are not aware of.

Thanks,
Josh

Updated tedious package breaks mssql sample.

Hi
Started a fresh install and found that mssql does not work. Tedious is not connecting to server at all.
I guess it has something to do with the new way to make a connection that was introduced in v10.
When using 9.2.1 it works.

https://github.com/tediousjs/tedious/releases
10.0.0 (2021-01-13)
BREAKING CHANGES
Creating a new Connection instance will no longer establish a connection to the server automatically. Please use the new connect helper function or call the .connect method on the newly created Connection object instead.

best regards
Magnus

Cannot PUT /Users

My Identity provider wants to PUT all the Users and Groups in a batch. scimgateway does not seem to support PUT for this, only POST and PATCH. That will not work with their software (ADFS?)

I Tried the Loki plugin with scim 2.0 and this JSON

[
  {
    "externalId": "Donald_D",
    "userName": "Donald_D",
    "active": "true",
    "schemas": [
      "urn:ietf:params:scim:schemas:core:2.0:User",
      "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
    ]
  },
  {
    "externalId": "Huey_D",
    "userName": "Huey_D",
    "active": "true",
    "schemas": [
      "urn:ietf:params:scim:schemas:core:2.0:User",
      "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
    ]
  },
  {
    "externalId": "Dewey_D",
    "userName": "Dewey_D",
    "active": "true",
    "schemas": [
      "urn:ietf:params:scim:schemas:core:2.0:User",
      "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
    ]
  },
  {
    "externalId": "Louie_D",
    "userName": "Louie_D",
    "active": "true",
    "schemas": [
      "urn:ietf:params:scim:schemas:core:2.0:User",
      "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
    ]
  }
]

Wrong parsing of Users PATCH body

Hello,
I'm currently implementing a custom scimgateway plugin, that must work with SCIM 2.0.

I have run some tests, using Azure AD Provisioning Service as IdP. During tests excution, I identified an issue in parsing body of Users PATCH requests.

Consider the following PATCH body:

{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
  "Operations": [
    {
      "op": "Add",
      "path": "name.givenName",
      "value": "Barbara"
    },
    {
      "op": "Add",
      "path": "name.familyName",
      "value": "Jensen"
    },
    {
      "op": "Add",
      "path": "name.formatted",
      "value": "Barbara Jensen"
    }
  ]
}

After parsing the body, scimgateway invokes my plugin by passing the following object:

{
  name: {
    givenName: undefined,
    familyName: undefined,
    formatted: undefined
  }
}

i.e. all values in the internal object are undefined.

This seems to be caused by the following line:

} else dot.str(element.path, element.value[0].value, scimdata) // handle e.g name.familyName

If i replace element.value[0].value with element.value, i.e.:

} else dot.str(element.path, element.value, scimdata) // handle e.g name.familyName

then it seems to work as expected. Indeed, after applying this change, my plugin code receives the following data:

{
  name: {
    givenName: 'Barbara',
    familyName: 'Jensen',
    formatted: 'Barbara Jensen'
  }
}

I am willing to open a PR for this issue. However, I'm not sure if this change would be correct in any scenario or if it is just a workaround for this case.

Using auth.bearerJwt option doesn't work if using public key

Tried using auth.bearerJwt option but it fails as the code is initializing only if secret is specified. Once secret is specified the token validation uses only the secret. Was able to get it working after fixing the code related to auth.bearerJwt initializatin.

Just a suggestion. How to run a new scimgateway project as a docker container.

Instructions for running a new scimgateway project as a docker container. This includes a solution for file system persistence (for the plugin configs and loki.db) between container restarts:

Documentation / How to:

https://gist.github.com/visualjeff/796f9b49d1b3ec633f794df719e6e1c6#file-gistfile1-txt

Three files need to be added to a new scimgateway project to dockerize it:

  1. docker-compose.yml

https://gist.githubusercontent.com/visualjeff/796f9b49d1b3ec633f794df719e6e1c6/raw/88483166411d7df6d791a7a3a20fccc038b3aad6/docker-compose.yml

  1. Dockerfile

https://gist.githubusercontent.com/visualjeff/796f9b49d1b3ec633f794df719e6e1c6/raw/88483166411d7df6d791a7a3a20fccc038b3aad6/Dockerfile

  1. DataDockerfile

https://gist.githubusercontent.com/visualjeff/796f9b49d1b3ec633f794df719e6e1c6/raw/88483166411d7df6d791a7a3a20fccc038b3aad6/DataDockerfile

Jeff

Hostname not guaranteed static

My organization has been experimenting with https://github.com/jelhub/scimgateway as a provisioning solution hosted and connected to MS Azure AAD. We found some limitations with the code and will make recommendations to correct these. This can apply to any cloud provider hosted solution and not just MS Azure.

The first problem we encountered is with the secrets management strategy chosen. With cloud fabric solutions you might not be guaranteed a static hostname be delivered to your app -- this is the case with MS Azure and any strategies used that rely on a static hostname should have a strategy to mitigate the fact when not be guaranteed static.

In the config recovery code (lib/utils.js) we added:

var myhost = process.env.hostname_deg || require('os').hostname();
var chi = require('path').basename(configFile) + myhost;

To ensure a static value on MS Azure this is required.

The hostname_deg value must be set on the environment variables prior to execution.

mssql does not return data

Hi
The mssql plugin does not return data in my installation.
It appears that the exploreUsers method returns an empty data set before the query is run. If I add logging statements in the Tedious Request callback the data is returned from SQL Server.
I cannot see how to resolve the synchronization with Tedious. Hope you can help.

Compliance Tests Failing

The server is failing the simplecloud.info compliance SCIM 1.1 tests relating to PATCH tests 7-16 when configured for plugin-test.

User synced From App type is immutable

hi @jelhub

While trying to update existing user from SCIM GW (plugin LDAP - which reads users/groups from on prem AD).
We are seeing this error on OCI IDCS

'The attribute urn:ietf:params:scim:schemas:oracle:idcs:extension:user:User:syncedFromApp.type is immutable.' error occurred at step: 'Update User'

Please note that we are using authorized sync to sync users from SCIM to Oracle Cloud IDCS.

Do we need to remove the existing user and sync it again or update should work fine as-is which is not happening in this case. Please let me know

thanks

Paginaton issue in plugin-loki

Pagination is not working as expected in plugin-loki. For e.g. ?startIndex=10&count=5 returns no records when total records > 15.

PUT requests are incorrectly returning 204

modifyUser does not work correctly for PUT requests. It always returns a 204. That is only a valid response for PATCH requests. Per spec, a PUT request must return a 200 with the entire resource within the response body".

"Unless otherwise specified, a successful PUT operation returns a 200
OK response code and the entire resource within the response body,
enabling the client to correlate the client's and the service
provider's views of the updated resource."

Modify Groups

Hi, how the best way to create a Group modify method? I couldn't find this method, only modify users.

primary email not set error while trying to sync users

Hi @jelhub

Using LDAP plugin - we can retrieve the AD users/groups details successfully. And We can register the SCIM GW application on Oracle cloud. However during users sync noticed that it is failing with error like "Primary email must be set"

When we invoke get /Users endpoint from browser - we see email details of type and value but no 'primary' information .
I have noticed that in plugin-ldap.js we need to expose the emails.primary attribute in /Users endpoint.

following are attributes mapping from cloud to application
$(account.primaryEmail) --> emails[primary eq true and type eq "work"].value
Please let me know your thoughts on this one.

many thanks

Security vunerability - SOAP / EJS

I mean vulnerability. Sorry.

SOAP dependency is outdated and insecure. See attachment below (a screen shot). Need to make we pull in a newer version of SOAP that is using a newer version of ejs. ejs is the source of the security issue. BTW, You'll notice SOAP's master branch has been updated.

screen shot 2017-03-03 at 1 55 21 pm

If you like I could update your project.json and submit a pull request?

Jeff
PS. I'm a co-worker of C. Watson.

PS. More details about the vulnerability can be found here: https://snyk.io/vuln/npm:ejs:20161128

compound operations in Patch result in an error

When posting a patch to replace all group memberships per the following:

{ "op":"remove", "path": "members" }, { "op":"add", "path":"members", "value": { "value": "Group1" } }

The gateway can process the filters individually, but not together. Per the SCIM standard, the operations should be accepted, and processed sequentially based on the input. As this is part of a custom plugin, perhaps the easiest way to deal with this is to allow bypassing the built in parse of the operations, and pass the entire body to the handler in the plugin. This could be based on a flag in the plugin configuration for ease of use.

add a property to disable activities of postinstall script

Using the ability for .npmrc properties to be available via process.env, add a check for a property which can disable postinstall script to simplify keeping up to date.

PR on it's way...

Why is this useful

this is what I added to the README:

When maintaining a set of modifications it useful to disable the postinstall operations to keep your changes intact by setting the property scimgateway_postinstall_skip = true in .npmrc.

What problem it solves

to not have (allows me to delete) plugins and integrations with databases I don’t use

password not synced

Hi @jelhub

Now with the plugin - ldap I see the users/groups are synched to Oracle IDCS
however when tried to login to OCI console - it throws "Invalid username / password"

do we need to mapping for password attribute as well from SCIM GW to IDCS. please let us know.

many thanks

Can we change path for log file ?

Hi jelhub

By default, scimgateway creates log file on logs/plugin-loki.log path. Can we provide custom path for log-file ?

Regards

How to get cleartext bearer token in functions?

When modifying users, I would like to keep track of who did the action based on the bearer token used. However, I can't seem to find a method or parameter which will return the bearer token for me to reference the respective user.

Is there a way to do so?

image

Okta + Auth0

Hi,
I would like to use Okta and Auth0 such that the input is Okta (SCIM 2.0) and the output is Auth0.
I assume that Okta is compatible with scimgateway.
Is there a plugin in the work for Auth0? Assuming Auth0 is extremely popular, I was hoping there is already a plugin available.

Thanks

Using SCIM Plugin for invoke one or more plugins

Hi there,

Seems that scim-plugin.js is a proxy/façade for the other scim extensions, am I right?

If it is the goal for scim-plugin.js how to add more than one endpoint as the requests destionation?

Cheers

Edgar

Operator gte not working on Mongo plugin

Hello @jelhub ,

First of all, thank you for including the mongodb plugin!
However, I am testing version 4.0.0 and this endpoint doesn't return any results.

After taking a look at this, I've tried with "ge" instead. But again, no results found.

Note: At MongoDB, I have the two test mode users (bjensen and jsmith).
Could you run this scenario, please?

Best Regards,
Filipe Ribeiro

Returning wrong schema for modifyGroup PATCH request

PATCH requests come in with urn:ietf:params:scim:api:messages:2.0:PatchOp for the schema value. The router.patch method is simply echoing back the schema that is sent from the server. It needs to be sure to return ['urn:ietf:params:scim:schemas:core:2.0:Group'] for the schema.

I inserted the following:
ctx.body = jsonBody // using original body instead of retrieving actual data
// The schema comes in ["urn:ietf:params:scim:api:messages:2.0:PatchOp"]. That needs to be converted to
// ['urn:ietf:params:scim:schemas:core:2.0:Group'] for the response. Line below was inserted
ctx.body.schemas=['urn:ietf:params:scim:schemas:core:2.0:Group']

This updates the schema to ensure the correct value is returned. Servers validating the schema value will fail until this is done

custom attribution addition

hi @jelhub

Thanks for SCIM GW. I have synced users from on-prem AD to Oracle IDCS
while verifying the sync user information - "Federated" option is disabled in IDCS

Inorder to enable this - I'm wondering if we need to create the following custom attribute on on-prem AD by updating the schema or just map custom attribute in SCIM GW.

  • Mapping type: Constant
  • Constant value: true
  • Target attribute: urn:ietf:params:scim:schemas:oracle:idcs:extension:user:User:isFederatedUser

please share your thoughts
https://docs.microsoft.com/en-us/azure/active-directory/saas-apps/oracle-cloud-infrastructure-console-provisioning-tutorial

thanks

MongoDB or MySQL plugins

Hi,

Do you know of anyone who has developed a plugin for MongoDB or MySQL? I can't seem to find any references anywhere.

If you develop that ourselves, would you like to add it to your repository?

Cheers.

Cannot access custom attributes in Create User function

While trying to do a manual provisioning as part of testing, I realise that only the userName and active attribute is sent. However from Azure's end, it shows the target attribute which I require to create the user. It seems I might have not configure something but I'm not sure what else needs to be configured on the SCIM gateway for me to receive the rest of the attributes.

screenshot

{
    "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User", "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"],
    "userName": "_____________",
    "active": true,
    "meta": {
        "resourceType": "User"
    }
}

add support for interpolation of raw text secrets files

Why is this requested

We store secure values in a secretes engine as individually managed units. Assembling all those values into files at deployment time is not a best practice.

The proposed solution

The predominant way to provide these secretes is by mounting them directly in the file system as individual files with raw text values. I'd like to propose to extend the process.env.|file. model adding process.text. which would allow a file to be read as just a (UTF-8) string.

Plugin LDAP not working (Open LDAP)

Hi there,

I am using a Open LDAP Container image (osixia/openldap:1.5.0) , the initial tree structure is based on:

dc=example,dc=org

I imported the attached LDIF:
democorp (1).ldif.zip

So, I have new users into my ldap tree, when I do configure my ldap plugin, like this:

        "username": "cn=admin,dc=example,dc=org",
        "password": "NGYzYjU3NTE3NjAwYWU0MmNiMTBmNTcxNGI3MjY5NGU6MjM1YWRjODI1M2FkMDljNjQyMTBlOTYxNjA1ZTZlNTY=",
        "ldap": {
          "userBase": "dc=example,dc=org",
          "groupBase": "",
          "userFilter": "",
          "groupFilter": null,
          "userNamingAttr": "cn",
          "groupNamingAttr": "cn",
          "userObjectClasses": [ 
            "person",
            "organizationalPerson",
            "inetOrgPerson",
            "top"
          ],

When I try to execute an HTTP GET, I am getting the following result:

{
    "Resources": [],
    "itemsPerPage": 0,
    "schemas": [
        "urn:ietf:params:scim:api:messages:2.0:ListResponse"
    ],
    "startIndex": 1,
    "totalResults": 0
}

Any idea of what I might be doing wrong? I've been investigating many ways to solve it, but not success so far.

Thanks in advance

Edgar

[BUG] Delete user on Azure, azure provisioning call to SIMGATEWAY to delete user but SIMGATEWAY response {"statusCode":204,"statusMessage":"No Content"}

Hi guys,
I set up scimgateway on my local machine, I linked my azure provisioning to my local scimgateway.
Create user, update user works just fine but delete is not working, scimgateway response no content.

Here is the log of delete user on my local scimgateway:

2021-12-22T14:01:40.129 debug: scimgateway[plugin-loki] [Modify User] [email protected]
2021-12-22T14:01:40.130 debug: scimgateway[plugin-loki] convertedBody={"active":false}
2021-12-22T14:01:40.130 debug: scimgateway[plugin-loki] calling "modifyUser" and awaiting result
2021-12-22T14:01:40.130 debug: plugin-loki[undefined] handling "modifyUser" [email protected] attrObj={"active":false}
2021-12-22T14:01:40.131 info: scimgateway[plugin-loki] 176ms [my-azure-ip] token PATCH http://mylocalsimgateway.com Inbound = {"schemas":["urn:ietf:params:scim:api:messages:2.0:PatchOp"],"Operations":[{"op":"Replace","path":"active","value":"False"}]} Outbound = {"statusCode":204,"statusMessage":"No Content"}

Is this an issue of azure provisioning or my local scimgateway?

No schemas included for /Users objects

Hi,

I am using 3.2.9

I can return /Users and /Groups, however, unlike the test rest/loki plugin, I get no User Schema in response(null):

{"Resources":[[{"uri":"/principal/internal/user/adam.arnold","id":"11","userName":"adam.arnold","type":"user","AlternateId":"ec29f73d-ec39-4327-9e35-13c0d21b2021","IdP":"internal"},null],[{"uri":"/principal/internal/user/pjones","id":"10","userName":"pjones","type":"user","AlternateId":"236ef0fc-0915-43a0-bbcf-1bdf0fe0d6d7","IdP":"internal"},null],
"totalResults":6,"itemsPerPage":6,"startIndex":1,"schemas":["urn:ietf:params:scim:api:messages:2.0:ListResponse"],"meta":{"resourceType":"User"}}

This is my ExploreUser js:
// =================================================
// exploreUsers
// =================================================
scimgateway.exploreUsers = async (baseEntity, attributes, startIndex, count) => {
const action = 'exploreUsers'
scimgateway.logger.debug(${pluginName}[${baseEntity}] handling "${action}" attributes=${attributes} startIndex=${startIndex} count=${count})
const ret = { // itemsPerPage will be set by scimgateway
Resources: [],
totalResults: null
}
const method = 'GET'
const path = /principal?verbose=true&depth=5&page_size=50&page_number=1
const authorization ='Bearer '+access_token
const options = {
headers: {
'Authorization': authorization , // body must be query string formatted (no JSON)
'Content-Type': 'application/json' , // body must be query string formatted (no JSON)
'Accept': 'application/json' // body must be query string formatted (no JSON)
}
}
const body = authorization
// const body = JSON.stringify(data)
try {
const response = await doRequest(baseEntity, method, path, body,options)
const res = JSON.stringify(response.body)
const obj = JSON.parse(res)
// const err = new Error(Response message: ${response.statusMessage} - ${JSON.stringify(response.body)})
console.log('User Count :'+obj['IdentityProviders'][0]['PrincipalTypes'][0]['Users'].length)
// throw (err)
if (response.statusCode < 200 || response.statusCode > 299) {
const err = new Error(Error message: ${response.statusMessage} - ${JSON.stringify(response.body)} - ${access_token})
throw (err)
} else if (!response.body.IdentityProviders) {
const err = new Error(${action}: Got empty response on REST request)
throw (err)
}
if (!startIndex && !count) { // client request without paging
startIndex = 1
count = obj['IdentityProviders'][0]['PrincipalTypes'][0]['Users'].length
}
console.log('count = '+count)

const arrAttr = attributes.split(',')

// const arrAttr = parsedAttr.split(',')
for (let index = startIndex - 1; index < obj['IdentityProviders'][0]['PrincipalTypes'][0]['Users'].length && (index + 1 - startIndex) < count; ++index) {
const retObj = obj['IdentityProviders'][0]['PrincipalTypes'][0]['Users'][index]
console.log('endpointMapper test : '+scimgateway.endpointMapper('inbound', 'Uri', scimgateway.endpointMap.SecretsSafeUser) )
console.log('endpointMapper test : '+scimgateway.endpointMapper('inbound', retObj, scimgateway.endpointMap.SecretsSafeUser) )
let parsedAttr = scimgateway.endpointMapper('inbound', retObj, scimgateway.endpointMap.SecretsSafeUser)
//const [scimUser] = scimgateway.endpointMapper('inbound', retObj, scimgateway.endpointMap.SecretsSafeUser)
if (!attributes) ret.Resources.push(parsedAttr)
else { // return according to attributes (userName or externalId should normally be included and id=userName/externalId)
console.log('EEEEEEEEEEEEEEEEEE else 154')
let found = false
const obj = {}
for (let i = 0; i < arrAttr.length; i++) {
const key = arrAttr[i].split('.')[0] // title => title, name.familyName => name
if (retObj[key]) {
obj[key] = retObj[key]
found = true
}
}
if (found) ret.Resources.push(obj)
}
}
// not needed if client or endpoint do not support paging
ret.totalResults = obj['IdentityProviders'][0]['PrincipalTypes'][0]['Users'].length
ret.startIndex = startIndex
return ret // all explored users
} catch (err) {
const newErr = err
throw newErr
}
}

Port number not guaranteed to be numeric

On cloud systems and especially MS Azure the network abstractions sometimes take alternate forms. Within Azure ports are identified as "named pipes" which may take a form other than numeric.

In the isValidconfig function checks for a numeric value:

else if (key === 'port') { // number
//on PaaS sometimes the port is delivered as non-numeric string
//if (!val || typeof (val) !== 'number') return false;
}

This needed to be commented out in order to run the solution on MS Azure. Since the plugin-xxxx.json config is tightly coupled with the plugin-xxxx.js modules would it make sense to move the validation to the plugin-xxxx.js?

In that fashion users can provide their own solution for the validation step that matches their context.

filter doesn't support customization

In developing a custom plugin, I would like to fully support the filtering as specified in the SCIM standard. However, it appears that the code only allows for displayname filtering .. and returns a 404 on any filter that doesn't include that attribute.

Is it possible to bypass the filter check, and pass the entirety of the filter querystring onto the plugin for manual parsing?

Just a suggestion. Might be worth adding to the project?

You can debug a running docker container (using Visual Studio Code) if you add the following file (docker-compose-debug.yml) to your project:

version: '2'
services:
  scimgateway:
    ports:
      - "8880:8880"
      - "5858:5858"

When you start-up the app using this command:

docker-compose -f docker-compose.yml -f docker-compose-debug.yml up -d
Start Visual Studio Code and follow these debugging instructions: https://code.visualstudio.com/docs/nodejs/nodejs-debugging

Jeff

PS. Hopefully users might find this helpful.

LDAP issue with SCIM Id attribute

Hi Jarle,

When a user, JohnDoe is created in Active Directory with SCIM Id mapped to LDAP DN it does not return the DN (for example: CN%3DJohnDoe%3Dxxx%3Dxxx%2CDC%3Dxx) but still JohnDoe.

When the SCIM Id is mapped to, for example, LDAP objectGUID or objectID, it still returns 'JohnDoe'.

Is DN the only attribute which can be used in combination with the SCIM Id attribute?

Regards,

Michael

installation on windows fails

\Code\my-scimgateway>npm install scimgateway
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE package: '@azure/[email protected]',
npm WARN EBADENGINE required: { node: '10 || 12 || 14 || 16 || 18' },
npm WARN EBADENGINE current: { node: 'v19.2.0', npm: '8.19.3' }
npm WARN EBADENGINE }

up to date, audited 352 packages in 4s

52 packages are looking for funding
run npm fund for details

5 high severity vulnerabilities

To address all issues (including breaking changes), run:
npm audit fix --force

Run npm audit for details.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.