scimgateway 6.2.0 → 6.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1117 -3440
- package/config/plugin-entra-id.json +3 -3
- package/config/plugin-generic.json +1 -4
- package/lib/helper-rest.ts +23 -46
- package/lib/plugin-entra-id.ts +587 -187
- package/lib/plugin-generic.ts +31 -18
- package/lib/plugin-ldap.ts +15 -2
- package/lib/plugin-loki.ts +11 -0
- package/lib/plugin-mongodb.ts +11 -0
- package/lib/plugin-mssql.ts +11 -0
- package/lib/plugin-saphana.ts +11 -0
- package/lib/plugin-soap.ts +11 -0
- package/lib/scimgateway.ts +55 -37
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,3727 +1,1404 @@
|
|
|
1
|
-
# SCIM Gateway
|
|
1
|
+
# SCIM Gateway
|
|
2
2
|
|
|
3
|
-
[](https://app.travis-ci.com/github/jelhub/scimgateway)
|
|
3
|
+
[](https://app.travis-ci.com/github/jelhub/scimgateway)
|
|
4
|
+
[](https://www.npmjs.com/package/scimgateway)
|
|
5
|
+
[](https://www.npmjs.com/package/scimgateway)
|
|
6
|
+
[](https://github.com/jelhub/scimgateway)
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
**Author:** Jarle Elshaug
|
|
7
|
-
|
|
8
|
-
**Validated through IdPs:**
|
|
8
|
+
**Author:** [Jarle Elshaug](https://www.elshaug.xyz)
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
* Microsoft Entra ID
|
|
12
|
-
* One Identity Manager
|
|
13
|
-
* Okta
|
|
14
|
-
* Omada
|
|
15
|
-
* SailPoint/IdentityNow
|
|
16
|
-
---
|
|
10
|
+
SCIM Gateway is a user provisioning bridge built with [Bun](https://bun.sh/) and [Node.js](https://nodejs.dev/) using TypeScript. It translates incoming SCIM 1.1/2.0 requests into endpoint-specific protocols — turning any destination into a SCIM-compatible interface without vendor lock-in.
|
|
17
11
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
- New `plugin-generic` replacing previous `plugin-scim`. This new plugin use the endpointMapper for flexible attribute mapping and also supports the new mapper option `valueMap` (e.g., group filtering and mapping).
|
|
21
|
-
- Now supports `GET /Roles` and `GET /Entitlements` endpoint requests, with corresponding user management via the standard SCIM `roles` and `entitlements` attributes. The Entra ID plugin uses `entitlements` for Entra ID licenses (read-only) and `roles` for Entra ID Permanent and Eligible roles (full management).
|
|
22
|
-
- Bun binary build is now supported, allowing SCIM Gateway to be compiled into a single executable binary for simplified deployment and execution. SCIM Gateway can now run as an ES module (TypeScript) in Node.js.
|
|
23
|
-
- Major release **v6.0.0** introduces changes to API method responses (not SCIM-related) and a new method `publicApi()` for handling public path `/pub/api` requests with no authentication required. In addition, the configuration option `bearerJwtAzure.tenantIdGUID` has been replaced by `bearerJwt.azureTenantId`. See the version history for details.
|
|
24
|
-
- Support for Entra ID [Federated Identity Credentials](https://learn.microsoft.com/en-us/graph/api/resources/federatedidentitycredentials-overview?view=graph-rest-1.0) has been added through internal JWKS (JSON Web Key Set), allowing SCIM Gateway to access Microsoft Entra–protected resources without the need to manage secrets
|
|
25
|
-
- External JWKS (JSON Web Key Set) is now supported by JWT authentication, allowing external applications to access SCIM Gateway without the need to manage secrets
|
|
26
|
-
- [Azure Relay](https://learn.microsoft.com/en-us/azure/azure-relay/relay-what-is-it) is now supported for secure and hassle-free outbound-only communication — with just one minute of configuration
|
|
27
|
-
- [ETag](https://datatracker.ietf.org/doc/html/rfc7644#section-3.14) is now supported
|
|
28
|
-
- [Bulk Operations](https://datatracker.ietf.org/doc/html/rfc7644#section-3.7) is now supported
|
|
29
|
-
- Remote real-time log subscription for centralized logging and monitoring. Using browser `https://<host>/logger`, curl or custom client API - see configuration notes
|
|
30
|
-
- By configuring the chainingBaseUrl, it is now possible to chain multiple gateways in sequence, such as `gateway1->gateway2->gateway3->endpoint`. In this setup, gateway behave like a reverse proxy, validating authorization at each step unless PassThrough mode is enabled. Chaining is also supported in stream subscriber mode
|
|
31
|
-
- Email, onError and sendMail() supports more secure RESTful OAuth for Microsoft Exchange Online (ExO) and Google Workspace Gmail, alongside traditional SMTP Auth for all mail systems. HelperRest supports a wide range of common authentication methods, including basicAuth, bearerAuth, tokenAuth, oauth, oauthSamlBearer, oauthJwtBearer and Auth PassTrough
|
|
32
|
-
- Major release **v5.0.0** marks a shift from JavaScript to native TypeScript and prioritizes [Bun](https://bun.sh/) over Node.js. This upgrade requires some modifications to existing plugins.
|
|
33
|
-
- **BREAKING**: [SCIM Stream](https://elshaug.xyz/docs/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
|
|
34
|
-
- Authentication PassThrough letting plugin pass authentication directly to endpoint for avoid maintaining secrets at the gateway. E.g., using Entra ID application OAuth
|
|
35
|
-
- Supports OAuth Client Credentials authentication
|
|
36
|
-
- Major release **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
|
|
37
|
-
- ipAllowList for restricting access to allowlisted IP addresses or subnets e.g. Azure IP-range
|
|
38
|
-
- General LDAP plugin configured for Active Directory
|
|
39
|
-
- [PlugSSO](https://elshaug.xyz/docs/plugsso) using SCIM Gateway
|
|
40
|
-
- Each authentication configuration allowing more than one admin user including option for readOnly
|
|
41
|
-
- Codebase moved from callback of h... to the the promise(d) land of async/await
|
|
42
|
-
- Supports configuration by environments and external files
|
|
43
|
-
- Health monitoring through "/ping" URL, and option for error notifications by email
|
|
44
|
-
- Entra ID user provisioning including license management e.g. Office 365, installed and configured within minutes!
|
|
45
|
-
- Includes API Gateway for none SCIM/provisioning - becomes what you want it to become
|
|
46
|
-
- Running SCIM Gateway as a Docker container
|
|
12
|
+

|
|
47
13
|
|
|
48
14
|
---
|
|
49
15
|
|
|
50
|
-
##
|
|
16
|
+
## Table of Contents
|
|
17
|
+
|
|
18
|
+
- [SCIM Gateway](#scim-gateway)
|
|
19
|
+
- [Table of Contents](#table-of-contents)
|
|
20
|
+
- [What's New](#whats-new)
|
|
21
|
+
- [Included Plugins](#included-plugins)
|
|
22
|
+
- [Installation](#installation)
|
|
23
|
+
- [Prerequisites](#prerequisites)
|
|
24
|
+
- [Install SCIM Gateway](#install-scim-gateway)
|
|
25
|
+
- [Verify the Default Loki Plugin](#verify-the-default-loki-plugin)
|
|
26
|
+
- [Upgrading](#upgrading)
|
|
27
|
+
- [Configuration](#configuration)
|
|
28
|
+
- [Entry Point — `index.ts`](#entry-point--indexts)
|
|
29
|
+
- [Plugin File Naming](#plugin-file-naming)
|
|
30
|
+
- [Core Options](#core-options)
|
|
31
|
+
- [Authentication](#authentication)
|
|
32
|
+
- [Basic Authentication](#basic-authentication)
|
|
33
|
+
- [Bearer Token (Shared Secret)](#bearer-token-shared-secret)
|
|
34
|
+
- [JWT (Standard)](#jwt-standard)
|
|
35
|
+
- [OAuth Client Credentials](#oauth-client-credentials)
|
|
36
|
+
- [Authentication PassThrough](#authentication-passthrough)
|
|
37
|
+
- [IP Allow List](#ip-allow-list)
|
|
38
|
+
- [TLS \& Certificates](#tls--certificates)
|
|
39
|
+
- [Using PEM files](#using-pem-files)
|
|
40
|
+
- [Using PFX / PKCS#12](#using-pfx--pkcs12)
|
|
41
|
+
- [No TLS](#no-tls)
|
|
42
|
+
- [Email Notifications](#email-notifications)
|
|
43
|
+
- [Microsoft Exchange Online (OAuth)](#microsoft-exchange-online-oauth)
|
|
44
|
+
- [Google Workspace Gmail (OAuth)](#google-workspace-gmail-oauth)
|
|
45
|
+
- [SMTP Auth](#smtp-auth)
|
|
46
|
+
- [Azure Relay](#azure-relay)
|
|
47
|
+
- [Secrets from External Sources](#secrets-from-external-sources)
|
|
48
|
+
- [Remote Log Subscription](#remote-log-subscription)
|
|
49
|
+
- [Gateway Chaining](#gateway-chaining)
|
|
50
|
+
- [HelperRest](#helperrest)
|
|
51
|
+
- [Basic Auth](#basic-auth)
|
|
52
|
+
- [Entra ID — Client Secret](#entra-id--client-secret)
|
|
53
|
+
- [Entra ID — Certificate Secret](#entra-id--certificate-secret)
|
|
54
|
+
- [Entra ID — Federated Credentials (no secrets)](#entra-id--federated-credentials-no-secrets)
|
|
55
|
+
- [General OAuth (Client Credentials)](#general-oauth-client-credentials)
|
|
56
|
+
- [Single Binary Deployment](#single-binary-deployment)
|
|
57
|
+
- [Running the Gateway](#running-the-gateway)
|
|
58
|
+
- [Manual Startup](#manual-startup)
|
|
59
|
+
- [Windows Task Scheduler](#windows-task-scheduler)
|
|
60
|
+
- [Docker](#docker)
|
|
61
|
+
- [Single Image](#single-image)
|
|
62
|
+
- [Docker Compose](#docker-compose)
|
|
63
|
+
- [Identity Provider Integration](#identity-provider-integration)
|
|
64
|
+
- [Microsoft Entra ID as IdP](#microsoft-entra-id-as-idp)
|
|
65
|
+
- [Symantec/Broadcom Identity Manager as IdP](#symantecbroadcom-identity-manager-as-idp)
|
|
66
|
+
- [Entra ID Provisioning Plugin](#entra-id-provisioning-plugin)
|
|
67
|
+
- [Entra ID App Registration](#entra-id-app-registration)
|
|
68
|
+
- [Plugin Configuration](#plugin-configuration)
|
|
69
|
+
- [Using with Symantec/Broadcom (ConnectorXpress)](#using-with-symantecbroadcom-connectorxpress)
|
|
70
|
+
- [API Gateway](#api-gateway)
|
|
71
|
+
- [Building Custom Plugins](#building-custom-plugins)
|
|
72
|
+
- [Setup](#setup)
|
|
73
|
+
- [Mandatory Plugin Initialization](#mandatory-plugin-initialization)
|
|
74
|
+
- [Implementation Order](#implementation-order)
|
|
75
|
+
- [Plugin Methods](#plugin-methods)
|
|
76
|
+
- [Custom Schemas](#custom-schemas)
|
|
77
|
+
- [License](#license)
|
|
78
|
+
- [Change Log](#change-log)
|
|
79
|
+
- [v6.2.2](#v622)
|
|
80
|
+
- [v6.2.1](#v621)
|
|
81
|
+
- [v6.2.0](#v620)
|
|
82
|
+
- [v6.1.20](#v6120)
|
|
83
|
+
- [v6.1.19](#v6119)
|
|
84
|
+
- [v6.1.18](#v6118)
|
|
85
|
+
- [v6.1.17](#v6117)
|
|
86
|
+
- [v6.1.16](#v6116)
|
|
87
|
+
- [v6.1.15](#v6115)
|
|
88
|
+
- [v6.1.14](#v6114)
|
|
89
|
+
- [v6.1.13](#v6113)
|
|
90
|
+
- [v6.1.12](#v6112)
|
|
91
|
+
- [v6.1.11](#v6111)
|
|
92
|
+
- [v6.1.10](#v6110)
|
|
93
|
+
- [v6.1.9](#v619)
|
|
94
|
+
- [v6.1.8 / v6.1.7](#v618--v617)
|
|
95
|
+
- [v6.1.6](#v616)
|
|
96
|
+
- [v6.1.5](#v615)
|
|
97
|
+
- [v6.1.4](#v614)
|
|
98
|
+
- [v6.1.3](#v613)
|
|
99
|
+
- [v6.1.2](#v612)
|
|
100
|
+
- [v6.1.1](#v611)
|
|
101
|
+
- [v6.1.0](#v610)
|
|
102
|
+
- [v6.0.0 — Major](#v600--major)
|
|
103
|
+
- [v5.x — Previous Major Series](#v5x--previous-major-series)
|
|
51
104
|
|
|
52
|
-
|
|
105
|
+
---
|
|
53
106
|
|
|
54
|
-
|
|
107
|
+
## What's New
|
|
108
|
+
|
|
109
|
+
- **`plugin-entra-id`** now supports Entra ID roles and access packages, in addition to reading licenses.
|
|
110
|
+
- **`plugin-generic`** replaces `plugin-scim` — a flexible template using `endpointMapper` with the new `valueMap` option for allowlisting and name mapping e.g., groups
|
|
111
|
+
- **`GET /Roles` and `GET /Entitlements`** endpoint support, with user management via SCIM `roles` and `entitlements` attributes; `plugin-entra-id` uses `entitlements` for Entra ID licenses (read-only) and `roles` for Permanent and Eligible PIM roles (full management)
|
|
112
|
+
- **AI Agent ready** — `x-agent-schema` configuration in `endpointMapper` enables custom schema generation with MCP tool instructions for autonomous provisioning agents
|
|
113
|
+
- **Bun binary builds** — compile a plugin into a single executable for simplified deployment
|
|
114
|
+
- **ES module / TypeScript support in Node.js** via `tsx`
|
|
115
|
+
- **v6.0.0** — API method response bodies returned as-is; new `publicApi()` method for unauthenticated `/pub/api` routes; `bearerJwtAzure.tenantIdGUID` replaced by `bearerJwt.azureTenantId`
|
|
116
|
+
- **Federated Identity Credentials** (Entra ID) — access Microsoft-protected resources without managing secrets, via internal JWKS
|
|
117
|
+
- **External JWKS** support for JWT authentication
|
|
118
|
+
- **Azure Relay** — secure outbound-only tunnel with one minute of setup (~$10/month per listener)
|
|
119
|
+
- **ETag** and **Bulk Operations** support (SCIM RFC 7644)
|
|
120
|
+
- **Remote real-time log subscription** via browser, curl, or custom client at `https://<host>/logger`
|
|
121
|
+
- **Gateway chaining** — chain `gateway1 → gateway2 → gateway3 → endpoint` with reverse-proxy-style auth validation
|
|
122
|
+
- **OAuth for email** — Microsoft Exchange Online and Google Workspace Gmail alongside traditional SMTP Auth
|
|
123
|
+
- [SCIM Stream](https://elshaug.xyz/docs/scim-stream) — subscribe-based provisioning as an alternative to top-down IGA polling
|
|
55
124
|
|
|
56
|
-
|
|
125
|
+
---
|
|
57
126
|
|
|
58
|
-
|
|
127
|
+
## Included Plugins
|
|
59
128
|
|
|
60
129
|
| Plugin | Endpoint Type | Description |
|
|
61
|
-
|
|
62
|
-
| **
|
|
63
|
-
| **
|
|
64
|
-
| **
|
|
65
|
-
| **
|
|
66
|
-
| **
|
|
67
|
-
| **
|
|
68
|
-
| **
|
|
69
|
-
| **
|
|
70
|
-
| **
|
|
71
|
-
|
|
72
|
-
## Installation
|
|
73
|
-
To get started with SCIM Gateway, follow the instructions below.
|
|
74
|
-
|
|
75
|
-
#### Install Bun
|
|
76
|
-
|
|
77
|
-
[Bun](https://bun.sh/) is a prerequisite and must be installed
|
|
78
|
-
|
|
79
|
-
Note, Bun installs by default in the current user’s `HOMEPATH\.bun`. To install it elsewhere, set `BUN_INSTALL=<install-path>` as a global or system environment variable before installing. The installation will add Bun to the current user’s path, but consider adding it to the global or system path for easier access across all users.
|
|
80
|
-
|
|
81
|
-
#### SCIM Gateway Installation
|
|
82
|
-
|
|
83
|
-
Create a package directory and install the SCIM Gateway:
|
|
84
|
-
|
|
85
|
-
mkdir c:\my-scimgateway
|
|
86
|
-
cd c:\my-scimgateway
|
|
87
|
-
bun init -y
|
|
88
|
-
bun install scimgateway
|
|
89
|
-
bun pm trust scimgateway
|
|
90
|
-
|
|
91
|
-
index.ts, lib and config directories containing example plugins are copied to your package. The command `bun pm trust scimgateway` is required to allow the `postinstall` script to copy these files.
|
|
92
|
-
|
|
93
|
-
#### Startup and verify default Loki plugin
|
|
94
|
-
|
|
95
|
-
bun c:\my-scimgateway
|
|
96
|
-
|
|
97
|
-
Start a browser
|
|
98
|
-
|
|
99
|
-
http://localhost:8880/ping
|
|
100
|
-
=> Returns a health check with a "hello" response
|
|
101
|
-
|
|
102
|
-
http://localhost:8880/Users
|
|
103
|
-
http://localhost:8880/Groups
|
|
104
|
-
=> Logon using gwadmin/password and two users and groups should be listed
|
|
105
|
-
|
|
106
|
-
Start a new browser for remote log monitoring
|
|
107
|
-
using url: http://localhost:8880/logger
|
|
108
|
-
|
|
109
|
-
http://localhost:8880/Users/bjensen
|
|
110
|
-
http://localhost:8880/Groups/Admins
|
|
111
|
-
or
|
|
112
|
-
http://localhost:8880/Users?filter=userName eq "bjensen"
|
|
113
|
-
http://localhost:8880/Groups?filter=displayName eq "Admins"
|
|
114
|
-
=> Lists all attributes for specified user/group
|
|
115
|
-
|
|
116
|
-
http://localhost:8880/Groups?filter=displayName eq "Admins"&excludedAttributes=members
|
|
117
|
-
http://localhost:8880/Groups?filter=members.value eq "bjensen"&attributes=id,displayName,members.value
|
|
118
|
-
http://localhost:8880/Users?filter=userName eq "bjensen"&attributes=userName,id,name.givenName
|
|
119
|
-
http://localhost:8880/Users?filter=meta.created ge "2010-01-01T00:00:00Z"&attributes=userName,name.familyName,meta.created
|
|
120
|
-
http://localhost:8880/Users?filter=emails.value co "@example.com"&attributes=userName,name.familyName,emails&sortBy=name.familyName&sortOrder=descending
|
|
121
|
-
=> Filtering and attribute examples
|
|
122
|
-
|
|
123
|
-
"Ctrl + c" to stop the SCIM Gateway
|
|
124
|
-
|
|
125
|
-
> For Node.js, the startup command is:
|
|
126
|
-
`node --import=tsx ./index.ts`
|
|
127
|
-
|
|
128
|
-
#### Upgrade Process
|
|
129
|
-
|
|
130
|
-
The recommended upgrade method is to rename the existing package folder, perform a fresh installation, and then copy your custom `index.ts`, `config`, and `lib` folders from the previous installation.
|
|
131
|
-
|
|
132
|
-
- Minor Upgrade: `bun install scimgateway`
|
|
133
|
-
- Major Upgrade: `bun install scimgateway@latest` (Use with caution, as it may break compatibility with existing custom plugins)
|
|
134
|
-
|
|
135
|
-
##### Avoid (re-)adding the example plugins created during `postinstall`
|
|
136
|
-
|
|
137
|
-
For production we do not need example plugins to be incuded by the `postinstall` job
|
|
138
|
-
Bun will by default exlude any `postinstall` jobs unless we have trusted the scimgateway package using the `bun pm trust scimgateway` that updates package.json `{ trustedDependencies: ["scimgateway"] }`
|
|
139
|
-
|
|
140
|
-
For Node.js (and also Bun), we might set the property `scimgateway_postinstall_skip = true` in `.npmrc` or setting environment `SCIMGATEWAY_POSTINSTALL_SKIP = true`
|
|
141
|
-
|
|
142
|
-
## Configuration
|
|
143
|
-
|
|
144
|
-
The `index.ts` file spesifies one or more plugins to be started.
|
|
145
|
-
|
|
146
|
-
// start one or more plugins:
|
|
147
|
-
import './lib/plugin-entra-id.ts'
|
|
148
|
-
export {}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
Each endpoint plugin needs a TypeScript file (.ts) and a configuration file (.json).
|
|
152
|
-
They both must have the **same naming prefix**. For the Entra ID endpoint, the corresponding files are:
|
|
153
|
-
>lib\plugin-entra-id.ts
|
|
154
|
-
>config\plugin-entra-id.json
|
|
155
|
-
|
|
156
|
-
A plugin configuration file has two main JSON objects: `scimgateway` and `endpoint`
|
|
157
|
-
|
|
158
|
-
{
|
|
159
|
-
"scimgateway": {
|
|
160
|
-
...
|
|
161
|
-
},
|
|
162
|
-
"endpoint": {
|
|
163
|
-
...
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
`scimgateway`: Contains fixed attributes used by the core gateway functionality, such as port, logging, and authentication.
|
|
168
|
-
|
|
169
|
-
`endpoint`: Contains customized definitions required by the plugin code for communication with the destination system, including host, port, and credentials.
|
|
170
|
-
|
|
171
|
-
- **port**: The gateway will listen on this port number. Clients, such as a provisioning server, will use this port to communicate with the gateway.
|
|
172
|
-
|
|
173
|
-
- **localhostonly**: Set to `true` to accept incoming requests only from localhost (127.0.0.1). Set to `false` to accept requests from all clients.
|
|
174
|
-
|
|
175
|
-
- **chainingBaseUrl**: The base URL for chaining another gateway, with the syntax `http(s)://host:port`. When defined, the gateway behaves like a reverse proxy, validating authorization unless PassThrough mode is enabled. See `Configuration notes` for details.
|
|
176
|
-
|
|
177
|
-
- **idleTimeout**: The number of seconds to wait before timing out a connection due to inactivity. The default value is 120 seconds.
|
|
178
|
-
|
|
179
|
-
- **scim.version**: Specifies the SCIM protocol version to use, either "1.1" or "2.0". The default is "2.0".
|
|
180
|
-
|
|
181
|
-
- **scim.skipTypeConvert**: When set to `true`, multivalue attributes with types (e.g., emails, phoneNumbers, ims, photos, addresses, entitlements, and x509Certificates, but not roles, groups, and members) will not be converted into "type converted objects" when sent to `modifyUser` and `createUser`. This is useful for simplifying attribute checks and for the `endpointMapper` method used by `plugin-ldap` and `plugin-entra-id`. For example:
|
|
182
|
-
|
|
183
|
-
"emails": {
|
|
184
|
-
"work": {"value": "jsmith@example.com", "type": "work"},
|
|
185
|
-
"home": {"value": "", "type": "home", "operation": "delete"},
|
|
186
|
-
"undefined": {"value": "jsmith@hotmail.com"}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
When `skipTypeConvert` is set to `true`, the attribute is provided "as-is" as an array, allowing duplicate types including blank types. Values to be deleted are marked with `"operation": "delete"`.
|
|
190
|
-
|
|
191
|
-
"emails": [
|
|
192
|
-
{"value": "jsmith@example.com", "type": "work"},
|
|
193
|
-
{"value": "john.smith.org", "type": "home", "operation": "delete"},
|
|
194
|
-
{"value": "jsmith@hotmail.com"}
|
|
195
|
-
]
|
|
196
|
-
|
|
197
|
-
- **scim.skipMetaLocation**: When set to `true`, the `meta.location` attribute, which contains the protocol and hostname from the request URL, will be excluded from the response (e.g., `"{...,meta":{"location":"https://my-company.com/<...>"}}`). This is useful when using a reverse proxy and not including the `X-Forwarded-Proto` and `X-Forwarded-Host` headers, as the originator will be the proxy and the internal protocol and hostname should not be exposed.
|
|
198
|
-
|
|
199
|
-
- **scim.groupMemberOfUser**: When set to `true`, and the request body contains groups, the `groups` attribute will remain on the user object (groups are members of the user). The default behavior is for the user to be a member of the groups, which uses the `modifyGroup` method to maintain group members.
|
|
200
|
-
|
|
201
|
-
- **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.
|
|
202
|
-
|
|
203
|
-
- **log.loglevel.file** - off, debug, info, warn or error. Default off. Output to plugin-logfile e.g. `logs\plugin-saphana.log`
|
|
204
|
-
|
|
205
|
-
- **log.loglevel.console** - off, debug, info, warn or error. Default off. Output to stdout and errors to stderr
|
|
206
|
-
|
|
207
|
-
- **log.loglevel.push** - debug, info, warn or error. Default info. Push to stream used by remote real-time log subscription
|
|
208
|
-
|
|
209
|
-
- **log.logDirectory** - custom defined log directory e.g. `/var/log/scimgateway` that will override default `<scimgateway path>/logs`. If not exist it will be created.
|
|
210
|
-
|
|
211
|
-
- **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.
|
|
212
|
-
|
|
213
|
-
- **log.colorize** - default true, gives colorized and minimized console output, if redirected to stdout/stderr standard JSON formatted output and no colors. Set to false give standard JSON
|
|
214
|
-
|
|
215
|
-
- **log.maxSize** - default 20 (MB) log file size
|
|
216
|
-
|
|
217
|
-
- **log.maxFiles** - default 5, keep only the last 5 logs - note, new and rotated file on startup
|
|
218
|
-
|
|
219
|
-
- **auth** - Contains one or more authentication/authorization methods used by clients for accessing gateway - may also include:
|
|
220
|
-
- **auth.xx.readOnly** - true/false, true gives read only access - only allowing `GET` requests for corresponding admin user
|
|
221
|
-
- **auth.xx.baseEntities** - array containing one or more `baseEntity` allowed for this user e.g. ["client-a"] - empty array allowing all.
|
|
222
|
-
**Methods are disabled by setting corresponding admin user to null or remove methods not used**
|
|
223
|
-
|
|
224
|
-
- **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.
|
|
225
|
-
|
|
226
|
-
- **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.
|
|
227
|
-
|
|
228
|
-
- **auth.bearerJwt** - Array of one or more standard JWT objects. Using **secret**, **publicKey**, **wellKnownUri** or **azureTenantId** 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. For JWKS (JSON Web Key Set), the **wellKnownUri** must be set to identity provider well-known URI which will be used for lookup the jwks_uri key. **options.issuer** should normally be set for validation when using secret or publicKey, for JWKS (wellKnownUri), the issuer will be included automatically. Other options may also be included according to the JWT standard. When using Azure Entra ID provisioning through scimgateway, set **azureTenantId** to the Entra tenant id. When using Entra ID application accessing gateway use: `wellKnownUri=https://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configuration` and `options.audience={application-id}`
|
|
229
|
-
|
|
230
|
-
- **auth.bearerOAuth** - Array of one or more Client Credentials OAuth configuration objects. **`clientId`** and **`clientSecret`** are mandatory. clientSecret value will become encrypted when gateway is started. OAuth token request url is **/oauth/token** e.g. `http://localhost:8880/oauth/token`
|
|
231
|
-
|
|
232
|
-
- **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
|
|
233
|
-
|
|
234
|
-
- **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:
|
|
235
|
-
|
|
236
|
-
"certificate": {
|
|
237
|
-
"key": "key.pem",
|
|
238
|
-
"cert": "cert.pem",
|
|
239
|
-
"ca": "ca.pem" // if several: "ca": ["ca1.pem", "ca2.pem"]
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
Example of how to make a self signed certificate:
|
|
243
|
-
|
|
244
|
-
openssl req -nodes -newkey rsa:2048 -x509 -sha256 -days 3650 -keyout key.pem -out cert.pem -subj "/O=My Company/OU=Application/CN=SCIM Gateway" -addext "subjectAltName=DNS:localhost,DNS:127.0.0.1,DNS:*.mycompany.com" -addext "extendedKeyUsage=serverAuth" -addext "keyUsage=digitalSignature"
|
|
245
|
-
|
|
246
|
-
Note, when using Symantec/Broadcom Provisioning, the "certificate authority - CA" also must be imported on the Connector Server. For self-signed certificate, CA and the certificate (public key) is the same.
|
|
247
|
-
|
|
248
|
-
PFX / PKCS#12 bundle can be used instead of key/cert/ca e.g:
|
|
249
|
-
|
|
250
|
-
"pfx": {
|
|
251
|
-
"bundle": "certbundle.pfx",
|
|
252
|
-
"password": "password"
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
Note, we should normally use certificate (https) for communicating with SCIM Gateway unless we install gateway locally on the manager (e.g. on the provisioning 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}
|
|
256
|
-
|
|
257
|
-
- **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](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:
|
|
258
|
-
|
|
259
|
-
"ipAllowList": [
|
|
260
|
-
"13.64.151.161/32",
|
|
261
|
-
"13.66.141.64/27",
|
|
262
|
-
...
|
|
263
|
-
"2603:1056:2000::/48",
|
|
264
|
-
"2603:1057:2::/48"
|
|
265
|
-
]
|
|
266
|
-
- **email** - Sending email from plugin or automated error notifications emailOnError. For emailOnError only the first error will be sent until sendInterval have passed. Supporting both SMTP Auth and modern REST OAuth. For OAuth, currently Microsoft Exchange Online (ExO) and Google Workspace Gmail are supported - see configuration notes
|
|
267
|
-
- **email.auth** - Authentication configuration
|
|
268
|
-
- **email.auth.type** - `oauth` or `smtp`
|
|
269
|
-
- **email.auth.options** - Authentication options - note, different options for type oauth and smtp
|
|
270
|
-
- **email.auth.options.azureTenantId (oauth/ExO)** - Entra tenant id or domain name
|
|
271
|
-
- **email.auth.options.clientId (oauth/ExO)** - Entra OAuth application Client ID
|
|
272
|
-
- **email.auth.options.clientSecret (oauth/ExO)** - Entra OAuth application Client Secret
|
|
273
|
-
- **email.auth.options.serviceAccountKeyFile (oauth/Gmail)** - Google Service Account key json-file name located in the `package-root>\config\certs` directory unless absolute path being defined
|
|
274
|
-
- **email.auth.options.host (smtp)** - Mailserver e.g. "smtp.gmail.com" - mandatory for smtp
|
|
275
|
-
- **email.auth.options.port (smtp)** - Port used by mailserver e.g. 587, 25 or 465 - mandatory for smtp
|
|
276
|
-
- **email.auth.options.username (smtp)** - Mail account for authentication normally same as sender of the email, e.g. "user@gmail.com"
|
|
277
|
-
- **email.auth.options.password (smtp)** - Mail account password
|
|
278
|
-
- **email.proxy** - Proxy configuration if using mailproxy
|
|
279
|
-
- **email.proxy.host** - Proxy host e.g. `http://proxy-host:1234`
|
|
280
|
-
- **email.proxy.username** - username if authentication is required
|
|
281
|
-
- **email.proxy.password** - password if authentication is required
|
|
282
|
-
- **email.emailOnError** - Contains configuration for sending error notifications by email. Note, only the first error will be sent until sendInterval have passed
|
|
283
|
-
- **email.emailOnError.enabled** - true or false, value set to true will enable email notifications
|
|
284
|
-
- **email.emailOnError.sendInterval** - Default 15. Mail notifications on error are deferred until sendInterval **minutes** have passed since the last notification
|
|
285
|
-
- **email.emailOnError.from** - Sender email addresses e.g: "noreply@example.com". **Mandatory for oauth**. For smtp email.auth.options.username will be used
|
|
286
|
-
- **email.emailOnError.to** - Comma separated list of recipients email addresses e.g: "someone@example.com"
|
|
287
|
-
- **email.emailOnError.cc** - Optional comma separated list of cc mail addresses
|
|
288
|
-
- **email.emailOnError.subject** - Optional mail subject, default `SCIM Gateway error message`
|
|
289
|
-
|
|
290
|
-
- **azureRelay** - Azure Relay outbound listener
|
|
291
|
-
- **azureRelay.enabled** - true or false, true will enable the Azure Relay listener
|
|
292
|
-
- **azureRelay.connectionUrl** - `https://<namespace-name>.servicebus.windows.net/<hybrid-connection-name>` - `<namespace-name>` is the name of the Relay created and `<hybrid-connection-name>` is the name of the Hybrid Connection entity created in the Relay
|
|
293
|
-
- **azureRelay.apiKey** - The `Private Key` found in the `Shared access policy` (RootManageSharedaccessKey)
|
|
294
|
-
- **azureRelay.keyRule** - Optional, the `Shared access policy` name - default using `RootManageSharedaccessKey`
|
|
295
|
-
|
|
296
|
-
- **stream** - See [SCIM Stream](https://elshaug.xyz/docs/scim-stream) for configuration details
|
|
297
|
-
|
|
298
|
-
- **endpoint** - Contains endpoint specific configuration according to customized **plugin code**.
|
|
299
|
-
|
|
300
|
-
### Configuration notes - general
|
|
301
|
-
|
|
302
|
-
- Custom Schemas, ServiceProviderConfig and ResourceType can be used if `./lib/scimdef-v2.json or scimdef-v1.json` exists. Original scimdef-v2.json/scimdef-v1.json can be copied from node_modules/scimgateway/lib to your plugin/lib and customized.
|
|
303
|
-
- 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`
|
|
304
|
-
- 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.
|
|
305
|
-
- 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.
|
|
306
|
-
- 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"
|
|
307
|
-
- 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".
|
|
308
|
-
|
|
309
|
-
Example:
|
|
310
|
-
|
|
311
|
-
{
|
|
312
|
-
"scimgateway": {
|
|
313
|
-
...
|
|
314
|
-
"port": "process.env.PORT",
|
|
315
|
-
...
|
|
316
|
-
"loglevel": {
|
|
317
|
-
"file": "process.env.LOG_LEVEL_FILE",
|
|
318
|
-
...
|
|
319
|
-
"auth": {
|
|
320
|
-
"basic": [
|
|
321
|
-
{
|
|
322
|
-
"username": "process.file./var/run/vault/secrets.json",
|
|
323
|
-
"password": "process.file./var/run/vault/secrets.json"
|
|
324
|
-
},
|
|
325
|
-
...
|
|
326
|
-
],
|
|
327
|
-
"bearerJwt": [
|
|
328
|
-
"secret": "process.text./var/run/vault/jwt.secret",
|
|
329
|
-
"publicKey": "process.text./var/run/vault/jwt.pub",
|
|
330
|
-
...
|
|
331
|
-
],
|
|
332
|
-
...
|
|
333
|
-
},
|
|
334
|
-
"endpoint": {
|
|
335
|
-
...
|
|
336
|
-
"username": "process.file./var/run/vault/secrets.json",
|
|
337
|
-
"password": "process.file./var/run/vault/secrets.json",
|
|
338
|
-
...
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
jwt.secret file content example:
|
|
344
|
-
|
|
345
|
-
thisIsSecret
|
|
346
|
-
|
|
347
|
-
secrets.json file content example for plugin-soap:
|
|
348
|
-
|
|
349
|
-
{
|
|
350
|
-
"plugin-soap.scimgateway.auth.basic[0].username": "gwadmin",
|
|
351
|
-
"plugin-soap.scimgateway.auth.basic[0].password": "password",
|
|
352
|
-
"plugin-soap.endpoint.username": "superuser",
|
|
353
|
-
"plugin-soap.endpoint.password": "secret"
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
### Configuration notes - Email, using Microsoft Exchange Online (ExO)
|
|
357
|
-
|
|
358
|
-
- Entra ID application must have application permissions `Mail.Send`
|
|
359
|
-
- To prevent the sending of emails from any defined mailboxes, an ExO `ApplicationAccessPolicy` must be defined through PowerShell.
|
|
360
|
-
|
|
361
|
-
First create a mail-enabled security-group that only includes those users (mailboxes) the application is allowed to send from
|
|
362
|
-
Note, `mail enabled security group` cannot be created from portal, only from admin or admin.exchange console
|
|
363
|
-
|
|
364
|
-
##Connect to Exchange
|
|
365
|
-
Install-Module -Name ExchangeOnlineManagement
|
|
366
|
-
Connect-ExchangeOnline
|
|
367
|
-
|
|
368
|
-
##Create ApplicationAccessPolicy
|
|
369
|
-
New-ApplicationAccessPolicy -AppId <AppClientID> -PolicyScopeGroupId <MailEnabledSecurityGrpId> -AccessRight RestrictAccess -Description "Restrict app to specific mailboxes"
|
|
370
|
-
|
|
371
|
-
### Configuration notes - Email, using Google Workspace Gmail
|
|
372
|
-
|
|
373
|
-
- https://console.cloud.google.com
|
|
374
|
-
- IAM & Admin > Service Accounts > Create Service Account
|
|
375
|
-
- Name=email-sender
|
|
376
|
-
- Create and Continue
|
|
377
|
-
- Grant this service account access to project - not needed
|
|
378
|
-
- Grant users access to this service - not needed
|
|
379
|
-
- IAM & Admin > Service Accounts > "email-sender" account > Keys
|
|
380
|
-
- Add Key > Create new key > JSON
|
|
381
|
-
- download json Service Account Key file, refere to configuration `email.auth.options.serviceAccountKeyFile`
|
|
382
|
-
|
|
383
|
-
- https://admin.google.com
|
|
384
|
-
- Security > Access and data control > API controls
|
|
385
|
-
- Manage Domain Wide Delegation > Add new
|
|
386
|
-
- Client ID = id of service account created
|
|
387
|
-
- OAuth scope = `https://www.googleapis.com/auth/gmail.send`
|
|
388
|
-
|
|
389
|
-
- https://admin.google.com
|
|
390
|
-
- Billing > Subscriptions - verify Google Workspace license
|
|
391
|
-
- Directory > Users > "user"
|
|
392
|
-
- Licenses > Edit > enable Google Workspace license
|
|
393
|
-
`email.emailOnError.from` mail address must have Google Workspace license
|
|
394
|
-
|
|
395
|
-
### Configuration notes - Gateway chainging and chainingBaseUrl
|
|
396
|
-
|
|
397
|
-
By configuring the `chainingBaseUrl`, it is possible to chain multiple gateways in sequence, such as `gateway1->gateway2->gateway3->endpoint`. In this setup, gateway behave much like a reverse proxy, validating authorization at each step unless PassThrough mode is enabled. Chaining is also supported in stream subscriber mode
|
|
398
|
-
|
|
399
|
-
{
|
|
400
|
-
"scimgateway": {
|
|
401
|
-
...
|
|
402
|
-
"chainingBaseUrl": "https:\\gateway2:8880",
|
|
403
|
-
...
|
|
404
|
-
"auth": {
|
|
405
|
-
...
|
|
406
|
-
"passThrough": {
|
|
407
|
-
"enabled": false,
|
|
408
|
-
"readOnly": false,
|
|
409
|
-
"baseEntities": []
|
|
410
|
-
}
|
|
411
|
-
...
|
|
412
|
-
}
|
|
413
|
-
},
|
|
414
|
-
...
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
Using above configuration example on gateway1, incoming requests will be routed to `https:\\gateway2:8880`
|
|
419
|
-
|
|
420
|
-
The plugin and its associated authentication configuration can mirror the setup running on the final gateway. However, in chaining mode, the plugin binary is used solely for initializing and configuring the gateway. This allows for the use of a simplified `plugin-<name>.ts` binary containing only the essential mandatory components:
|
|
421
|
-
|
|
422
|
-
// start - mandatory plugin initialization
|
|
423
|
-
const ScimGateway: typeof import('scimgateway').ScimGateway = await (async () => {
|
|
424
|
-
try {
|
|
425
|
-
return (await import('scimgateway')).ScimGateway
|
|
426
|
-
} catch (err) {
|
|
427
|
-
const source = './scimgateway.ts'
|
|
428
|
-
return (await import(source)).ScimGateway
|
|
429
|
-
}
|
|
430
|
-
})()
|
|
431
|
-
const scimgateway = new ScimGateway()
|
|
432
|
-
const config = scimgateway.getConfig()
|
|
433
|
-
scimgateway.authPassThroughAllowed = false
|
|
434
|
-
// end - mandatory plugin initialization
|
|
435
|
-
|
|
436
|
-
Using `scimgateway.authPassThroughAllowed = true` and `plugin-<name>.json` configuration `scimgateway.auth.passThrough=true` enables Authentication PassTrhough
|
|
437
|
-
|
|
438
|
-
### Configuration notes - HelperRest used by plugins
|
|
439
|
-
For REST endpoints, plugins may use HelperRest to simplify authentication and communication
|
|
440
|
-
doRequest() executes REST request and return response
|
|
441
|
-
`doRequest(<baseEntity>, <method>, <path>, <body>, <ctx>, <options>)`
|
|
442
|
-
|
|
443
|
-
* baseEntity - 'undefined' if not used and must correspond with endpoint configuration that defines baseUrls and connection options.
|
|
444
|
-
* method - GET, PATCH, PUT, DELETE
|
|
445
|
-
* path - either full url or just the path that will be added to baseUrl. Using full url will override baseUrl. Using path is preferred because of auth caching logic and simplicity
|
|
446
|
-
* body - optional body to be used
|
|
447
|
-
* ctx - optional, passing authorization header if Auth PassThrough is enabled
|
|
448
|
-
* opt - optional, connection options that will extend/override any endpoint.entity.undefined.connection definitions
|
|
449
|
-
|
|
450
|
-
Configuration showing connection settings:
|
|
451
|
-
|
|
452
|
-
{
|
|
453
|
-
"scimgateway": {
|
|
454
|
-
...
|
|
455
|
-
}
|
|
456
|
-
"endpoint": {
|
|
457
|
-
"entity": {
|
|
458
|
-
"undefined": {
|
|
459
|
-
"connection": {
|
|
460
|
-
"baseUrls": [],
|
|
461
|
-
"auth": {
|
|
462
|
-
"type": "xxx",
|
|
463
|
-
"options": {
|
|
464
|
-
...
|
|
465
|
-
"jwtPayload": {},
|
|
466
|
-
"samlPayload": {},
|
|
467
|
-
"tls": {} // files located in ./config/certs
|
|
468
|
-
}
|
|
469
|
-
},
|
|
470
|
-
"options": {
|
|
471
|
-
"headers": {},
|
|
472
|
-
"tls": {} // files located in ./config/certs
|
|
473
|
-
},
|
|
474
|
-
"proxy": {}
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
* baseUrls - Endpoint URL. Several may be defined for failower. There are retry logic on connection failures
|
|
483
|
-
* auth.type - defines authentication being used: `basic`, `oauth`, `token`, `bearer`, `oauthSamlBearer` or `oauthJwtBearer`
|
|
484
|
-
* auth.options - for each valid type there are different options. azureTenantId is special for Entra ID and serviceAccountKeyFile is special for Google. Using these will simplify and reduce options to be included. Also note we do not need to include baseUrls when using azureTenantId/serviceAccountKeyFile as long as endpoint is Entra ID (Microsoft Graph) or Google.
|
|
485
|
-
|
|
486
|
-
Example using basic auth:
|
|
487
|
-
|
|
488
|
-
"connection": {
|
|
489
|
-
"baseUrls": [
|
|
490
|
-
"https://localhost:8880"
|
|
491
|
-
],
|
|
492
|
-
"auth": {
|
|
493
|
-
"type": "basic",
|
|
494
|
-
"options": {
|
|
495
|
-
"username": "gwadmin",
|
|
496
|
-
"password": "password"
|
|
497
|
-
}
|
|
498
|
-
},
|
|
499
|
-
"options": {
|
|
500
|
-
"tls": {
|
|
501
|
-
"rejectUnauthorized": false,
|
|
502
|
-
"ca": "ca.pem"
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
Example Entra ID (plugin-entra-id) using clientId/clientSecret:
|
|
508
|
-
|
|
509
|
-
"connection": {
|
|
510
|
-
"baseUrls": [],
|
|
511
|
-
"auth": {
|
|
512
|
-
"type": "oauth",
|
|
513
|
-
"options": {
|
|
514
|
-
"azureTenantId": "<tenantId>",
|
|
515
|
-
"clientId": "<clientId>",
|
|
516
|
-
"clientSecret": "<clientSecret>"
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
Example Entra ID (plugin-entra-id) using certificate secret:
|
|
522
|
-
|
|
523
|
-
"connection": {
|
|
524
|
-
"baseUrls": [],
|
|
525
|
-
"auth": {
|
|
526
|
-
"type": "oauthJwtBearer",
|
|
527
|
-
"options": {
|
|
528
|
-
"azureTenantId": "<tenantId>",
|
|
529
|
-
"clientId": "<clientId>",
|
|
530
|
-
"tls": {
|
|
531
|
-
"key": "key.pem",
|
|
532
|
-
"cert": "cert.pem"
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
Example Entra ID (plugin-entra-id) using federated credentials:
|
|
539
|
-
|
|
540
|
-
"connection": {
|
|
541
|
-
"baseUrls": [],
|
|
542
|
-
"auth": {
|
|
543
|
-
"type": "oauthJwtBearer",
|
|
544
|
-
"options": {
|
|
545
|
-
"azureTenantId": "<tenantId>",
|
|
546
|
-
"fedCred": {
|
|
547
|
-
"issuer": "<https://FQDN-scimgateway>",
|
|
548
|
-
"subject": "<entra id application object id - client id>",
|
|
549
|
-
"name": "<entra id federated credentials unique name>"
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
// Note, fedCred configuration must match corresponding configuration in Entra ID Application - Certificates & Secrets - Federated credentials - scenario "Other issuer"
|
|
555
|
-
// example issuer: "https://scimgateway.my-company.com" note, this scimgateway base URL must be reachable from the internet
|
|
556
|
-
// example name: "plugin-entra-id"
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
Example using general OAuth:
|
|
560
|
-
|
|
561
|
-
"connection": {
|
|
562
|
-
"baseUrls": [<"endpointUrl">],
|
|
563
|
-
"auth": {
|
|
564
|
-
"type": "oauth",
|
|
565
|
-
"options": {
|
|
566
|
-
"tokenUrl": "<tokenUrl>"
|
|
567
|
-
"clientId": "<clientId>",
|
|
568
|
-
"clientSecret": "<clientSecret>"
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
Please see code editor method HelperRest doRequest() IntelliSense for type and option details
|
|
574
|
-
|
|
575
|
-
### Configuration notes - Remote real-time log subscription
|
|
576
|
-
Using remote real-time log subscription we may implement custom logic like monitoring and centralized logging
|
|
577
|
-
|
|
578
|
-
- browser and url: https://host/logger
|
|
579
|
-
- curl with -u or -H "Authorization: Bearer secret"
|
|
580
|
-
```
|
|
581
|
-
curl -Ns http://localhost:8880/logger -u gwadmin:password | awk '
|
|
582
|
-
/^data: / {sub(/^data: /,""); printf "%s", $0; last=1; next}
|
|
583
|
-
/^$/ {if (last) print ""; last=0}
|
|
584
|
-
'
|
|
585
|
-
```
|
|
586
|
-
- custom client API (see example below)
|
|
587
|
-
- not supported by Azure Relay
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
We may configure read-only user/secret for log collection purpose
|
|
591
|
-
|
|
592
|
-
"auth": {
|
|
593
|
-
"basic": [
|
|
594
|
-
{
|
|
595
|
-
"username": "gwadmin",
|
|
596
|
-
"password": "password",
|
|
597
|
-
"readOnly": false,
|
|
598
|
-
"baseEntities": []
|
|
599
|
-
},
|
|
600
|
-
{
|
|
601
|
-
"username": "gwread",
|
|
602
|
-
"password": "password",
|
|
603
|
-
"readOnly": true,
|
|
604
|
-
"baseEntities": []
|
|
605
|
-
}
|
|
606
|
-
],
|
|
607
|
-
"bearerToken": [
|
|
608
|
-
{
|
|
609
|
-
"token": "secret",
|
|
610
|
-
"readOnly": true,
|
|
611
|
-
"baseEntities": []
|
|
612
|
-
}
|
|
613
|
-
],
|
|
614
|
-
...
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
Remote log subscription is configured by log.loglevel.push and the push logger has default loglevel set to `info`
|
|
618
|
-
Example using debug loglevel:
|
|
619
|
-
|
|
620
|
-
"log": {
|
|
621
|
-
"loglevel": {
|
|
622
|
-
"push": "debug"
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
Example code implementing remote real-time log subscription and custom message handling
|
|
627
|
-
|
|
628
|
-
```
|
|
629
|
-
//
|
|
630
|
-
// usage: bun <scriptname.ts>
|
|
631
|
-
// update url and the auth according to environment used
|
|
632
|
-
//
|
|
633
|
-
const username = "gwadmin"
|
|
634
|
-
const password = "password"
|
|
635
|
-
const url = "http://localhost:8880/logger"
|
|
636
|
-
|
|
637
|
-
const headers = new Headers({
|
|
638
|
-
Authorization: "Basic " + btoa(`${username}:${password}`),
|
|
639
|
-
Accept: "text/event-stream"
|
|
640
|
-
})
|
|
641
|
-
|
|
642
|
-
// message handling and custom logic
|
|
643
|
-
// we could also do JSON.parse(message) and granular filtering on log "level"
|
|
644
|
-
const messageHandler = async (message: string) => {
|
|
645
|
-
console.log(message)
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
async function startup() {
|
|
649
|
-
while (true) {
|
|
650
|
-
try {
|
|
651
|
-
const resp = await fetch(url, { headers });
|
|
652
|
-
if (!resp.ok || !resp.body) {
|
|
653
|
-
console.error(`❌ Response error: ${resp.status} ${resp.statusText}`)
|
|
654
|
-
await Bun.sleep(10_000)
|
|
655
|
-
continue
|
|
656
|
-
}
|
|
657
|
-
console.log('✅ Now awaiting log events...\n')
|
|
658
|
-
|
|
659
|
-
const reader = resp.body.pipeThrough(new TextDecoderStream()).getReader()
|
|
660
|
-
|
|
661
|
-
while (true) {
|
|
662
|
-
const { value, done } = await reader.read()
|
|
663
|
-
if (done) break
|
|
664
|
-
if (!value.startsWith('data: ')) continue
|
|
665
|
-
const i = value.indexOf("\n\n")
|
|
666
|
-
if (i < 1) continue
|
|
667
|
-
const msg = value.slice(6, i)
|
|
668
|
-
messageHandler(msg)
|
|
669
|
-
}
|
|
670
|
-
console.error("⚠️ Connection closed");
|
|
671
|
-
await Bun.sleep(10_000)
|
|
672
|
-
} catch (err: any) {
|
|
673
|
-
console.error("❌ Connection error:", err?.message || err)
|
|
674
|
-
await Bun.sleep(10_000)
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
startup()
|
|
680
|
-
```
|
|
681
|
-
|
|
682
|
-
### Configuration notes - Azure Relay
|
|
683
|
-
|
|
684
|
-
Using Azure technology we have different options for setting up a communication tunnel to SCIM Gateway:
|
|
685
|
-
|
|
686
|
-
- `Microsoft Entra Application Proxy + Microsoft Entra Application Proxy Connector` (SCIM Gateway located on-premises or using Azure private VNet/IP)
|
|
687
|
-
- `Azure Application Gateway` - Layer 7 (SCIM Gateway located in Azure)
|
|
688
|
-
- `Azure Relay` (SCIM Gateway located on-premises or in Azure)
|
|
689
|
-
|
|
690
|
-
SCIM Gateway have builtin [Azure Relay](https://learn.microsoft.com/en-us/azure/azure-relay/relay-what-is-it) support which gives secure and hassle-free outbound communication — with just one minute of configuration
|
|
691
|
-
|
|
692
|
-
Azure pricing for using Azure Relay is approx. 10$ per month for each listener (SCIM Gateway plugin)
|
|
693
|
-
|
|
694
|
-
**Using out-of-the-box Azure Relay:**
|
|
695
|
-
|
|
696
|
-
- Prerequisite: SCIM Gateway having outbound internet access (https/443)
|
|
697
|
-
- In Azure create a `Relay` - `<namespace-name>`
|
|
698
|
-
- In the Relay, create an entity of type `Hybrid Connection` - `<hybrid-connection-name>` **one for each SCIM Gateway plugin**
|
|
699
|
-
- The `Requires Client Authorization` option **should be unchecked (not activated)**, unless we are using custom IdP/API having logic for including SAS-token in the communication header
|
|
700
|
-
- Shared access policies - RootManageSharedaccessKey - Primary Key (copy this one)
|
|
701
|
-
Instead of RootManageSharedaccessKey policy in the `<namespace-name>`, we could create dedicated policy in the sub level `<hybrid-connection-name>` and use this policy name in plugin configuration `scimgateway.azureRelay.keyRule`
|
|
702
|
-
|
|
703
|
-
SCIM Gateway plugin configuration:
|
|
704
|
-
|
|
705
|
-
```
|
|
706
|
-
{
|
|
707
|
-
"scimgateway: {
|
|
708
|
-
...
|
|
709
|
-
"azureRelay": {
|
|
710
|
-
"enabled": true,
|
|
711
|
-
"connectionUrl": "https://<namespace-name>.servicebus.windows.net/<hybrid-connection-name>",
|
|
712
|
-
"apiKey": "<primary-key>"
|
|
713
|
-
},
|
|
714
|
-
...
|
|
715
|
-
},
|
|
716
|
-
...
|
|
717
|
-
}
|
|
718
|
-
````
|
|
719
|
-
|
|
720
|
-
`connectionUrl` will be the SCIM base URL used by IdP/API for accessing SCIM Gateway
|
|
721
|
-
|
|
722
|
-
Example:
|
|
723
|
-
GET `https://<namespace-name>.servicebus.windows.net/<hybrid-connection-name>/Users`
|
|
724
|
-
GET `https://<namespace-name>.servicebus.windows.net/<hybrid-connection-name>/<baseEntity>/Users`
|
|
725
|
-
|
|
726
|
-
If several SCIM Gateway´s (same plugin) connect listeners using the same Azure Relay connectionUrl, there will be load-balancing and round-robin distribution
|
|
727
|
-
|
|
728
|
-
### Configuration notes - running SCIM Gateway as a single binary
|
|
729
|
-
|
|
730
|
-
Bun binary build allowing SCIM Gateway to be compiled into a single executable binary for simplified deployment and execution. The binary must have the same name (prefix) as the configuration file in the config directory, and this directory must be located in the same folder as the binary.
|
|
130
|
+
|---|---|---|
|
|
131
|
+
| **loki** | NoSQL | Standalone SCIM endpoint using [LokiJS](https://github.com/techfort/LokiJS). Includes test users and groups. Ideal for development. |
|
|
132
|
+
| **mongodb** | NoSQL | Like Loki but backed by an external MongoDB. Demonstrates multi-tenant via `baseEntity`. |
|
|
133
|
+
| **entra-id** | REST | Users/Groups/Roles/AccessPackages/Licenses provisioning to Microsoft Entra ID via Microsoft Graph API. |
|
|
134
|
+
| **generic** | REST | Generic template using `endpointMapper` and the `valueMap` option for allowlisting and name mapping e.g., groups. Defaults to plugin-loki as the SCIM target. Can also act as a SCIM version gateway (e.g. 1.1 → 2.0). |
|
|
135
|
+
| **api** | REST | Non-SCIM plugin demonstrating API Gateway mode for custom REST specifications. |
|
|
136
|
+
| **soap** | SOAP | User provisioning to a SOAP-based endpoint with example WSDLs. |
|
|
137
|
+
| **mssql** | SQL | User provisioning to Microsoft SQL Server. |
|
|
138
|
+
| **saphana** | SQL | SAP HANA–specific user provisioning. |
|
|
139
|
+
| **ldap** | Directory | Full LDAP plugin pre-configured for Microsoft Active Directory. |
|
|
731
140
|
|
|
732
|
-
|
|
733
|
-
bun build --compile ./lib/plugin-loki.ts --target=bun-darwin-arm64 --outfile ./build/plugin-loki
|
|
734
|
-
# for target options, see: https://bun.com/docs/bundler/executables#cross-compile-to-other-platforms
|
|
735
|
-
|
|
736
|
-
cp -r ./config ./build
|
|
737
|
-
# build directory now ready for production deployment
|
|
738
|
-
cd build
|
|
739
|
-
# run the binary - note, binary must have same name (prefix) as the configuration file in the config directory
|
|
740
|
-
./plugin-loki
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
## Manual startup
|
|
745
|
-
|
|
746
|
-
Gateway can be started from a command window running in administrative mode
|
|
747
|
-
|
|
748
|
-
3 ways to start:
|
|
749
|
-
|
|
750
|
-
bun c:\my-scimgateway
|
|
751
|
-
|
|
752
|
-
bun c:\my-scimgateway\index.ts
|
|
753
|
-
|
|
754
|
-
<package-root>bun .
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
<kbd>Ctrl</kbd>+<kbd>c</kbd> to stop
|
|
758
|
-
|
|
759
|
-
## Automatic startup - Windows Task Scheduler
|
|
760
|
-
|
|
761
|
-
Start Windows Task Scheduler (taskschd.msc), right click on "Task Scheduler Library" and choose "Create Task"
|
|
762
|
-
|
|
763
|
-
General tab:
|
|
764
|
-
-----------
|
|
765
|
-
Name = SCIM Gateway
|
|
766
|
-
User account = SYSTEM
|
|
767
|
-
Run with highest privileges
|
|
768
|
-
|
|
769
|
-
Triggers tab:
|
|
770
|
-
-------------
|
|
771
|
-
Begin the task = At startup
|
|
772
|
-
|
|
773
|
-
Actions tab:
|
|
774
|
-
------------
|
|
775
|
-
Action = Start a program
|
|
776
|
-
Program/script = <install path>\bun.exe
|
|
777
|
-
Arguments = c:\my-scimgateway
|
|
778
|
-
|
|
779
|
-
Settings - tab:
|
|
780
|
-
---------------
|
|
781
|
-
Stop the task if runs longer than = Disabled (greyed out)
|
|
782
|
-
|
|
783
|
-
Verification:
|
|
784
|
-
|
|
785
|
-
- 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`
|
|
786
|
-
- Right click task - **End**, verify process node.exe have been terminated and disappeared from task manager
|
|
787
|
-
- **Reboot** server and verify SCIM Gateway have been automatically started
|
|
788
|
-
|
|
789
|
-
## Running as a isolated virtual Docker container
|
|
790
|
-
|
|
791
|
-
Installing Docker Desktop may be an alternative for creating and testing docker images and containers
|
|
792
|
-
|
|
793
|
-
There are two options: run SCIM Gateway in a single image, or use Docker Compose, which allows configuration and data outside the image and including other images as dependencies (e.g., MSSQL)
|
|
794
|
-
|
|
795
|
-
### Docker single image
|
|
796
|
-
|
|
797
|
-
- Install SCIM Gateway within your own package and copy provided docker files:
|
|
798
|
-
|
|
799
|
-
```
|
|
800
|
-
mkdir /opt/my-scimgateway
|
|
801
|
-
cd /opt/my-scimgateway
|
|
802
|
-
bun init -y
|
|
803
|
-
bun install scimgateway
|
|
804
|
-
bun pm trust scimgateway
|
|
805
|
-
cp ./config/docker/* .
|
|
806
|
-
cp ./config/docker/.dockerignore .
|
|
807
|
-
```
|
|
808
|
-
|
|
809
|
-
**Dockerfile** <== Main dockerfile
|
|
810
|
-
**.dockerignore** <== Files to exclude from the build context
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
- Build docker images
|
|
814
|
-
|
|
815
|
-
`docker build --platform linux/amd64 --force-rm=true -t my-scimgateway:1.0.0 .`
|
|
816
|
-
|
|
817
|
-
- Create container
|
|
818
|
-
|
|
819
|
-
`docker create --init --ulimit memlock=-1:-1 --name my-scimgateway -p 8880:8880 my-scimgateway:1.0.0`
|
|
820
|
-
|
|
821
|
-
Note, consider using `-e SEED=<random-characters>` and plugin configuration file my-scimgateway.json must already be encrypted using same SEED environment
|
|
822
|
-
|
|
823
|
-
- Start container
|
|
824
|
-
|
|
825
|
-
`docker start my-scimgateway`
|
|
826
|
-
|
|
827
|
-
- Stop container
|
|
828
|
-
|
|
829
|
-
`docker stop my-scimgateway`
|
|
830
|
-
|
|
831
|
-
### Docker image using docker-compose
|
|
832
|
-
|
|
833
|
-
* Docker Pre-requisites:
|
|
834
|
-
**docker-ce
|
|
835
|
-
docker-compose**
|
|
836
|
-
|
|
837
|
-
- Install SCIM Gateway within your own package and copy provided docker files:
|
|
838
|
-
|
|
839
|
-
```
|
|
840
|
-
mkdir /opt/my-scimgateway
|
|
841
|
-
cd /opt/my-scimgateway
|
|
842
|
-
bun init -y
|
|
843
|
-
bun install scimgateway
|
|
844
|
-
bun pm trust scimgateway
|
|
845
|
-
cp ./config/docker/* .
|
|
846
|
-
```
|
|
847
|
-
|
|
848
|
-
**docker-compose.yml** <== Here is where you would set the exposed port and environment
|
|
849
|
-
**Dockerfile** <== Main dockerfile
|
|
850
|
-
**DataDockerfile** <== Handles volume mapping
|
|
851
|
-
**docker-compose-debug.yml** <== Debugging
|
|
852
|
-
**docker-compose-mssql.yml** <== Example including MSSQL docker image
|
|
853
|
-
**.dockerignore** <== Files to exclude from the build context
|
|
854
|
-
|
|
855
|
-
- Create a scimgateway user on your Linux VM.
|
|
856
|
-
|
|
857
|
-
`adduser scimgateway`
|
|
858
|
-
|
|
859
|
-
- Create a directory on your VM host for the scimgateway configs:
|
|
860
|
-
|
|
861
|
-
`mkdir /home/scimgateway/config`
|
|
862
|
-
|
|
863
|
-
- Copy your updated configuration file e.g. /opt/my-scimgateway/config/plugin-loki.json to /home/scimgateway/config. Use scp to perform the copy.
|
|
864
|
-
|
|
865
|
-
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.
|
|
866
|
-
|
|
867
|
-
- Build docker images and start it up
|
|
868
|
-
|
|
869
|
-
`docker-compose up --build -d`
|
|
870
|
-
|
|
871
|
-
NOTE: Add the -d flag to run the command above detached.
|
|
872
|
-
|
|
873
|
-
Be sure to confirm that port 8880 is available with a simple http request
|
|
874
|
-
|
|
875
|
-
If using default plugin-loki and we have configured `{"persistence": true}`, we could confirm scimgateway created loki.db:
|
|
876
|
-
|
|
877
|
-
```
|
|
878
|
-
su scimgateway
|
|
879
|
-
cd /home/scimgateway/config
|
|
880
|
-
ls loki.db
|
|
881
|
-
```
|
|
882
|
-
|
|
883
|
-
To list running containers information:
|
|
884
|
-
`docker ps`
|
|
885
|
-
|
|
886
|
-
To list available images:
|
|
887
|
-
`docker images`
|
|
888
|
-
|
|
889
|
-
To view the logs:
|
|
890
|
-
`docker logs scimgateway`
|
|
891
|
-
|
|
892
|
-
To execute command within your running container:
|
|
893
|
-
`docker exec scimgateway <bash command>`
|
|
894
|
-
|
|
895
|
-
To stop scimgateway:
|
|
896
|
-
`docker-compose stop`
|
|
897
|
-
|
|
898
|
-
To restart scimgateway:
|
|
899
|
-
`docker-compose start`
|
|
900
|
-
|
|
901
|
-
To debug running container (using Visual Studio Code):
|
|
902
|
-
`docker-compose -f docker-compose.yml -f docker-compose-debug.yml up -d`
|
|
903
|
-
Start Visual Studio Code and follow [these](https://code.visualstudio.com/docs/nodejs/nodejs-debugging) debugging instructions
|
|
904
|
-
|
|
905
|
-
To upgrade scimgateway docker image (remove the old stuff before running docker-compose up --build):
|
|
906
|
-
|
|
907
|
-
docker rm scimgateway
|
|
908
|
-
docker rm $(docker ps -a -q); docker rmi $(docker images -q -f "dangling=true")
|
|
909
|
-
|
|
910
|
-
## Entra ID as IdP using SCIM Gateway
|
|
911
|
-
|
|
912
|
-
Entra ID could do automatic user provisioning by synchronizing users towards SCIM Gateway, and gateway plugins will update endpoints.
|
|
913
|
-
|
|
914
|
-
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** (scimgateway.auth.bearerJwt[x].azureTenantId) or both:
|
|
915
|
-
|
|
916
|
-
scimgateway: {
|
|
917
|
-
"scim": {
|
|
918
|
-
"version": "2.0",
|
|
919
|
-
...
|
|
920
|
-
},
|
|
921
|
-
...
|
|
922
|
-
"auth": {
|
|
923
|
-
"bearerToken": [
|
|
924
|
-
{
|
|
925
|
-
"token": "shared-secret"
|
|
926
|
-
}
|
|
927
|
-
],
|
|
928
|
-
"bearerJwt": [
|
|
929
|
-
{
|
|
930
|
-
"azureTenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
|
931
|
-
}
|
|
932
|
-
]
|
|
933
|
-
}
|
|
934
|
-
...
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
`token` configuration must correspond with "Secret Token" defined in Entra ID
|
|
938
|
-
`azureTenantId` configuration must correspond with Entra ID Tenant ID
|
|
939
|
-
|
|
940
|
-
In Azure Portal:
|
|
941
|
-
`Azure-Microsoft Entra ID-Enterprise Application-<My Application>-Provisioning-Secret Token`
|
|
942
|
-
Note, when "Secret Token" is left blank, Azure will use JWT (azureTenantId)
|
|
943
|
-
|
|
944
|
-
`Azure-Microsoft Entra ID-Overview-Tenant ID`
|
|
945
|
-
|
|
946
|
-
User mappings attributes between AD and SCIM also needs to be configured
|
|
947
|
-
|
|
948
|
-
`Azure-Microsoft Entra ID-Enterprise Application-<My Application>-Provisioning-Edit attribute mappings-Mappings`
|
|
949
|
-
|
|
950
|
-
Entra ID default SCIM attribute mapping for **USER** must have:
|
|
951
|
-
|
|
952
|
-
userPrincipalName mapped to userName (matching precedence #1)
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
Entra ID default SCIM attribute mapping for **GROUP** must have:
|
|
956
|
-
|
|
957
|
-
displayName mapped to displayName (matching precedence #1)
|
|
958
|
-
members mapped to members
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
Some notes related to Entra ID:
|
|
963
|
-
|
|
964
|
-
- Entra ID SCIM [documentation](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/use-scim-to-provision-users-and-groups)
|
|
965
|
-
|
|
966
|
-
- For using OAuth/JWT credentials, Entra ID configuration "Secret Token" (bearer token) should be blank. Plugin configuration must then include bearerJwt.azureTenantId. Click "Test Connection" in Azure to verify
|
|
967
|
-
|
|
968
|
-
- Entra ID do a regular check for a "non" existing user/group. This check seems to be a "keep alive" to verify connection.
|
|
969
|
-
|
|
970
|
-
- Entra ID first checks if user/group exists, if not exist they will be created (no explore of all users like CA Identity Manager)
|
|
971
|
-
|
|
972
|
-
- 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.
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
## Symantec Identity Manager as IdP using SCIM Gateway
|
|
976
|
-
|
|
977
|
-
Using Symantec/Broadcom Identity Manger, plugin configuration must use **SCIM Version "1.1"** (scimgateway.scim.version).
|
|
978
|
-
|
|
979
|
-
In the Provisioning Manager we could use `Endpoint type = SCIM (DYN Endpoint)` or create our own custom endpoint type based on this one
|
|
980
|
-
|
|
981
|
-
SCIM endpoint configuration example for Loki plugin (plugin-loki)
|
|
982
|
-
|
|
983
|
-
Endpoint Name = Loki-8880
|
|
984
|
-
User Name = gwadmin
|
|
985
|
-
Password = password
|
|
986
|
-
SCIM Authentication Method = HTTP Basic Authentication
|
|
987
|
-
SCIM Based URL = http://localhost:8880
|
|
988
|
-
|
|
989
|
-
or:
|
|
990
|
-
|
|
991
|
-
SCIM Based URL = http://localhost:8880/<baseEntity>
|
|
992
|
-
|
|
993
|
-
Username, password and port must correspond with plugin configuration file. For "Loki" plugin it will be `config\plugin-loki.json`
|
|
994
|
-
|
|
995
|
-
"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.
|
|
996
|
-
|
|
997
|
-
"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:
|
|
998
|
-
|
|
999
|
-
http://localhost:8880/client-a
|
|
1000
|
-
http://localhost:8880/client-b
|
|
1001
|
-
|
|
1002
|
-
Each baseEntity should then be defined in the plugin configuration file with custom attributes needed. Please see examples in plugin-soap.json
|
|
1003
|
-
|
|
1004
|
-
## Entra ID provisioning
|
|
1005
|
-
Using plugin-entra-id we could do user provisioning towards Entra ID
|
|
1006
|
-
|
|
1007
|
-
For testing purposes we could get an Azure free account
|
|
1008
|
-
|
|
1009
|
-
### Entra ID configuration
|
|
1010
|
-
|
|
1011
|
-
- Logon to [Azure](https://portal.azure.com) as global administrator
|
|
1012
|
-
- Microsoft Entra ID - App registrations
|
|
1013
|
-
- Click "New registration"
|
|
1014
|
-
- Name = SCIM Gateway Inbound
|
|
1015
|
-
- Select: Accounts in this organizational directory only
|
|
1016
|
-
- Click "Register"
|
|
1017
|
-
- Overview:
|
|
1018
|
-
- Copy "Application (client) ID"
|
|
1019
|
-
- Copy "Directory (tentant) ID"
|
|
1020
|
-
- Certificates & secrets:
|
|
1021
|
-
- Click "New client secret"
|
|
1022
|
-
- Description = SCIM Gateway Inbound secret#1
|
|
1023
|
-
- Select an appropriate "Expires"
|
|
1024
|
-
- Click "Add"
|
|
1025
|
-
- Copy "Value" of the new secret that was created
|
|
1026
|
-
- API permissions: - Add a permission - Microsoft Graph - Application permissions
|
|
1027
|
-
- Optionally remove any defaults included e.g. User.Read
|
|
1028
|
-
- Click "Add a permission"
|
|
1029
|
-
- Microsoft Graph
|
|
1030
|
-
- Application permissions
|
|
1031
|
-
- Directory - Directory.ReadWriteAll
|
|
1032
|
-
- Organization - Organization.ReadWrite.All
|
|
1033
|
-
- AuditLog - AuditLog.Read.All (required if using plugin configuration `map.user.signInActivity`)
|
|
1034
|
-
- RoleEligibilitySchedule - RoleEligibilitySchedule.Read.Directory (PIM Eligible roles; required if using plugin configuration `map.user.roles`)
|
|
1035
|
-
- RoleManagement - RoleManagement.ReadWrite.Directory' (PIM Permanent roles; required if using plugin configuration `map.user.roles`)
|
|
1036
|
-
- Click "Add permissions"
|
|
1037
|
-
- API permissions: - Grant Admin consent
|
|
1038
|
-
Or we could go to Enterprise application to grant these consents:
|
|
1039
|
-
- Microsoft Entra ID - Enterprise applications - SCIM Gateway Inbound
|
|
1040
|
-
- Permissions:
|
|
1041
|
-
- Click "Grant admin consent for [tenant name]"
|
|
1042
|
-
- In the logon dialog, logon as global administrator
|
|
1043
|
-
- In permissions request dialog, click "Accept"
|
|
1044
|
-
- Click "Refresh", directory and organization permissions are now listed and OK
|
|
1045
|
-
|
|
1046
|
-
- Microsoft Entra ID - Manage - Roles and administrators
|
|
1047
|
-
- Search: User administrator
|
|
1048
|
-
- Click on role **User administrator**
|
|
1049
|
-
- Click "Add assignments"
|
|
1050
|
-
- Click "No member selected" to add members
|
|
1051
|
-
- Search: SCIM Gateway Inbound (name of the application we have created)
|
|
1052
|
-
- Select the application name that shows up and click "Add"
|
|
1053
|
-
- Click Next
|
|
1054
|
-
- Assignment type=Active and enable "Permanent assigned", add some justification text and click "Assign"
|
|
1055
|
-
|
|
1056
|
-
Note: Entra ID has a role hierarchy, and running SCIM Gateway as a `User Administrator` has some limitations when administering users who have administrative roles. For full administrative access to all users, SCIM Gateway must have the `Global Administrator` role (`62e90394-69f5-4237-9190-012177145e10`).
|
|
1057
|
-
|
|
1058
|
-
### SCIM Gateway configuration
|
|
1059
|
-
|
|
1060
|
-
**Edit index.ts**
|
|
1061
|
-
Set plugin to be started to `entra-id`
|
|
1062
|
-
|
|
1063
|
-
const plugins = ['entra-id']
|
|
1064
|
-
|
|
1065
|
-
**Edit plugin-entra-id.json**
|
|
1066
|
-
|
|
1067
|
-
Note, for Symantec/Broadcom Provisioning we must use SCIM version 1.1
|
|
1068
|
-
|
|
1069
|
-
scimgateway: {
|
|
1070
|
-
"scim": {
|
|
1071
|
-
"version": "1.1"
|
|
1072
|
-
},
|
|
1073
|
-
|
|
1074
|
-
`username` and `password` used to connect the SCIM Gateway must be defined.
|
|
1075
|
-
|
|
1076
|
-
"auth": {
|
|
1077
|
-
"basic": [
|
|
1078
|
-
{
|
|
1079
|
-
"username": "gwadmin",
|
|
1080
|
-
"password": "password",
|
|
1081
|
-
"readOnly": false,
|
|
1082
|
-
"baseEntities": []
|
|
1083
|
-
}
|
|
1084
|
-
],
|
|
1085
|
-
|
|
1086
|
-
Update `azureTenantId`, `clientID` and `clientSecret` according to what you copied from the previous Entra ID configuration.
|
|
1087
|
-
|
|
1088
|
-
If using proxy, set proxy.host to `"http://<FQDN-ProxyHost>:<port>"` e.g `"http://proxy.mycompany.com:3128"`
|
|
1089
|
-
|
|
1090
|
-
"endpoint": {
|
|
1091
|
-
"entity": {
|
|
1092
|
-
"undefined": {
|
|
1093
|
-
"connection": {
|
|
1094
|
-
"baseUrls": [
|
|
1095
|
-
"not in use for Entra ID when azureTenantId is defined"
|
|
1096
|
-
],
|
|
1097
|
-
"auth": {
|
|
1098
|
-
"type": "oauth",
|
|
1099
|
-
"options": {
|
|
1100
|
-
"tokenUrl": "oauth token_url - not in use when azureTenantId is defined",
|
|
1101
|
-
"azureTenantId": "Entra ID Tenant ID (GUID) or Primary domain name - only used by plugin-entra-id",
|
|
1102
|
-
"clientId": "oauth client_id - Entra ID: Application ID",
|
|
1103
|
-
"clientSecret": "oauth client_secret - Entra ID: generated application secret value"
|
|
1104
|
-
}
|
|
1105
|
-
},
|
|
1106
|
-
"proxy": {
|
|
1107
|
-
"host": null,
|
|
1108
|
-
"username": null,
|
|
1109
|
-
"password": null
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
|
-
},
|
|
1114
|
-
"map": {
|
|
1115
|
-
...
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
|
-
Note, clientSecret and any proxy.password will become encrypted in this file on the first Azure connection.
|
|
1120
|
-
|
|
1121
|
-
For multi-tenant or multi-endpoint support, we may add several entities:
|
|
1122
|
-
|
|
1123
|
-
"endpoint": {
|
|
1124
|
-
"entity": {
|
|
1125
|
-
"undefined": {
|
|
1126
|
-
...
|
|
1127
|
-
},
|
|
1128
|
-
"client-a": {
|
|
1129
|
-
...
|
|
1130
|
-
},
|
|
1131
|
-
"client-b": {
|
|
1132
|
-
...
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
}
|
|
1136
|
-
|
|
1137
|
-
For additional details, see baseEntity description.
|
|
1138
|
-
|
|
1139
|
-
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}
|
|
1140
|
-
|
|
1141
|
-
### Using Symantec/Broadcom Provisioning
|
|
1142
|
-
Create a new endpoint type "Azure - ScimGateway"
|
|
1143
|
-
|
|
1144
|
-
- Start SCIM Gateway
|
|
1145
|
-
- Using plugin-entra-id: `const plugins = ['entra-id']` in `index.ts`
|
|
1146
|
-
- username, password and port defined in `plugin-entra-id.json` must also be known
|
|
1147
|
-
- Start ConnectorXpress
|
|
1148
|
-
- Setup Data Sources
|
|
1149
|
-
- Add
|
|
1150
|
-
- Layer7 (this is SCIM)
|
|
1151
|
-
- Name = SCIM Gateway-8881
|
|
1152
|
-
- Base URL = http://localhost:8881 (SCIM Gateway installed locally on Connector Server)
|
|
1153
|
-
- Add the new "Azure - ScimGateway" endpoint type
|
|
1154
|
-
- Metadata - Import - "my-scimgateway\node_modules\scimgateway\config\resources\Azure - ScimGateway.xml"
|
|
1155
|
-
- Select the datasource we created - SCIM Gateway-8881
|
|
1156
|
-
- Enter password for the user defined in datasource (e.g. gwadmin/password)
|
|
1157
|
-
- On the right - expand Provisioning Servers - your server - and logon
|
|
1158
|
-
- Right Click "Endpoint Types", Create New Endpoint Type
|
|
1159
|
-
- You may use default name "Azure - ScimGateway" and click "OK" to create endpoint
|
|
1160
|
-
|
|
1161
|
-
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.
|
|
1162
|
-
|
|
1163
|
-
**Provisioning Manager configuration**
|
|
1164
|
-
|
|
1165
|
-
`Endpoint type = Azure - ScimGateway (DYN Endpoint)`
|
|
1166
|
-
|
|
1167
|
-
Endpoint configuration example:
|
|
1168
|
-
|
|
1169
|
-
Endpoint Name = AzureAD-8881
|
|
1170
|
-
User Name = gwadmin
|
|
1171
|
-
Password = password
|
|
1172
|
-
SCIM Authentication Method = HTTP Basic Authentication
|
|
1173
|
-
SCIM Based URL = http://localhost:8881
|
|
1174
|
-
or
|
|
1175
|
-
SCIM Based URL = http://localhost:8881/<baseEntity>
|
|
1176
|
-
|
|
1177
|
-
For details, please see section "CA Identity Manager as IdP using SCIM Gateway"
|
|
1178
|
-
|
|
1179
|
-
## API Gateway
|
|
1180
|
-
|
|
1181
|
-
SCIM Gateway also works as an API Gateway when using url `/api` or `/<baseEntity>/api`
|
|
1182
|
-
|
|
1183
|
-
Following methods for the none SCIM based api-plugin are supported:
|
|
1184
|
-
|
|
1185
|
-
GET /api
|
|
1186
|
-
GET /api?queries
|
|
1187
|
-
GET /api/{id}
|
|
1188
|
-
POST /api + body
|
|
1189
|
-
PUT /api/{id} + body
|
|
1190
|
-
PATCH /api/{id} + body
|
|
1191
|
-
DELETE /api/{id}
|
|
1192
|
-
|
|
1193
|
-
These methods can also be included in standard SCIM plugins
|
|
1194
|
-
Please see example plugin: **plugin-api.ts**
|
|
1195
|
-
|
|
1196
|
-
## How to build your own plugins
|
|
1197
|
-
For coding editor you may use [Visual Studio Code](https://code.visualstudio.com/ "Visual Studio Code")
|
|
1198
|
-
|
|
1199
|
-
Preparation:
|
|
1200
|
-
|
|
1201
|
-
* Copy "best matching" example plugin e.g. `lib\plugin-mssql.ts` and `config\plugin-mssql.json` and rename both copies to your plugin name prefix e.g. plugin-mine.ts and plugin-mine.json
|
|
1202
|
-
* Edit plugin-mine.json and define a unique port number for the gateway setting
|
|
1203
|
-
* Edit index.ts and include your plugin in the startup e.g. `import './lib/plugin-mine.ts'`
|
|
1204
|
-
* Start SCIM Gateway and verify
|
|
1205
|
-
|
|
1206
|
-
We are now ready for custom coding by editing plugin-mine.ts
|
|
1207
|
-
Coding should be done step by step and each step should be verified and tested before starting the next
|
|
1208
|
-
|
|
1209
|
-
1. **Turn off group functionality** - getGroups to return empty response (gateway automatically use getGroups for some of the methods if groups not included)
|
|
1210
|
-
Please see plugin-saphana that do not use groups.
|
|
1211
|
-
2. **getUsers** (test provisioning retrieve all accounts and single account)
|
|
1212
|
-
3. **createUser** (test provisioning new account)
|
|
1213
|
-
4. **deleteUser** (test provisioning delete account)
|
|
1214
|
-
5. **modifyUser** (test provisioning modify account)
|
|
1215
|
-
6. **Turn on group functionality** - getGroups having logic for returning groups if groups are supported
|
|
1216
|
-
7. **getGroups** (test provisioning retrieve groups)
|
|
1217
|
-
8. **modifyGroup** (test provisioning modify group members)
|
|
1218
|
-
9. **createGroup** (test provisioning new group)
|
|
1219
|
-
10. **deleteGroup** (test provisioning delete account)
|
|
1220
|
-
|
|
1221
|
-
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)
|
|
1222
|
-
|
|
1223
|
-
CA Provisioning using default SCIM endpoint do not support SCIM Enterprise User Schema Extension (having attributes like employeeNumber, costCenter, organization, division, department and manager). If we need these or other attributes not found in CA Provisioning, we could define our own by using the free-text "type" definition in the multivalue entitlements or roles attribute. In the template entitlements definition, we could for example define type=Company and set value to %UCOMP%. Please see plugin-soap.ts using Company as a multivalue "type" definition.
|
|
1224
|
-
|
|
1225
|
-
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".
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
For project setup:
|
|
1229
|
-
|
|
1230
|
-
* Datasource = Layer7 (CA API) - this is SCIM
|
|
1231
|
-
* Layer7 Base URL = SCIM Gateway url and port (SCIM Base URL)
|
|
1232
|
-
* Authentication = Basic Authentication
|
|
1233
|
-
(connect using gwadmin/password defined in plugin config-file)
|
|
1234
|
-
|
|
1235
|
-
### How to change "user member of groups" to "group member of users"
|
|
1236
|
-
|
|
1237
|
-
Using Connector Xpress based on the original SCIM endpoint.
|
|
1238
|
-
|
|
1239
|
-
Delete defaults:
|
|
1240
|
-
Group - Associations - with User Account
|
|
1241
|
-
Group - Attributes - members
|
|
1242
|
-
User Account - Attributes - Group Membership
|
|
1243
|
-
|
|
1244
|
-
Create new attribute:
|
|
1245
|
-
User Account - Attributes: Groups - Flexi DN - Multivalue - **groups**
|
|
1246
|
-
|
|
1247
|
-
Create User - Group associations:
|
|
1248
|
-
User Account - Accociations - **Direct association with = Group**
|
|
1249
|
-
User Account - Accociations - with Group
|
|
1250
|
-
|
|
1251
|
-
Note, "Include a Reverse Association" - not needed if we don't need Group object functionality e.g list/add/remove group members
|
|
1252
|
-
|
|
1253
|
-
User Attribute = **Physical Attribute = Groups**
|
|
1254
|
-
Match Group = By Attribute = ID
|
|
1255
|
-
|
|
1256
|
-
Objects Must Exist
|
|
1257
|
-
Use DNs in Attribute = activated (toggled on)
|
|
1258
|
-
|
|
1259
|
-
Include a Reverse Association (if needed)
|
|
1260
|
-
Group Attribute = **Virtual Attribute = User Membership**
|
|
1261
|
-
Match User Account = By Attribute = User Name
|
|
1262
|
-
|
|
1263
|
-
Note, groups should be capability attribute (updated when account is synchronized with template):
|
|
1264
|
-
advanced options - **Synchronized** = enabled (toggled on)
|
|
1265
|
-
|
|
1266
|
-
## Methods
|
|
1267
|
-
|
|
1268
|
-
Plugins should have following initialization:
|
|
141
|
+
---
|
|
1269
142
|
|
|
1270
|
-
|
|
1271
|
-
import { ScimGateway, HelperRest } from 'scimgateway'
|
|
1272
|
-
const scimgateway = new ScimGateway()
|
|
1273
|
-
const helper = new HelperRest(scimgateway)
|
|
1274
|
-
const config = scimgateway.getConfig()
|
|
1275
|
-
scimgateway.authPassThroughAllowed = false
|
|
1276
|
-
// end - mandatory plugin initialization
|
|
143
|
+
## Installation
|
|
1277
144
|
|
|
1278
|
-
|
|
145
|
+
### Prerequisites
|
|
1279
146
|
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
* scimgateway.getUsers()
|
|
1283
|
-
* scimgateway.createUser()
|
|
1284
|
-
* scimgateway.deleteUser()
|
|
1285
|
-
* scimgateway.modifyUser()
|
|
1286
|
-
* scimgateway.getGroups()
|
|
1287
|
-
* scimgateway.createGroup()
|
|
1288
|
-
* scimgateway.deleteGroup()
|
|
1289
|
-
* scimgateway.modifyGroup()
|
|
1290
|
-
|
|
1291
|
-
In addition following general API methods are available for use:
|
|
1292
|
-
|
|
1293
|
-
* scimgateway.postApi()
|
|
1294
|
-
* scimgateway.putApi()
|
|
1295
|
-
* scimgateway.patchApi()
|
|
1296
|
-
* scimgateway.getApi()
|
|
1297
|
-
* scimgateway.deleteApi()
|
|
1298
|
-
* scimgateway.publicApi()
|
|
1299
|
-
|
|
1300
|
-
In code editor (e.g., Visual Studio Code), method details and documentation are shown by IntelliSense
|
|
1301
|
-
|
|
1302
|
-
## License
|
|
1303
|
-
|
|
1304
|
-
MIT © [Jarle Elshaug](https://www.elshaug.xyz)
|
|
1305
|
-
|
|
1306
|
-
## Change log
|
|
1307
|
-
|
|
1308
|
-
### v6.2.0
|
|
1309
|
-
|
|
1310
|
-
[Fixed]
|
|
1311
|
-
|
|
1312
|
-
- `helper-rest` failed on Bun v1.3.14 due to stricter compliance with Fetch standards.
|
|
1313
|
-
|
|
1314
|
-
[Improved]
|
|
1315
|
-
|
|
1316
|
-
- New `plugin-generic` replacing previous `plugin-scim`. This new plugin use the endpointMapper for flexible attribute mapping and also supports the new mapper option `valueMap` (e.g., group filtering and mapping). The default configuration uses one-to-one SCIM mapping, with plugin-loki as the target SCIM endpoint.
|
|
1317
|
-
- endpointMapper now supports the 'valueMap' option
|
|
1318
|
-
|
|
1319
|
-
Example configuration:
|
|
1320
|
-
|
|
1321
|
-
"map": {
|
|
1322
|
-
"group": {
|
|
1323
|
-
...
|
|
1324
|
-
"displayName": {
|
|
1325
|
-
"mapTo": "displayName",
|
|
1326
|
-
"type": "string",
|
|
1327
|
-
"valueMap": {
|
|
1328
|
-
"outboundEndpointGrp1": "inboundScimGrp1",
|
|
1329
|
-
"Employees": "Admins"
|
|
1330
|
-
}
|
|
1331
|
-
},
|
|
1332
|
-
...
|
|
1333
|
-
}
|
|
1334
|
-
...
|
|
1335
|
-
}
|
|
1336
|
-
|
|
1337
|
-
Using the above settings restricts the client using SCIM Gateway with regard to group management.
|
|
1338
|
-
The client will only see and be able to manage groups with SCIM names "inboundScimGrp1" and "Admins",
|
|
1339
|
-
if their mapped counterparts exist at the target endpoint as "outboundEndpointGrp1" and "Employees".
|
|
1340
|
-
|
|
1341
|
-
Use case:
|
|
1342
|
-
|
|
1343
|
-
- Allowlisting specific groups or user objects that includes attribute mapping having the valueMap option configured.
|
|
1344
|
-
- Supporting different inbound/outbound names (e.g., Entra ID group provisioning to SCIM Gateway).
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
### v6.1.20
|
|
1348
|
-
|
|
1349
|
-
[Fixed]
|
|
1350
|
-
|
|
1351
|
-
- plugin-entra-id: Roles introduced in v6.1.19 were missing when retrieving a single user.
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
### v6.1.19
|
|
1355
|
-
|
|
1356
|
-
[Fixed]
|
|
1357
|
-
|
|
1358
|
-
- SCIM v2.0 ResourceType endpoint schemas using incorrect id.
|
|
1359
|
-
|
|
1360
|
-
[Improved]
|
|
1361
|
-
|
|
1362
|
-
- SCIM Gateway now supports `GET /Roles` and `GET /Entitlements` endpoint requests, with corresponding user management via the standard SCIM `roles` and `entitlements` attributes.
|
|
1363
|
-
- plugin-entra-id: Uses `entitlements` for Entra ID licenses (read-only) and `roles` for Entra ID Permanent and Eligible roles (full management).
|
|
1364
|
-
- PIM Eligible roles requires API permissions `RoleEligiblitySchedule.ReadWrite.All`
|
|
1365
|
-
- PIM Permanent roles requires API permissions `RoleManagement.ReadWrite.Directory`
|
|
1366
|
-
- Remove mapping configuration `map.user.roles` if conditions not met (or use only the Eligible permissions set to Read if user role management is not needed).
|
|
1367
|
-
- The `skipSignInActivity` option, introduced in v6.1.17, is no longer used. Instead, permissions for both `signInActivity` and PIM roles are validated at startup.
|
|
1368
|
-
|
|
1369
|
-
### v6.1.18
|
|
1370
|
-
|
|
1371
|
-
[Fixed]
|
|
1372
|
-
|
|
1373
|
-
- createUser and modifyUser returns full user object. Some endpoints like Entra ID hasn’t caught up yet due to internal sync and changes are not reflected. This update ensure returned user object contains what have been modified.
|
|
1374
|
-
|
|
1375
|
-
### v6.1.17
|
|
1376
|
-
|
|
1377
|
-
[Fixed]
|
|
1378
|
-
|
|
1379
|
-
- plugin-entra-id:
|
|
1380
|
-
|
|
1381
|
-
- Fixed an issue where `filter=userName eq "user_upn"` was broken in v6.1.11 when using the updated configuration file that includes `map.user.signInActivity`.
|
|
1382
|
-
- Added new configuration option `endpoint.entity.[baseEntity].skipSignInActivity = true` to exclude the `signInActivity` attribute. This attribute requires a Microsoft Entra ID Premium license and the `AuditLog.Read.All` API permission.
|
|
1383
|
-
|
|
1384
|
-
### v6.1.16
|
|
1385
|
-
|
|
1386
|
-
[Improved]
|
|
1387
|
-
|
|
1388
|
-
- plugin-entra-id: `GET /Entitlements` using derivedIncludes, fully flattened (recursive expansion of previous includes).
|
|
1389
|
-
|
|
1390
|
-
### v6.1.15
|
|
1391
|
-
|
|
1392
|
-
[Fixed]
|
|
1393
|
-
|
|
1394
|
-
- plugin-entra-id: fixed `filter=entitlements pr`
|
|
1395
|
-
|
|
1396
|
-
### v6.1.14
|
|
1397
|
-
|
|
1398
|
-
[Improved]
|
|
1399
|
-
|
|
1400
|
-
- Some cosmetics like supporting filter `attribute not pr`
|
|
1401
|
-
- Dependencies bump
|
|
1402
|
-
|
|
1403
|
-
### v6.1.13
|
|
1404
|
-
|
|
1405
|
-
[Improved]
|
|
1406
|
-
|
|
1407
|
-
- plugin-entra-id: `signInActivity` attributes are filterable
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
### v6.1.12
|
|
1411
|
-
|
|
1412
|
-
[Improved]
|
|
1413
|
-
|
|
1414
|
-
- filter operator `pr` (precense) now sent to plugin (previoulsy rejected)
|
|
1415
|
-
- plugin-entra-id: now handles the pr filter operator for entitlements
|
|
1416
|
-
|
|
1417
|
-
### v6.1.11
|
|
1418
|
-
|
|
1419
|
-
[Fixed]
|
|
1420
|
-
|
|
1421
|
-
- From v6.1.6, schemas are autogenerated when using `endpointMapper` (configuration `map.user` and `map.group`). Fixed incorrect schema generation logic.
|
|
1422
|
-
|
|
1423
|
-
[Improved]
|
|
1424
|
-
|
|
1425
|
-
- New endpoint `GET /Entitlements` and corresponding new plugin method `scimgateway.getEntitlements()`, which is currently used by plugin-entra-id.
|
|
1426
|
-
- plugin-entra-id: User license information through entitlements attribute.
|
|
1427
|
-
- plugin-entra-id: The `plugin-entra-id.json` configuration file includes `map.user.signInActivity`. Using the `signInActivity` attribute requires an Entra ID Premium license and the API permission `AuditLog.Read.All`.
|
|
1428
|
-
**Remove this mapping configuration if these conditions are not met**, otherwise provisioning will fail and errors such as `Authentication_RequestFromNonPremiumTenantOrB2CTenant` may occur.
|
|
1429
|
-
|
|
1430
|
-
### v6.1.10
|
|
1431
|
-
|
|
1432
|
-
[Fixed]
|
|
1433
|
-
|
|
1434
|
-
- plugin-entra-id: user group membership now includes nested (transitive) groups (`direct` and `indirect`)
|
|
1435
|
-
- Docker example files `config/docker/.dockerignore` and `docker-compose-mssql.yml` were missing
|
|
1436
|
-
|
|
1437
|
-
### v6.1.9
|
|
1438
|
-
|
|
1439
|
-
[Improved]
|
|
1440
|
-
|
|
1441
|
-
- Some improvements to createUser/createGroup regarding the response object, which should contain the newly generated ID
|
|
1442
|
-
|
|
1443
|
-
### v6.1.8
|
|
1444
|
-
|
|
1445
|
-
[Fixed]
|
|
1446
|
-
|
|
1447
|
-
- Incorrect masking of secrets in the final info log message for requests
|
|
1448
|
-
|
|
1449
|
-
### v6.1.7
|
|
1450
|
-
|
|
1451
|
-
[Fixed]
|
|
1452
|
-
|
|
1453
|
-
- Incorrect masking of secrets in the final info log message for requests
|
|
1454
|
-
- plugin-entra, fixed an issue where creating a user with a manager sometimes failed
|
|
1455
|
-
|
|
1456
|
-
### v6.1.6
|
|
1457
|
-
|
|
1458
|
-
[Fixed]
|
|
1459
|
-
|
|
1460
|
-
- plugin-loki and plugin-mongodb, using extension schema attributes in search returned empty result
|
|
1461
|
-
- Auth validation failure because of readOnly protection now returns 405 instead of 401
|
|
1462
|
-
- The post-install step now verifies and updates `package.json` to ensure the mandatory `"type": "module"` setting is applied. Using `npm init -y` instead of the recommended `bun init -y` sets `"type": "commonjs"` by default, which is incorrect.
|
|
1463
|
-
|
|
1464
|
-
[Improved]
|
|
1465
|
-
|
|
1466
|
-
- Using the endpointMapper configuration (`endpoint.map.user` / `endpoint.map.group`) will now generate a custom schema instead of using the default SCIM schema by `GET /Schemas`. In addition the configuration `endpoint.map` now supports a special `"x-agent-schema": {...}` configuration which is used by the schema generator for updating `description` and including AI MCP tools related instructions. See `plugin-entra-id.json` for examples.
|
|
1467
|
-
- Dependencies bump
|
|
1468
|
-
|
|
1469
|
-
### v6.1.5
|
|
1470
|
-
|
|
1471
|
-
[Improved]
|
|
1472
|
-
|
|
1473
|
-
- complex filtering (and/or) now handled by scimgateway using plugin's simple filtering logic
|
|
1474
|
-
- modify group response now returns http status 204 (No Content) instead of 200 OK (full group object)
|
|
1475
|
-
- url `/auth` can now be used for validating external authentication
|
|
1476
|
-
- plugin-entra-id, now supports filter `sw` (startsWith)
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
### v6.1.4
|
|
1480
|
-
|
|
1481
|
-
[Fixed]
|
|
1482
|
-
|
|
1483
|
-
- plugin-entra-id, OData paging was not working, so some users/groups/members might be missing
|
|
1484
|
-
- helper-rest, OData paging
|
|
1485
|
-
- user’s group membership did not iterate through paging and may be incomplete
|
|
1486
|
-
|
|
1487
|
-
### v6.1.3
|
|
1488
|
-
|
|
1489
|
-
[Fixed]
|
|
1490
|
-
|
|
1491
|
-
- azure relay, recover on failure
|
|
1492
|
-
- plugin-ldap, some improvements for Active Directory and the use of objectGUID/mS-DS-ConsistencyGuid
|
|
1493
|
-
- plugin-mongodb, group meta.version not standarized
|
|
1494
|
-
- when modifying group members, if an error occurs, the gateway now checks whether it was caused by adding an existing member or removing a non-existing member. In such cases, it returns 200 OK instead of an error.
|
|
1495
|
-
|
|
1496
|
-
[Improved]
|
|
1497
|
-
- Dependencies bump
|
|
1498
|
-
|
|
1499
|
-
### v6.1.2
|
|
1500
|
-
|
|
1501
|
-
[Fixed]
|
|
1502
|
-
|
|
1503
|
-
- SMTP mail functionality failed because of an updated dependency
|
|
1504
|
-
- endpointMapper failed when `mapTo` included multiple comma-separated attributes and one of them was a multivalued attribute, e.g. `{ "mail": { "mapTo": "userName,emails.work.value" } }`
|
|
1505
|
-
|
|
1506
|
-
### v6.1.1
|
|
1507
|
-
|
|
1508
|
-
[Fixed]
|
|
1509
|
-
|
|
1510
|
-
- plugin-ldap, a createUser operation followed immediately by a readUser (automatically performed by SCIM Gateway) may not find the newly created user on some systems, such as Samba AD, due to timing issues
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
[Improved]
|
|
1514
|
-
|
|
1515
|
-
- the final info log message now includes a JSON serialization of all elements, such as durationMs, status, requestBody, responseBody, ...
|
|
1516
|
-
|
|
1517
|
-
### v6.1.0
|
|
1518
|
-
|
|
1519
|
-
[Improved]
|
|
1520
|
-
|
|
1521
|
-
- `tsx` is now included, allowing SCIM Gateway to run as an ES module (TypeScript) in Node.js. The mandatory plugin section, which previously required complex dynamic loading, can now be simplified using static imports
|
|
1522
|
-
|
|
1523
|
-
**Old plugin-xxx.ts:**
|
|
1524
|
-
|
|
1525
|
-
// start - mandatory plugin initialization
|
|
1526
|
-
const ScimGateway: typeof import('scimgateway').ScimGateway = await (async () => {
|
|
1527
|
-
try {
|
|
1528
|
-
return (await import('scimgateway')).ScimGateway
|
|
1529
|
-
} catch (err) {
|
|
1530
|
-
const source = './scimgateway.ts'
|
|
1531
|
-
return (await import(source)).ScimGateway
|
|
1532
|
-
}
|
|
1533
|
-
})()
|
|
1534
|
-
const scimgateway = new ScimGateway()
|
|
1535
|
-
const config = scimgateway.getConfig()
|
|
1536
|
-
scimgateway.authPassThroughAllowed = false
|
|
1537
|
-
// end - mandatory plugin initialization
|
|
1538
|
-
|
|
1539
|
-
**New plugin-xxx.ts:**
|
|
1540
|
-
|
|
1541
|
-
// start - mandatory plugin initialization
|
|
1542
|
-
import { ScimGateway } from 'scimgateway'
|
|
1543
|
-
const scimgateway = new ScimGateway()
|
|
1544
|
-
const config = scimgateway.getConfig()
|
|
1545
|
-
scimgateway.authPassThroughAllowed = false
|
|
1546
|
-
// end - mandatory plugin initialization
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
**Old Node.js startup:**
|
|
1550
|
-
|
|
1551
|
-
node --experimental-strip-types c:\scimgateway\index.ts // scimgateway downloaded from github
|
|
1552
|
-
|
|
1553
|
-
**New Node.js startup:**
|
|
1554
|
-
|
|
1555
|
-
node --import=tsx ./index.ts // running in local package
|
|
1556
|
-
|
|
1557
|
-
- index.ts now using static import instead of dynamic
|
|
1558
|
-
|
|
1559
|
-
**Old index.ts:**
|
|
1560
|
-
|
|
1561
|
-
const plugins = ['loki']
|
|
1562
|
-
for (const plugin of plugins) {
|
|
1563
|
-
try {
|
|
1564
|
-
await import(`./lib/plugin-${plugin}.ts`)
|
|
1565
|
-
} catch (err: any) {
|
|
1566
|
-
console.error(err)
|
|
1567
|
-
}
|
|
1568
|
-
}
|
|
1569
|
-
|
|
1570
|
-
**New index.ts:**
|
|
1571
|
-
|
|
1572
|
-
// start one or more plugins:
|
|
1573
|
-
// import './lib/plugin-scim.ts'
|
|
1574
|
-
// import './lib/plugin-entra-id.ts'
|
|
1575
|
-
// import './lib/plugin-ldap.ts'
|
|
1576
|
-
// import './lib/plugin-mongodb.ts'
|
|
1577
|
-
// import './lib/plugin-api.ts'
|
|
1578
|
-
// import './lib/plugin-mssql.ts'
|
|
1579
|
-
// import './lib/plugin-saphana.ts'
|
|
1580
|
-
// import './lib/plugin-soap.ts'
|
|
1581
|
-
|
|
1582
|
-
import './lib/plugin-loki.ts'
|
|
1583
|
-
export {}
|
|
1584
|
-
|
|
1585
|
-
- Bun binary build is now supported allowing SCIM Gateway to be compiled into a single executable binary for simplified deployment and execution. The binary must have the same name (prefix) as the configuration file in the config directory, and this directory must be located in the same folder as the binary.
|
|
1586
|
-
|
|
1587
|
-
cd my-scimgateway
|
|
1588
|
-
bun build --compile ./lib/plugin-loki.ts --target=bun-darwin-arm64 --outfile ./build/plugin-loki
|
|
1589
|
-
# for target options, see: https://bun.com/docs/bundler/executables#cross-compile-to-other-platforms
|
|
1590
|
-
|
|
1591
|
-
cp -r ./config ./build
|
|
1592
|
-
# build directory now ready for production deployment
|
|
1593
|
-
cd build
|
|
1594
|
-
# run the binary - note, binary must have same name (prefix) as the configuration file in the config directory
|
|
1595
|
-
./plugin-loki
|
|
1596
|
-
|
|
1597
|
-
- Dependencies bump
|
|
1598
|
-
|
|
1599
|
-
### v6.0.2
|
|
1600
|
-
|
|
1601
|
-
[Fixed]
|
|
1602
|
-
- Gateway now passing provided filter attributes for getUsers()/getGroups to plugin instead of using empty array for having all supported attributes returned
|
|
1603
|
-
|
|
1604
|
-
### v6.0.1
|
|
1605
|
-
|
|
1606
|
-
[Fixed]
|
|
1607
|
-
- plugin-ldap, failed when the RDN value contained the character '=' e.g., `CN=Firstname \= Lastname,CN=Users,DC=my-company,DC=com`
|
|
1608
|
-
- GET using filter failed when filter value contained the character '%' e.g., `GET /Users?filter=userName eq "my % name"`
|
|
1609
|
-
|
|
1610
|
-
### v6.0.0
|
|
1611
|
-
|
|
1612
|
-
**[MAJOR]**
|
|
1613
|
-
|
|
1614
|
-
- API method response bodies (no SCIM related) will now be returned "as-is". Previously response body had format `{ result: <content> }`. If response body is parsed by client, client must be changeed to reflect the new response body format.
|
|
1615
|
-
- New plugin API method `scimgateway.publicApi()` for handling public path `/pub/api` with no authentication required, please see `plugin-api`
|
|
1616
|
-
e.g. `GET /pub/api?model=Tesla`
|
|
1617
|
-
- Configuration `scimgateway.auth.bearerJwtAzure` is no longer supported. Instead use the new `scimgateway.auth.bearerJwt.azureTenantId` for allowing Entra ID initiated provisioning through scimgateway
|
|
1618
|
-
|
|
1619
|
-
**Old configuration:**
|
|
1620
|
-
|
|
1621
|
-
"bearerJwtAzure": [
|
|
1622
|
-
{
|
|
1623
|
-
"tenantIdGUID": {entra-tenant-id},
|
|
1624
|
-
"readOnly": false,
|
|
1625
|
-
"baseEntities": []
|
|
1626
|
-
}
|
|
1627
|
-
],
|
|
1628
|
-
|
|
1629
|
-
**New configuration:**
|
|
1630
|
-
|
|
1631
|
-
"bearerJwt": [
|
|
1632
|
-
{
|
|
1633
|
-
"secret": null,
|
|
1634
|
-
"publicKey": null,
|
|
1635
|
-
"wellKnownUri": null,
|
|
1636
|
-
"azureTenantId": {entra-tenant-id},
|
|
1637
|
-
"options": {
|
|
1638
|
-
"issuer": null
|
|
1639
|
-
},
|
|
1640
|
-
"readOnly": false,
|
|
1641
|
-
"baseEntities": []
|
|
1642
|
-
}
|
|
1643
|
-
],
|
|
1644
|
-
|
|
1645
|
-
- All existing configurations having key `tenantIdGUID` must be replaced with the new key `azureTenantId`. This also applies to endpoint configuration used by HelperRest()
|
|
1646
|
-
|
|
1647
|
-
**Old configuration:**
|
|
1648
|
-
|
|
1649
|
-
"email": {
|
|
1650
|
-
"auth": {
|
|
1651
|
-
"type": "oauth",
|
|
1652
|
-
"options": {
|
|
1653
|
-
"tenantIdGUID": null,
|
|
1654
|
-
"clientId": null,
|
|
1655
|
-
"clientSecret": null
|
|
1656
|
-
}
|
|
1657
|
-
},
|
|
1658
|
-
|
|
1659
|
-
**New configuration:**
|
|
1660
|
-
|
|
1661
|
-
"email": {
|
|
1662
|
-
"auth": {
|
|
1663
|
-
"type": "oauth",
|
|
1664
|
-
"options": {
|
|
1665
|
-
"azureTenantId": null,
|
|
1666
|
-
"clientId": null,
|
|
1667
|
-
"clientSecret": null
|
|
1668
|
-
}
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
Example of HelperRest() endpoint configuration used by plugin-entra-id having tenantIdGUID replaced with azureTenantId:
|
|
1672
|
-
|
|
1673
|
-
"connection": {
|
|
1674
|
-
"baseUrls": [],
|
|
1675
|
-
"auth": {
|
|
1676
|
-
"type": "oauth",
|
|
1677
|
-
"options": {
|
|
1678
|
-
"azureTenantId": "Entra ID Tenant ID (GUID)",
|
|
1679
|
-
"clientId": "Entra ID Application ID",
|
|
1680
|
-
"clientSecret": "Entra ID Application secret value"
|
|
1681
|
-
}
|
|
1682
|
-
},
|
|
1683
|
-
|
|
1684
|
-
### v5.5.5
|
|
1685
|
-
|
|
1686
|
-
[Improved]
|
|
1687
|
-
- Dependencies bump
|
|
1688
|
-
- Docker - `.dockerignore` included at root, same as `./config/docker/.dockerignore`
|
|
1689
|
-
|
|
1690
|
-
### v5.5.4
|
|
1691
|
-
|
|
1692
|
-
[Fixed]
|
|
1693
|
-
- Docker - exclude any package postinstall script to be run `--ignore-scripts`, because of `bun pm trust` prerequirement
|
|
1694
|
-
|
|
1695
|
-
### v5.5.3
|
|
1696
|
-
|
|
1697
|
-
[Fixed]
|
|
1698
|
-
- Docker - fixed `docker build` error introduced in v5.5.0 (using bun.lock instead of binary bun.lockb)
|
|
1699
|
-
|
|
1700
|
-
[Improved]
|
|
1701
|
-
- plugin-mssql - attribute externalId included
|
|
1702
|
-
- .dockerignore - new docker configuration file, contains files to be excluded from the build context
|
|
1703
|
-
|
|
1704
|
-
### v5.5.2
|
|
1705
|
-
|
|
1706
|
-
[Improved]
|
|
1707
|
-
|
|
1708
|
-
- Entra ID Federated Identity Credentials introduced in v5.5.0, the issuer configuration should be scimgateway base URL
|
|
1709
|
-
old: `"issuer": "<https://FQDN-scimgateway>/oauth"`
|
|
1710
|
-
new: `"issuer": "<https://FQDN-scimgateway>"`
|
|
1711
|
-
|
|
1712
|
-
Change log v5.5.0 have been corrected with the new issuer having base URL only
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
### v5.5.1
|
|
1716
|
-
|
|
1717
|
-
[Fixed]
|
|
1718
|
-
|
|
1719
|
-
- 401 Unauthorized response did include scim-formatted error message when using `helper-rest` and authentication `PassThrough`. 401 should not include scim-formatted error message
|
|
1720
|
-
|
|
1721
|
-
### v5.5.0
|
|
1722
|
-
|
|
1723
|
-
[Improved]
|
|
1724
|
-
|
|
1725
|
-
- Entra ID [Federated Identity Credentials](https://learn.microsoft.com/en-us/graph/api/resources/federatedidentitycredentials-overview?view=graph-rest-1.0) is now supported. Identity federation allows SCIM Gateway to access Microsoft Entra protected resources without needing to manage secrets
|
|
1726
|
-
|
|
1727
|
-
helper-rest includes options for federated credentials:
|
|
1728
|
-
|
|
1729
|
-
"auth {
|
|
1730
|
-
"type": "oauthJwtBearer",
|
|
1731
|
-
"options": {
|
|
1732
|
-
"tenantIdGUID": "<Entra ID tenantIdGUID",
|
|
1733
|
-
"fedCred": {
|
|
1734
|
-
"issuer": "<https://FQDN-scimgateway>",
|
|
1735
|
-
"subject": "<entra id application object id - client id>",
|
|
1736
|
-
"name": "<entra id federated credentials unique name>"
|
|
1737
|
-
}
|
|
1738
|
-
}
|
|
1739
|
-
}
|
|
1740
|
-
|
|
1741
|
-
Example:
|
|
1742
|
-
|
|
1743
|
-
"auth {
|
|
1744
|
-
"type": "oauthJwtBearer",
|
|
1745
|
-
"options": {
|
|
1746
|
-
"tenantIdGUID": "11111111-2222-3333-4444-555555555555",
|
|
1747
|
-
"fedCred": {
|
|
1748
|
-
"issuer": "https://scimgateway.my-company.com",
|
|
1749
|
-
"subject": "99999999-8888-7777-6666-555555555555",
|
|
1750
|
-
"name": "plugin-entra-id"
|
|
1751
|
-
}
|
|
1752
|
-
}
|
|
1753
|
-
}
|
|
1754
|
-
|
|
1755
|
-
Note: Federated credentials (scenario "Other issuer") defined for the application in Entra ID must match the corresponding `issuer`, `subject`, and `name` values defined in the SCIM Gateway endpoint configuration. An example of this can be using `plugin-entra-id` and other plugins that interact with endpoints or applications protected by Entra ID.
|
|
1756
|
-
|
|
1757
|
-
Also note: SCIM Gateway must be reachable from the internet (as defined by the `issuer` URL). This requires allowing inbound internet communication — or alternatively, Azure Relay can be used for outbound-only communication.
|
|
1758
|
-
|
|
1759
|
-
### v5.4.4
|
|
1760
|
-
|
|
1761
|
-
[Improved]
|
|
1762
|
-
|
|
1763
|
-
- External JWKS (JSON Web Key Set) is now supported by JWT Authentication. These are public and typically frequent rotated by modern identity providers
|
|
1764
|
-
|
|
1765
|
-
JKWS is enabled by setting scimgateway.auth.bearerJwt[].wellKnownUri to the identity provider's well-known URI
|
|
1766
|
-
|
|
1767
|
-
Keycloak example:
|
|
1768
|
-
|
|
1769
|
-
auth: {
|
|
1770
|
-
"bearerJwt": [
|
|
1771
|
-
{
|
|
1772
|
-
"wellKnownUri": "https://keycloak.example.com/realms/example-realm/.well-known/openid-configuration",
|
|
1773
|
-
"options": {
|
|
1774
|
-
...
|
|
1775
|
-
},
|
|
1776
|
-
...
|
|
1777
|
-
}
|
|
1778
|
-
]
|
|
1779
|
-
}
|
|
1780
|
-
|
|
1781
|
-
### v5.4.3
|
|
1782
|
-
|
|
1783
|
-
[Fixed]
|
|
1784
|
-
|
|
1785
|
-
- helper-rest, fixed an issue introduced in v5.3.8 that caused problems using OAuth
|
|
1786
|
-
|
|
1787
|
-
[Improved]
|
|
1788
|
-
|
|
1789
|
-
- Remote real-time logger
|
|
1790
|
-
|
|
1791
|
-
### v5.4.2
|
|
1792
|
-
|
|
1793
|
-
[Improved]
|
|
1794
|
-
|
|
1795
|
-
- baseEntity included as json-key in logs
|
|
1796
|
-
- Remote real-time logger now supports baseEntity. `http(s)://host/logger` gives all log entries for plugin. `http(s)://host/<baseEntity>/logger` gives only log entries for the baseEntity used.
|
|
1797
|
-
|
|
1798
|
-
Note, using `baseEntity` is optional. This is a parameter used for multi tenant or multi endpoint solutions. We could create several endpoint configurations having unique baseEntity. Also note that we can configure auth linked to baseEntity including readOnly.
|
|
1799
|
-
|
|
1800
|
-
### v5.4.1
|
|
1801
|
-
|
|
1802
|
-
[Improved]
|
|
1803
|
-
|
|
1804
|
-
- Remote real-time logger, stop/start button added when using browser
|
|
1805
|
-
|
|
1806
|
-
### v5.4.0
|
|
1807
|
-
|
|
1808
|
-
[Improved]
|
|
1809
|
-
|
|
1810
|
-
- Some underlying enhancements have been made to the remote real-time logger. When using a browser, log level colors are now shown. Note: the remote logger is not supported via Azure Relay
|
|
1811
|
-
|
|
1812
|
-
### v5.3.8
|
|
1813
|
-
|
|
1814
|
-
[Improved]
|
|
1815
|
-
|
|
1816
|
-
- [Azure Relay](https://learn.microsoft.com/en-us/azure/azure-relay/relay-what-is-it) is now supported for secure and hassle-free outbound communication — with just one minute of configuration
|
|
1817
|
-
|
|
1818
|
-
Using Azure technology we have different options for setting up a communication tunnel to SCIM Gateway:
|
|
1819
|
-
|
|
1820
|
-
`Microsoft Entra Application Proxy + Microsoft Entra Application Proxy Connector` (SCIM Gateway located on-premises or using Azure private VNet/IP)
|
|
1821
|
-
`Azure Application Gateway` - Layer 7 (SCIM Gateway located in Azure)
|
|
1822
|
-
`Azure Relay` (SCIM Gateway located on-premises or in Azure)
|
|
1823
|
-
|
|
1824
|
-
Azure pricing for using Azure Relay is approx. 10$ per month for each listener (SCIM Gateway plugin)
|
|
1825
|
-
|
|
1826
|
-
**Using out-of-the-box Azure Relay:**
|
|
1827
|
-
|
|
1828
|
-
Prerequisite: SCIM Gateway having outbound internet access (https/443)
|
|
1829
|
-
In Azure create a `Relay` - `<namespace-name>`
|
|
1830
|
-
In the Relay, create an entity of type `Hybrid Connection` - `<hybrid-connection-name>` **one for each SCIM Gateway plugin**
|
|
1831
|
-
The `Requires Client Authorization` option **should be unchecked (not activated)**, unless we are using custom IdP/API having logic for including SAS-token in the communication header
|
|
1832
|
-
Shared access policies - RootManageSharedaccessKey - Primary Key (copy this one)
|
|
1833
|
-
|
|
1834
|
-
SCIM Gateway plugin configuration:
|
|
1835
|
-
|
|
1836
|
-
{
|
|
1837
|
-
"scimgateway: {
|
|
1838
|
-
...
|
|
1839
|
-
"azureRelay": {
|
|
1840
|
-
"enabled": true,
|
|
1841
|
-
"connectionUrl": "https://<namespace-name>.servicebus.windows.net/<hybrid-connection-name>",
|
|
1842
|
-
"apiKey": "<primary-key>"
|
|
1843
|
-
},
|
|
1844
|
-
...
|
|
1845
|
-
},
|
|
1846
|
-
...
|
|
1847
|
-
}
|
|
1848
|
-
|
|
1849
|
-
`connectionUrl` will be the SCIM base URL used by IdP/API for accessing SCIM Gateway
|
|
1850
|
-
|
|
1851
|
-
Example:
|
|
1852
|
-
GET `https://<namespace-name>.servicebus.windows.net/<hybrid-connection-name>/Users`
|
|
1853
|
-
GET `https://<namespace-name>.servicebus.windows.net/<hybrid-connection-name>/<baseEntity>/Users`
|
|
1854
|
-
|
|
1855
|
-
If several SCIM Gateway´s (same plugin) connect listeners using the same Azure Relay connectionUrl, there will be load-balancing and round-robin distribution
|
|
1856
|
-
|
|
1857
|
-
### v5.3.7
|
|
1858
|
-
|
|
1859
|
-
[Improved]
|
|
1860
|
-
|
|
1861
|
-
- Normalize line endings to LF
|
|
1862
|
-
|
|
1863
|
-
### v5.3.6
|
|
1864
|
-
|
|
1865
|
-
[Fixed]
|
|
1866
|
-
|
|
1867
|
-
- Some minor ETag improvements
|
|
1868
|
-
|
|
1869
|
-
### v5.3.5
|
|
1870
|
-
|
|
1871
|
-
[Improved]
|
|
1872
|
-
|
|
1873
|
-
- ETag now supported and default included for all requests. Plugin may use custom ETag by returning meta.version.
|
|
1874
|
-
|
|
1875
|
-
### v5.3.4
|
|
1876
|
-
|
|
1877
|
-
[Fixed]
|
|
1878
|
-
|
|
1879
|
-
- PATCH operations (modifyUser/modifyGroup) that includes `null` values, will now be converted to empty string `""`
|
|
1880
|
-
|
|
1881
|
-
{
|
|
1882
|
-
"schemas": [
|
|
1883
|
-
"urn:ietf:params:scim:api:messages:2.0:PatchOp"
|
|
1884
|
-
],
|
|
1885
|
-
"Operations": [{
|
|
1886
|
-
"op": "replace",
|
|
1887
|
-
"value": {
|
|
1888
|
-
"name": {
|
|
1889
|
-
"formatted": "Smith, John",
|
|
1890
|
-
"honorificPrefix": null
|
|
1891
|
-
}
|
|
1892
|
-
}}
|
|
1893
|
-
]
|
|
1894
|
-
}
|
|
1895
|
-
|
|
1896
|
-
In the example above, following will be sent to plugin:
|
|
1897
|
-
{ "name": { "formatted": "Smith, John", "honorificPrefix": "" } }
|
|
1898
|
-
|
|
1899
|
-
### v5.3.3
|
|
1900
|
-
|
|
1901
|
-
[Fixed]
|
|
1902
|
-
|
|
1903
|
-
- helper-rest, SamlBearer token-request now includes `new_token=true` to avoid retrieving an existing token that is about to expire
|
|
1904
|
-
|
|
1905
|
-
### v5.3.2
|
|
1906
|
-
|
|
1907
|
-
[Improved]
|
|
1908
|
-
|
|
1909
|
-
- helper-rest, retry on request error 504 Gateway Timeout
|
|
1910
|
-
- performance micro-optimization on log mask logic
|
|
1911
|
-
|
|
1912
|
-
### v5.3.1
|
|
1913
|
-
|
|
1914
|
-
[Fixed]
|
|
1915
|
-
|
|
1916
|
-
- Incorrect log masking of SCIM 2.0 PATCH Operations
|
|
1917
|
-
- plugin-ldap, create user/group having DN special character `#` failed on OpenLDAP
|
|
1918
|
-
|
|
1919
|
-
### v5.3.0
|
|
1920
|
-
|
|
1921
|
-
[Improved]
|
|
1922
|
-
|
|
1923
|
-
- [Bulk Operations](https://datatracker.ietf.org/doc/html/rfc7644#section-3.7) now supported
|
|
1924
|
-
- Dependencies bump
|
|
1925
|
-
|
|
1926
|
-
### v5.2.5
|
|
1927
|
-
|
|
1928
|
-
[Fixed]
|
|
1929
|
-
|
|
1930
|
-
- endpointMapper (used by plugin-entra-id and plugin-ldap) in v5 when using mapping type=array, the first element was excluded on outbound mapping in some use cases
|
|
1931
|
-
|
|
1932
|
-
### v5.2.4
|
|
1933
|
-
|
|
1934
|
-
[Improved]
|
|
1935
|
-
|
|
1936
|
-
- New configuration `log.logDirectory` for custom defined log directory e.g. `/var/log/scimgateway` that will override default `<scimgateway path>/logs`.
|
|
1937
|
-
**Thanks to [@Gerrit Lansing](https://github.com/gerritlansing)**
|
|
1938
|
-
- Base URL like `/scim/v1` and `/scim/v2` is now supported, also with baseEntity e.g. `/scim/v2/client1/Users`
|
|
1939
|
-
|
|
1940
|
-
### v5.2.3
|
|
1941
|
-
|
|
1942
|
-
[Fixed]
|
|
1943
|
-
|
|
1944
|
-
- GET /ResourceTypes was missing in v5
|
|
1945
|
-
|
|
1946
|
-
### v5.2.2
|
|
1947
|
-
|
|
1948
|
-
[Fixed]
|
|
1949
|
-
|
|
1950
|
-
- plugin-ldap, tls configuration now supported for Bun > v1.2.4, previously environments had to be used
|
|
1951
|
-
|
|
1952
|
-
"tls": {
|
|
1953
|
-
"ca": "ca-file-name", // located in config/certs
|
|
1954
|
-
"rejectUnauthorized": true
|
|
1955
|
-
}
|
|
1956
|
-
|
|
1957
|
-
[Improved]
|
|
1958
|
-
|
|
1959
|
-
- Dependencies bump
|
|
1960
|
-
|
|
1961
|
-
### v5.2.1
|
|
1962
|
-
|
|
1963
|
-
[Fixed]
|
|
1964
|
-
|
|
1965
|
-
- Logger did not use the correct plugin rollover filename when the gateway ran multiple plugins
|
|
1966
|
-
|
|
1967
|
-
### v5.2.0
|
|
1968
|
-
|
|
1969
|
-
[Improved]
|
|
1970
|
-
|
|
1971
|
-
- Logger have been redesigned
|
|
1972
|
-
|
|
1973
|
-
Supports console, file and push (client subscriber) logging
|
|
1974
|
-
Remote real-time log subscription, see configuration notes
|
|
1975
|
-
JSON formatted log messages
|
|
1976
|
-
UTC (Coordinated Universal Time)
|
|
1977
|
-
File logging will rotate on startup
|
|
1978
|
-
File logging now includes configuration options for maxFiles and maxSize
|
|
1979
|
-
Console using default colorized and minimized output. If redirecting stdout/stderr, standard JSON will be used and no color encoding
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
### v5.1.8
|
|
1983
|
-
|
|
1984
|
-
[Fixed]
|
|
1985
|
-
|
|
1986
|
-
- plugin-ldap, dn that includes double underscore `__` not correctly handled
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
### v5.1.7
|
|
1990
|
-
|
|
1991
|
-
[Fixed]
|
|
1992
|
-
|
|
1993
|
-
- Using gateway certificate CA, the CA did not load correctly. It now also supports an array of multiple CAs.
|
|
1994
|
-
|
|
1995
|
-
[Improved]
|
|
1996
|
-
|
|
1997
|
-
- Dependencies bump
|
|
1998
|
-
|
|
1999
|
-
### v5.1.6
|
|
2000
|
-
|
|
2001
|
-
[Improved]
|
|
2002
|
-
|
|
2003
|
-
- HelperRest, payload/claims configuration now defined in auth.options.jwtPayload and auth.options.samlPayload. Previously all was defiend in auth.options
|
|
2004
|
-
- README configuration notes updated
|
|
2005
|
-
|
|
2006
|
-
### v5.1.5
|
|
2007
|
-
|
|
2008
|
-
[Improved]
|
|
2009
|
-
|
|
2010
|
-
- 404 NOT_FOUND is now logged as a warning instead of error
|
|
2011
|
-
|
|
2012
|
-
### v5.1.4
|
|
2013
|
-
|
|
2014
|
-
[Fixed]
|
|
2015
|
-
|
|
2016
|
-
- Postinstall failed using the new Bun v1.2.0
|
|
2017
|
-
|
|
2018
|
-
### v5.1.3
|
|
2019
|
-
|
|
2020
|
-
[Fixed]
|
|
2021
|
-
|
|
2022
|
-
- HelperRest, auth.type=`oauthJwtBearer` and auth.options=`tenantIdGUID`
|
|
2023
|
-
|
|
2024
|
-
Configuration example using Entra ID application having uploaded cert.pem as certificate secret:
|
|
2025
|
-
|
|
2026
|
-
"endpoint": {
|
|
2027
|
-
"entity": {
|
|
2028
|
-
"undefined": {
|
|
2029
|
-
"connection": {
|
|
2030
|
-
"baseUrls": [],
|
|
2031
|
-
"auth": {
|
|
2032
|
-
"type": "oauthJwtBearer",
|
|
2033
|
-
"options": {
|
|
2034
|
-
"tenantIdGUID": "Entra ID Tenant ID (GUID)",
|
|
2035
|
-
"clientId": "<application clientId>",
|
|
2036
|
-
"tls": { // files located in ./config/certs
|
|
2037
|
-
"key": "key.pem",
|
|
2038
|
-
"cert": "cert.pem"
|
|
2039
|
-
}
|
|
2040
|
-
}
|
|
2041
|
-
}
|
|
2042
|
-
}
|
|
2043
|
-
}
|
|
2044
|
-
}
|
|
2045
|
-
}
|
|
2046
|
-
|
|
2047
|
-
Please see code editor method HelperRest doRequest() IntelliSense for details
|
|
2048
|
-
|
|
2049
|
-
Note, this fix may break `plugin-entra-id` if baseUrls configuration not empty. If baseUrl not empty, it will be used. If empty, baseUrl will automatically be set according to graph api when using tenantIdGUID definition
|
|
2050
|
-
|
|
2051
|
-
### v5.1.2
|
|
2052
|
-
|
|
2053
|
-
[Improved]
|
|
2054
|
-
|
|
2055
|
-
- Simplified some initialization logic
|
|
2056
|
-
|
|
2057
|
-
### v5.1.1
|
|
2058
|
-
|
|
2059
|
-
[Fixed]
|
|
2060
|
-
|
|
2061
|
-
- SCIM Gateway failed to start on linux using Bun >= v1.1.43
|
|
2062
|
-
|
|
2063
|
-
### v5.1.0
|
|
2064
|
-
|
|
2065
|
-
[Improved]
|
|
2066
|
-
|
|
2067
|
-
- By configuring the `chainingBaseUrl`, it is now possible to chain multiple gateways in sequence, such as `gateway1->gateway2->gateway3->endpoint`. In this setup, gateway beave much like a reverse proxy, validating authorization at each step unless PassThrough mode is enabled. Chaining is also supported in stream subscriber mode
|
|
2068
|
-
|
|
2069
|
-
Please see `Configuration notes` for details
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
### v5.0.15
|
|
2073
|
-
|
|
2074
|
-
[Improved]
|
|
2075
|
-
|
|
2076
|
-
- HelperRest, auth.type=oauthSamlAssertion and auth.type=oauthJwtAssertion have been updated to `oauthSamlBearer` and `oauthJwtBearer` for consistency
|
|
2077
|
-
|
|
2078
|
-
### v5.0.14
|
|
2079
|
-
|
|
2080
|
-
[Improved]
|
|
2081
|
-
|
|
2082
|
-
- email now supports Google Workspace Gmail using REST OAuth
|
|
2083
|
-
- email workaround for ExO national characters introduced in v5.0.7 not needed anymore - ExO/GraphApi seems to have been fixed
|
|
2084
|
-
- some minor cosmetics on email message layout formatting when using plain text message
|
|
2085
|
-
- HelperRest now includes authentication type `oauthJwtAssertion`
|
|
2086
|
-
|
|
2087
|
-
### v5.0.13
|
|
2088
|
-
|
|
2089
|
-
[Improved]
|
|
2090
|
-
|
|
2091
|
-
- scim-stream, using the new reorganized nats.js v3 client library
|
|
2092
|
-
- cosmetics, `use strict` not needed and removed because ES modules are always strict mode
|
|
2093
|
-
|
|
2094
|
-
### v5.0.12
|
|
2095
|
-
|
|
2096
|
-
[Fixed]
|
|
2097
|
-
|
|
2098
|
-
- HelperRest doRequest() incorrect Auth PassThrough handling
|
|
2099
|
-
|
|
2100
|
-
[Improved]
|
|
2101
|
-
|
|
2102
|
-
- Dependencies bump
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
### v5.0.11
|
|
2106
|
-
|
|
2107
|
-
[Fixed]
|
|
2108
|
-
|
|
2109
|
-
- OAuth token response on error missing error_description in v5
|
|
2110
|
-
- HelperRest doRequest() now also includes retry logic on invalid token that has not expired - will renew token
|
|
2111
|
-
|
|
2112
|
-
### v5.0.10
|
|
2113
|
-
|
|
2114
|
-
[Improved]
|
|
2115
|
-
|
|
2116
|
-
- OAuth token request now accept missing or invalid Content-Type header
|
|
2117
|
-
|
|
2118
|
-
### v5.0.9
|
|
2119
|
-
|
|
2120
|
-
[Improved]
|
|
2121
|
-
|
|
2122
|
-
- HelperRest doRequest() now support configuration auth type `oauthSamlAssertion` for OAuth SAML token assertion. Please see code editor method IntelliSense for details
|
|
2123
|
-
|
|
2124
|
-
### v5.0.8
|
|
2125
|
-
|
|
2126
|
-
[Fixed]
|
|
2127
|
-
|
|
2128
|
-
- Ensure Bun compatibility with Azure Reverse Proxy for large and long running response
|
|
2129
|
-
- HelperRest was not compatible with Node.js
|
|
2130
|
-
- plugin-mssql, some error handling should not throw an error
|
|
2131
|
-
- Configuration files updated according to the v5 configuration syntax of `scimgateway.auth.bearerOAuth` - `clientId/clientSecret` now replacing deprecated `client_id/client_secret`
|
|
2132
|
-
|
|
2133
|
-
### v5.0.7
|
|
2134
|
-
|
|
2135
|
-
[Improved]
|
|
2136
|
-
|
|
2137
|
-
- plugin-mssql all methods now implemented, also includes docker and dbinit configuration, **thanks to [@Peter Havekes](https://github.com/phavekes) and [@mrvanes](https://github.com/mrvanes)**
|
|
2138
|
-
|
|
2139
|
-
[Fixed]
|
|
2140
|
-
|
|
2141
|
-
- mail sending option introduced in v5.0.6 did not fully support national special charcters when using Microsoft Exchange Online and html formatted email
|
|
2142
|
-
|
|
2143
|
-
### v5.0.6
|
|
2144
|
-
|
|
2145
|
-
[Improved]
|
|
2146
|
-
|
|
2147
|
-
- new configuration option: `scimgateway.idleTimeout` default 120, sets the the number of seconds to wait before timing out a connection due to inactivity
|
|
2148
|
-
- deprecated configuration option: `scimgateway.payloadSize` Bun using default maxRequestBodySize 128MB
|
|
2149
|
-
- new configuration option: `scimgateway.email` replacing legacy `scimgateway.emailOnError` (legacy still supported). Email now support oauth authentication
|
|
2150
|
-
|
|
2151
|
-
**old configuration:**
|
|
2152
|
-
|
|
2153
|
-
{
|
|
2154
|
-
"scimgateway": {
|
|
2155
|
-
...
|
|
2156
|
-
"emailOnError": {
|
|
2157
|
-
"smtp": {
|
|
2158
|
-
"enabled": false,
|
|
2159
|
-
"host": null,
|
|
2160
|
-
"port": 587,
|
|
2161
|
-
"proxy": null,
|
|
2162
|
-
"authenticate": true,
|
|
2163
|
-
"username": null,
|
|
2164
|
-
"password": null,
|
|
2165
|
-
"sendInterval": 15,
|
|
2166
|
-
"to": null,
|
|
2167
|
-
"cc": null
|
|
2168
|
-
}
|
|
2169
|
-
},
|
|
2170
|
-
...
|
|
2171
|
-
},
|
|
2172
|
-
...
|
|
2173
|
-
}
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
**new configuration:**
|
|
2177
|
-
Using Microsoft Exchange Online and oauth authencation which also is default and recommended by Microsoft. For other mail servers and options like SMTP AUTH (basic/oauth), please see configuration description. Plugin may also send mail using method scimgateway.sendMail()
|
|
2178
|
-
|
|
2179
|
-
{
|
|
2180
|
-
"scimgateway": {
|
|
2181
|
-
...
|
|
2182
|
-
"email": {
|
|
2183
|
-
"auth": {
|
|
2184
|
-
"type": "oauth",
|
|
2185
|
-
"options": {
|
|
2186
|
-
"tenantIdGUID": null,
|
|
2187
|
-
"clientId": null,
|
|
2188
|
-
"clientSecret": null
|
|
2189
|
-
}
|
|
2190
|
-
},
|
|
2191
|
-
"emailOnError": {
|
|
2192
|
-
"enabled": false,
|
|
2193
|
-
"from": null,
|
|
2194
|
-
"to": null
|
|
2195
|
-
}
|
|
2196
|
-
},
|
|
2197
|
-
...
|
|
2198
|
-
},
|
|
2199
|
-
...
|
|
2200
|
-
}
|
|
2201
|
-
|
|
2202
|
-
Configuration notes when using oauth and tenantIdGUID - Microsoft Exchange Online (ExO):
|
|
2203
|
-
|
|
2204
|
-
- Entra ID application must have application permissions `Mail.Send`
|
|
2205
|
-
- To prevent the sending of emails from any defined mailboxes, an ExO `ApplicationAccessPolicy` must be defined through PowerShell.
|
|
2206
|
-
|
|
2207
|
-
First create a mail-enabled security-group that only includes those users (mailboxes) the application is allowed to send from
|
|
2208
|
-
Note, `mail enabled security group` cannot be created from portal, only from admin or admin.exchange console
|
|
2209
|
-
|
|
2210
|
-
##Connect to Exchange
|
|
2211
|
-
Install-Module -Name ExchangeOnlineManagement
|
|
2212
|
-
Connect-ExchangeOnline
|
|
2213
|
-
|
|
2214
|
-
##Create ApplicationAccessPolicy
|
|
2215
|
-
New-ApplicationAccessPolicy -AppId <AppClientID> -PolicyScopeGroupId <MailEnabledSecurityGrpId> -AccessRight RestrictAccess -Description "Restrict app to specific mailboxes"
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
### v5.0.5
|
|
2219
|
-
|
|
2220
|
-
[Fixed]
|
|
2221
|
-
|
|
2222
|
-
- plugin-ldap, dn special character not correct for ascii code 128(dec)/80(hex)
|
|
2223
|
-
|
|
2224
|
-
### v5.0.4
|
|
2225
|
-
|
|
2226
|
-
[Improved]
|
|
2227
|
-
|
|
2228
|
-
- minor type definition cosmetics
|
|
2229
|
-
|
|
2230
|
-
### v5.0.3
|
|
2231
|
-
|
|
2232
|
-
[Fixed]
|
|
2233
|
-
|
|
2234
|
-
- unauthorized connection when using configuration bearerJwtAzure
|
|
2235
|
-
|
|
2236
|
-
[Improved]
|
|
2237
|
-
|
|
2238
|
-
- minor type definition cosmetics
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
### v5.0.2
|
|
2242
|
-
|
|
2243
|
-
[Improved]
|
|
2244
|
-
|
|
2245
|
-
- minor cosmetics readme updates
|
|
2246
|
-
|
|
2247
|
-
### v5.0.1
|
|
2248
|
-
|
|
2249
|
-
[Fixed]
|
|
2250
|
-
|
|
2251
|
-
- postinstall did not update index.ts when default bun index.ts did exist
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
### v5.0.0
|
|
2255
|
-
|
|
2256
|
-
**[MAJOR]**
|
|
2257
|
-
|
|
2258
|
-
Major version v5.0.0 marks a shift to native TypeScript support and prioritizes [Bun](https://bun.sh/) over Node.js.
|
|
2259
|
-
|
|
2260
|
-
Besides going from JavaScript to TypeScript, following can be mentioned:
|
|
2261
|
-
|
|
2262
|
-
* Code editor now having IntelliSense showing available methods and documentation details for scimgateway methods
|
|
2263
|
-
* index.ts having new logic for starting plugins e.g.: `const plugins = ['ldap']` for starting plugin-ldap
|
|
2264
|
-
* If using Node.js: node must be version >= 22.6.0, scimgateway must be downloaded from github (because stripping types is currently unsupported for files under node_modules) and startup argument `--experimental-strip-types` e.g.; `node --experimental-strip-types index.ts`
|
|
2265
|
-
* Plugins can use `scimgateway.HelperRest()` for REST functionality. Previously this logic was included in each plugin that used REST.
|
|
2266
|
-
|
|
2267
|
-
// start - mandatory plugin initialization
|
|
2268
|
-
...
|
|
2269
|
-
const HelperRest: typeof import('scimgateway').HelperRest = await (async () => {
|
|
2270
|
-
try {
|
|
2271
|
-
return (await import('scimgateway')).HelperRest
|
|
2272
|
-
} catch (err) {
|
|
2273
|
-
const source = './scimgateway.ts'
|
|
2274
|
-
return (await import(source)).HelperRest
|
|
2275
|
-
}
|
|
2276
|
-
})()
|
|
2277
|
-
...
|
|
2278
|
-
// end - mandatory plugin initialization
|
|
2279
|
-
|
|
2280
|
-
Note, HelperRest use fetch which is not fully supported by Node.js regarding TLS.
|
|
2281
|
-
For TLS and Node.js, environment must instead be used and set before started, e.g.,:
|
|
2282
|
-
`export NODE_EXTRA_CA_CERTS=/package-path/config/certs/ca.pem`
|
|
2283
|
-
or
|
|
2284
|
-
`export NODE_TLS_REJECT_UNAUTHORIZED=0`
|
|
2285
|
-
|
|
2286
|
-
* Configuration secrets (password, secret, token, client_secret, ... ) defined in the `endpoint` section of the configuration file, will automatically be encrypted/decrypted. If there are secrets not handled by the automated encryption/decryption, we may use `scimgateway.getSecret()`. In the old version, corresponding method was named scimgateway.getPassword().
|
|
2287
|
-
* kubernetes configuration and logic have been removed. Kubernetes can use default `/ping` url for healthchecks, and graceful shutdown is taken care of the gateway
|
|
2288
|
-
* In case using custom schemas defined in lib/scimdef-v1/v2.js, these files have now changed to scimdef-v1/v2.json
|
|
2289
|
-
* `config/docker/Dockerfile` now using Bun
|
|
2290
|
-
* plugin-entra, modify licenses/servicePlans is not included anymore, only listing. For license management we instead use groups.
|
|
2291
|
-
* plugin-ldap, for LDAPS/TLS and Bun, we must use environments e.g.:
|
|
2292
|
-
`export NODE_EXTRA_CA_CERTS=/package-path/config/certs/ca.pem`
|
|
2293
|
-
or
|
|
2294
|
-
`export NODE_TLS_REJECT_UNAUTHORIZED=0`
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
**How to migrate existing plugins:**
|
|
2298
|
-
|
|
2299
|
-
* Remove old index.js, use the new index.ts and update `const plugins = ['xxx']` to include your plugin name(s)
|
|
2300
|
-
* Rename plugin-xxx.js to plugin-xxx.ts
|
|
2301
|
-
* import must be used instead of require for loading modules e.g.:
|
|
2302
|
-
const Loki = require('lokijs') => `import Loki from 'lokijs'`
|
|
2303
|
-
* Use the new mandatory settings:
|
|
2304
|
-
|
|
2305
|
-
// start - mandatory plugin initialization
|
|
2306
|
-
const ScimGateway: typeof import('scimgateway').ScimGateway = await (async () => {
|
|
2307
|
-
try {
|
|
2308
|
-
return (await import('scimgateway')).ScimGateway
|
|
2309
|
-
} catch (err) {
|
|
2310
|
-
const source = './scimgateway.ts'
|
|
2311
|
-
return (await import(source)).ScimGateway
|
|
2312
|
-
}
|
|
2313
|
-
})()
|
|
2314
|
-
const scimgateway = new ScimGateway()
|
|
2315
|
-
const config = scimgateway.getConfig()
|
|
2316
|
-
scimgateway.authPassThroughAllowed = false
|
|
2317
|
-
// end - mandatory plugin initialization
|
|
2318
|
-
|
|
2319
|
-
* Use the new `config` object (mentioned above) which contains the `scimgatway.endpoint` configuration having automated encryption/decryption of any attributes named password, secret, client_secret, token and APIKey
|
|
2320
|
-
* The old scimgateway.getPassword() is not normally not needed because of scimgateway automated `config` logic. If needed, use the new scimgateway.getSecret().
|
|
2321
|
-
* Use the new logging syntax:
|
|
2322
|
-
|
|
2323
|
-
replace: scimgateway.logger.debug(`${pluginName}[${baseEntity}] xxx`)
|
|
2324
|
-
with: scimgateway.logDebug(baseEntity, `xxx`)
|
|
2325
|
-
|
|
2326
|
-
* Use scimgateway.HelperRest() for REST functionlity, also supports Auth PassThrough
|
|
2327
|
-
* scimgateway.endpointMapper() may be used for inbound/outbound attribute mappings
|
|
2328
|
-
* In general when using TypeScript, variables should be type-defined: `let isDone: boolean = false`, `catch (err: any)`, ...
|
|
2329
|
-
|
|
2330
|
-
### v4.5.12
|
|
2331
|
-
|
|
2332
|
-
[Improved]
|
|
2333
|
-
|
|
2334
|
-
- plugin-ldap, new configuration { allowModifyDN: true } allows DN being changed based on modified mapping or namingAttribute
|
|
2335
|
-
|
|
2336
|
-
### v4.5.11
|
|
2337
|
-
|
|
2338
|
-
[Improved]
|
|
2339
|
-
|
|
2340
|
-
- deleteUser will try to revoke user from groups before deleting user
|
|
2341
|
-
- advanced or-filter (e.g., used by One Identity Manager) will be chunked and handled by scimgateway as separate calls to plugin
|
|
2342
|
-
- baseEntity now included in scimgateway log entries like plugin log entries
|
|
2343
|
-
|
|
2344
|
-
[Fixed]
|
|
2345
|
-
|
|
2346
|
-
- plugin-ldap, using OpenLDAP - configuration { "isOpenLdap": true } and adding an already existing group member returned 500 Error instead of 200 OK.
|
|
2347
|
-
- plugin-ldap, using OpenLDAP in combination with endpoint user mapping `"type":"array"` and `"typeInbound":"string"` for handling comma separated SCIM string mapping towards an endpoint array/multivalue attribute, did not return correct sort order of the comma separated string when using OpenLDAP. Mapping example:
|
|
2348
|
-
|
|
2349
|
-
"<endpointAttr>": {
|
|
2350
|
-
"mapTo": "<scimAttr>",
|
|
2351
|
-
"type": "array",
|
|
2352
|
-
"typeInbound": "string"
|
|
2353
|
-
},
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
### v4.5.10
|
|
2357
|
-
|
|
2358
|
-
[Fixed]
|
|
2359
|
-
|
|
2360
|
-
- PUT changes introduced in v4.5.7 had incorrect check of configuration groupMemberOfUser (default not set)
|
|
2361
|
-
|
|
2362
|
-
### v4.5.9
|
|
2363
|
-
|
|
2364
|
-
[Improved]
|
|
2365
|
-
|
|
2366
|
-
- Dependencies bump
|
|
2367
|
-
|
|
2368
|
-
### v4.5.8
|
|
2369
|
-
|
|
2370
|
-
[Fixed]
|
|
2371
|
-
|
|
2372
|
-
- plugin-ldap failed when using national special characters and some other LDAP special characters in DN
|
|
2373
|
-
|
|
2374
|
-
Note, plugin-ldap now has following new configuration:
|
|
2375
|
-
|
|
2376
|
-
"ldap": {
|
|
2377
|
-
"isOpenLdap": false,
|
|
2378
|
-
...
|
|
2379
|
-
"namingAttribute": {
|
|
2380
|
-
"user": [
|
|
2381
|
-
{
|
|
2382
|
-
"attribute": "CN",
|
|
2383
|
-
"mapTo": "userName"
|
|
2384
|
-
}
|
|
2385
|
-
],
|
|
2386
|
-
"group": [
|
|
2387
|
-
{
|
|
2388
|
-
"attribute": "CN",
|
|
2389
|
-
"mapTo": "displayName"
|
|
2390
|
-
}
|
|
2391
|
-
]
|
|
2392
|
-
},
|
|
2393
|
-
...
|
|
2394
|
-
}
|
|
2395
|
-
|
|
2396
|
-
`isOpenLdap` true/false decides whether or not OpenLDAP Foundation protocol should be used for national characters and special characters in DN. For Active Directory, default isOpenLdap=false should be used.
|
|
2397
|
-
|
|
2398
|
-
`namingAttribute` can now be linked to scim `mapTo` attribute and is not hardcoded like it was in previous version.
|
|
2399
|
-
|
|
2400
|
-
Previous `userNamingAttr` and `groupNamingAttr` shown below, is now deprecated
|
|
2401
|
-
|
|
2402
|
-
"ldap": {
|
|
2403
|
-
...
|
|
2404
|
-
"userNamingAttr": "CN",
|
|
2405
|
-
"groupNamingAttr": "CN",
|
|
2406
|
-
...
|
|
2407
|
-
}
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
### v4.5.7
|
|
2411
|
-
|
|
2412
|
-
[Fixed]
|
|
2413
|
-
|
|
2414
|
-
- PUT changes introduced in v4.4.6 did not handle PUT /Groups correctly
|
|
2415
|
-
|
|
2416
|
-
[Improved]
|
|
2417
|
-
- configuration scim.usePutGroupMemberOfUser replaced by scim.groupMemberOfUser
|
|
2418
|
-
- misc cosmetics
|
|
2419
|
-
|
|
2420
|
-
### v4.5.6
|
|
2421
|
-
|
|
2422
|
-
[Improved]
|
|
2423
|
-
|
|
2424
|
-
- plugin-ldap preserve multivalue-attribute order on modify. Do not apply to groups/members.
|
|
2425
|
-
|
|
2426
|
-
### v4.5.5
|
|
2427
|
-
|
|
2428
|
-
[Fixed]
|
|
2429
|
-
|
|
2430
|
-
- PUT /Groups/xxx failed on final group lookup and returned error
|
|
2431
|
-
- endpointMapper failed to correctly map customExtensions in certain use cases
|
|
2432
|
-
|
|
2433
|
-
### v4.5.4
|
|
2434
|
-
|
|
2435
|
-
[Fixed]
|
|
2436
|
-
|
|
2437
|
-
- Delete User missing url-decoding of id e.g. using ldap-dn as id
|
|
2438
|
-
|
|
2439
|
-
### v4.5.3
|
|
2440
|
-
|
|
2441
|
-
[Fixed]
|
|
2442
|
-
|
|
2443
|
-
- plugin-api configuration file having new credentials for dummy-json testing
|
|
2444
|
-
|
|
2445
|
-
[Improved]
|
|
2446
|
-
|
|
2447
|
-
- Dependencies bump
|
|
2448
|
-
- plugin-loki and plugin-mongodb, minor improvements for handling raw mulitivalue updates when not using default skipTypeConvert=false
|
|
2449
|
-
- endpointMapper supporting comma separated string to be converted to array, e.g.:
|
|
2450
|
-
SCIM otherMails = "myAlias1@company.com,myAlias2@company.com,myAlias3@company.com"
|
|
2451
|
-
|
|
2452
|
-
endpointMapper configuration for endpoint attribute emails of type array:
|
|
2453
|
-
|
|
2454
|
-
"map": {
|
|
2455
|
-
"user": {
|
|
2456
|
-
"emails": {
|
|
2457
|
-
"mapTo": "otherMails",
|
|
2458
|
-
"type": "array",
|
|
2459
|
-
"typeInbound": "string"
|
|
2460
|
-
},
|
|
2461
|
-
...
|
|
2462
|
-
|
|
2463
|
-
### v4.5.1
|
|
2464
|
-
|
|
2465
|
-
[Improved]
|
|
2466
|
-
|
|
2467
|
-
- scim-stream, client reconnect improvements
|
|
2468
|
-
|
|
2469
|
-
### v4.5.0
|
|
2470
|
-
|
|
2471
|
-
[Improved]
|
|
2472
|
-
|
|
2473
|
-
- scim-stream, scimgateway now supports stream publishing mode having [SCIM Stream](https://elshaug.xyz/docs/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.
|
|
2474
|
-
- scim-stream, subscriber will do automatic retry until connected when plugin not able to connect to endpoint (offline endpoint)
|
|
2475
|
-
- plugin-ldap, modifyGroup now supports all attributes and not only add/remove members
|
|
2476
|
-
- certificate absolute path may be used in plugin configuration file instead of default relative path
|
|
2477
|
-
- dependencies bump
|
|
2478
|
-
|
|
2479
|
-
### v4.4.6
|
|
2480
|
-
|
|
2481
|
-
[Improved]
|
|
2482
|
-
|
|
2483
|
-
- Some PUT logic redesign. More granularity on mulitvalues, instead of including all elements, now only those that differ are sent to modifyUser.
|
|
2484
|
-
|
|
2485
|
-
### v4.4.5
|
|
2486
|
-
|
|
2487
|
-
[Fixed]
|
|
2488
|
-
|
|
2489
|
-
- PATCH group members=[] should remove all members
|
|
2490
|
-
- scim-stream modify user fix
|
|
2491
|
-
|
|
2492
|
-
[Improved]
|
|
2493
|
-
|
|
2494
|
-
- 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
|
|
2495
|
-
- PUT improvements
|
|
2496
|
-
|
|
2497
|
-
### v4.4.4
|
|
2498
|
-
|
|
2499
|
-
[Improved]
|
|
2500
|
-
|
|
2501
|
-
- New configuration: **scim.skipMetaLocation**
|
|
2502
|
-
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.
|
|
2503
|
-
|
|
2504
|
-
Below is an example of nginx reverse proxy configuration supporting SCIM Gateway ipAllowList and correct meta.location response:
|
|
2505
|
-
|
|
2506
|
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
2507
|
-
proxy_set_header X-Forwarded-Proto $scheme;
|
|
2508
|
-
proxy_set_header X-Forwarded-Host $http_host;
|
|
2509
|
-
|
|
2510
|
-
### v4.4.3
|
|
2511
|
-
|
|
2512
|
-
[Improved]
|
|
2513
|
-
|
|
2514
|
-
- Dependencies bump
|
|
2515
|
-
|
|
2516
|
-
### v4.4.2
|
|
2517
|
-
|
|
2518
|
-
[Improved]
|
|
2519
|
-
|
|
2520
|
-
- scim-stream subscriber configuration have been changed:
|
|
2521
|
-
old: `"convertRolesToGroups": false`
|
|
2522
|
-
new: `"skipConvertRolesToGroups": false`
|
|
2523
|
-
This means convert roles to groups is default behavior unless skipConvertRolesToGroups=true
|
|
2524
|
-
|
|
2525
|
-
### v4.4.1
|
|
2526
|
-
|
|
2527
|
-
[Improved]
|
|
2528
|
-
|
|
2529
|
-
- scim-stream subscriber using latest api and some additional recovery logic
|
|
2530
|
-
Prerequisite: [SCIM Stream](https://elshaug.xyz/docs/scim-stream) version > v1.0.0
|
|
2531
|
-
|
|
2532
|
-
[Fixed]
|
|
2533
|
-
|
|
2534
|
-
- plugin-loki was missing async await and could cause problems in some stress test use cases
|
|
2535
|
-
|
|
2536
|
-
### v4.4.0
|
|
2537
|
-
|
|
2538
|
-
[Improved]
|
|
2539
|
-
|
|
2540
|
-
- SCIM Gateway now offers enhanced functionality with support for message subscription and automated provisioning using [SCIM Stream](https://elshaug.xyz/docs/scim-stream)
|
|
2541
|
-
- plugin-entra-id, plugin-scim and plugin-api having updated `REST endpoint helpers-template` to address and resolve endpoint throttling
|
|
2542
|
-
|
|
2543
|
-
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
|
|
2544
|
-
|
|
2545
|
-
### v4.3.0
|
|
2546
|
-
|
|
2547
|
-
[Improved]
|
|
2548
|
-
|
|
2549
|
-
- configuration `scimgateway.scim.port` can now be set to 0 or removed for deactivating listener
|
|
2550
|
-
- configuration `cimgateway.scim.usePutSoftSync` set to `true` now includes additional logic that do not change existing user attributes not included in PUT body content
|
|
2551
|
-
- 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.
|
|
2552
|
-
- plugin-ldap supporting simpel filtering
|
|
2553
|
-
- plugin-loki using baseEntity configuration for supporting multi loki endpoints
|
|
2554
|
-
- plugin-azure-ad renamed to plugin-entra-id
|
|
2555
|
-
- 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,...
|
|
2556
|
-
- Dependencies bump
|
|
2557
|
-
|
|
2558
|
-
### v4.2.17
|
|
2559
|
-
|
|
2560
|
-
[Fixed]
|
|
2561
|
-
|
|
2562
|
-
- plugin-loki incorrect unique filtering
|
|
2563
|
-
|
|
2564
|
-
[Improved]
|
|
2565
|
-
|
|
2566
|
-
- Dependencies bump
|
|
2567
|
-
|
|
2568
|
-
### v4.2.15
|
|
2569
|
-
|
|
2570
|
-
[Improved]
|
|
2571
|
-
|
|
2572
|
-
- 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)
|
|
2573
|
-
|
|
2574
|
-
This change replace statusCode logic introduced in v4.2.11
|
|
2575
|
-
|
|
2576
|
-
### v4.2.14
|
|
2577
|
-
|
|
2578
|
-
[Fixed]
|
|
2579
|
-
|
|
2580
|
-
- PUT now returning 404 instead of 500 when trying to update a user/group that does not exist
|
|
2581
|
-
|
|
2582
|
-
### v4.2.13
|
|
2583
|
-
|
|
2584
|
-
[Fixed]
|
|
2585
|
-
|
|
2586
|
-
- `/ping` now excluded from info logs. If we want ping logging, use something else than lowercase e.g., `/Ping` or `/PING`
|
|
2587
|
-
|
|
2588
|
-
### v4.2.12
|
|
2589
|
-
|
|
2590
|
-
[Improved]
|
|
2591
|
-
|
|
2592
|
-
- 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.
|
|
2593
|
-
|
|
2594
|
-
### v4.2.11
|
|
2595
|
-
|
|
2596
|
-
[Improved]
|
|
2597
|
-
|
|
2598
|
-
Note, obsolete - see v4.2.15 comments
|
|
2599
|
-
|
|
2600
|
-
- 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.
|
|
2601
|
-
|
|
2602
|
-
### v4.2.10
|
|
2603
|
-
|
|
2604
|
-
[Fixed]
|
|
2605
|
-
|
|
2606
|
-
- plugin-ldap broken after dependencies bump of ldapjs (from 2.x.x to 3.x.x) in version 4.2.7
|
|
2607
|
-
|
|
2608
|
-
### v4.2.9
|
|
2609
|
-
|
|
2610
|
-
[Fixed]
|
|
2611
|
-
|
|
2612
|
-
- installation require nodejs >= v.16.0.0 due to previous dependencies bump
|
|
2613
|
-
|
|
2614
|
-
### v4.2.8
|
|
2615
|
-
|
|
2616
|
-
[Fixed]
|
|
2617
|
-
|
|
2618
|
-
- PUT did not allow group name to be modified
|
|
2619
|
-
|
|
2620
|
-
### v4.2.7
|
|
2621
|
-
|
|
2622
|
-
[Improved]
|
|
2623
|
-
|
|
2624
|
-
- 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
|
|
2625
|
-
- plugin-forwardinc renamed to plugin-soap
|
|
2626
|
-
- Dependencies bump
|
|
2627
|
-
|
|
2628
|
-
[Fixed]
|
|
2629
|
-
|
|
2630
|
-
- plugin-azure-ad fixed some issues introduced in v4.2.4
|
|
2631
|
-
- plugin-mongodb fixed some issues introduced in v4.2.4
|
|
2632
|
-
|
|
2633
|
-
### v4.2.6
|
|
2634
|
-
|
|
2635
|
-
[Fixed]
|
|
2636
|
-
|
|
2637
|
-
- cosmetics related to 401 error handling introduced in v4.2.4
|
|
2638
|
-
|
|
2639
|
-
### v4.2.5
|
|
2640
|
-
|
|
2641
|
-
[Fixed]
|
|
2642
|
-
|
|
2643
|
-
- travis test build cosmetics
|
|
2644
|
-
|
|
2645
|
-
### v4.2.4
|
|
2646
|
-
|
|
2647
|
-
[Improved]
|
|
2648
|
-
|
|
2649
|
-
- 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)
|
|
2650
|
-
|
|
2651
|
-
### v4.2.3
|
|
2652
|
-
|
|
2653
|
-
[Fixed]
|
|
2654
|
-
|
|
2655
|
-
- 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.
|
|
2656
|
-
|
|
2657
|
-
### v4.2.2
|
|
2658
|
-
|
|
2659
|
-
[Fixed]
|
|
2660
|
-
|
|
2661
|
-
- some minor SCIM protocol complient adjustments for beeing fully SCIM API complient with [https://scimvalidator.microsoft.com](https://scimvalidator.microsoft.com)
|
|
2662
|
-
|
|
2663
|
-
### v4.2.1
|
|
2664
|
-
|
|
2665
|
-
[Fixed]
|
|
2666
|
-
|
|
2667
|
-
- plugin-azure-ad createUser failed when manager was included
|
|
2668
|
-
- plugin-ldap slow when not using group/groupBase configuration
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
### v4.2.0
|
|
2672
|
-
|
|
2673
|
-
[Improved]
|
|
2674
|
-
|
|
2675
|
-
- Kubernetes health checks and shutdown handler support
|
|
2676
|
-
|
|
2677
|
-
Plugin configuration prerequisite: **kubernetes.enabled=true**
|
|
2678
|
-
|
|
2679
|
-
"kubernetes": {
|
|
2680
|
-
"enabled": true,
|
|
2681
|
-
"shutdownTimeout": 15000,
|
|
2682
|
-
"forceExitTimeout": 1000
|
|
2683
|
-
}
|
|
2684
|
-
|
|
2685
|
-
**Thanks to [@Kevin Osborn](https://github.com/osbornk)**
|
|
2686
|
-
|
|
2687
|
-
### v4.1.15
|
|
2688
|
-
|
|
2689
|
-
[Improved]
|
|
2690
|
-
|
|
2691
|
-
- 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.
|
|
2692
|
-
|
|
2693
|
-
Plugin configuration prerequisites: **auth.passThrough.enabled=true**
|
|
2694
|
-
|
|
2695
|
-
"auth": {
|
|
2696
|
-
...
|
|
2697
|
-
"passThrough": {
|
|
2698
|
-
"enabled": true,
|
|
2699
|
-
"readOnly": false,
|
|
2700
|
-
"baseEntities": []
|
|
2701
|
-
}
|
|
2702
|
-
...
|
|
2703
|
-
}
|
|
2704
|
-
|
|
2705
|
-
Plugin binary prerequisites:
|
|
2706
|
-
|
|
2707
|
-
scimgateway.authPassThroughAllowed = true
|
|
2708
|
-
// also need endpoint logic for handling/passing ctx.request.header.authorization
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
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.:
|
|
2712
|
-
|
|
2713
|
-
scimgateway.getUsers = async (baseEntity, getObj, attributes, ctx)
|
|
2714
|
-
// tip, see provided example plugins
|
|
2715
|
-
|
|
2716
|
-
**Thanks to [@Kevin Osborn](https://github.com/osbornk)**
|
|
2717
|
-
|
|
2718
|
-
### v4.1.14
|
|
2719
|
-
|
|
2720
|
-
[Fixed]
|
|
2721
|
-
|
|
2722
|
-
- 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
|
|
2723
|
-
|
|
2724
|
-
### v4.1.12
|
|
2725
|
-
|
|
2726
|
-
[Improved]
|
|
2727
|
-
|
|
2728
|
-
- Dependencies bump
|
|
2729
|
-
|
|
2730
|
-
### v4.1.11
|
|
2731
|
-
|
|
2732
|
-
[Fixed]
|
|
2733
|
-
|
|
2734
|
-
- basic auth logon dialog should not show up when not configured
|
|
2735
|
-
|
|
2736
|
-
### v4.1.10
|
|
2737
|
-
|
|
2738
|
-
[Improved]
|
|
2739
|
-
|
|
2740
|
-
- 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"
|
|
2741
|
-
**Thanks to [@Sam Murphy*](https://github.com/SamMurphyDev)**
|
|
2742
|
-
|
|
2743
|
-
[Fixed]
|
|
2744
|
-
|
|
2745
|
-
- 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.
|
|
2746
|
-
|
|
2747
|
-
### v4.1.9
|
|
2748
|
-
|
|
2749
|
-
[Fixed]
|
|
2750
|
-
|
|
2751
|
-
- plugin-azure-ad.json configuration file introduced in v.4.1.7 was missing passwordProfile attribute mappings
|
|
2752
|
-
- Symantec/Broadcom/CA ConnectorXpress configuration file `config\resources\Azure - ScimGateway.xml` now using standard text on manager attribute instead of selection dialogbox.
|
|
2753
|
-
|
|
2754
|
-
### v4.1.8
|
|
2755
|
-
|
|
2756
|
-
[Fixed]
|
|
2757
|
-
|
|
2758
|
-
- endpointMap and Symantec/Broadcom/CA ConnectorXpress configuration file `config\resources\Azure - ScimGateway.xml` introduced in v.4.1.7 had some missing logic
|
|
2759
|
-
|
|
2760
|
-
### v4.1.7
|
|
2761
|
-
|
|
2762
|
-
**Note, this version breaks compability with previous versions of plugin-azure-ad**
|
|
2763
|
-
|
|
2764
|
-
[Improved]
|
|
2765
|
-
|
|
2766
|
-
- endpointMap moved from scimgateway to plugin-azure-ad
|
|
2767
|
-
- plugin-azure-ad.json configuration file now includes attribute mapping giving flexibility to add or customize AAD-SCIM attribute mappings
|
|
2768
|
-
- 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
|
|
2769
|
-
|
|
2770
|
-
### v4.1.6
|
|
2771
|
-
|
|
2772
|
-
[Improved]
|
|
2773
|
-
|
|
2774
|
-
- Dependencies bump
|
|
2775
|
-
|
|
2776
|
-
### v4.1.5
|
|
2777
|
-
|
|
2778
|
-
[Improved]
|
|
2779
|
-
|
|
2780
|
-
SCIM Gateway related news:
|
|
2781
|
-
|
|
2782
|
-
- [SCIM Stream](https://elshaug.xyz/docs/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
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
### v4.1.4
|
|
2786
|
-
[Fixed]
|
|
2787
|
-
|
|
2788
|
-
- TypeConvert logic for multivalue attribute `addresses` did not correctly catch duplicate entries
|
|
2789
|
-
- 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
|
|
2790
|
-
|
|
2791
|
-
### v4.1.3
|
|
2792
|
-
[Fixed]
|
|
2793
|
-
|
|
2794
|
-
- createUser response did not include the id that was returned by plugin
|
|
2795
|
-
|
|
2796
|
-
[Improved]
|
|
2797
|
-
|
|
2798
|
-
- 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
|
|
2799
|
-
|
|
2800
|
-
Example:
|
|
2801
|
-
|
|
2802
|
-
PUT /Users/bjensen
|
|
2803
|
-
{
|
|
2804
|
-
...
|
|
2805
|
-
"groups": [
|
|
2806
|
-
{"value":"Employees","display":"Employees"},
|
|
2807
|
-
{"value":"Admins","display":"Admins"}
|
|
2808
|
-
],
|
|
2809
|
-
...
|
|
2810
|
-
}
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
### v4.1.2
|
|
2816
|
-
[Improved]
|
|
2817
|
-
|
|
2818
|
-
- endpointMapper supporting one to many mappings using a comma separated list of attributes in the `mapTo`
|
|
2819
|
-
|
|
2820
|
-
Configuration example:
|
|
2821
|
-
|
|
2822
|
-
"map": {
|
|
2823
|
-
"user": {
|
|
2824
|
-
"PersonnelNumber": {
|
|
2825
|
-
"mapTo": "id,userName",
|
|
2826
|
-
"type": "string"
|
|
2827
|
-
},
|
|
2828
|
-
...
|
|
2829
|
-
}
|
|
2830
|
-
}
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
### v4.1.1
|
|
2834
|
-
[Improved]
|
|
2835
|
-
|
|
2836
|
-
- plugin-ldap support userFilter/groupFilter configuration for restricting scope
|
|
2837
|
-
|
|
2838
|
-
Configuration example:
|
|
2839
|
-
|
|
2840
|
-
{
|
|
2841
|
-
...
|
|
2842
|
-
"userFilter": "(memberOf=CN=grp1,OU=Groups,DC=test,DC=com)(!(memberOf=CN=Domain Admins,CN=Users,DC=test,DC=com))",
|
|
2843
|
-
"groupFilter": "(!(cn=grp2))",
|
|
2844
|
-
...
|
|
2845
|
-
}
|
|
2846
|
-
|
|
2847
|
-
### v4.1.0
|
|
2848
|
-
[Improved]
|
|
2849
|
-
|
|
2850
|
-
- Supporting OAuth Client Credentials authentication
|
|
2851
|
-
|
|
2852
|
-
Configuration example:
|
|
2853
|
-
|
|
2854
|
-
"bearerOAuth": [
|
|
2855
|
-
{
|
|
2856
|
-
"client_id": "my_client_id",
|
|
2857
|
-
"client_secret": "my_client_secret",
|
|
2858
|
-
"readOnly": false,
|
|
2859
|
-
"baseEntities": []
|
|
2860
|
-
}
|
|
2861
|
-
]
|
|
147
|
+
Install [Bun](https://bun.sh/) first. By default Bun installs to `HOMEPATH\.bun`. To install elsewhere, set `BUN_INSTALL=<path>` as a system environment variable before running the installer. Consider adding Bun to the system path for all users.
|
|
2862
148
|
|
|
149
|
+
### Install SCIM Gateway
|
|
2863
150
|
|
|
2864
|
-
|
|
151
|
+
```sh
|
|
152
|
+
mkdir c:\my-scimgateway
|
|
153
|
+
cd c:\my-scimgateway
|
|
154
|
+
bun init -y
|
|
155
|
+
bun install scimgateway
|
|
156
|
+
bun pm trust scimgateway # required to allow postinstall to copy example files
|
|
157
|
+
```
|
|
2865
158
|
|
|
2866
|
-
|
|
2867
|
-
client_secret = my_client_secret
|
|
2868
|
-
token request url = http(s)://<host>:<port>/oauth/token
|
|
159
|
+
This copies `index.ts`, `lib/`, and `config/` (with example plugins) into your package directory.
|
|
2869
160
|
|
|
161
|
+
### Verify the Default Loki Plugin
|
|
2870
162
|
|
|
2871
|
-
|
|
2872
|
-
|
|
163
|
+
```sh
|
|
164
|
+
bun c:\my-scimgateway
|
|
165
|
+
```
|
|
2873
166
|
|
|
2874
|
-
|
|
2875
|
-
- plugin-restful renamed to plugin-scim
|
|
2876
|
-
- plugin-ldap having improved SID/GUID support for Active Directory, also supporting domain map of userPrincipalName e.g. Azure AD => Active Directory
|
|
2877
|
-
|
|
2878
|
-
"userPrincipalName": {
|
|
2879
|
-
"mapTo": "userName",
|
|
2880
|
-
"type": "string",
|
|
2881
|
-
"mapDomain": {
|
|
2882
|
-
"inbound": "test.onmicrosoft.com",
|
|
2883
|
-
"outbound": "my-company.com"
|
|
2884
|
-
}
|
|
167
|
+
Then open a browser and try:
|
|
2885
168
|
|
|
2886
|
-
|
|
2887
|
-
|
|
169
|
+
```
|
|
170
|
+
# Health check
|
|
171
|
+
GET http://localhost:8880/ping
|
|
2888
172
|
|
|
173
|
+
# List users and groups (basic auth: gwadmin / password)
|
|
174
|
+
GET http://localhost:8880/Users
|
|
175
|
+
GET http://localhost:8880/Groups
|
|
2889
176
|
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
- New `getUsers()` replacing deprecated exploreUsers(), getUser() and getGroupUsers()
|
|
2894
|
-
- New `getGroups()` replacing deprecated exploreGroups(), getGroup() and getGroupMembers()
|
|
2895
|
-
- Fully filter and sort support
|
|
2896
|
-
- Authentication configuration may now include a baseEntities array containing one or more `baseEntity` allowed for corresponding admin user
|
|
2897
|
-
- New plugin-mongodb, **Thanks to [@Filipe Ribeiro](https://github.com/fribeiro-keeps) and [@Miguel Ferreira](https://github.com/jmaferreira) (KEEP SOLUTIONS)**
|
|
177
|
+
# Real-time remote log monitoring
|
|
178
|
+
http://localhost:8880/logger
|
|
2898
179
|
|
|
2899
|
-
|
|
180
|
+
# Fetch a specific user or group
|
|
181
|
+
GET http://localhost:8880/Users/bjensen
|
|
182
|
+
GET http://localhost:8880/Groups/Admins
|
|
2900
183
|
|
|
2901
|
-
|
|
184
|
+
# Filter examples
|
|
185
|
+
GET http://localhost:8880/Users?filter=userName eq "bjensen"
|
|
186
|
+
GET http://localhost:8880/Users?filter=emails.value co "@example.com"&attributes=userName,name.familyName,emails&sortBy=name.familyName&sortOrder=descending
|
|
187
|
+
GET http://localhost:8880/Groups?filter=displayName eq "Admins"&excludedAttributes=members
|
|
188
|
+
GET http://localhost:8880/Groups?filter=members.value eq "bjensen"&attributes=id,displayName,members.value
|
|
189
|
+
```
|
|
2902
190
|
|
|
2903
|
-
|
|
2904
|
-
With: scimgateway.getUsers = async (baseEntity, getObj, attributes) => {
|
|
191
|
+
Press `Ctrl+C` to stop.
|
|
2905
192
|
|
|
2906
|
-
|
|
193
|
+
> Using **Node.js**, the startup command is: `node --import=tsx ./index.ts`
|
|
2907
194
|
|
|
2908
|
-
|
|
195
|
+
### Upgrading
|
|
2909
196
|
|
|
2910
|
-
|
|
2911
|
-
if (getObj.operator) {
|
|
2912
|
-
if (getObj.operator === 'eq' && ['id', 'userName', 'externalId'].includes(getObj.attribute)) {
|
|
2913
|
-
// mandatory - unique filtering - single unique user to be returned - correspond to getUser() in versions < 4.x.x
|
|
2914
|
-
} else if (getObj.operator === 'eq' && getObj.attribute === 'group.value') {
|
|
2915
|
-
// optional - only used when groups are member of users, not default behavior - correspond to getGroupUsers() in versions < 4.x.x
|
|
2916
|
-
throw new Error(`${action} error: not supporting groups member of user filtering: ${getObj.rawFilter}`)
|
|
2917
|
-
} else {
|
|
2918
|
-
// optional - simpel filtering
|
|
2919
|
-
throw new Error(`${action} error: not supporting simpel filtering: ${getObj.rawFilter}`)
|
|
2920
|
-
}
|
|
2921
|
-
} else if (getObj.rawFilter) {
|
|
2922
|
-
// optional - advanced filtering having and/or/not - use getObj.rawFilter
|
|
2923
|
-
throw new Error(`${action} error: not supporting advanced filtering: ${getObj.rawFilter}`)
|
|
2924
|
-
} else {
|
|
2925
|
-
// mandatory - no filtering (!getObj.operator && !getObj.rawFilter) - all users to be returned - correspond to exploreUsers() in versions < 4.x.x
|
|
2926
|
-
}
|
|
2927
|
-
// mandatory if-else logic - end
|
|
197
|
+
The recommended approach is to rename the old package folder, do a fresh install, then copy your customized `index.ts`, `config/`, and `lib/` from the previous install.
|
|
2928
198
|
|
|
199
|
+
```sh
|
|
200
|
+
# Minor upgrade
|
|
201
|
+
bun install scimgateway
|
|
2929
202
|
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
203
|
+
# Major upgrade (may break existing plugins — review change log first)
|
|
204
|
+
bun install scimgateway@latest
|
|
205
|
+
```
|
|
2933
206
|
|
|
207
|
+
**Excluding example plugins in production:** Bun skips `postinstall` unless you run `bun pm trust scimgateway`. For npm or Node.js environments, set `scimgateway_postinstall_skip = true` in `.npmrc` or the environment variable `SCIMGATEWAY_POSTINSTALL_SKIP=true`.
|
|
2934
208
|
|
|
2935
|
-
|
|
2936
|
-
With: scimgateway.getGroups = async (baseEntity, getObj, attributes) => {
|
|
209
|
+
---
|
|
2937
210
|
|
|
2938
|
-
|
|
211
|
+
## Configuration
|
|
2939
212
|
|
|
2940
|
-
|
|
2941
|
-
if (getObj.operator) {
|
|
2942
|
-
if (getObj.operator === 'eq' && ['id', 'displayName', 'externalId'].includes(getObj.attribute)) {
|
|
2943
|
-
// mandatory - unique filtering - single unique user to be returned - correspond to getUser() in versions < 4.x.x
|
|
2944
|
-
} else if (getObj.operator === 'eq' && getObj.attribute === 'members.value') {
|
|
2945
|
-
// mandatory - return all groups the user 'id' (getObj.value) is member of - correspond to getGroupMembers() in versions < 4.x.x
|
|
2946
|
-
// Resources = [{ id: <id-group>> , displayName: <displayName-group>, members [{value: <id-user>}] }]
|
|
2947
|
-
} else {
|
|
2948
|
-
// optional - simpel filtering
|
|
2949
|
-
throw new Error(`${action} error: not supporting simpel filtering: ${getObj.rawFilter}`)
|
|
2950
|
-
}
|
|
2951
|
-
} else if (getObj.rawFilter) {
|
|
2952
|
-
// optional - advanced filtering having and/or/not - use getObj.rawFilter
|
|
2953
|
-
throw new Error(`${action} error: not supporting advanced filtering: ${getObj.rawFilter}`)
|
|
2954
|
-
} else {
|
|
2955
|
-
// mandatory - no filtering (!getObj.operator && !getObj.rawFilter) - all groups to be returned - correspond to exploreGroups() in versions < 4.x.x
|
|
2956
|
-
}
|
|
2957
|
-
// mandatory if-else logic - end
|
|
213
|
+
### Entry Point — `index.ts`
|
|
2958
214
|
|
|
215
|
+
`index.ts` defines which plugins to start:
|
|
2959
216
|
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
217
|
+
```ts
|
|
218
|
+
// Start one or more plugins:
|
|
219
|
+
import './lib/plugin-entra-id.ts'
|
|
220
|
+
export {}
|
|
221
|
+
```
|
|
2963
222
|
|
|
223
|
+
### Plugin File Naming
|
|
2964
224
|
|
|
2965
|
-
|
|
225
|
+
Each plugin requires a TypeScript file and a JSON configuration file sharing the same name prefix:
|
|
2966
226
|
|
|
227
|
+
```
|
|
228
|
+
lib/plugin-entra-id.ts
|
|
229
|
+
config/plugin-entra-id.json
|
|
230
|
+
```
|
|
2967
231
|
|
|
2968
|
-
|
|
2969
|
-
[Fixed]
|
|
232
|
+
The JSON file has two top-level objects:
|
|
2970
233
|
|
|
2971
|
-
|
|
234
|
+
```json
|
|
235
|
+
{
|
|
236
|
+
"scimgateway": { ... },
|
|
237
|
+
"endpoint": { ... }
|
|
238
|
+
}
|
|
239
|
+
```
|
|
2972
240
|
|
|
2973
|
-
|
|
2974
|
-
[Fixed]
|
|
241
|
+
`scimgateway` holds gateway core settings (port, auth, logging, TLS). `endpoint` holds plugin-specific connection details (host, credentials, mappings).
|
|
2975
242
|
|
|
2976
|
-
|
|
243
|
+
---
|
|
2977
244
|
|
|
2978
|
-
|
|
2979
|
-
|
|
245
|
+
### Core Options
|
|
246
|
+
|
|
247
|
+
| Option | Type | Default | Description |
|
|
248
|
+
|---|---|---|---|
|
|
249
|
+
| `port` | number | — | Port the gateway listens on |
|
|
250
|
+
| `localhostonly` | boolean | false | Accept requests only from `127.0.0.1` |
|
|
251
|
+
| `chainingBaseUrl` | string | — | Route requests to another gateway (`http(s)://host:port`) |
|
|
252
|
+
| `idleTimeout` | number | 120 | Seconds before an idle connection is dropped |
|
|
253
|
+
| `scim.version` | string | `"2.0"` | SCIM protocol version: `"1.1"` or `"2.0"` |
|
|
254
|
+
| `scim.skipTypeConvert` | boolean | false | Pass multivalue attributes as-is instead of type-converted objects |
|
|
255
|
+
| `scim.skipMetaLocation` | boolean | false | Omit `meta.location` from responses (useful behind a reverse proxy) |
|
|
256
|
+
| `scim.groupMemberOfUser` | boolean | false | Keep `groups` on the user object instead of managing group membership via `modifyGroup` |
|
|
257
|
+
| `scim.usePutSoftSync` | boolean | false | `PUT` replaces only the attributes in the body; existing attributes are preserved |
|
|
258
|
+
|
|
259
|
+
**Logging options (`log.*`):**
|
|
260
|
+
|
|
261
|
+
| Option | Values | Default | Description |
|
|
262
|
+
|---|---|---|---|
|
|
263
|
+
| `log.loglevel.file` | off, debug, info, warn, error | off | Log level for the plugin log file |
|
|
264
|
+
| `log.loglevel.console` | off, debug, info, warn, error | off | Log level for stdout/stderr |
|
|
265
|
+
| `log.loglevel.push` | debug, info, warn, error | info | Log level for the remote real-time subscriber |
|
|
266
|
+
| `log.logDirectory` | path | `<package>/logs` | Override the default log directory |
|
|
267
|
+
| `log.customMasking` | string[] | `[]` | Additional attribute names to mask in logs, e.g. `["SSN", "weight"]` |
|
|
268
|
+
| `log.colorize` | boolean | true | Colorized console output; set false for plain JSON |
|
|
269
|
+
| `log.maxSize` | number | 20 | Max log file size in MB |
|
|
270
|
+
| `log.maxFiles` | number | 5 | Number of rotated log files to keep |
|
|
271
|
+
|
|
272
|
+
**`scim.skipTypeConvert` example:**
|
|
273
|
+
|
|
274
|
+
With `skipTypeConvert: false` (default), emails are converted to type-keyed objects:
|
|
275
|
+
|
|
276
|
+
```json
|
|
277
|
+
"emails": {
|
|
278
|
+
"work": { "value": "jsmith@example.com", "type": "work" },
|
|
279
|
+
"home": { "value": "", "type": "home", "operation": "delete" }
|
|
280
|
+
}
|
|
281
|
+
```
|
|
2980
282
|
|
|
2981
|
-
|
|
2982
|
-
[Fixed]
|
|
283
|
+
With `skipTypeConvert: true`, the array is passed as-is:
|
|
2983
284
|
|
|
2984
|
-
|
|
285
|
+
```json
|
|
286
|
+
"emails": [
|
|
287
|
+
{ "value": "jsmith@example.com", "type": "work" },
|
|
288
|
+
{ "value": "john.smith.org", "type": "home", "operation": "delete" }
|
|
289
|
+
]
|
|
290
|
+
```
|
|
2985
291
|
|
|
2986
|
-
|
|
2987
|
-
[Fixed]
|
|
292
|
+
---
|
|
2988
293
|
|
|
2989
|
-
|
|
294
|
+
### Authentication
|
|
2990
295
|
|
|
2991
|
-
|
|
2992
|
-
[Improved]
|
|
296
|
+
The `auth` object supports multiple concurrent methods. Set any admin user to `null` to disable that method. Each entry supports:
|
|
2993
297
|
|
|
2994
|
-
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
"objectGUID": {
|
|
2998
|
-
"mapTo": "id",
|
|
2999
|
-
"type": "string"
|
|
3000
|
-
}
|
|
298
|
+
- `readOnly` — if `true`, only `GET` requests are allowed
|
|
299
|
+
- `baseEntities` — restrict this credential to specific baseEntity values (empty array = all)
|
|
3001
300
|
|
|
3002
|
-
|
|
301
|
+
#### Basic Authentication
|
|
3003
302
|
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
303
|
+
```json
|
|
304
|
+
"auth": {
|
|
305
|
+
"basic": [
|
|
306
|
+
{
|
|
307
|
+
"username": "gwadmin",
|
|
308
|
+
"password": "password",
|
|
309
|
+
"readOnly": false,
|
|
310
|
+
"baseEntities": []
|
|
311
|
+
}
|
|
312
|
+
]
|
|
313
|
+
}
|
|
314
|
+
```
|
|
3007
315
|
|
|
3008
|
-
|
|
3009
|
-
[Fixed]
|
|
316
|
+
Cleartext passwords are encrypted on first gateway start.
|
|
3010
317
|
|
|
3011
|
-
|
|
3012
|
-
- 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
|
|
318
|
+
#### Bearer Token (Shared Secret)
|
|
3013
319
|
|
|
3014
|
-
|
|
3015
|
-
[
|
|
320
|
+
```json
|
|
321
|
+
"bearerToken": [
|
|
322
|
+
{
|
|
323
|
+
"token": "my-shared-secret",
|
|
324
|
+
"readOnly": false,
|
|
325
|
+
"baseEntities": []
|
|
326
|
+
}
|
|
327
|
+
]
|
|
328
|
+
```
|
|
3016
329
|
|
|
3017
|
-
|
|
3018
|
-
- plugin-loki supporting type = "undefined"
|
|
330
|
+
Supported by Entra ID provisioning. The token is encrypted on first start.
|
|
3019
331
|
|
|
3020
|
-
|
|
332
|
+
#### JWT (Standard)
|
|
3021
333
|
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
334
|
+
```json
|
|
335
|
+
"bearerJwt": [
|
|
336
|
+
{
|
|
337
|
+
"secret": null,
|
|
338
|
+
"publicKey": "jwt-public-key.pem",
|
|
339
|
+
"wellKnownUri": null,
|
|
340
|
+
"azureTenantId": null,
|
|
341
|
+
"options": {
|
|
342
|
+
"issuer": "https://my-idp.example.com"
|
|
343
|
+
},
|
|
344
|
+
"readOnly": false,
|
|
345
|
+
"baseEntities": []
|
|
346
|
+
}
|
|
347
|
+
]
|
|
348
|
+
```
|
|
3027
349
|
|
|
3028
|
-
|
|
3029
|
-
|
|
350
|
+
- `secret` — HMAC shared secret (encrypted on start)
|
|
351
|
+
- `publicKey` — filename of a PEM file in `config/certs/`
|
|
352
|
+
- `wellKnownUri` — JWKS discovery URL, e.g. `https://keycloak.example.com/realms/my-realm/.well-known/openid-configuration`
|
|
353
|
+
- `azureTenantId` — Entra ID tenant ID; enables Entra-initiated provisioning using JWT validation
|
|
3030
354
|
|
|
3031
|
-
|
|
3032
|
-
[Fixed]
|
|
355
|
+
For Entra ID apps accessing the gateway:
|
|
3033
356
|
|
|
3034
|
-
|
|
357
|
+
```json
|
|
358
|
+
"wellKnownUri": "https://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configuration",
|
|
359
|
+
"options": { "audience": "{application-id}" }
|
|
360
|
+
```
|
|
3035
361
|
|
|
3036
|
-
|
|
3037
|
-
[Fixed]
|
|
362
|
+
#### OAuth Client Credentials
|
|
3038
363
|
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
364
|
+
```json
|
|
365
|
+
"bearerOAuth": [
|
|
366
|
+
{
|
|
367
|
+
"clientId": "my-client-id",
|
|
368
|
+
"clientSecret": "my-client-secret",
|
|
369
|
+
"readOnly": false,
|
|
370
|
+
"baseEntities": []
|
|
371
|
+
}
|
|
372
|
+
]
|
|
373
|
+
```
|
|
3042
374
|
|
|
3043
|
-
|
|
3044
|
-
[Fixed]
|
|
375
|
+
Clients request a token from `POST /oauth/token` (e.g. `http://localhost:8880/oauth/token`).
|
|
3045
376
|
|
|
3046
|
-
|
|
3047
|
-
- Pre and post actions onAddGroups/onRemoveGroups introduced in v.3.2.0 has been withdrawn
|
|
377
|
+
#### Authentication PassThrough
|
|
3048
378
|
|
|
3049
|
-
|
|
379
|
+
```json
|
|
380
|
+
"passThrough": {
|
|
381
|
+
"enabled": true,
|
|
382
|
+
"readOnly": false,
|
|
383
|
+
"baseEntities": []
|
|
384
|
+
}
|
|
385
|
+
```
|
|
3050
386
|
|
|
3051
|
-
|
|
387
|
+
The gateway forwards the raw `Authorization` header to the plugin. The plugin must set `scimgateway.authPassThroughAllowed = true` and implement its own auth handling against the endpoint.
|
|
3052
388
|
|
|
389
|
+
---
|
|
3053
390
|
|
|
3054
|
-
###
|
|
3055
|
-
[Fixed]
|
|
391
|
+
### IP Allow List
|
|
3056
392
|
|
|
3057
|
-
|
|
3058
|
-
- plugin-azure-ad listing groups for user did also include Azure roles
|
|
3059
|
-
- SCIM v2.0 none core schema attributes handling
|
|
3060
|
-
- response not always including correct schemas
|
|
393
|
+
Restrict incoming traffic to specific subnets (CIDR notation). Useful for Entra ID provisioning where you want to accept traffic only from Azure IP ranges:
|
|
3061
394
|
|
|
3062
|
-
|
|
395
|
+
```json
|
|
396
|
+
"ipAllowList": [
|
|
397
|
+
"13.64.151.161/32",
|
|
398
|
+
"13.66.141.64/27",
|
|
399
|
+
"2603:1056:2000::/48"
|
|
400
|
+
]
|
|
401
|
+
```
|
|
3063
402
|
|
|
3064
|
-
|
|
403
|
+
> Azure IP ranges can be downloaded from [azureipranges.azurewebsites.net](https://azureipranges.azurewebsites.net) — search for `AzureActiveDirectory` and copy the `addressPrefixes` array.
|
|
3065
404
|
|
|
3066
|
-
|
|
3067
|
-
[Improved]
|
|
405
|
+
When running behind a load balancer or reverse proxy, the proxy must include the client IP in the `X-Forwarded-For` header.
|
|
3068
406
|
|
|
3069
|
-
|
|
3070
|
-
Configuration example:
|
|
3071
|
-
|
|
3072
|
-
"ipAllowList": [
|
|
3073
|
-
"13.66.60.119/32",
|
|
3074
|
-
"13.66.143.220/30",
|
|
3075
|
-
...
|
|
3076
|
-
"2603:1056:2000::/48",
|
|
3077
|
-
"2603:1057:2::/48"
|
|
3078
|
-
]
|
|
407
|
+
---
|
|
3079
408
|
|
|
3080
|
-
|
|
409
|
+
### TLS & Certificates
|
|
3081
410
|
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
"scim": {
|
|
3085
|
-
"version": "2.0"
|
|
3086
|
-
}
|
|
3087
|
-
|
|
3088
|
-
Old configuration:
|
|
3089
|
-
|
|
3090
|
-
"scim": {
|
|
3091
|
-
"version": "1.1"
|
|
3092
|
-
}
|
|
411
|
+
#### Using PEM files
|
|
3093
412
|
|
|
413
|
+
```json
|
|
414
|
+
"certificate": {
|
|
415
|
+
"key": "key.pem",
|
|
416
|
+
"cert": "cert.pem",
|
|
417
|
+
"ca": "ca.pem"
|
|
418
|
+
}
|
|
419
|
+
```
|
|
3094
420
|
|
|
3095
|
-
|
|
3096
|
-
[Improved]
|
|
421
|
+
Files must be in `config/certs/` or use absolute paths. For multiple CAs: `"ca": ["ca1.pem", "ca2.pem"]`.
|
|
3097
422
|
|
|
3098
|
-
|
|
3099
|
-
- Pre and post actions onAddGroups/onRemoveGroups can be configured and needed logic to be defined in plugin method `pre_post_Action`
|
|
3100
|
-
- Dependencies bump
|
|
423
|
+
**Generate a self-signed certificate:**
|
|
3101
424
|
|
|
3102
|
-
|
|
3103
|
-
|
|
425
|
+
```sh
|
|
426
|
+
openssl req -nodes -newkey rsa:2048 -x509 -sha256 -days 3650 \
|
|
427
|
+
-keyout key.pem -out cert.pem \
|
|
428
|
+
-subj "/O=My Company/OU=Application/CN=SCIM Gateway" \
|
|
429
|
+
-addext "subjectAltName=DNS:localhost,DNS:127.0.0.1,DNS:*.mycompany.com" \
|
|
430
|
+
-addext "extendedKeyUsage=serverAuth" \
|
|
431
|
+
-addext "keyUsage=digitalSignature"
|
|
432
|
+
```
|
|
3104
433
|
|
|
3105
|
-
|
|
434
|
+
#### Using PFX / PKCS#12
|
|
3106
435
|
|
|
3107
|
-
|
|
3108
|
-
|
|
436
|
+
```json
|
|
437
|
+
"pfx": {
|
|
438
|
+
"bundle": "certbundle.pfx",
|
|
439
|
+
"password": "password"
|
|
440
|
+
}
|
|
441
|
+
```
|
|
3109
442
|
|
|
3110
|
-
|
|
443
|
+
> If communicating over localhost only (e.g. gateway installed directly on the provisioning server), you can skip TLS and use `http://localhost:<port>` with `"localhostonly": true`.
|
|
3111
444
|
|
|
3112
|
-
|
|
3113
|
-
[Fixed]
|
|
445
|
+
#### No TLS
|
|
3114
446
|
|
|
3115
|
-
|
|
447
|
+
```json
|
|
448
|
+
"certificate": {
|
|
449
|
+
"key": null,
|
|
450
|
+
"cert": null,
|
|
451
|
+
"ca": null
|
|
452
|
+
}
|
|
453
|
+
```
|
|
3116
454
|
|
|
3117
|
-
|
|
3118
|
-
[Improved]
|
|
455
|
+
---
|
|
3119
456
|
|
|
3120
|
-
|
|
457
|
+
### Email Notifications
|
|
3121
458
|
|
|
3122
|
-
|
|
3123
|
-
[Fixed]
|
|
459
|
+
The `email` section supports alerting on errors and sending mail from plugin code via `scimgateway.sendMail()`.
|
|
3124
460
|
|
|
3125
|
-
|
|
461
|
+
#### Microsoft Exchange Online (OAuth)
|
|
3126
462
|
|
|
3127
|
-
|
|
3128
|
-
|
|
463
|
+
```json
|
|
464
|
+
"email": {
|
|
465
|
+
"auth": {
|
|
466
|
+
"type": "oauth",
|
|
467
|
+
"options": {
|
|
468
|
+
"azureTenantId": "<tenant-id>",
|
|
469
|
+
"clientId": "<client-id>",
|
|
470
|
+
"clientSecret": "<client-secret>"
|
|
471
|
+
}
|
|
472
|
+
},
|
|
473
|
+
"emailOnError": {
|
|
474
|
+
"enabled": true,
|
|
475
|
+
"from": "noreply@example.com",
|
|
476
|
+
"to": "ops-team@example.com",
|
|
477
|
+
"cc": null,
|
|
478
|
+
"subject": "SCIM Gateway error",
|
|
479
|
+
"sendInterval": 15
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
```
|
|
3129
483
|
|
|
3130
|
-
|
|
484
|
+
**Entra ID requirements:**
|
|
485
|
+
1. Grant the application permission `Mail.Send`
|
|
486
|
+
2. Restrict which mailboxes the app can send from via an Exchange `ApplicationAccessPolicy`:
|
|
3131
487
|
|
|
3132
|
-
|
|
3133
|
-
|
|
488
|
+
```powershell
|
|
489
|
+
Install-Module -Name ExchangeOnlineManagement
|
|
490
|
+
Connect-ExchangeOnline
|
|
3134
491
|
|
|
3135
|
-
-
|
|
492
|
+
New-ApplicationAccessPolicy `
|
|
493
|
+
-AppId <AppClientID> `
|
|
494
|
+
-PolicyScopeGroupId <MailEnabledSecurityGroupId> `
|
|
495
|
+
-AccessRight RestrictAccess `
|
|
496
|
+
-Description "Restrict app to specific mailboxes"
|
|
497
|
+
```
|
|
3136
498
|
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
scimgateway.getApi = async (baseEntity, id, apiQuery) => {
|
|
3140
|
-
|
|
3141
|
-
New syntax:
|
|
3142
|
-
|
|
3143
|
-
scimgateway.getApi = async (baseEntity, id, apiQuery, apiObj) => {
|
|
499
|
+
#### Google Workspace Gmail (OAuth)
|
|
3144
500
|
|
|
501
|
+
```json
|
|
502
|
+
"email": {
|
|
503
|
+
"auth": {
|
|
504
|
+
"type": "oauth",
|
|
505
|
+
"options": {
|
|
506
|
+
"serviceAccountKeyFile": "google-service-account.json"
|
|
507
|
+
}
|
|
508
|
+
},
|
|
509
|
+
"emailOnError": {
|
|
510
|
+
"enabled": true,
|
|
511
|
+
"from": "sender@example.com",
|
|
512
|
+
"to": "ops@example.com"
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
```
|
|
3145
516
|
|
|
3146
|
-
|
|
3147
|
-
|
|
517
|
+
**Google setup:**
|
|
518
|
+
1. [Google Cloud Console](https://console.cloud.google.com): create a Service Account → download the JSON key
|
|
519
|
+
2. [Google Admin](https://admin.google.com): Security → API controls → Domain Wide Delegation → add Client ID with scope `https://www.googleapis.com/auth/gmail.send`
|
|
520
|
+
3. Ensure `from` address has a Google Workspace license
|
|
521
|
+
|
|
522
|
+
#### SMTP Auth
|
|
523
|
+
|
|
524
|
+
```json
|
|
525
|
+
"email": {
|
|
526
|
+
"auth": {
|
|
527
|
+
"type": "smtp",
|
|
528
|
+
"options": {
|
|
529
|
+
"host": "smtp.gmail.com",
|
|
530
|
+
"port": 587,
|
|
531
|
+
"username": "user@gmail.com",
|
|
532
|
+
"password": "app-password"
|
|
533
|
+
}
|
|
534
|
+
},
|
|
535
|
+
"emailOnError": {
|
|
536
|
+
"enabled": true,
|
|
537
|
+
"to": "ops@example.com"
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
```
|
|
3148
541
|
|
|
3149
|
-
|
|
3150
|
-
- deprecated modifyGroupMembers - now using modifyGroup
|
|
3151
|
-
- deprecated configuration `scimgateway.scim.customUniqueAttrMapping` - replaced by getObj logic
|
|
3152
|
-
- loglevel=off turns of logging
|
|
3153
|
-
- Auth methods allowing more than one user/object including option for readOnly
|
|
3154
|
-
- Includes latest versions of module dependencies
|
|
3155
|
-
|
|
542
|
+
---
|
|
3156
543
|
|
|
3157
|
-
|
|
544
|
+
### Azure Relay
|
|
3158
545
|
|
|
3159
|
-
|
|
546
|
+
Azure Relay lets the gateway listen for inbound SCIM requests over an outbound HTTPS/443 connection — no inbound firewall rules required.
|
|
3160
547
|
|
|
3161
|
-
|
|
548
|
+
**Cost:** ~$10/month per Hybrid Connection listener.
|
|
3162
549
|
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
550
|
+
**Azure setup:**
|
|
551
|
+
1. Create a Relay namespace in Azure → create a Hybrid Connection entity (one per plugin)
|
|
552
|
+
2. Leave **Requires Client Authorization** unchecked unless your IdP includes a SAS token
|
|
553
|
+
3. Copy the primary key from Shared Access Policies → RootManageSharedaccessKey
|
|
3166
554
|
|
|
3167
|
-
|
|
555
|
+
**Plugin configuration:**
|
|
3168
556
|
|
|
3169
|
-
|
|
3170
|
-
|
|
557
|
+
```json
|
|
558
|
+
"azureRelay": {
|
|
559
|
+
"enabled": true,
|
|
560
|
+
"connectionUrl": "https://<namespace>.servicebus.windows.net/<hybrid-connection>",
|
|
561
|
+
"apiKey": "<primary-key>",
|
|
562
|
+
"keyRule": "RootManageSharedaccessKey"
|
|
563
|
+
}
|
|
564
|
+
```
|
|
3171
565
|
|
|
3172
|
-
|
|
3173
|
-
const displayName = getObj.identifier // gives v2.x compatibility
|
|
566
|
+
The `connectionUrl` becomes the SCIM base URL. Examples:
|
|
3174
567
|
|
|
3175
|
-
|
|
3176
|
-
|
|
568
|
+
```
|
|
569
|
+
GET https://<namespace>.servicebus.windows.net/<hybrid-connection>/Users
|
|
570
|
+
GET https://<namespace>.servicebus.windows.net/<hybrid-connection>/<baseEntity>/Users
|
|
571
|
+
```
|
|
3177
572
|
|
|
3178
|
-
|
|
3179
|
-
getObj = `{ filter: <filterAttribute>, identifier: <identifier> }`
|
|
3180
|
-
e.g: getObj = `{ filter: 'userName', identifier: 'bjensen'}`
|
|
3181
|
-
filter: userName and id must be supported
|
|
573
|
+
Multiple gateway instances sharing the same `connectionUrl` will round-robin load-balance.
|
|
3182
574
|
|
|
3183
|
-
|
|
3184
|
-
getObj = `{ filter: <filterAttribute>, identifier: <identifier> }`
|
|
3185
|
-
e.g: getObj = `{ filter: 'displayName', identifier: 'GroupA' }`
|
|
3186
|
-
filter: displayName and id must be supported
|
|
575
|
+
> Azure Relay does not support remote log subscription.
|
|
3187
576
|
|
|
3188
|
-
|
|
577
|
+
---
|
|
3189
578
|
|
|
3190
|
-
|
|
3191
|
-
`http://localhost:8880/Users?filter=emails.value eq "jsmith@example.com"&attributes=userName,name.givenName`
|
|
3192
|
-
getObj = `{ filter: 'emails.value', identifier: 'jsmith@example.com'}`
|
|
3193
|
-
attributes = `'userName,name.givenName'`
|
|
579
|
+
### Secrets from External Sources
|
|
3194
580
|
|
|
3195
|
-
|
|
581
|
+
All configuration values can be sourced from environment variables, external JSON files, or plain text files. This supports secret managers and Kubernetes secrets.
|
|
3196
582
|
|
|
3197
|
-
|
|
583
|
+
**From environment variables:**
|
|
3198
584
|
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
"password": "password",
|
|
3204
|
-
"readOnly": false
|
|
3205
|
-
}
|
|
3206
|
-
],
|
|
3207
|
-
"bearerToken": [
|
|
3208
|
-
{
|
|
3209
|
-
"token": null,
|
|
3210
|
-
"readOnly": false
|
|
3211
|
-
}
|
|
3212
|
-
],
|
|
3213
|
-
"bearerJwtAzure": [
|
|
3214
|
-
{
|
|
3215
|
-
"tenantIdGUID": null
|
|
3216
|
-
}
|
|
3217
|
-
],
|
|
3218
|
-
"bearerJwt": [
|
|
3219
|
-
{
|
|
3220
|
-
"secret": null,
|
|
3221
|
-
"publicKey": null,
|
|
3222
|
-
"options": {
|
|
3223
|
-
"issuer": null
|
|
3224
|
-
},
|
|
3225
|
-
"readOnly": false
|
|
3226
|
-
}
|
|
3227
|
-
]
|
|
3228
|
-
}
|
|
585
|
+
```json
|
|
586
|
+
"port": "process.env.PORT",
|
|
587
|
+
"log": { "loglevel": { "file": "process.env.LOG_LEVEL_FILE" } }
|
|
588
|
+
```
|
|
3229
589
|
|
|
590
|
+
**From a shared JSON file** (dot-notation keyed by plugin name):
|
|
3230
591
|
|
|
3231
|
-
|
|
3232
|
-
|
|
592
|
+
```json
|
|
593
|
+
"username": "process.file./var/run/vault/secrets.json"
|
|
594
|
+
```
|
|
3233
595
|
|
|
3234
|
-
|
|
596
|
+
Where `secrets.json` contains:
|
|
3235
597
|
|
|
3236
|
-
|
|
3237
|
-
|
|
598
|
+
```json
|
|
599
|
+
{
|
|
600
|
+
"plugin-soap.scimgateway.auth.basic[0].username": "gwadmin",
|
|
601
|
+
"plugin-soap.scimgateway.auth.basic[0].password": "password",
|
|
602
|
+
"plugin-soap.endpoint.username": "superuser",
|
|
603
|
+
"plugin-soap.endpoint.password": "secret"
|
|
604
|
+
}
|
|
605
|
+
```
|
|
3238
606
|
|
|
3239
|
-
|
|
607
|
+
**From a single-value text file:**
|
|
3240
608
|
|
|
609
|
+
```json
|
|
610
|
+
"secret": "process.text./var/run/vault/jwt.secret"
|
|
611
|
+
```
|
|
3241
612
|
|
|
3242
|
-
|
|
3243
|
-
[Improved]
|
|
613
|
+
Where the file contains the raw value: `thisIsSecret`
|
|
3244
614
|
|
|
3245
|
-
|
|
3246
|
-
customMasking may include an array of attributes to be masked
|
|
3247
|
-
e.g. `"customMasking": ["SSN", "weight"]`
|
|
3248
|
-
- Note, configurationfiles must be changed (old syntax still supported)
|
|
3249
|
-
old syntax:
|
|
615
|
+
> Set the environment variable `SEED` to a random string to override default password seeding. This also lets you copy an encrypted configuration file between machines.
|
|
3250
616
|
|
|
3251
|
-
|
|
3252
|
-
"file": "debug",
|
|
3253
|
-
"console": "error"
|
|
3254
|
-
},
|
|
3255
|
-
new syntax:
|
|
617
|
+
---
|
|
3256
618
|
|
|
3257
|
-
|
|
3258
|
-
"loglevel": {
|
|
3259
|
-
"file": "debug",
|
|
3260
|
-
"console": "error"
|
|
3261
|
-
},
|
|
3262
|
-
"customMasking": []
|
|
3263
|
-
},
|
|
3264
|
-
By default SCIM Gateway includes masking of standard attributes like password
|
|
619
|
+
### Remote Log Subscription
|
|
3265
620
|
|
|
3266
|
-
|
|
3267
|
-
[Fixed]
|
|
621
|
+
Stream real-time logs from the gateway to a browser, curl, or custom client.
|
|
3268
622
|
|
|
3269
|
-
|
|
3270
|
-
- AAD as IdP, none gallery app support
|
|
3271
|
-
- Incorrect SCIM 2.0 multivalue converting
|
|
3272
|
-
- plugin-saphana not correctly ported to v2.x
|
|
623
|
+
**Browser:** `https://<host>/logger`
|
|
3273
624
|
|
|
3274
|
-
**
|
|
625
|
+
**curl:**
|
|
3275
626
|
|
|
3276
|
-
|
|
3277
|
-
|
|
627
|
+
```sh
|
|
628
|
+
curl -Ns http://localhost:8880/logger -u gwadmin:password | awk '
|
|
629
|
+
/^data: / {sub(/^data: /,""); printf "%s", $0; last=1; next}
|
|
630
|
+
/^$/ {if (last) print ""; last=0}
|
|
631
|
+
'
|
|
632
|
+
```
|
|
3278
633
|
|
|
3279
|
-
|
|
634
|
+
**Custom client (TypeScript/Bun):**
|
|
3280
635
|
|
|
3281
|
-
|
|
3282
|
-
|
|
636
|
+
```ts
|
|
637
|
+
const username = "gwadmin"
|
|
638
|
+
const password = "password"
|
|
639
|
+
const url = "http://localhost:8880/logger"
|
|
3283
640
|
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
-
|
|
3287
|
-
|
|
641
|
+
const headers = new Headers({
|
|
642
|
+
Authorization: "Basic " + btoa(`${username}:${password}`),
|
|
643
|
+
Accept: "text/event-stream"
|
|
644
|
+
})
|
|
3288
645
|
|
|
3289
|
-
|
|
3290
|
-
|
|
646
|
+
// message handling and custom logic
|
|
647
|
+
const messageHandler = async (message: string) => {
|
|
648
|
+
console.log(message)
|
|
649
|
+
}
|
|
3291
650
|
|
|
3292
|
-
|
|
651
|
+
async function startup() {
|
|
652
|
+
while (true) {
|
|
653
|
+
try {
|
|
654
|
+
const resp = await fetch(url, { headers })
|
|
655
|
+
if (!resp.ok || !resp.body) {
|
|
656
|
+
console.error(`❌ Response error: ${resp.status} ${resp.statusText}`)
|
|
657
|
+
await Bun.sleep(10_000)
|
|
658
|
+
continue
|
|
659
|
+
}
|
|
660
|
+
console.log('✅ Connected — awaiting log events...\n')
|
|
661
|
+
const reader = resp.body.pipeThrough(new TextDecoderStream()).getReader()
|
|
662
|
+
while (true) {
|
|
663
|
+
const { value, done } = await reader.read()
|
|
664
|
+
if (done) break
|
|
665
|
+
if (!value.startsWith('data: ')) continue
|
|
666
|
+
const i = value.indexOf("\n\n")
|
|
667
|
+
if (i < 1) continue
|
|
668
|
+
messageHandler(value.slice(6, i))
|
|
669
|
+
}
|
|
670
|
+
console.error("⚠️ Connection closed")
|
|
671
|
+
await Bun.sleep(10_000)
|
|
672
|
+
} catch (err: any) {
|
|
673
|
+
console.error("❌ Connection error:", err?.message || err)
|
|
674
|
+
await Bun.sleep(10_000)
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}
|
|
3293
678
|
|
|
3294
|
-
|
|
679
|
+
startup()
|
|
680
|
+
```
|
|
3295
681
|
|
|
3296
|
-
|
|
682
|
+
Set a dedicated read-only credential for log collection:
|
|
683
|
+
|
|
684
|
+
```json
|
|
685
|
+
"auth": {
|
|
686
|
+
"basic": [
|
|
687
|
+
{ "username": "gwadmin", "password": "password", "readOnly": false },
|
|
688
|
+
{ "username": "gwread", "password": "password", "readOnly": true }
|
|
689
|
+
],
|
|
690
|
+
"bearerToken": [
|
|
691
|
+
{ "token": "log-secret", "readOnly": true }
|
|
692
|
+
]
|
|
693
|
+
}
|
|
694
|
+
```
|
|
3297
695
|
|
|
3298
|
-
|
|
3299
|
-
[Fixed]
|
|
696
|
+
Set push log level (default `info`):
|
|
3300
697
|
|
|
3301
|
-
|
|
3302
|
-
|
|
698
|
+
```json
|
|
699
|
+
"log": { "loglevel": { "push": "debug" } }
|
|
700
|
+
```
|
|
3303
701
|
|
|
3304
|
-
|
|
3305
|
-
[Fixed]
|
|
702
|
+
You can also scope log output to a specific `baseEntity`: `https://<host>/<baseEntity>/logger`
|
|
3306
703
|
|
|
3307
|
-
|
|
3308
|
-
- Not allowing plugins to return password
|
|
3309
|
-
- Colorize option now automatically turned off when using stdout/stderr redirect (configuration file `loglevel.colorize` is not needed)
|
|
704
|
+
---
|
|
3310
705
|
|
|
3311
|
-
###
|
|
3312
|
-
[Fixed]
|
|
706
|
+
### Gateway Chaining
|
|
3313
707
|
|
|
3314
|
-
|
|
708
|
+
Chain multiple gateways: `gateway1 → gateway2 → gateway3 → endpoint`. Each gateway validates authorization and forwards the request unless PassThrough is enabled.
|
|
3315
709
|
|
|
3316
|
-
|
|
710
|
+
**gateway1 configuration:**
|
|
3317
711
|
|
|
3318
|
-
|
|
3319
|
-
|
|
712
|
+
```json
|
|
713
|
+
{
|
|
714
|
+
"scimgateway": {
|
|
715
|
+
"chainingBaseUrl": "https://gateway2:8880",
|
|
716
|
+
"auth": {
|
|
717
|
+
"passThrough": {
|
|
718
|
+
"enabled": false
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
```
|
|
3320
724
|
|
|
3321
|
-
|
|
3322
|
-
[Fixed]
|
|
725
|
+
In chaining mode the plugin binary is only used for initialization. You can simplify the plugin to the mandatory section only:
|
|
3323
726
|
|
|
3324
|
-
|
|
3325
|
-
|
|
727
|
+
```ts
|
|
728
|
+
// start - mandatory plugin initialization
|
|
729
|
+
import { ScimGateway } from 'scimgateway'
|
|
730
|
+
const scimgateway = new ScimGateway()
|
|
731
|
+
const config = scimgateway.getConfig()
|
|
732
|
+
scimgateway.authPassThroughAllowed = true // and configuration file having: scimgateway.auth.passThrough=true
|
|
733
|
+
scimgateway.pluginAndOrFilterEnabled = false
|
|
734
|
+
// end - mandatory plugin initialization
|
|
735
|
+
```
|
|
3326
736
|
|
|
3327
|
-
|
|
3328
|
-
[Improved]
|
|
737
|
+
---
|
|
3329
738
|
|
|
3330
|
-
|
|
739
|
+
### HelperRest
|
|
3331
740
|
|
|
3332
|
-
|
|
741
|
+
`HelperRest` provides a unified REST client for plugins with built-in support for authentication, retries, failover, and proxies.
|
|
3333
742
|
|
|
3334
|
-
|
|
3335
|
-
|
|
743
|
+
```ts
|
|
744
|
+
helper.doRequest(baseEntity, method, path, body?, ctx?, options?)
|
|
745
|
+
```
|
|
3336
746
|
|
|
3337
|
-
|
|
3338
|
-
|
|
747
|
+
- `baseEntity` — `'undefined'` if not used; must match a key in `endpoint.entity`
|
|
748
|
+
- `method` — `GET`, `POST`, `PATCH`, `PUT`, `DELETE`
|
|
749
|
+
- `path` — full URL or path appended to `baseUrl`
|
|
750
|
+
- `body` — optional request body
|
|
751
|
+
- `ctx` — optional, passes the `Authorization` header for PassThrough auth
|
|
752
|
+
- `options` — optional overrides for connection settings
|
|
753
|
+
|
|
754
|
+
**Endpoint connection structure:**
|
|
755
|
+
|
|
756
|
+
```json
|
|
757
|
+
"endpoint": {
|
|
758
|
+
"entity": {
|
|
759
|
+
"undefined": {
|
|
760
|
+
"connection": {
|
|
761
|
+
"baseUrls": ["https://api.example.com"],
|
|
762
|
+
"auth": {
|
|
763
|
+
"type": "basic|oauth|token|bearer|oauthSamlBearer|oauthJwtBearer",
|
|
764
|
+
"options": { ... }
|
|
765
|
+
},
|
|
766
|
+
"options": {
|
|
767
|
+
"headers": {},
|
|
768
|
+
"tls": {} // // files located in ./config/certs
|
|
769
|
+
},
|
|
770
|
+
"proxy": {}
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
```
|
|
3339
776
|
|
|
3340
|
-
|
|
3341
|
-
"version": "1.1",
|
|
3342
|
-
"customSchema": null
|
|
3343
|
-
},
|
|
3344
|
-
Note, "1.1" is default, if using "2.0" the new syntax must be used.
|
|
777
|
+
#### Basic Auth
|
|
3345
778
|
|
|
779
|
+
```json
|
|
780
|
+
"connection": {
|
|
781
|
+
"baseUrls": ["https://localhost:8880"],
|
|
782
|
+
"auth": {
|
|
783
|
+
"type": "basic",
|
|
784
|
+
"options": {
|
|
785
|
+
"username": "gwadmin",
|
|
786
|
+
"password": "password"
|
|
787
|
+
}
|
|
788
|
+
},
|
|
789
|
+
"options": {
|
|
790
|
+
"tls": { "rejectUnauthorized": false, "ca": "ca.pem" }
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
```
|
|
3346
794
|
|
|
3347
|
-
|
|
3348
|
-
|
|
795
|
+
#### Entra ID — Client Secret
|
|
796
|
+
|
|
797
|
+
```json
|
|
798
|
+
"connection": {
|
|
799
|
+
"baseUrls": [],
|
|
800
|
+
"auth": {
|
|
801
|
+
"type": "oauth",
|
|
802
|
+
"options": {
|
|
803
|
+
"azureTenantId": "<tenant-id>",
|
|
804
|
+
"clientId": "<client-id>",
|
|
805
|
+
"clientSecret": "<client-secret>"
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
```
|
|
3349
810
|
|
|
3350
|
-
|
|
3351
|
-
|
|
811
|
+
#### Entra ID — Certificate Secret
|
|
812
|
+
|
|
813
|
+
```json
|
|
814
|
+
"connection": {
|
|
815
|
+
"baseUrls": [],
|
|
816
|
+
"auth": {
|
|
817
|
+
"type": "oauthJwtBearer",
|
|
818
|
+
"options": {
|
|
819
|
+
"azureTenantId": "<tenant-id>",
|
|
820
|
+
"clientId": "<client-id>",
|
|
821
|
+
"tls": {
|
|
822
|
+
"key": "key.pem",
|
|
823
|
+
"cert": "cert.pem"
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
```
|
|
3352
829
|
|
|
830
|
+
#### Entra ID — Federated Credentials (no secrets)
|
|
831
|
+
|
|
832
|
+
```json
|
|
833
|
+
"connection": {
|
|
834
|
+
"baseUrls": [],
|
|
835
|
+
"auth": {
|
|
836
|
+
"type": "oauthJwtBearer",
|
|
837
|
+
"options": {
|
|
838
|
+
"azureTenantId": "<tenant-id>",
|
|
839
|
+
"fedCred": {
|
|
840
|
+
"issuer": "<https://FQDN-scimgateway>", // https://scimgateway.my-company.com
|
|
841
|
+
"subject": "<entra-application-object-id>",
|
|
842
|
+
"name": "<entra-fed-cred-unique-name>" // plugin-entra-id
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
```
|
|
3353
848
|
|
|
3354
|
-
|
|
3355
|
-
**[MAJOR]**
|
|
849
|
+
> The `issuer`, `subject`, and `name` must match the Federated Credentials configured in Entra ID (scenario: "Other issuer"). The gateway must be reachable from the internet at the `issuer` URL, or use Azure Relay for outbound-only communication.
|
|
3356
850
|
|
|
3357
|
-
|
|
3358
|
-
- Koa replacing Express
|
|
3359
|
-
- Some log enhancements
|
|
3360
|
-
- Deprecated cipher methods have been replaced
|
|
3361
|
-
- Plugin restful (REST) and
|
|
3362
|
-
- forwardinc (SOAP) includes failover logic based on endpoints defined in array baseUrls/baseServiceEndpoints.
|
|
851
|
+
#### General OAuth (Client Credentials)
|
|
3363
852
|
|
|
3364
|
-
|
|
853
|
+
```json
|
|
854
|
+
"connection": {
|
|
855
|
+
"baseUrls": ["https://api.example.com"],
|
|
856
|
+
"auth": {
|
|
857
|
+
"type": "oauth",
|
|
858
|
+
"options": {
|
|
859
|
+
"tokenUrl": "https://idp.example.com/oauth/token",
|
|
860
|
+
"clientId": "<client-id>",
|
|
861
|
+
"clientSecret": "<client-secret>"
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
```
|
|
3365
866
|
|
|
3366
|
-
|
|
867
|
+
Use VS Code IntelliSense on `HelperRest.doRequest()` for full type and option documentation.
|
|
3367
868
|
|
|
3368
|
-
|
|
3369
|
-
npm install scimgateway@latest
|
|
869
|
+
---
|
|
3370
870
|
|
|
3371
|
-
|
|
871
|
+
### Single Binary Deployment
|
|
3372
872
|
|
|
3373
|
-
|
|
3374
|
-
- Rest and SOAP using `doRequest` method having endpoint failover logic through array `baseUrls/baseServiceEndpoints` defined in corresponding plugin configuration file.
|
|
3375
|
-
- Additional argument `attributes` included in exploreUsers and exploreGroups method
|
|
3376
|
-
- Proxy configuration includes option for user/password
|
|
3377
|
-
- Encrypted passwords in configuration files needs to be reset to clear text passwords
|
|
873
|
+
Compile a plugin to a self-contained native binary (no Bun/Node runtime required):
|
|
3378
874
|
|
|
875
|
+
```sh
|
|
876
|
+
cd my-scimgateway
|
|
3379
877
|
|
|
3380
|
-
|
|
3381
|
-
|
|
878
|
+
bun build --compile ./lib/plugin-loki.ts \
|
|
879
|
+
--target=bun-darwin-arm64 \
|
|
880
|
+
--outfile ./build/plugin-loki
|
|
3382
881
|
|
|
3383
|
-
|
|
882
|
+
# See https://bun.sh/docs/bundler/executables#cross-compile-to-other-platforms for all targets
|
|
3384
883
|
|
|
3385
|
-
|
|
884
|
+
cp -r ./config ./build
|
|
3386
885
|
|
|
3387
|
-
|
|
886
|
+
cd build
|
|
887
|
+
./plugin-loki # binary name must match the config file prefix
|
|
888
|
+
```
|
|
3388
889
|
|
|
890
|
+
The `config/` directory must be in the same folder as the binary.
|
|
3389
891
|
|
|
3390
|
-
|
|
3391
|
-
[Fixed]
|
|
892
|
+
---
|
|
3392
893
|
|
|
3393
|
-
|
|
894
|
+
## Running the Gateway
|
|
3394
895
|
|
|
3395
|
-
###
|
|
3396
|
-
[Improved]
|
|
896
|
+
### Manual Startup
|
|
3397
897
|
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
-
|
|
3401
|
-
-
|
|
3402
|
-
|
|
898
|
+
```sh
|
|
899
|
+
# All three are equivalent:
|
|
900
|
+
bun c:\my-scimgateway
|
|
901
|
+
bun c:\my-scimgateway\index.ts
|
|
902
|
+
bun . # from the package root
|
|
903
|
+
```
|
|
3403
904
|
|
|
3404
|
-
|
|
905
|
+
Press `Ctrl+C` to stop.
|
|
3405
906
|
|
|
3406
|
-
|
|
3407
|
-
old syntax:
|
|
907
|
+
### Windows Task Scheduler
|
|
3408
908
|
|
|
3409
|
-
|
|
3410
|
-
new syntax:
|
|
909
|
+
Open Task Scheduler (`taskschd.msc`), right-click "Task Scheduler Library" → "Create Task":
|
|
3411
910
|
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
911
|
+
| Tab | Setting |
|
|
912
|
+
|---|---|
|
|
913
|
+
| General | Name: `SCIM Gateway`; User: `SYSTEM`; Run with highest privileges |
|
|
914
|
+
| Triggers | Begin the task: At startup |
|
|
915
|
+
| Actions | Start a program: `<bun-install-path>\bun.exe`; Arguments: `c:\my-scimgateway` |
|
|
916
|
+
| Settings | Stop the task if it runs longer than: **Disabled** |
|
|
3417
917
|
|
|
3418
|
-
|
|
3419
|
-
|
|
918
|
+
**Verify:**
|
|
919
|
+
1. Right-click → Run → confirm process appears in Task Manager
|
|
920
|
+
2. Right-click → End → confirm process disappears
|
|
921
|
+
3. Reboot → confirm auto-start
|
|
3420
922
|
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
### v1.0.13
|
|
3424
|
-
[Fixed]
|
|
923
|
+
---
|
|
3425
924
|
|
|
3426
|
-
|
|
925
|
+
## Docker
|
|
3427
926
|
|
|
3428
|
-
|
|
927
|
+
### Single Image
|
|
3429
928
|
|
|
3430
|
-
|
|
929
|
+
```sh
|
|
930
|
+
mkdir /opt/my-scimgateway
|
|
931
|
+
cd /opt/my-scimgateway
|
|
932
|
+
bun init -y
|
|
933
|
+
bun install scimgateway
|
|
934
|
+
bun pm trust scimgateway
|
|
935
|
+
cp ./config/docker/* .
|
|
936
|
+
cp ./config/docker/.dockerignore .
|
|
3431
937
|
|
|
3432
|
-
|
|
3433
|
-
|
|
938
|
+
# Build
|
|
939
|
+
docker build --platform linux/amd64 --force-rm=true -t my-scimgateway:1.0.0 .
|
|
3434
940
|
|
|
3435
|
-
|
|
941
|
+
# Create and run
|
|
942
|
+
docker create --init --ulimit memlock=-1:-1 --name my-scimgateway -p 8880:8880 my-scimgateway:1.0.0
|
|
943
|
+
docker start my-scimgateway
|
|
944
|
+
docker stop my-scimgateway
|
|
945
|
+
```
|
|
3436
946
|
|
|
3437
|
-
|
|
3438
|
-
[Fixed]
|
|
947
|
+
Consider passing `-e SEED=<random>` at create time if using encrypted configuration files.
|
|
3439
948
|
|
|
3440
|
-
|
|
949
|
+
### Docker Compose
|
|
3441
950
|
|
|
951
|
+
Pre-requisites: `docker-compose` and `docker-ce`
|
|
3442
952
|
|
|
3443
|
-
|
|
3444
|
-
|
|
953
|
+
```sh
|
|
954
|
+
mkdir /opt/my-scimgateway && cd /opt/my-scimgateway
|
|
955
|
+
bun init -y && bun install scimgateway && bun pm trust scimgateway
|
|
956
|
+
cp ./config/docker/* .
|
|
3445
957
|
|
|
3446
|
-
|
|
958
|
+
adduser scimgateway
|
|
959
|
+
mkdir /home/scimgateway/config
|
|
3447
960
|
|
|
3448
|
-
|
|
3449
|
-
|
|
961
|
+
# Copy your plugin config to the persistent volume
|
|
962
|
+
scp config/plugin-loki.json scimgateway@host:/home/scimgateway/config/
|
|
3450
963
|
|
|
3451
|
-
-
|
|
964
|
+
docker-compose up --build -d
|
|
965
|
+
```
|
|
3452
966
|
|
|
3453
|
-
|
|
3454
|
-
|
|
967
|
+
Provided compose files:
|
|
968
|
+
|
|
969
|
+
| File | Purpose |
|
|
970
|
+
|---|---|
|
|
971
|
+
| `docker-compose.yml` | Main compose file — set exposed ports and environment here |
|
|
972
|
+
| `Dockerfile` | Main image definition |
|
|
973
|
+
| `DataDockerfile` | Volume mapping |
|
|
974
|
+
| `docker-compose-debug.yml` | Attach VS Code debugger |
|
|
975
|
+
| `docker-compose-mssql.yml` | Compose example including an MSSQL container |
|
|
976
|
+
|
|
977
|
+
**Common Docker commands:**
|
|
978
|
+
|
|
979
|
+
```sh
|
|
980
|
+
docker ps # list running containers
|
|
981
|
+
docker images # list images
|
|
982
|
+
docker logs scimgateway # view logs
|
|
983
|
+
docker exec scimgateway <command> # run command in container
|
|
984
|
+
docker-compose stop / start # stop / restart
|
|
985
|
+
docker-compose -f docker-compose.yml \
|
|
986
|
+
-f docker-compose-debug.yml up -d # debug mode (VS Code)
|
|
987
|
+
|
|
988
|
+
# Upgrade — remove old container and dangling images first
|
|
989
|
+
docker rm scimgateway
|
|
990
|
+
docker rm $(docker ps -a -q)
|
|
991
|
+
docker rmi $(docker images -q -f "dangling=true")
|
|
992
|
+
```
|
|
3455
993
|
|
|
3456
|
-
|
|
3457
|
-
- Option for error notifications by email
|
|
994
|
+
---
|
|
3458
995
|
|
|
3459
|
-
|
|
996
|
+
## Identity Provider Integration
|
|
3460
997
|
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
### v1.0.7
|
|
3465
|
-
[Improved]
|
|
998
|
+
### Microsoft Entra ID as IdP
|
|
3466
999
|
|
|
3467
|
-
|
|
3468
|
-
- Minor log cosmetics
|
|
1000
|
+
Entra ID can automatically provision users to SCIM Gateway, which then forwards to your endpoint plugin.
|
|
3469
1001
|
|
|
3470
|
-
|
|
3471
|
-
[Fixed]
|
|
1002
|
+
**Plugin configuration requirements:**
|
|
3472
1003
|
|
|
3473
|
-
|
|
1004
|
+
```json
|
|
1005
|
+
"scimgateway": {
|
|
1006
|
+
"scim": { "version": "2.0" },
|
|
1007
|
+
"auth": {
|
|
1008
|
+
"bearerToken": [
|
|
1009
|
+
{ "token": "shared-secret" }
|
|
1010
|
+
],
|
|
1011
|
+
"bearerJwt": [
|
|
1012
|
+
{ "azureTenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" }
|
|
1013
|
+
]
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
```
|
|
3474
1017
|
|
|
3475
|
-
|
|
3476
|
-
|
|
1018
|
+
- `token` must match the "Secret Token" in the Entra ID provisioning configuration
|
|
1019
|
+
- `azureTenantId` must match the Entra tenant ID
|
|
1020
|
+
- If "Secret Token" is left blank in Entra ID, JWT (`azureTenantId`) is used automatically
|
|
3477
1021
|
|
|
3478
|
-
|
|
3479
|
-
- After more than 3 invalid auth attempts, response will be delayed to prevent brute force
|
|
1022
|
+
**Azure Portal paths:**
|
|
3480
1023
|
|
|
3481
|
-
|
|
1024
|
+
```
|
|
1025
|
+
Secret Token: Microsoft Entra ID → Enterprise Apps → <App> → Provisioning → Secret Token
|
|
1026
|
+
Tenant ID: Microsoft Entra ID → Overview → Tenant ID
|
|
1027
|
+
Attribute maps: Enterprise Apps → <App> → Provisioning → Edit attribute mappings → Mappings
|
|
1028
|
+
```
|
|
3482
1029
|
|
|
3483
|
-
|
|
1030
|
+
**Required attribute mappings:**
|
|
3484
1031
|
|
|
3485
|
-
|
|
1032
|
+
| Object | Source | Target | Matching |
|
|
1033
|
+
|---|---|---|---|
|
|
1034
|
+
| User | `userPrincipalName` | `userName` | Precedence #1 |
|
|
1035
|
+
| Group | `displayName` | `displayName` | Precedence #1 |
|
|
1036
|
+
| Group | `members` | `members` | — |
|
|
3486
1037
|
|
|
3487
|
-
|
|
3488
|
-
|
|
1038
|
+
**Entra ID behavior notes:**
|
|
1039
|
+
- Deleting a user sends `PATCH { "active": "False" }` rather than a `DELETE` request
|
|
1040
|
+
- Entra ID periodically checks for non-existent users/groups as a keep-alive
|
|
1041
|
+
- Entra ID checks existence before creating (no full user explore like some other IdPs)
|
|
3489
1042
|
|
|
3490
|
-
|
|
1043
|
+
---
|
|
3491
1044
|
|
|
3492
|
-
|
|
1045
|
+
### Symantec/Broadcom Identity Manager as IdP
|
|
3493
1046
|
|
|
3494
|
-
|
|
1047
|
+
Use **SCIM version `"1.1"`** for Symantec/Broadcom Provisioning.
|
|
3495
1048
|
|
|
3496
|
-
|
|
3497
|
-
[Fixed]
|
|
1049
|
+
In Provisioning Manager use endpoint type `SCIM (DYN Endpoint)` or create a custom type.
|
|
3498
1050
|
|
|
3499
|
-
|
|
1051
|
+
**Example endpoint configuration (plugin-loki):**
|
|
3500
1052
|
|
|
3501
|
-
|
|
3502
|
-
|
|
1053
|
+
```
|
|
1054
|
+
Endpoint Name: Loki-8880
|
|
1055
|
+
User Name: gwadmin
|
|
1056
|
+
Password: password
|
|
1057
|
+
SCIM Authentication Method: HTTP Basic Authentication
|
|
1058
|
+
SCIM Based URL: http://localhost:8880
|
|
1059
|
+
or: http://localhost:8880/<baseEntity>
|
|
1060
|
+
```
|
|
3503
1061
|
|
|
3504
|
-
-
|
|
1062
|
+
The `baseEntity` parameter enables multi-tenant setups — create multiple endpoints with the same base URL but different `baseEntity` values (e.g. `/client-a`, `/client-b`). Define per-entity connection attributes in the plugin JSON configuration.
|
|
3505
1063
|
|
|
3506
|
-
|
|
3507
|
-
[Fixed]
|
|
1064
|
+
---
|
|
3508
1065
|
|
|
3509
|
-
|
|
1066
|
+
## Entra ID Provisioning Plugin
|
|
3510
1067
|
|
|
3511
|
-
|
|
3512
|
-
[Improved]
|
|
1068
|
+
`plugin-entra-id` provisions users and groups to Microsoft Entra ID via the Microsoft Graph API.
|
|
3513
1069
|
|
|
3514
|
-
|
|
3515
|
-
- Includes latest versions of module dependencies
|
|
3516
|
-
- Module hdb (for SapHana) and saml is not included by default anymore and therefore have to be manually installed if needed.
|
|
1070
|
+
### Entra ID App Registration
|
|
3517
1071
|
|
|
3518
|
-
**
|
|
3519
|
-
|
|
1072
|
+
1. **Microsoft Entra ID → App registrations → New registration**
|
|
1073
|
+
- Name: `SCIM Gateway Inbound`
|
|
1074
|
+
- Accounts: This organizational directory only
|
|
1075
|
+
2. **Overview** — copy Application (client) ID and Directory (tenant) ID
|
|
1076
|
+
3. **Certificates & secrets → New client secret** — copy the value
|
|
1077
|
+
4. **API permissions → Add → Microsoft Graph → Application permissions:**
|
|
1078
|
+
- `Directory.ReadWriteAll`
|
|
1079
|
+
- `Organization.ReadWrite.All`
|
|
1080
|
+
- Additional for signInActivity, roles, licenses and access packages:
|
|
1081
|
+
- `AuditLog.Read.All` *(only if using `map.user.signInActivity`; requires Entra ID Premium)*
|
|
1082
|
+
- `RoleEligibilitySchedule.ReadWrite.Directory` *(PIM Eligible roles; only if using `map.user.roles`)*
|
|
1083
|
+
- `RoleManagement.ReadWrite.Directory` *(PIM Permanent roles; only if using `map.user.roles`)*
|
|
1084
|
+
- `EntitlementManagement.ReadWrite.All` *(IGA Access Packages; only if using `map.user.entitlements`)*
|
|
1085
|
+
- Click **Grant admin consent**
|
|
1086
|
+
5. **Entra ID → Roles and administrators → User administrator → Add assignments** — add `SCIM Gateway Inbound`
|
|
3520
1087
|
|
|
3521
|
-
|
|
1088
|
+
> For full access to admin users, assign the `Global Administrator` role. The `User Administrator` role has limitations on users with admin roles.
|
|
3522
1089
|
|
|
3523
|
-
|
|
3524
|
-
...
|
|
3525
|
-
let ret = {
|
|
3526
|
-
'Resources' : [],
|
|
3527
|
-
'totalResults' : null
|
|
3528
|
-
}
|
|
3529
|
-
...
|
|
3530
|
-
ret.Resources.push(userGroup)
|
|
3531
|
-
...
|
|
3532
|
-
callback(null, ret)
|
|
1090
|
+
> `signInActivity, roles, licenses and access packages` requires permissions above. Note, `ReadWrite` can be replaced with `Read` if management is not required. **Remove any mapping configuration whose conditions are not met** — Minimum read permissions are validated at startup.
|
|
3533
1091
|
|
|
1092
|
+
### Plugin Configuration
|
|
3534
1093
|
|
|
3535
|
-
|
|
1094
|
+
**`index.ts`:**
|
|
3536
1095
|
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
arrRet.push(userGroup)
|
|
3542
|
-
...
|
|
3543
|
-
callback(null, arrRet)
|
|
1096
|
+
```ts
|
|
1097
|
+
import './lib/plugin-entra-id.ts'
|
|
1098
|
+
export {}
|
|
1099
|
+
```
|
|
3544
1100
|
|
|
3545
|
-
|
|
3546
|
-
[Improved]
|
|
1101
|
+
**`config/plugin-entra-id.json` (key sections):**
|
|
3547
1102
|
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
1103
|
+
```json
|
|
1104
|
+
{
|
|
1105
|
+
"scimgateway": {
|
|
1106
|
+
"scim": { "version": "2.0", "skipTypeConvert": true}, // skipTypeConvert if Access Package management (entitlements)
|
|
1107
|
+
"auth": {
|
|
1108
|
+
"basic": [
|
|
1109
|
+
{
|
|
1110
|
+
"username": "gwadmin",
|
|
1111
|
+
"password": "password",
|
|
1112
|
+
"readOnly": false
|
|
1113
|
+
}
|
|
1114
|
+
]
|
|
1115
|
+
}
|
|
1116
|
+
},
|
|
1117
|
+
"endpoint": {
|
|
1118
|
+
"entity": {
|
|
1119
|
+
"undefined": {
|
|
1120
|
+
"connection": {
|
|
1121
|
+
"baseUrls": [],
|
|
1122
|
+
"auth": {
|
|
1123
|
+
"type": "oauth",
|
|
1124
|
+
"options": {
|
|
1125
|
+
"azureTenantId": "<Tenant ID>",
|
|
1126
|
+
"clientId": "<Application ID>",
|
|
1127
|
+
"clientSecret": "<Secret value>"
|
|
1128
|
+
}
|
|
1129
|
+
},
|
|
1130
|
+
"proxy": {
|
|
1131
|
+
"host": null,
|
|
1132
|
+
"username": null,
|
|
1133
|
+
"password": null
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
```
|
|
3557
1141
|
|
|
1142
|
+
`clientSecret` and any proxy passwords are automatically encrypted on the first connection.
|
|
3558
1143
|
|
|
3559
|
-
|
|
3560
|
-
[Improved]
|
|
1144
|
+
**Multi-tenant setup:**
|
|
3561
1145
|
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
1146
|
+
```json
|
|
1147
|
+
"endpoint": {
|
|
1148
|
+
"entity": {
|
|
1149
|
+
"undefined": { ... },
|
|
1150
|
+
"client-a": { ... },
|
|
1151
|
+
"client-b": { ... }
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
```
|
|
3567
1155
|
|
|
3568
|
-
|
|
1156
|
+
### Using with Symantec/Broadcom (ConnectorXpress)
|
|
3569
1157
|
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
- Copy existing scimgateway.oauth.accesstoken value to new auth.bearer.token value
|
|
3575
|
-
- Delete scimgateway.username
|
|
3576
|
-
- Delete scimgateway.password
|
|
3577
|
-
- Delete scimgateway.oauth
|
|
1158
|
+
1. Start SCIM Gateway with `plugin-entra-id`
|
|
1159
|
+
2. Open ConnectorXpress → Setup Data Sources → Add Layer7 → Base URL: `http://localhost:8881`
|
|
1160
|
+
3. Import the endpoint type metadata: `node_modules/scimgateway/config/resources/Azure - ScimGateway.xml`
|
|
1161
|
+
4. Create endpoint type `Azure - ScimGateway`
|
|
3578
1162
|
|
|
1163
|
+
**Provisioning Manager endpoint example:**
|
|
3579
1164
|
|
|
3580
|
-
|
|
3581
|
-
|
|
1165
|
+
```
|
|
1166
|
+
Endpoint Name: AzureAD-8881
|
|
1167
|
+
User Name: gwadmin
|
|
1168
|
+
Password: password
|
|
1169
|
+
SCIM Authentication Method: HTTP Basic Authentication
|
|
1170
|
+
SCIM Based URL: http://localhost:8881
|
|
1171
|
+
```
|
|
3582
1172
|
|
|
3583
|
-
|
|
3584
|
-
- `config\docker` includes docker configuration examples
|
|
3585
|
-
**Thanks to [@cwatsonc](https://github.com/cwatsonc) and [@visualjeff](https://github.com/visualjeff)**
|
|
1173
|
+
---
|
|
3586
1174
|
|
|
1175
|
+
## API Gateway
|
|
3587
1176
|
|
|
3588
|
-
|
|
3589
|
-
[Improved]
|
|
1177
|
+
SCIM Gateway doubles as a general API gateway via the `/api` path (no SCIM schema required):
|
|
3590
1178
|
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
1179
|
+
```
|
|
1180
|
+
GET /api
|
|
1181
|
+
GET /api?<query>
|
|
1182
|
+
GET /api/{id}
|
|
1183
|
+
POST /api + body
|
|
1184
|
+
PUT /api/{id} + body
|
|
1185
|
+
PATCH /api/{id} + body
|
|
1186
|
+
DELETE /api/{id}
|
|
1187
|
+
```
|
|
3594
1188
|
|
|
3595
|
-
|
|
1189
|
+
With `baseEntity`: `/<baseEntity>/api`
|
|
3596
1190
|
|
|
3597
|
-
|
|
3598
|
-
- Encrypted passwords needs to be reset to clear text passwords
|
|
3599
|
-
- Start SCIM Gateway and passwords will become encrypted
|
|
1191
|
+
A public (unauthenticated) API path is also available:
|
|
3600
1192
|
|
|
3601
|
-
|
|
3602
|
-
|
|
1193
|
+
```
|
|
1194
|
+
GET /pub/api?model=Tesla
|
|
1195
|
+
```
|
|
3603
1196
|
|
|
3604
|
-
-
|
|
3605
|
-
This plugin now replace previous `plugin-testmode`
|
|
3606
|
-
**Thanks to [@visualjeff](https://github.com/visualjeff)**
|
|
3607
|
-
- Minor code/comment reorganizations in provided plugins
|
|
3608
|
-
- Minor adjustments to multi-value logic introduced in v0.4.0
|
|
1197
|
+
See `lib/plugin-api.ts` for a complete example.
|
|
3609
1198
|
|
|
3610
|
-
|
|
1199
|
+
---
|
|
3611
1200
|
|
|
3612
|
-
|
|
3613
|
-
- Edit index.js, replace tesmode with loki
|
|
1201
|
+
## Building Custom Plugins
|
|
3614
1202
|
|
|
3615
|
-
|
|
3616
|
-
[Fixed]
|
|
1203
|
+
**Recommended editor:** [Visual Studio Code](https://code.visualstudio.com/) — provides IntelliSense for all `scimgateway` methods.
|
|
3617
1204
|
|
|
3618
|
-
|
|
1205
|
+
### Setup
|
|
3619
1206
|
|
|
3620
|
-
|
|
3621
|
-
|
|
1207
|
+
1. Copy the closest matching example plugin (e.g. `lib/plugin-mssql.ts` + `config/plugin-mssql.json`) and rename both with your prefix (e.g. `plugin-mine`)
|
|
1208
|
+
2. Set a unique `port` in `config/plugin-mine.json`
|
|
1209
|
+
3. Add your plugin to `index.ts`: `import './lib/plugin-mine.ts'`
|
|
1210
|
+
4. Start the gateway and verify
|
|
3622
1211
|
|
|
3623
|
-
|
|
3624
|
-
- Automated tests run on Travis-ci.org (click on build badge)
|
|
3625
|
-
- **Thanks to [@visualjeff](https://github.com/visualjeff)**
|
|
1212
|
+
### Mandatory Plugin Initialization
|
|
3626
1213
|
|
|
1214
|
+
```ts
|
|
1215
|
+
// start - mandatory plugin initialization
|
|
1216
|
+
import { ScimGateway, HelperRest } from 'scimgateway'
|
|
1217
|
+
const scimgateway = new ScimGateway()
|
|
1218
|
+
const helper = new HelperRest(scimgateway) // include if using REST
|
|
1219
|
+
const config = scimgateway.getConfig()
|
|
1220
|
+
scimgateway.authPassThroughAllowed = false
|
|
1221
|
+
scimgateway.pluginAndOrFilterEnabled = false
|
|
1222
|
+
// end - mandatory plugin initialization
|
|
1223
|
+
```
|
|
3627
1224
|
|
|
3628
|
-
|
|
3629
|
-
[Fixed]
|
|
1225
|
+
### Implementation Order
|
|
3630
1226
|
|
|
3631
|
-
|
|
1227
|
+
Build and test incrementally:
|
|
3632
1228
|
|
|
3633
|
-
|
|
3634
|
-
|
|
1229
|
+
1. **`getGroups`** — return empty response to disable group handling initially (see `plugin-saphana` for a groups-free example)
|
|
1230
|
+
2. **`getUsers`** — retrieve all accounts and a single account by filter
|
|
1231
|
+
3. **`createUser`** — create new accounts
|
|
1232
|
+
4. **`deleteUser`** — delete accounts
|
|
1233
|
+
5. **`modifyUser`** — update accounts
|
|
1234
|
+
6. **`getGroups`** — re-enable with real logic if groups are supported
|
|
1235
|
+
7. **`createGroup`**, **`deleteGroup`**, **`modifyGroup`** — group lifecycle
|
|
3635
1236
|
|
|
3636
|
-
|
|
3637
|
-
- Module dependencies updated to latest versions
|
|
1237
|
+
### Plugin Methods
|
|
3638
1238
|
|
|
3639
|
-
**
|
|
1239
|
+
**SCIM methods (implement in your plugin):**
|
|
3640
1240
|
|
|
3641
|
-
|
|
1241
|
+
| Method | Description |
|
|
1242
|
+
|---|---|
|
|
1243
|
+
| `scimgateway.getUsers()` | Retrieve users (all or filtered) |
|
|
1244
|
+
| `scimgateway.createUser()` | Create a new user |
|
|
1245
|
+
| `scimgateway.deleteUser()` | Delete a user |
|
|
1246
|
+
| `scimgateway.modifyUser()` | Update user attributes |
|
|
1247
|
+
| `scimgateway.getGroups()` | Retrieve groups (all or filtered) |
|
|
1248
|
+
| `scimgateway.createGroup()` | Create a new group |
|
|
1249
|
+
| `scimgateway.deleteGroup()` | Delete a group |
|
|
1250
|
+
| `scimgateway.modifyGroup()` | Update group members/attributes |
|
|
1251
|
+
| `scimgateway.getEntitlements()` | Retrieve entitlements (e.g. Entra ID licenses) |
|
|
1252
|
+
| `scimgateway.getRoles()` | Retrieve roles (e.g. Entra ID PIM roles) |
|
|
3642
1253
|
|
|
3643
|
-
|
|
3644
|
-
[Fixed]
|
|
1254
|
+
**API Gateway methods:**
|
|
3645
1255
|
|
|
3646
|
-
|
|
1256
|
+
| Method | Path |
|
|
1257
|
+
|---|---|
|
|
1258
|
+
| `scimgateway.getApi()` | `GET /api` |
|
|
1259
|
+
| `scimgateway.postApi()` | `POST /api` |
|
|
1260
|
+
| `scimgateway.putApi()` | `PUT /api/{id}` |
|
|
1261
|
+
| `scimgateway.patchApi()` | `PATCH /api/{id}` |
|
|
1262
|
+
| `scimgateway.deleteApi()` | `DELETE /api/{id}` |
|
|
1263
|
+
| `scimgateway.publicApi()` | `GET /pub/api` (no auth) |
|
|
3647
1264
|
|
|
3648
|
-
|
|
3649
|
-
[Improved]
|
|
1265
|
+
Use VS Code IntelliSense on any method for inline documentation and type information.
|
|
3650
1266
|
|
|
3651
|
-
|
|
1267
|
+
### Custom Schemas
|
|
3652
1268
|
|
|
3653
|
-
|
|
3654
|
-
[Improved]
|
|
1269
|
+
If plugin use `endpointMapper`, SCIM schemas will be generated based on configured mapping.
|
|
3655
1270
|
|
|
3656
|
-
|
|
3657
|
-
- SCIM version 2.0 is supported
|
|
3658
|
-
- Create group is supported
|
|
1271
|
+
To use custom SCIM schemas, copy `node_modules/scimgateway/lib/scimdef-v2.json` (or `scimdef-v1.json`) to `lib/` and edit as needed. The gateway will use your version when it detects the file.
|
|
3659
1272
|
|
|
3660
|
-
|
|
1273
|
+
---
|
|
3661
1274
|
|
|
3662
|
-
|
|
1275
|
+
## License
|
|
3663
1276
|
|
|
1277
|
+
MIT © [Jarle Elshaug](https://www.elshaug.xyz)
|
|
3664
1278
|
|
|
1279
|
+
---
|
|
3665
1280
|
|
|
3666
|
-
|
|
3667
|
-
[Fixed]
|
|
1281
|
+
## Change Log
|
|
3668
1282
|
|
|
3669
|
-
|
|
1283
|
+
### v6.2.2
|
|
1284
|
+
- **[Improved]** `plugin-entra-id` now supports Entra ID IGA Access Packages. For required API permissions, see [Entra ID App Registration](#entra-id-app-registration)
|
|
3670
1285
|
|
|
3671
|
-
###
|
|
3672
|
-
|
|
1286
|
+
### v6.2.1
|
|
1287
|
+
- `HelperRest`: fixed minor log cosmetics introduced in v6.2.0
|
|
3673
1288
|
|
|
3674
|
-
|
|
3675
|
-
-
|
|
1289
|
+
### v6.2.0
|
|
1290
|
+
- **[Fixed]** `HelperRest`: failed on Bun v1.3.14 due to stricter Fetch standards compliance
|
|
1291
|
+
- **[Improved]** New `plugin-generic` replaces `plugin-scim`. Uses `endpointMapper` with the new `valueMap` option for group allowlisting and name mapping. Default config uses one-to-one SCIM mapping with plugin-loki as the target endpoint.
|
|
1292
|
+
- **[Improved]** `endpointMapper` now supports `valueMap`:
|
|
1293
|
+
|
|
1294
|
+
```json
|
|
1295
|
+
"map": {
|
|
1296
|
+
"group": {
|
|
1297
|
+
"displayName": {
|
|
1298
|
+
"mapTo": "displayName",
|
|
1299
|
+
"type": "string",
|
|
1300
|
+
"valueMap": {
|
|
1301
|
+
"outboundEndpointGrp1": "inboundScimGrp1",
|
|
1302
|
+
"Employees": "Admins"
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
```
|
|
3676
1308
|
|
|
3677
|
-
|
|
1309
|
+
Clients only see and manage the SCIM-named groups (`inboundScimGrp1`, `Admins`), mapped to their endpoint counterparts (`outboundEndpointGrp1`, `Employees`). Useful for allowlisting specific groups or supporting different inbound/outbound names.
|
|
3678
1310
|
|
|
3679
|
-
|
|
1311
|
+
### v6.1.20
|
|
1312
|
+
- `plugin-entra-id`: roles introduced in v6.1.19 were missing when retrieving a single user
|
|
3680
1313
|
|
|
1314
|
+
### v6.1.19
|
|
1315
|
+
- **[Fixed]** SCIM v2.0 ResourceType endpoint schemas using incorrect id
|
|
1316
|
+
- **[Improved]** `GET /Roles` and `GET /Entitlements` endpoint support, with user management via SCIM `roles` and `entitlements` attributes
|
|
1317
|
+
- **[Improved]** `plugin-entra-id`: `entitlements` for Entra ID licenses (read-only); `roles` for Permanent and Eligible PIM roles (full management)
|
|
1318
|
+
- PIM Eligible roles: requires `RoleEligibilitySchedule.ReadWrite.All`
|
|
1319
|
+
- PIM Permanent roles: requires `RoleManagement.ReadWrite.Directory`
|
|
1320
|
+
- Remove `map.user.roles` if above conditions are not met
|
|
1321
|
+
- `skipSignInActivity` option (v6.1.17) no longer used; `signInActivity` and PIM role permissions are validated at startup
|
|
3681
1322
|
|
|
3682
|
-
###
|
|
3683
|
-
|
|
1323
|
+
### v6.1.18
|
|
1324
|
+
- `createUser` and `modifyUser` now return the full user object, ensuring returned data reflects what was modified even when the endpoint hasn't internally synced yet
|
|
3684
1325
|
|
|
3685
|
-
|
|
3686
|
-
-
|
|
1326
|
+
### v6.1.17
|
|
1327
|
+
- `plugin-entra-id`: fixed broken `filter=userName eq "user_upn"` introduced in v6.1.11 when using updated config with `map.user.signInActivity`
|
|
1328
|
+
- `plugin-entra-id`: new option `endpoint.entity.[baseEntity].skipSignInActivity = true` to exclude `signInActivity` (requires Entra ID Premium + `AuditLog.Read.All`)
|
|
3687
1329
|
|
|
3688
|
-
|
|
1330
|
+
### v6.1.16
|
|
1331
|
+
- `plugin-entra-id`: `GET /Entitlements` now uses `derivedIncludes` with full recursive expansion
|
|
3689
1332
|
|
|
3690
|
-
|
|
1333
|
+
### v6.1.15
|
|
1334
|
+
- `plugin-entra-id`: fixed `filter=entitlements pr`
|
|
3691
1335
|
|
|
3692
|
-
###
|
|
3693
|
-
|
|
1336
|
+
### v6.1.14
|
|
1337
|
+
- Support for filter `attribute not pr`
|
|
1338
|
+
- Dependencies bump
|
|
3694
1339
|
|
|
3695
|
-
|
|
1340
|
+
### v6.1.13
|
|
1341
|
+
- `plugin-entra-id`: `signInActivity` attributes are now filterable
|
|
3696
1342
|
|
|
3697
|
-
###
|
|
3698
|
-
|
|
1343
|
+
### v6.1.12
|
|
1344
|
+
- Filter operator `pr` (presence) now forwarded to plugins (previously rejected)
|
|
1345
|
+
- `plugin-entra-id`: handles `pr` filter on entitlements
|
|
3699
1346
|
|
|
3700
|
-
|
|
1347
|
+
### v6.1.11
|
|
1348
|
+
- **[Fixed]** Incorrect schema generation when using `endpointMapper` (regression from v6.1.6)
|
|
1349
|
+
- **[Improved]** New `GET /Entitlements` endpoint and `scimgateway.getEntitlements()` method
|
|
1350
|
+
- `plugin-entra-id`: user license information via `entitlements`; remove `map.user.signInActivity` if Entra ID Premium is unavailable
|
|
3701
1351
|
|
|
3702
|
-
###
|
|
3703
|
-
|
|
1352
|
+
### v6.1.10
|
|
1353
|
+
- `plugin-entra-id`: group membership now includes nested (transitive) groups (`direct` and `indirect`)
|
|
1354
|
+
- Fixed missing Docker files: `config/docker/.dockerignore` and `docker-compose-mssql.yml`
|
|
3704
1355
|
|
|
3705
|
-
|
|
3706
|
-
-
|
|
3707
|
-
- plugin-forwardinc includes examples of baseEntity, custom soap header and signed saml assertion
|
|
3708
|
-
- Support groups defined on user object "group member of user"
|
|
3709
|
-
- New module dependendcies included: saml, async and callsite
|
|
1356
|
+
### v6.1.9
|
|
1357
|
+
- `createUser`/`createGroup` responses now correctly include the generated ID
|
|
3710
1358
|
|
|
1359
|
+
### v6.1.8 / v6.1.7
|
|
1360
|
+
- Fixed incorrect masking of secrets in request info log messages
|
|
1361
|
+
- `plugin-entra-id`: fixed edge case where `createUser` with a manager could fail
|
|
3711
1362
|
|
|
3712
|
-
|
|
1363
|
+
### v6.1.6
|
|
1364
|
+
- Fixed `plugin-loki` and `plugin-mongodb` returning empty results when using extension schema attributes in search
|
|
1365
|
+
- Auth failure due to `readOnly` now returns HTTP 405 instead of 401
|
|
1366
|
+
- `postinstall` ensures `"type": "module"` is set in `package.json`
|
|
1367
|
+
- `endpointMapper` now generates a custom schema; supports `"x-agent-schema"` for AI MCP tool instructions
|
|
3713
1368
|
|
|
3714
|
-
|
|
1369
|
+
### v6.1.5
|
|
1370
|
+
- Complex filtering (`and`/`or`) handled by the gateway using the plugin's simple filter logic
|
|
1371
|
+
- `modifyGroup` now returns HTTP 204 instead of 200
|
|
1372
|
+
- New `/auth` endpoint for validating external authentication
|
|
1373
|
+
- `plugin-entra-id`: supports `sw` (startsWith) filter
|
|
3715
1374
|
|
|
3716
|
-
###
|
|
3717
|
-
|
|
1375
|
+
### v6.1.4
|
|
1376
|
+
- Fixed OData paging in `plugin-entra-id` and `helper-rest` — missing users/groups/members in large directories
|
|
1377
|
+
- Fixed incomplete group membership when paging not fully iterated
|
|
3718
1378
|
|
|
3719
|
-
|
|
1379
|
+
### v6.1.3
|
|
1380
|
+
- Azure Relay: improved recovery on failure
|
|
1381
|
+
- `plugin-ldap`: improvements for Active Directory and `objectGUID`/`mS-DS-ConsistencyGuid`
|
|
1382
|
+
- `modifyGroup`: adding an existing member or removing a non-existent member now returns 200 OK instead of an error
|
|
3720
1383
|
|
|
3721
|
-
###
|
|
3722
|
-
|
|
1384
|
+
### v6.1.2
|
|
1385
|
+
- Fixed SMTP mail failure caused by an updated dependency
|
|
1386
|
+
- Fixed `endpointMapper` when `mapTo` contained multiple comma-separated attributes including a multivalued one
|
|
3723
1387
|
|
|
3724
|
-
|
|
1388
|
+
### v6.1.1
|
|
1389
|
+
- `plugin-ldap`: fixed race condition where `createUser` immediately followed by `readUser` could fail on some systems (e.g. Samba AD)
|
|
1390
|
+
- Final info log message now includes full JSON serialization (durationMs, status, requestBody, responseBody, …)
|
|
3725
1391
|
|
|
3726
|
-
###
|
|
3727
|
-
|
|
1392
|
+
### v6.1.0
|
|
1393
|
+
- `tsx` included — SCIM Gateway now runs as ES module (TypeScript) in Node.js: `node --import=tsx ./index.ts`
|
|
1394
|
+
- Simplified mandatory plugin initialization using static `import`
|
|
1395
|
+
- `index.ts` updated to use static imports
|
|
1396
|
+
- Bun binary builds now supported (see [Single Binary Deployment](#single-binary-deployment))
|
|
1397
|
+
|
|
1398
|
+
### v6.0.0 — Major
|
|
1399
|
+
- API method response bodies returned as-is (previously wrapped in `{ result: <content> }`) — **clients parsing responses must be updated**
|
|
1400
|
+
- New `scimgateway.publicApi()` for unauthenticated `/pub/api` routes
|
|
1401
|
+
- `bearerJwtAzure.tenantIdGUID` replaced by `bearerJwt.azureTenantId` — **existing configurations must be updated**
|
|
1402
|
+
|
|
1403
|
+
### v5.x — Previous Major Series
|
|
1404
|
+
For v5.x change history (Bun/TypeScript migration, Azure Relay, Bulk Operations, SCIM Stream, HelperRest, Docker, email OAuth, and more), see the [GitHub commit history](https://github.com/jelhub/scimgateway/commits/master/).
|