ldap-rest 1.0.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/bin/index.mjs +8 -7
  2. package/dist/abstract/ldapFlat.js +1 -1
  3. package/dist/abstract/plugin.js +1 -1
  4. package/dist/abstract/twakePlugin.js +1 -1
  5. package/dist/bin/index.js +1 -1
  6. package/dist/config/args.js +1 -1
  7. package/dist/config/schema.js +1 -1
  8. package/dist/lib/changeContext.js +1 -1
  9. package/dist/lib/entitySchema/validator.js +1 -0
  10. package/dist/lib/expressFormatedResponses.js +1 -1
  11. package/dist/lib/health.js +1 -0
  12. package/dist/lib/instanceProviders.js +1 -1
  13. package/dist/lib/ldapActions.js +1 -1
  14. package/dist/lib/metrics.js +1 -0
  15. package/dist/lib/requestContext.js +1 -1
  16. package/dist/lib/schemaFile.js +1 -1
  17. package/dist/lib/shutdown.js +1 -0
  18. package/dist/lib/staticFiles.js +1 -0
  19. package/dist/lib/storage/store.js +1 -1
  20. package/dist/lib/utils.js +1 -1
  21. package/dist/logger/winston.js +1 -1
  22. package/dist/plugins/auth/crowdsec.js +1 -1
  23. package/dist/plugins/auth/openidconnect.js +1 -1
  24. package/dist/plugins/demo/helloworld.js +1 -1
  25. package/dist/plugins/ldap/bulkImport.js +1 -1
  26. package/dist/plugins/ldap/flatGeneric.js +1 -1
  27. package/dist/plugins/ldap/groups.js +1 -1
  28. package/dist/plugins/ldap/organizations.js +1 -1
  29. package/dist/plugins/metrics.js +1 -0
  30. package/dist/plugins/rabbitmq.js +1 -1
  31. package/dist/plugins/scim/scim.js +1 -1
  32. package/dist/plugins/static.js +1 -1
  33. package/dist/plugins/storage/file.js +1 -1
  34. package/dist/plugins/storage/postgres.js +1 -1
  35. package/dist/plugins/storage/valkey.js +1 -1
  36. package/dist/plugins/storage.js +1 -1
  37. package/dist/plugins/twake/calendar.js +1 -1
  38. package/dist/plugins/twake/clouderyProvision.js +1 -1
  39. package/dist/plugins/twake/cozyProvision.js +1 -1
  40. package/dist/plugins/twake/drive.js +1 -1
  41. package/dist/plugins/twake/james.js +1 -1
  42. package/dist/plugins/twake/migrationProxy.js +1 -0
  43. package/dist/plugins/weblogs.js +1 -1
  44. package/dist/src/abstract/ldapFlat.d.ts +3 -13
  45. package/dist/src/abstract/plugin.d.ts +20 -0
  46. package/dist/src/abstract/twakePlugin.d.ts +23 -1
  47. package/dist/src/bin/index.d.ts +46 -1
  48. package/dist/src/config/args.d.ts +17 -1
  49. package/dist/src/lib/changeContext.d.ts +11 -0
  50. package/dist/src/lib/entitySchema/validator.d.ts +64 -0
  51. package/dist/src/lib/expressFormatedResponses.d.ts +19 -0
  52. package/dist/src/lib/health.d.ts +63 -0
  53. package/dist/src/lib/instanceProviders.d.ts +4 -0
  54. package/dist/src/lib/ldapActions.d.ts +28 -0
  55. package/dist/src/lib/metrics.d.ts +44 -0
  56. package/dist/src/lib/requestContext.d.ts +40 -0
  57. package/dist/src/lib/schemaFile.d.ts +10 -0
  58. package/dist/src/lib/shutdown.d.ts +20 -0
  59. package/dist/src/lib/staticFiles.d.ts +33 -0
  60. package/dist/src/lib/storage/store.d.ts +8 -0
  61. package/dist/src/lib/utils.d.ts +9 -0
  62. package/dist/src/logger/winston.d.ts +4 -0
  63. package/dist/src/plugins/ldap/groups.d.ts +18 -3
  64. package/dist/src/plugins/ldap/organizations.d.ts +3 -5
  65. package/dist/src/plugins/metrics.d.ts +17 -0
  66. package/dist/src/plugins/rabbitmq.d.ts +37 -1
  67. package/dist/src/plugins/scim/scim.d.ts +2 -0
  68. package/dist/src/plugins/static.d.ts +28 -0
  69. package/dist/src/plugins/storage/file.d.ts +4 -0
  70. package/dist/src/plugins/storage/postgres.d.ts +7 -14
  71. package/dist/src/plugins/storage/valkey.d.ts +2 -15
  72. package/dist/src/plugins/storage.d.ts +8 -0
  73. package/dist/src/plugins/twake/drive.d.ts +8 -0
  74. package/dist/src/plugins/twake/james.d.ts +2 -0
  75. package/dist/src/plugins/twake/migrationProxy.d.ts +71 -0
  76. package/docs/client-development/api/reference.md +5 -9
  77. package/docs/client-development/api/rest-api.md +4 -10
  78. package/docs/client-development/schemas/README.md +60 -21
  79. package/docs/plugin-development/README.md +15 -13
  80. package/docs/plugin-development/dependencies.md +8 -0
  81. package/docs/plugin-development/hooks.md +1 -1
  82. package/docs/usage/README.md +1 -0
  83. package/docs/usage/configuration.md +57 -15
  84. package/docs/usage/operations.md +193 -0
  85. package/docs/usage/plugins/README.md +2 -0
  86. package/docs/usage/plugins/auth/authz-per-branch.md +2 -1
  87. package/docs/usage/plugins/integrations/README.md +8 -4
  88. package/docs/usage/plugins/integrations/mail-migration.md +102 -0
  89. package/docs/usage/plugins/integrations/scim.md +10 -2
  90. package/docs/usage/plugins/ldap/bulk-import.md +3 -1
  91. package/docs/usage/plugins/ldap/flat-generic.md +5 -2
  92. package/docs/usage/plugins/ldap/on-change.md +2 -1
  93. package/docs/usage/plugins/ldap/organizations.md +7 -7
  94. package/docs/usage/plugins/utilities/metrics.md +21 -0
  95. package/docs/usage/plugins/utilities/static.md +81 -34
  96. package/docs/usage/plugins/utilities/storage.md +7 -0
  97. package/docs/usage/plugins/utilities/weblogs.md +51 -30
  98. package/docs/usage/upgrading.md +97 -0
  99. package/package.json +11 -2
  100. package/static/schemas/example/README.md +1 -0
@@ -11,20 +11,30 @@ The `static` plugin serves static files (HTML, CSS, JS, JSON, images) from a dir
11
11
  ```bash
12
12
  --plugin core/static \
13
13
  --static-path ./static \
14
- --static-prefix /static
14
+ --static-name static
15
15
  ```
16
16
 
17
17
  **Environment Variables:**
18
18
 
19
19
  ```bash
20
20
  DM_STATIC_PATH="./static"
21
- DM_STATIC_PREFIX="/static"
21
+ DM_STATIC_NAME="static"
22
22
  ```
23
23
 
24
24
  ### Parameters
25
25
 
26
26
  - `--static-path`: Directory containing static files (required)
27
- - `--static-prefix`: URL prefix for serving files (default: `/static`)
27
+ - `--static-name`: the path the files are served under, without a slash
28
+ around it (default: `static`, for `/static/…`). Slashes around it are left
29
+ out and an empty value is `static`; a segment that is empty, `.` or `..`,
30
+ or that holds what a URL encodes or Express reads as route syntax (a
31
+ space, a letter outside ASCII, `:`, `*`, `?`, `#`, `%`, brackets, quotes…), stops the server at startup
32
+ - `--static-csp` (`DM_STATIC_CSP`): the `Content-Security-Policy` of the
33
+ files it serves, default `frame-ancestors 'self'`; `off` sends none. See
34
+ [Security headers](#security-headers)
35
+ - `--static-frame-options` (`DM_STATIC_FRAME_OPTIONS`): the
36
+ `X-Frame-Options` of the files it serves, default `SAMEORIGIN`; `off`
37
+ sends none
28
38
 
29
39
  ## How It Works
30
40
 
@@ -105,7 +115,7 @@ Configuration keys are transformed:
105
115
  | `__LDAP_BASE__` | `--ldap-base` | `dc=example,dc=com` |
106
116
  | `__LDAP_TOP_ORGANIZATION__` | `--ldap-top-organization` | `ou=organization,dc=example,dc=com` |
107
117
  | `__API_PREFIX__` | `--api-prefix` | `/api` |
108
- | `__STATIC_PREFIX__` | `--static-prefix` | `/static` |
118
+ | `__STATIC_NAME__` | `--static-name` | `static` |
109
119
 
110
120
  ## Use Cases
111
121
 
@@ -137,17 +147,17 @@ Serve web-based LDAP management interface:
137
147
  ```bash
138
148
  --plugin core/static \
139
149
  --static-path ./static \
140
- --static-prefix /
150
+ --static-name app
141
151
  ```
142
152
 
143
153
  Files:
144
154
 
145
155
  ```
146
156
  ./static/
147
- index.html → http://localhost:8081/
148
- css/app.css → http://localhost:8081/css/app.css
149
- js/ldap-tree.js → http://localhost:8081/js/ldap-tree.js
150
- schemas/users.json → http://localhost:8081/schemas/users.json
157
+ index.html → http://localhost:8081/app/
158
+ css/app.css → http://localhost:8081/app/css/app.css
159
+ js/ldap-tree.js → http://localhost:8081/app/js/ldap-tree.js
160
+ schemas/users.json → http://localhost:8081/app/schemas/users.json
151
161
  ```
152
162
 
153
163
  ### 3. API Documentation
@@ -157,7 +167,7 @@ Serve OpenAPI/Swagger documentation:
157
167
  ```bash
158
168
  --plugin core/static \
159
169
  --static-path ./api-docs \
160
- --static-prefix /docs
170
+ --static-name docs
161
171
  ```
162
172
 
163
173
  ```
@@ -172,7 +182,7 @@ GET /docs/swagger-ui/ → ./api-docs/swagger-ui/index.html
172
182
  ```bash
173
183
  --plugin core/static \
174
184
  --static-path ./public \
175
- --static-prefix /static
185
+ --static-name static
176
186
  ```
177
187
 
178
188
  **Directory structure:**
@@ -198,25 +208,17 @@ http://localhost:8081/static/js/app.js
198
208
 
199
209
  ### Example 2: Root Path Serving
200
210
 
201
- ```bash
202
- --plugin core/static \
203
- --static-path ./web \
204
- --static-prefix /
205
- ```
206
-
207
- Serves files from root:
208
-
209
- ```
210
- http://localhost:8081/index.html
211
- http://localhost:8081/about.html
212
- ```
211
+ Not supported: the files are always served under `/<static-name>/`, and
212
+ the schema routes, which replace the placeholders, are built on that name.
213
+ To show an application at `/`, have the reverse proxy redirect `/` to it,
214
+ for instance to `/static/index.html`.
213
215
 
214
216
  ### Example 3: Schema Deployment
215
217
 
216
218
  ```bash
217
219
  --plugin core/static \
218
220
  --static-path ./static \
219
- --static-prefix /static \
221
+ --static-name static \
220
222
  --ldap-base "dc=example,dc=com"
221
223
  ```
222
224
 
@@ -240,12 +242,7 @@ http://localhost:8081/about.html
240
242
 
241
243
  ### Example 4: Multiple Static Plugins
242
244
 
243
- Not directly supported, but you can nest directories:
244
-
245
- ```bash
246
- --plugin core/static \
247
- --static-path ./static
248
- ```
245
+ One plugin serves several applications from sub-directories:
249
246
 
250
247
  ```
251
248
  ./static/
@@ -257,14 +254,27 @@ Not directly supported, but you can nest directories:
257
254
  users.json
258
255
  ```
259
256
 
260
- Access via:
261
-
262
257
  ```
263
258
  /static/docs/index.html
264
259
  /static/app/index.html
265
260
  /static/schemas/users.json
266
261
  ```
267
262
 
263
+ A second directory takes a second instance, loaded under a name of its own
264
+ with its own `static_name` and `static_path`
265
+ ([`module:name:{json}`](../auth/README.md#serving-several-populations-from-one-server)):
266
+
267
+ ```bash
268
+ --plugin core/static --static-path ./static \
269
+ --plugin 'core/static:console:{"static_name":"console","static_path":"./console"}'
270
+ ```
271
+
272
+ Give them paths that do not nest: `console` and `console/app` would have the
273
+ first one answer requests meant for the second. The plugins that announce a
274
+ schema URL (groups, organizations, flat entities, SCIM) ask every instance,
275
+ the one registered as `static` first, and leave out one whose path lies under
276
+ an earlier one's, or holds it.
277
+
268
278
  ## Security Considerations
269
279
 
270
280
  ### Path Traversal
@@ -298,6 +308,43 @@ For restricted access:
298
308
  2. Implement custom middleware
299
309
  3. Use reverse proxy with access controls
300
310
 
311
+ ### Security headers
312
+
313
+ The files served here are applications, an administration console among
314
+ them. So that no other origin frames one signed in (clickjacking), another
315
+ sub-domain or port of the same site included, the responses under the prefix
316
+ carry:
317
+
318
+ ```
319
+ Content-Security-Policy: frame-ancestors 'self'
320
+ X-Frame-Options: SAMEORIGIN
321
+ ```
322
+
323
+ `X-Frame-Options` is for browsers that ignore `frame-ancestors`. A page that
324
+ must be framed by another origin names it:
325
+
326
+ ```bash
327
+ --static-csp "frame-ancestors 'self' https://portal.example.com"
328
+ --static-frame-options off
329
+ ```
330
+
331
+ A full policy can be given the same way, for instance
332
+ `default-src 'self'; frame-ancestors 'none'`, as long as the applications
333
+ served allow it: the policy applies to every file under the prefix. One
334
+ written on several lines, as a YAML block holds it, is sent as one line; a
335
+ value a header cannot hold stops the server at startup. An empty value keeps
336
+ the default, as a compose file expands an unset `${VAR:-}` to one; `off`
337
+ sends no header (`false` in a plugin's JSON override), when the reverse
338
+ proxy sets its own. Keeping both is harmless as long as they agree.
339
+
340
+ A redirect or a 404 that Express answers itself (a directory without its
341
+ slash, a missing file) carries `Content-Security-Policy: default-src 'none'`
342
+ instead; `X-Frame-Options`, unless set to `off`, still keeps it from being
343
+ framed, and it shows nothing to click.
344
+
345
+ Every response of the server, API routes included, also carries
346
+ `X-Content-Type-Options: nosniff`, and none says `X-Powered-By: Express`.
347
+
301
348
  ## MIME Types
302
349
 
303
350
  Express automatically sets Content-Type based on file extension:
@@ -374,9 +421,9 @@ GET /static/index.html → 404
374
421
  --static-path ./static
375
422
  ```
376
423
 
377
- 3. Verify prefix matches URL:
424
+ 3. Verify that the name matches the first segment of the URL:
378
425
  ```bash
379
- --static-prefix /static
426
+ --static-name static
380
427
  ```
381
428
 
382
429
  ### Problem: Placeholders Not Replaced
@@ -110,6 +110,13 @@ answer "absent" with a warning and writes fail at once instead of waiting.
110
110
  does not answer or a package that is not installed; the server starts anyway,
111
111
  and every operation tries to connect again.
112
112
 
113
+ ## Readiness
114
+
115
+ `GET /readyz` lists the plugin as `degraded` when the backend does not
116
+ answer; the `ldap` backend keeps its records in the directory the probe
117
+ checks on its own, see
118
+ [operations](../../operations.md#what-the-shipped-plugins-report).
119
+
113
120
  ## Expiry
114
121
 
115
122
  Two rules the backends do not get to reinterpret:
@@ -18,6 +18,9 @@ No additional configuration required.
18
18
 
19
19
  ### Request Logging
20
20
 
21
+ Each line carries the `requestId` of the answer's `X-Request-Id`, see
22
+ [operations](../../operations.md#request-id).
23
+
21
24
  Each request is logged when it arrives:
22
25
 
23
26
  ```
@@ -31,26 +34,31 @@ Each response is logged when completed at **notice** level (between info and war
31
34
  ```json
32
35
  {
33
36
  "level": "notice",
34
- "message": "GET /api/v1/ldap/users 200 45ms",
35
- "user": "admin",
36
- "method": "GET",
37
- "url": "/api/v1/ldap/users",
38
- "status": 200,
39
- "responseTime": "45ms"
37
+ "message": {
38
+ "requestId": "6effd260-b079-4335-b727-544189ed33a6",
39
+ "method": "GET",
40
+ "url": "/api/v1/ldap/users",
41
+ "status": 200,
42
+ "duration": 45,
43
+ "ip": "10.0.9.12",
44
+ "user": "admin"
45
+ },
46
+ "requestId": "6effd260-b079-4335-b727-544189ed33a6",
47
+ "timestamp": "2026-10-26T18:07:03.286Z"
40
48
  }
41
49
  ```
42
50
 
43
51
  ## Log Fields
44
52
 
45
- | Field | Description | Example |
46
- | -------------- | ------------------------------- | --------------------------------- |
47
- | `message` | Summary line | `GET /api/v1/ldap/users 200 45ms` |
48
- | `user` | Authenticated user (if any) | `admin` |
49
- | `method` | HTTP method | `GET`, `POST`, `PUT`, `DELETE` |
50
- | `url` | Full URL including query params | `/api/v1/ldap/users?match=*` |
51
- | `status` | HTTP status code | `200`, `404`, `500` |
52
- | `responseTime` | Request duration | `45ms`, `123ms` |
53
- | `error` | Error message (if applicable) | `Connection timeout` |
53
+ | Field | Description | Example |
54
+ | ----------- | ------------------------------- | ------------------------------ |
55
+ | `user` | Authenticated user (if any) | `admin` |
56
+ | `requestId` | The answer's `X-Request-Id` | `6effd260-b079-…` |
57
+ | `method` | HTTP method | `GET`, `POST`, `PUT`, `DELETE` |
58
+ | `url` | Full URL including query params | `/api/v1/ldap/users?match=*` |
59
+ | `status` | HTTP status code | `200`, `404`, `500` |
60
+ | `duration` | Request duration, in ms | `45`, `123` |
61
+ | `error` | Error message (if applicable) | `Connection timeout` |
54
62
 
55
63
  ## Enriching the Log Line From Another Plugin
56
64
 
@@ -77,6 +85,7 @@ Output:
77
85
  "level": "notice",
78
86
  "message": {
79
87
  "uids": ["jdoe", "asmith"],
88
+ "requestId": "6effd260-b079-4335-b727-544189ed33a6",
80
89
  "method": "POST",
81
90
  "url": "/api/_getldapentries",
82
91
  "status": 200,
@@ -89,7 +98,7 @@ Output:
89
98
 
90
99
  Notes:
91
100
 
92
- - Core fields (`method`, `url`, `status`, `duration`, `ip`, `user`, `error`)
101
+ - Core fields (`requestId`, `method`, `url`, `status`, `duration`, `ip`, `user`, `error`)
93
102
  always take precedence: a plugin cannot overwrite them.
94
103
  - The value must be set **before** the response completes (i.e. before
95
104
  `res.json()` / `res.end()`), since the entry is written on the `finish` event.
@@ -319,27 +328,40 @@ res.on('close', () => {
319
328
  Logs are in JSON format for easy parsing:
320
329
 
321
330
  ```bash
322
- cat app.log | jq 'select(.status >= 400)'
331
+ cat app.log | jq 'select(.message.status? >= 400)'
323
332
  ```
324
333
 
325
334
  Filters 4xx and 5xx responses:
326
335
 
327
336
  ```json
328
337
  {
329
- "level": "info",
330
- "message": "GET /api/v1/ldap/users/notfound 404 12ms",
331
- "status": 404,
332
- "method": "GET",
333
- "url": "/api/v1/ldap/users/notfound"
338
+ "level": "notice",
339
+ "message": {
340
+ "requestId": "6effd260-b079-4335-b727-544189ed33a6",
341
+ "method": "GET",
342
+ "url": "/api/v1/ldap/users/notfound",
343
+ "status": 404,
344
+ "duration": 12,
345
+ "ip": "10.0.9.12"
346
+ },
347
+ "requestId": "6effd260-b079-4335-b727-544189ed33a6",
348
+ "timestamp": "2026-10-26T18:07:03.286Z"
334
349
  }
335
350
  ```
336
351
 
352
+ The lines of one request, the access line and what the server logged while
353
+ serving it:
354
+
355
+ ```bash
356
+ cat app.log | jq 'select(.requestId == "6effd260-b079-4335-b727-544189ed33a6")'
357
+ ```
358
+
337
359
  ### Statistics
338
360
 
339
361
  Generate request statistics:
340
362
 
341
363
  ```bash
342
- cat app.log | jq -r '.message' | awk '{print $1}' | sort | uniq -c
364
+ cat app.log | jq -r 'select(.message.method?) | .message.method' | sort | uniq -c
343
365
  ```
344
366
 
345
367
  Output:
@@ -356,8 +378,7 @@ Output:
356
378
  Average response time per endpoint:
357
379
 
358
380
  ```bash
359
- cat app.log | jq -r 'select(.responseTime) | "\(.url) \(.responseTime)"' | \
360
- sed 's/ms$//' | \
381
+ cat app.log | jq -r 'select(.message.duration?) | "\(.message.url) \(.message.duration)"' | \
361
382
  awk '{sum[$1]+=$2; count[$1]++} END {for (url in sum) print url, sum[url]/count[url] "ms"}'
362
383
  ```
363
384
 
@@ -377,16 +398,16 @@ For high-traffic deployments:
377
398
 
378
399
  ## Log Rotation
379
400
 
380
- Configure log rotation using environment or external tools:
401
+ Rotate the log file with external tools:
381
402
 
382
- ### Using Winston File Transport
403
+ ### Writing to a file
383
404
 
384
405
  ```bash
385
- --log-file ./logs/ldap-rest.log \
386
- --log-max-size 10485760 \ # 10MB
387
- --log-max-files 5
406
+ --logger file --log-file ./logs/ldap-rest.log
388
407
  ```
389
408
 
409
+ The server does not rotate the file itself.
410
+
390
411
  ### Using logrotate (Linux)
391
412
 
392
413
  ```
@@ -4,6 +4,103 @@ What to check before deploying, newest first. Only releases that need a
4
4
  decision or a configuration change appear here; see the
5
5
  [CHANGELOG](../../CHANGELOG.md) for everything else.
6
6
 
7
+ ## From 1.1 to 1.2.0
8
+
9
+ ### The process stops on an uncaught exception
10
+
11
+ **Who is affected:** every deployment; a supervisor, Kubernetes or systemd,
12
+ restarts the process, as it should.
13
+
14
+ An exception nothing caught was logged and the process kept serving in a
15
+ state nobody knew. The binary now shuts down and exits with 1. On
16
+ `SIGTERM` it also drains what is in flight within `--shutdown-timeout`
17
+ (20 s) and closes its connections before the signal ends it, where the
18
+ signal ended the process at once, the broker connection closed first when
19
+ `core/rabbitmq` was loaded. A host assembling the server in its own
20
+ process gets neither unless it asks: `run()` no longer installs the handlers
21
+ that logged an uncaught exception or an unhandled rejection and kept the
22
+ process alive, so without `exitOnCrash()` or handlers of its own, Node's
23
+ action applies and the process ends on either. See
24
+ [shutdown](operations.md#shutdown).
25
+
26
+ ### The readiness of a pod follows the directory
27
+
28
+ **Who is affected:** a deployment of the Helm chart, whose probes now call
29
+ `GET /healthz` and `GET /readyz` instead of opening the listen port.
30
+
31
+ A pod leaves the endpoints while the directory does not answer, where it
32
+ kept receiving requests and answering 500; a rollout started during a
33
+ directory outage waits for the directory. Both routes are served without
34
+ authentication: an Ingress routing `/` exposes them, keep the two paths to
35
+ the cluster. See [operations](operations.md#health-and-readiness).
36
+
37
+ ### `--ldap-dn` and `--ldap-pwd` are required
38
+
39
+ **Who is affected:** a deployment that left one of them unset, and so bound
40
+ as `cn=admin,dc=example,dc=com` or with the password `admin`; the published
41
+ Docker image carried both in its `ENV`, and the Helm chart's example only set
42
+ the password.
43
+
44
+ The server now stops at startup naming the missing option. Set `DM_LDAP_DN`
45
+ and `DM_LDAP_PWD` (or `--ldap-dn` and `--ldap-pwd`) to the values that were
46
+ implied.
47
+
48
+ ### Every entity route checks the shape of a value
49
+
50
+ **Who is affected:** a script or connector writing through `/api/v1/ldap/<entity>`,
51
+ `/api/v1/ldap/groups` or `/api/v1/ldap/organizations` text that is not a
52
+ number for a `number` or `integer`, a `delete` of a `required` attribute as
53
+ a whole, or a change naming an attribute a strict schema does not declare;
54
+ one writing through `/api/v1/ldap/<entity>` several values for an attribute
55
+ the schema does not type `array`; and one changing a `fixed` attribute of a
56
+ group, which the server dropped from the change and answered 200. The
57
+ server now answers 400, naming the attribute. A group creation sending a
58
+ value under a `fixed` attribute now writes the schema's default, or the
59
+ value when the schema gives none, where it wrote nothing. The shipped LSC connector sends shapes that stay
60
+ accepted, a list of one in a `replace` and one value for an `array` on a
61
+ creation; its whole-attribute delete is refused for a `required` attribute,
62
+ as any, and a group synchronisation that forces `objectClass` or another
63
+ `fixed` attribute now has the whole update refused: keep those attributes
64
+ out of the group updates.
65
+
66
+ Send one value for a single-valued attribute, a list for an `array` (one
67
+ value, or a list of one, is taken either way), numbers as numbers or digits,
68
+ and `null` or `[]` in a `replace` to clear an attribute. The rules are in
69
+ [what a value must look like](../client-development/schemas/README.md#what-a-value-must-look-like).
70
+
71
+ ### `--logger`: `console` or `file`
72
+
73
+ A `DM_LOGGER` set to anything else wrote `error.log` in the working
74
+ directory; the server now stops at startup. Set `DM_LOGGER=file` to keep
75
+ that file, and `DM_LOG_FILE` to name another one. An empty `DM_LOGGER` is
76
+ `console`.
77
+
78
+ ## From 1.0 to 1.1.0
79
+
80
+ ### The static files can no longer be framed by another origin
81
+
82
+ `core/static` sends `Content-Security-Policy: frame-ancestors 'self'` and
83
+ `X-Frame-Options: SAMEORIGIN`. A page of another origin, another sub-domain
84
+ or port of the same site included, that showed one of its applications in an
85
+ `<iframe>`, a portal for instance, now shows an empty frame. Name it:
86
+
87
+ ```bash
88
+ --static-csp "frame-ancestors 'self' https://portal.example.com"
89
+ --static-frame-options off
90
+ ```
91
+
92
+ See [security headers](plugins/utilities/static.md#security-headers).
93
+
94
+ ### `--static-name`: an empty value is `static`
95
+
96
+ With `DM_STATIC_NAME=` the files were served at the root while the
97
+ configuration API and SCIM announced `/static`; they are now served under
98
+ `/static`. Slashes around the name are left out (`/static/` is `static`). A
99
+ name Express would not match as written, with an empty, `.` or `..` segment,
100
+ or what a URL encodes or Express reads as route syntax in it (a space, a
101
+ letter outside ASCII, `:`, `*`, `?`, `#`, `%`, brackets, quotes…), stops
102
+ the server at startup.
103
+
7
104
  ## From 0.26 to 1.0.0
8
105
 
9
106
  Every breaking change since 0.26.0. Authorization fails closed in 1.0.0:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ldap-rest",
3
- "version": "1.0.1",
3
+ "version": "1.2.0",
4
4
  "description": "Light directory manager",
5
5
  "keywords": [
6
6
  "Identity-Manager"
@@ -160,6 +160,10 @@
160
160
  "types": "./dist/src/plugins/ldap/trash.d.ts",
161
161
  "import": "./dist/plugins/ldap/trash.js"
162
162
  },
163
+ "./plugin-metrics": {
164
+ "types": "./dist/src/plugins/metrics.d.ts",
165
+ "import": "./dist/plugins/metrics.js"
166
+ },
163
167
  "./plugin-rabbitmq": {
164
168
  "types": "./dist/src/plugins/rabbitmq.d.ts",
165
169
  "import": "./dist/plugins/rabbitmq.js"
@@ -288,6 +292,10 @@
288
292
  "types": "./dist/src/plugins/twake/lifecycleEvents.d.ts",
289
293
  "import": "./dist/plugins/twake/lifecycleEvents.js"
290
294
  },
295
+ "./plugin-twake-migrationproxy": {
296
+ "types": "./dist/src/plugins/twake/migrationProxy.d.ts",
297
+ "import": "./dist/plugins/twake/migrationProxy.js"
298
+ },
291
299
  "./plugin-twake-spaces": {
292
300
  "types": "./dist/src/plugins/twake/spaces.d.ts",
293
301
  "import": "./dist/plugins/twake/spaces.js"
@@ -754,6 +762,7 @@
754
762
  "multer": "^2.0.2",
755
763
  "node-fetch": "^3.3.2",
756
764
  "p-limit": "^7.1.1",
765
+ "prom-client": "^15.1.3",
757
766
  "winston": "^3.17.0"
758
767
  },
759
768
  "devDependencies": {
@@ -795,7 +804,7 @@
795
804
  "typescript": "^5.9.2"
796
805
  },
797
806
  "optionalDependencies": {
798
- "@linagora/rabbitmq-client": "^0.1.2",
807
+ "@linagora/rabbitmq-client": "^0.7.2",
799
808
  "express-openid-connect": "^2.19.2",
800
809
  "iovalkey": "^0.4.0",
801
810
  "lemonldap-ng-handler": "^0.7.3",
@@ -20,6 +20,7 @@ Point a server at them with:
20
20
  ```sh
21
21
  node bin/index.mjs \
22
22
  --ldap-base dc=example,dc=org \
23
+ --ldap-dn cn=admin,dc=example,dc=org --ldap-pwd secret \
23
24
  --ldap-top-organization ou=organization,dc=example,dc=org \
24
25
  --ldap-group-base ou=lists,ou=groups,dc=example,dc=org \
25
26
  --group-schema static/schemas/example/groups.json \