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.
- package/bin/index.mjs +8 -7
- package/dist/abstract/ldapFlat.js +1 -1
- package/dist/abstract/plugin.js +1 -1
- package/dist/abstract/twakePlugin.js +1 -1
- package/dist/bin/index.js +1 -1
- package/dist/config/args.js +1 -1
- package/dist/config/schema.js +1 -1
- package/dist/lib/changeContext.js +1 -1
- package/dist/lib/entitySchema/validator.js +1 -0
- package/dist/lib/expressFormatedResponses.js +1 -1
- package/dist/lib/health.js +1 -0
- package/dist/lib/instanceProviders.js +1 -1
- package/dist/lib/ldapActions.js +1 -1
- package/dist/lib/metrics.js +1 -0
- package/dist/lib/requestContext.js +1 -1
- package/dist/lib/schemaFile.js +1 -1
- package/dist/lib/shutdown.js +1 -0
- package/dist/lib/staticFiles.js +1 -0
- package/dist/lib/storage/store.js +1 -1
- package/dist/lib/utils.js +1 -1
- package/dist/logger/winston.js +1 -1
- package/dist/plugins/auth/crowdsec.js +1 -1
- package/dist/plugins/auth/openidconnect.js +1 -1
- package/dist/plugins/demo/helloworld.js +1 -1
- package/dist/plugins/ldap/bulkImport.js +1 -1
- package/dist/plugins/ldap/flatGeneric.js +1 -1
- package/dist/plugins/ldap/groups.js +1 -1
- package/dist/plugins/ldap/organizations.js +1 -1
- package/dist/plugins/metrics.js +1 -0
- package/dist/plugins/rabbitmq.js +1 -1
- package/dist/plugins/scim/scim.js +1 -1
- package/dist/plugins/static.js +1 -1
- package/dist/plugins/storage/file.js +1 -1
- package/dist/plugins/storage/postgres.js +1 -1
- package/dist/plugins/storage/valkey.js +1 -1
- package/dist/plugins/storage.js +1 -1
- package/dist/plugins/twake/calendar.js +1 -1
- package/dist/plugins/twake/clouderyProvision.js +1 -1
- package/dist/plugins/twake/cozyProvision.js +1 -1
- package/dist/plugins/twake/drive.js +1 -1
- package/dist/plugins/twake/james.js +1 -1
- package/dist/plugins/twake/migrationProxy.js +1 -0
- package/dist/plugins/weblogs.js +1 -1
- package/dist/src/abstract/ldapFlat.d.ts +3 -13
- package/dist/src/abstract/plugin.d.ts +20 -0
- package/dist/src/abstract/twakePlugin.d.ts +23 -1
- package/dist/src/bin/index.d.ts +46 -1
- package/dist/src/config/args.d.ts +17 -1
- package/dist/src/lib/changeContext.d.ts +11 -0
- package/dist/src/lib/entitySchema/validator.d.ts +64 -0
- package/dist/src/lib/expressFormatedResponses.d.ts +19 -0
- package/dist/src/lib/health.d.ts +63 -0
- package/dist/src/lib/instanceProviders.d.ts +4 -0
- package/dist/src/lib/ldapActions.d.ts +28 -0
- package/dist/src/lib/metrics.d.ts +44 -0
- package/dist/src/lib/requestContext.d.ts +40 -0
- package/dist/src/lib/schemaFile.d.ts +10 -0
- package/dist/src/lib/shutdown.d.ts +20 -0
- package/dist/src/lib/staticFiles.d.ts +33 -0
- package/dist/src/lib/storage/store.d.ts +8 -0
- package/dist/src/lib/utils.d.ts +9 -0
- package/dist/src/logger/winston.d.ts +4 -0
- package/dist/src/plugins/ldap/groups.d.ts +18 -3
- package/dist/src/plugins/ldap/organizations.d.ts +3 -5
- package/dist/src/plugins/metrics.d.ts +17 -0
- package/dist/src/plugins/rabbitmq.d.ts +37 -1
- package/dist/src/plugins/scim/scim.d.ts +2 -0
- package/dist/src/plugins/static.d.ts +28 -0
- package/dist/src/plugins/storage/file.d.ts +4 -0
- package/dist/src/plugins/storage/postgres.d.ts +7 -14
- package/dist/src/plugins/storage/valkey.d.ts +2 -15
- package/dist/src/plugins/storage.d.ts +8 -0
- package/dist/src/plugins/twake/drive.d.ts +8 -0
- package/dist/src/plugins/twake/james.d.ts +2 -0
- package/dist/src/plugins/twake/migrationProxy.d.ts +71 -0
- package/docs/client-development/api/reference.md +5 -9
- package/docs/client-development/api/rest-api.md +4 -10
- package/docs/client-development/schemas/README.md +60 -21
- package/docs/plugin-development/README.md +15 -13
- package/docs/plugin-development/dependencies.md +8 -0
- package/docs/plugin-development/hooks.md +1 -1
- package/docs/usage/README.md +1 -0
- package/docs/usage/configuration.md +57 -15
- package/docs/usage/operations.md +193 -0
- package/docs/usage/plugins/README.md +2 -0
- package/docs/usage/plugins/auth/authz-per-branch.md +2 -1
- package/docs/usage/plugins/integrations/README.md +8 -4
- package/docs/usage/plugins/integrations/mail-migration.md +102 -0
- package/docs/usage/plugins/integrations/scim.md +10 -2
- package/docs/usage/plugins/ldap/bulk-import.md +3 -1
- package/docs/usage/plugins/ldap/flat-generic.md +5 -2
- package/docs/usage/plugins/ldap/on-change.md +2 -1
- package/docs/usage/plugins/ldap/organizations.md +7 -7
- package/docs/usage/plugins/utilities/metrics.md +21 -0
- package/docs/usage/plugins/utilities/static.md +81 -34
- package/docs/usage/plugins/utilities/storage.md +7 -0
- package/docs/usage/plugins/utilities/weblogs.md +51 -30
- package/docs/usage/upgrading.md +97 -0
- package/package.json +11 -2
- 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-
|
|
14
|
+
--static-name static
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
**Environment Variables:**
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
20
|
DM_STATIC_PATH="./static"
|
|
21
|
-
|
|
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-
|
|
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
|
-
| `
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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-
|
|
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
|
-
|
|
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
|
|
424
|
+
3. Verify that the name matches the first segment of the URL:
|
|
378
425
|
```bash
|
|
379
|
-
--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":
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
|
46
|
-
|
|
|
47
|
-
| `
|
|
48
|
-
| `
|
|
49
|
-
| `method`
|
|
50
|
-
| `url`
|
|
51
|
-
| `status`
|
|
52
|
-
| `
|
|
53
|
-
| `error`
|
|
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": "
|
|
330
|
-
"message":
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
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
|
|
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(.
|
|
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
|
-
|
|
401
|
+
Rotate the log file with external tools:
|
|
381
402
|
|
|
382
|
-
###
|
|
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
|
```
|
package/docs/usage/upgrading.md
CHANGED
|
@@ -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
|
|
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.
|
|
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 \
|