ldap-rest 0.12.0 → 0.13.1
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/dist/abstract/ldapFlat.js +1 -1
- package/dist/bin/index.js +1 -1
- package/dist/config/args.js +1 -1
- package/dist/lib/errors.js +1 -1
- package/dist/lib/instanceProviders.js +1 -1
- package/dist/lib/ldapActions.js +1 -1
- package/dist/plugins/auth/openidconnect.js +1 -1
- package/dist/plugins/ldap/groups.js +1 -1
- package/dist/plugins/ldap/trash.js +1 -1
- package/dist/plugins/scim/filter.js +1 -1
- package/dist/plugins/scim/groups.js +1 -1
- package/dist/plugins/scim/mapping.js +1 -1
- package/dist/plugins/scim/patch.js +1 -1
- package/dist/plugins/scim/users.js +1 -1
- package/dist/plugins/twake/groups.js +1 -0
- package/dist/plugins/twake/instances.js +1 -1
- package/dist/plugins/twake/lifecycleAttributes.js +1 -1
- package/dist/plugins/twake/lifecycleEvents.js +1 -1
- package/dist/plugins/twake/tombstone.js +1 -1
- package/dist/src/abstract/ldapFlat.d.ts +34 -6
- package/dist/src/config/args.d.ts +12 -0
- package/dist/src/lib/errors.d.ts +3 -0
- package/dist/src/lib/instanceProviders.d.ts +2 -0
- package/dist/src/lib/ldapActions.d.ts +6 -0
- package/dist/src/plugins/auth/openidconnect.d.ts +15 -0
- package/dist/src/plugins/ldap/groups.d.ts +5 -0
- package/dist/src/plugins/scim/filter.d.ts +2 -1
- package/dist/src/plugins/scim/groups.d.ts +1 -0
- package/dist/src/plugins/scim/mapping.d.ts +18 -7
- package/dist/src/plugins/scim/patch.d.ts +2 -2
- package/dist/src/plugins/twake/groups.d.ts +89 -0
- package/dist/src/plugins/twake/instances.d.ts +14 -0
- package/dist/src/plugins/twake/lifecycleEvents.d.ts +20 -3
- package/docs/client-development/api/rest-api.md +32 -2
- package/docs/usage/configuration.md +22 -1
- package/docs/usage/plugins/README.md +1 -0
- package/docs/usage/plugins/auth/oidc.md +19 -0
- package/docs/usage/plugins/integrations/README.md +1 -0
- package/docs/usage/plugins/integrations/groups.md +225 -0
- package/docs/usage/plugins/integrations/instances.md +31 -3
- package/docs/usage/plugins/integrations/lifecycle-events.md +38 -5
- package/docs/usage/plugins/integrations/scim.md +44 -34
- package/docs/usage/plugins/integrations/tombstone.md +2 -10
- package/docs/usage/plugins/ldap/flat-generic.md +38 -2
- package/docs/usage/plugins/ldap/trash.md +4 -4
- package/docs/usage/upgrading.md +56 -0
- package/package.json +9 -1
- package/static/schemas/twake/organizationGroups.json +32 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# Lifecycle Events
|
|
2
2
|
|
|
3
|
-
`core/twake/lifecycleEvents` publishes an account's lifecycle to
|
|
4
|
-
the directory write itself. REST, SCIM and any other plugin writing through
|
|
3
|
+
`core/twake/lifecycleEvents` publishes an account's or a group's lifecycle to
|
|
4
|
+
RabbitMQ from the directory write itself. REST, SCIM and any other plugin writing through
|
|
5
5
|
LDAP-Rest announce the same events, with the same payloads.
|
|
6
6
|
|
|
7
|
-
Which entries are accounts, which attributes carry the role, the
|
|
8
|
-
deletion, and where each event goes are
|
|
7
|
+
Which entries are accounts or groups, which attributes carry the role, the
|
|
8
|
+
lock, the deletion and the members, and where each event goes are
|
|
9
|
+
configuration.
|
|
9
10
|
|
|
10
11
|
## Events
|
|
11
12
|
|
|
@@ -22,6 +23,14 @@ publishes nothing.
|
|
|
22
23
|
role in a single-valued attribute.
|
|
23
24
|
- `disabled`: the lock attribute takes the lock value.
|
|
24
25
|
- `enabled`: the lock attribute no longer holds the lock value.
|
|
26
|
+
- `updated`: a target whose payload has `$changed.` sources publishes when one
|
|
27
|
+
of them changed, with those that did not left out. A target without them
|
|
28
|
+
publishes on every change of the entry.
|
|
29
|
+
- `memberAdded`, `memberRemoved`: the member attribute gains or loses values.
|
|
30
|
+
The old and new lists are compared as sets, so a whole list replaced
|
|
31
|
+
publishes only the members that came or went. The group placeholder
|
|
32
|
+
(`--group-dummy-user`) is never a member here. A group created with
|
|
33
|
+
members publishes `created` only, its members in `$members`.
|
|
25
34
|
- `deleted`: the entry becomes a tombstone (the deleted attribute takes the
|
|
26
35
|
deleted value), or an entry that is not a tombstone is removed.
|
|
27
36
|
|
|
@@ -102,6 +111,8 @@ operational one such as `pwdAccountLockedTime` is seen on both sides.
|
|
|
102
111
|
- `--twake-lifecycle-deleted-at-attribute`,
|
|
103
112
|
`--twake-lifecycle-deleted-at-format` (`iso8601`, the default, or
|
|
104
113
|
`generalizedTime`): the deletion date. It is always published as ISO 8601.
|
|
114
|
+
- `--twake-lifecycle-member-attribute` (default `member`): the attribute
|
|
115
|
+
`memberAdded`, `memberRemoved` and member lists read.
|
|
105
116
|
- `--twake-lifecycle-rules`: a JSON file, or the JSON itself.
|
|
106
117
|
|
|
107
118
|
Each option has a `DM_` environment variable, for example
|
|
@@ -177,12 +188,34 @@ Payload and `when` values are sources:
|
|
|
177
188
|
- `$context.actor`, `$context.requestId`, `$context.source`: who made the
|
|
178
189
|
write, the request it belongs to, and the API it came through (`rest`,
|
|
179
190
|
`scim`); left out for a write no request made, such as a scheduled task
|
|
191
|
+
- `$changed.attr`: the attribute after the write, only if the write changed
|
|
192
|
+
it; an attribute the write removed gives `""`
|
|
180
193
|
- `$attr|domain`, `$previous.attr|domain`: what follows the `@`
|
|
181
194
|
- `$now`: the current time, ISO 8601
|
|
182
195
|
- anything else: the value itself
|
|
183
196
|
|
|
184
197
|
`$attr` and `$previous.attr` carry the first value of a multi-valued
|
|
185
|
-
attribute. A source with no value leaves its field out.
|
|
198
|
+
attribute. A source with no value leaves its field out.
|
|
199
|
+
|
|
200
|
+
A payload field can also list members, as an object with one key:
|
|
201
|
+
|
|
202
|
+
- `$members`: the members after the write
|
|
203
|
+
- `$added`, `$removed`: the members `memberAdded` and `memberRemoved` are about
|
|
204
|
+
|
|
205
|
+
```json
|
|
206
|
+
"members": { "$added": { "username": "$uid", "email": "$mail" } }
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Each member is read once, and shaped by the object it maps to, whose
|
|
210
|
+
sources are its own attributes (`$attr`) or plain values; any other source is
|
|
211
|
+
refused at startup. A tombstone is left
|
|
212
|
+
out, and a target whose `$added` or `$removed` is left empty publishes
|
|
213
|
+
nothing. A member no longer in the directory is known by its RDN alone:
|
|
214
|
+
`uid=jdoe,…` gives `{ "username": "jdoe" }` above. A group of 1,000 members
|
|
215
|
+
takes 1,000 reads, one after the other, off the path of the write's
|
|
216
|
+
response. A member that cannot be read, for a reason other than being gone,
|
|
217
|
+
drops that target, logged as an error: a member the service account may not
|
|
218
|
+
read silences every target of the group that lists its members. Every message carries
|
|
186
219
|
a random AMQP `messageId`.
|
|
187
220
|
|
|
188
221
|
A source can read any attribute of the entry: `$userPassword` would put the
|
|
@@ -51,7 +51,7 @@ All SCIM endpoints sit behind the auth middleware registered before the plugin
|
|
|
51
51
|
| `--scim-base-map` | `DM_SCIM_BASE_MAP` | — | Path to JSON file mapping authenticated user → `{userBase, groupBase}` |
|
|
52
52
|
| `--scim-user-object-class` | `DM_SCIM_USER_OBJECT_CLASSES` | `top, inetOrgPerson, organizationalPerson, person` | Object classes for created Users |
|
|
53
53
|
| `--scim-user-rdn-attribute` | `DM_SCIM_USER_RDN_ATTRIBUTE` | `uid` | RDN attribute for Users |
|
|
54
|
-
| `--scim-user-lock-attribute` | `DM_SCIM_USER_LOCK_ATTRIBUTE` | `pwdAccountLockedTime` | LDAP attribute whose
|
|
54
|
+
| `--scim-user-lock-attribute` | `DM_SCIM_USER_LOCK_ATTRIBUTE` | `pwdAccountLockedTime` | LDAP attribute whose lock value marks a User as `active: false` |
|
|
55
55
|
| `--scim-user-lock-value` | `DM_SCIM_USER_LOCK_VALUE` | — | Value written to that attribute when deactivating (required unless the attribute is the default) |
|
|
56
56
|
| `--scim-group-object-class` | `DM_SCIM_GROUP_OBJECT_CLASSES` | `top, groupOfNames` | Object classes for created Groups |
|
|
57
57
|
| `--scim-group-rdn-attribute` | `DM_SCIM_GROUP_RDN_ATTRIBUTE` | `cn` | RDN attribute for Groups |
|
|
@@ -113,23 +113,23 @@ All responses have `Content-Type: application/scim+json`.
|
|
|
113
113
|
|
|
114
114
|
### Default mapping (LDAP ⇄ SCIM User)
|
|
115
115
|
|
|
116
|
-
| SCIM | LDAP
|
|
117
|
-
| ------------------------------------ |
|
|
118
|
-
| `id` | `uid` (or `entryUUID`)
|
|
119
|
-
| `userName` | `uid`
|
|
120
|
-
| `externalId` | `employeeNumber`
|
|
121
|
-
| `name.familyName` | `sn`
|
|
122
|
-
| `name.givenName` | `givenName`
|
|
123
|
-
| `name.formatted` | `cn`
|
|
124
|
-
| `displayName` | `displayName`
|
|
125
|
-
| `title` | `title`
|
|
126
|
-
| `preferredLanguage` | `preferredLanguage`
|
|
127
|
-
| `emails[primary=true].value` | `mail`
|
|
128
|
-
| `emails[primary=false].value` | `mailAlternateAddress`
|
|
129
|
-
| `phoneNumbers[primary=true].value` | `telephoneNumber`
|
|
130
|
-
| `phoneNumbers[primary=false].value` | `mobile`
|
|
131
|
-
| `active` | pseudo (false if the lock attribute
|
|
132
|
-
| `meta.created` / `meta.lastModified` | `createTimestamp` / `modifyTimestamp`
|
|
116
|
+
| SCIM | LDAP |
|
|
117
|
+
| ------------------------------------ | --------------------------------------------------------- |
|
|
118
|
+
| `id` | `uid` (or `entryUUID`) |
|
|
119
|
+
| `userName` | `uid` |
|
|
120
|
+
| `externalId` | `employeeNumber` |
|
|
121
|
+
| `name.familyName` | `sn` |
|
|
122
|
+
| `name.givenName` | `givenName` |
|
|
123
|
+
| `name.formatted` | `cn` |
|
|
124
|
+
| `displayName` | `displayName` |
|
|
125
|
+
| `title` | `title` |
|
|
126
|
+
| `preferredLanguage` | `preferredLanguage` |
|
|
127
|
+
| `emails[primary=true].value` | `mail` |
|
|
128
|
+
| `emails[primary=false].value` | `mailAlternateAddress` |
|
|
129
|
+
| `phoneNumbers[primary=true].value` | `telephoneNumber` |
|
|
130
|
+
| `phoneNumbers[primary=false].value` | `mobile` |
|
|
131
|
+
| `active` | pseudo (false if the lock attribute holds the lock value) |
|
|
132
|
+
| `meta.created` / `meta.lastModified` | `createTimestamp` / `modifyTimestamp` |
|
|
133
133
|
|
|
134
134
|
Override with `--scim-user-mapping /path/to/user-mapping.json` (same schema as
|
|
135
135
|
`static/schemas/scim/default-mapping.json`).
|
|
@@ -140,14 +140,18 @@ SCIM models account status with the boolean `active` (RFC 7643 §4.1.1), and it
|
|
|
140
140
|
is how Okta, Entra ID and JumpCloud disable a user — they PATCH `active` to
|
|
141
141
|
`false` rather than DELETE the resource.
|
|
142
142
|
|
|
143
|
-
LDAP has no single equivalent, so the plugin models it on
|
|
144
|
-
|
|
143
|
+
LDAP has no single equivalent, so the plugin models it on **one attribute
|
|
144
|
+
holding one value**: `--scim-user-lock-value` in `--scim-user-lock-attribute`
|
|
145
|
+
means locked, anything else means active. A ppolicy lockout after failed binds
|
|
146
|
+
is a timestamp in `pwdAccountLockedTime`, so it reads as active, and
|
|
147
|
+
`"active": true` leaves it in place. It lasts `pwdLockoutDuration`, or until
|
|
148
|
+
an administrator clears it when that is 0.
|
|
145
149
|
|
|
146
150
|
| SCIM | LDAP |
|
|
147
151
|
| ----------------- | ----------------------------------------------- |
|
|
148
152
|
| `"active": false` | write `--scim-user-lock-value` to the attribute |
|
|
149
|
-
| `"active": true` | remove the attribute
|
|
150
|
-
|
|
|
153
|
+
| `"active": true` | remove the attribute if it holds the lock value |
|
|
154
|
+
| lock value absent | `"active": true` |
|
|
151
155
|
|
|
152
156
|
The default targets the ppolicy overlay:
|
|
153
157
|
|
|
@@ -184,8 +188,8 @@ neither can be told apart from a deliberate local schema:
|
|
|
184
188
|
|
|
185
189
|
**None of this can tell whether your directory honours the value you chose.**
|
|
186
190
|
The checks are on the shape of the configuration. `active` is read back from
|
|
187
|
-
the
|
|
188
|
-
|
|
191
|
+
the value this plugin wrote, so a value the directory stores and ignores still
|
|
192
|
+
reads as `false`. Verify once, by hand, that a deactivation
|
|
189
193
|
actually prevents a bind.
|
|
190
194
|
|
|
191
195
|
`active` is not a mapping entry and must not be added to a mapping file: it is
|
|
@@ -347,16 +351,16 @@ group entries works; use a mapping override if you would rather name it there.
|
|
|
347
351
|
SCIM filters are translated to LDAP filters (RFC 4515). Values are always escaped
|
|
348
352
|
via `escapeLdapFilter()` — no LDAP injection is possible.
|
|
349
353
|
|
|
350
|
-
| SCIM | LDAP
|
|
351
|
-
| -------------------------------- |
|
|
352
|
-
| `userName eq "alice"` | `(uid=alice)`
|
|
353
|
-
| `name.familyName sw "Du"` | `(sn=Du*)`
|
|
354
|
-
| `emails.value co "@example.com"` | `(mail=*@example.com*)`
|
|
355
|
-
| `displayName pr` | `(displayName=*)`
|
|
356
|
-
| `active eq true` | `(!(pwdAccountLockedTime
|
|
357
|
-
| `active pr` | `(objectClass=*)`
|
|
358
|
-
| `a eq "x" and b eq "y"` | `(&(a=x)(b=y))`
|
|
359
|
-
| `not (a eq "x")` | `(!(a=x))`
|
|
354
|
+
| SCIM | LDAP |
|
|
355
|
+
| -------------------------------- | ----------------------------------------- |
|
|
356
|
+
| `userName eq "alice"` | `(uid=alice)` |
|
|
357
|
+
| `name.familyName sw "Du"` | `(sn=Du*)` |
|
|
358
|
+
| `emails.value co "@example.com"` | `(mail=*@example.com*)` |
|
|
359
|
+
| `displayName pr` | `(displayName=*)` |
|
|
360
|
+
| `active eq true` | `(!(pwdAccountLockedTime=000001010000Z))` |
|
|
361
|
+
| `active pr` | `(objectClass=*)` |
|
|
362
|
+
| `a eq "x" and b eq "y"` | `(&(a=x)(b=y))` |
|
|
363
|
+
| `not (a eq "x")` | `(!(a=x))` |
|
|
360
364
|
|
|
361
365
|
Unknown SCIM attributes raise `400 invalidFilter`.
|
|
362
366
|
|
|
@@ -616,6 +620,12 @@ Other plugins can observe and transform SCIM operations via the dynamic hooks
|
|
|
616
620
|
`scimuserdelete`, `scimuserdeletedone`, and their `scimgroup*` equivalents, plus
|
|
617
621
|
`scimbulkdone` for Bulk.
|
|
618
622
|
|
|
623
|
+
`scimgroupcreate` receives the group, the request and the group base. A
|
|
624
|
+
group's RDN value is its `displayName`, unless the hook sets `id` on the group
|
|
625
|
+
and the group mapping stores nothing in the RDN attribute: that `id` is then
|
|
626
|
+
the RDN value. An `id` sent by the client is ignored. A hook returns all
|
|
627
|
+
three, so that the hooks after it still get the base.
|
|
628
|
+
|
|
619
629
|
## Exposing the configuration to client apps (`configApi`)
|
|
620
630
|
|
|
621
631
|
Load `core/configApi` alongside the SCIM plugin, and `GET /api/v1/config` will
|
|
@@ -38,16 +38,8 @@ a delete that an authorization plugin refuses writes nothing.
|
|
|
38
38
|
|
|
39
39
|
`core/ldap/trash` moves a deleted entry before this plugin sees the delete,
|
|
40
40
|
so no tombstone would be written in a branch it watches. The server refuses
|
|
41
|
-
to start when `--trash-watched-bases` covers
|
|
42
|
-
|
|
43
|
-
every branch.
|
|
44
|
-
|
|
45
|
-
The trash splits `--trash-watched-bases` on every comma, a bug
|
|
46
|
-
([#226](https://github.com/linagora/ldap-rest/issues/226)): a base such as
|
|
47
|
-
`ou=users,dc=example,dc=com` becomes the suffixes `ou=users`, `dc=example`
|
|
48
|
-
and `dc=com`, and `dc=com` watches every branch below it. The check follows
|
|
49
|
-
the trash as it behaves, so such a value refuses to start next to any
|
|
50
|
-
tombstone pattern under `dc=com`.
|
|
41
|
+
to start when one of the `;`-separated `--trash-watched-bases` covers or sits under
|
|
42
|
+
a `--twake-tombstone-dn` pattern, and an empty list watches every branch.
|
|
51
43
|
|
|
52
44
|
## Reason
|
|
53
45
|
|
|
@@ -318,13 +318,13 @@ For each schema, the plugin generates REST API endpoints:
|
|
|
318
318
|
### List Entries
|
|
319
319
|
|
|
320
320
|
```bash
|
|
321
|
-
GET /api/v1/ldap/{pluralName}?match={
|
|
321
|
+
GET /api/v1/ldap/{pluralName}?match={value}&attribute={attrs}&attributes={attrs}&limit={n}
|
|
322
322
|
```
|
|
323
323
|
|
|
324
324
|
**Example:**
|
|
325
325
|
|
|
326
326
|
```bash
|
|
327
|
-
curl http://localhost:8081/api/v1/ldap/users?match=uid
|
|
327
|
+
curl 'http://localhost:8081/api/v1/ldap/users?match=smith&attribute=uid&attributes=uid,cn,mail&limit=50'
|
|
328
328
|
```
|
|
329
329
|
|
|
330
330
|
**Response:**
|
|
@@ -340,6 +340,42 @@ curl http://localhost:8081/api/v1/ldap/users?match=uid=*smith*&attributes=uid,cn
|
|
|
340
340
|
}
|
|
341
341
|
```
|
|
342
342
|
|
|
343
|
+
#### Long lists
|
|
344
|
+
|
|
345
|
+
A directory lists at most a set number of entries per search for the account
|
|
346
|
+
LDAP-Rest binds as (OpenLDAP: `olcSizeLimit`, default 500, or `olcLimits`;
|
|
347
|
+
`size.prtotal` bounds paged searches). OpenLDAP refuses a longer list as a
|
|
348
|
+
whole rather than cutting it short:
|
|
349
|
+
|
|
350
|
+
- **Without `limit`**, the answer is every match or `422`:
|
|
351
|
+
|
|
352
|
+
```json
|
|
353
|
+
{
|
|
354
|
+
"error": "Too many entries to list at once: the directory's size limit was exceeded. Narrow the search, or pass `limit`."
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
- **With `limit`** (a positive integer, `400` otherwise), at most `limit`
|
|
359
|
+
entries come back, with the header `X-Result-Truncated: true` when others
|
|
360
|
+
were left out. When the directory refuses the list, LDAP-Rest asks again
|
|
361
|
+
for `limit + 1` entries and answers what it gets, at most `limit` —
|
|
362
|
+
possibly fewer, if the account's own limit is lower — always with the
|
|
363
|
+
header: the directory does not say whether that answer was cut, so a
|
|
364
|
+
shorter one is not taken for complete. A request with `limit` is never
|
|
365
|
+
answered `422`.
|
|
366
|
+
|
|
367
|
+
The header is absent from a complete answer. LDAP-Rest sets no CORS headers:
|
|
368
|
+
a browser client on another origin sees `X-Result-Truncated` only if the
|
|
369
|
+
proxy answering for it lists the header in `Access-Control-Expose-Headers`.
|
|
370
|
+
|
|
371
|
+
A small `limit` costs a page of the directory's answer. A `limit` larger than
|
|
372
|
+
the directory's own limit costs a walk up to that limit, then the second
|
|
373
|
+
search: memory stays bounded by the directory, not by `limit`.
|
|
374
|
+
|
|
375
|
+
Only the lists of the entities this plugin serves honour `limit`,
|
|
376
|
+
`X-Result-Truncated` and the `422` for now. The groups list
|
|
377
|
+
(`GET /api/v1/ldap/groups`) ignores `limit` and still fails with `500`.
|
|
378
|
+
|
|
343
379
|
### Get Entry
|
|
344
380
|
|
|
345
381
|
```bash
|
|
@@ -16,7 +16,7 @@ Plugin to intercept LDAP delete operations and move entries to a trash branch in
|
|
|
16
16
|
### Environment Variables
|
|
17
17
|
|
|
18
18
|
- `DM_TRASH_BASE`: LDAP base DN for trash (default: `ou=trash,dc=example,dc=com`)
|
|
19
|
-
- `DM_TRASH_WATCHED_BASES`:
|
|
19
|
+
- `DM_TRASH_WATCHED_BASES`: branches to watch, each a full DN, separated by `;` (default: all branches except trash)
|
|
20
20
|
- `DM_TRASH_ADD_METADATA`: Add metadata to trashed entries (default: `true`)
|
|
21
21
|
- `DM_TRASH_AUTO_CREATE`: Auto-create trash branch if missing (default: `true`)
|
|
22
22
|
|
|
@@ -25,7 +25,7 @@ Plugin to intercept LDAP delete operations and move entries to a trash branch in
|
|
|
25
25
|
```bash
|
|
26
26
|
--plugin core/ldap/trash \
|
|
27
27
|
--trash-base "ou=trash,dc=example,dc=com" \
|
|
28
|
-
--trash-watched-bases "ou=users,dc=example,dc=com
|
|
28
|
+
--trash-watched-bases "ou=users,dc=example,dc=com;ou=groups,dc=example,dc=com" \
|
|
29
29
|
--trash-add-metadata true \
|
|
30
30
|
--trash-auto-create true
|
|
31
31
|
```
|
|
@@ -68,7 +68,7 @@ This watches all LDAP branches except the trash branch itself.
|
|
|
68
68
|
ldap-rest \
|
|
69
69
|
--plugin core/ldap/trash \
|
|
70
70
|
--trash-base "ou=trash,dc=example,dc=com" \
|
|
71
|
-
--trash-watched-bases "ou=users,dc=example,dc=com
|
|
71
|
+
--trash-watched-bases "ou=users,dc=example,dc=com;ou=groups,dc=example,dc=com"
|
|
72
72
|
```
|
|
73
73
|
|
|
74
74
|
This only intercepts deletes from `ou=users` and `ou=groups`. Deletes from other branches proceed normally.
|
|
@@ -248,7 +248,7 @@ ldap-rest \
|
|
|
248
248
|
--ldap-pwd "admin" \
|
|
249
249
|
--ldap-base "dc=example,dc=com" \
|
|
250
250
|
--trash-base "ou=trash,dc=example,dc=com" \
|
|
251
|
-
--trash-watched-bases "ou=users,dc=example,dc=com
|
|
251
|
+
--trash-watched-bases "ou=users,dc=example,dc=com;ou=groups,dc=example,dc=com" \
|
|
252
252
|
--trash-add-metadata true \
|
|
253
253
|
--auth-token "secret-token"
|
|
254
254
|
```
|
package/docs/usage/upgrading.md
CHANGED
|
@@ -4,6 +4,62 @@ 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
|
+
## To 0.13.0
|
|
8
|
+
|
|
9
|
+
### An OpenID Connect session ends with its access token
|
|
10
|
+
|
|
11
|
+
**Who is affected:** a deployment loading `core/auth/openidconnect`.
|
|
12
|
+
|
|
13
|
+
A session used to last as long as its cookie, a day of inactivity and a week
|
|
14
|
+
at most. It now ends when its access token expires, unless the provider gave
|
|
15
|
+
a refresh token to renew it: a browser then goes back through the provider,
|
|
16
|
+
silently while the provider's own session lasts, and a client asking for
|
|
17
|
+
JSON only (`Accept: application/json`) is answered `401`.
|
|
18
|
+
|
|
19
|
+
To keep sessions going without that round trip, have the provider issue
|
|
20
|
+
refresh tokens to the client
|
|
21
|
+
([details](plugins/auth/oidc.md#session-lifetime)).
|
|
22
|
+
|
|
23
|
+
### SCIM `active` reads the lock value
|
|
24
|
+
|
|
25
|
+
**Who is affected:** a SCIM client of a directory with ppolicy lockouts. An
|
|
26
|
+
account locked out after failed binds now reads `active: true`, is left out
|
|
27
|
+
of `active eq false`, and keeps its lockout on `"active": true`; only the
|
|
28
|
+
configured lock value reads as inactive. See
|
|
29
|
+
[the SCIM plugin documentation](plugins/integrations/scim.md#deactivating-an-account-active).
|
|
30
|
+
|
|
31
|
+
### twake/instances links an organization before its members
|
|
32
|
+
|
|
33
|
+
**Who is affected:** a deployment running 0.12.0 with
|
|
34
|
+
`--twake-instance-provider cloudery` and `--twake-instance-organization-base`.
|
|
35
|
+
|
|
36
|
+
0.12.0 sent each member's `user.created` at once and marked the member, while
|
|
37
|
+
the Cloudery refused it because the organization was not linked to its
|
|
38
|
+
instance. The plugin now links the organization and holds its members until
|
|
39
|
+
then, but only releases members that are not marked, so those already marked
|
|
40
|
+
are not sent again on their own.
|
|
41
|
+
|
|
42
|
+
To repair an organization, clear `--twake-instance-sent-attribute` on its
|
|
43
|
+
marked members, then replay its `workplace.created` or call
|
|
44
|
+
`ensureOrganization` for it ([details](plugins/integrations/instances.md#organizations)).
|
|
45
|
+
|
|
46
|
+
### Trash watched bases are separated by `;`
|
|
47
|
+
|
|
48
|
+
**Who is affected:** a deployment loading `core/ldap/trash` with
|
|
49
|
+
`--trash-watched-bases` set.
|
|
50
|
+
|
|
51
|
+
The list was split on commas, so a DN such as `ou=users,dc=example,dc=com`
|
|
52
|
+
became the suffixes `ou=users`, `dc=example` and `dc=com`, and the trash
|
|
53
|
+
caught deletes in every branch under `dc=com`. Each base is now a whole DN,
|
|
54
|
+
and bases are separated by `;`:
|
|
55
|
+
`ou=users,dc=example,dc=com;ou=groups,dc=example,dc=com`. A single DN needs
|
|
56
|
+
no change. A list of full DNs joined by commas, such as
|
|
57
|
+
`ou=users,dc=example,dc=com,ou=groups,dc=example,dc=com`, or a list of RDNs,
|
|
58
|
+
such as `ou=users,ou=groups`, now reads as one DN that no entry sits under,
|
|
59
|
+
so the trash catches nothing and deletes there are permanent: rewrite it with
|
|
60
|
+
`;`, each branch as its full DN. The server logs a warning at startup for a
|
|
61
|
+
watched base that is not one DN under `--ldap-base`.
|
|
62
|
+
|
|
7
63
|
## To 0.12.0
|
|
8
64
|
|
|
9
65
|
### twake/instances replaces cozyProvision and clouderyProvision
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ldap-rest",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.1",
|
|
4
4
|
"description": "Light directory manager",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Identity-Manager"
|
|
@@ -268,6 +268,10 @@
|
|
|
268
268
|
"types": "./dist/src/plugins/twake/drive.d.ts",
|
|
269
269
|
"import": "./dist/plugins/twake/drive.js"
|
|
270
270
|
},
|
|
271
|
+
"./plugin-twake-groups": {
|
|
272
|
+
"types": "./dist/src/plugins/twake/groups.d.ts",
|
|
273
|
+
"import": "./dist/plugins/twake/groups.js"
|
|
274
|
+
},
|
|
271
275
|
"./plugin-twake-instances": {
|
|
272
276
|
"types": "./dist/src/plugins/twake/instances.d.ts",
|
|
273
277
|
"import": "./dist/plugins/twake/instances.js"
|
|
@@ -660,6 +664,10 @@
|
|
|
660
664
|
"import": "./static/schemas/twake/nomenclature/twakeTitle.json",
|
|
661
665
|
"require": "./static/schemas/twake/nomenclature/twakeTitle.json"
|
|
662
666
|
},
|
|
667
|
+
"./schema-twake-organizationgroups": {
|
|
668
|
+
"import": "./static/schemas/twake/organizationGroups.json",
|
|
669
|
+
"require": "./static/schemas/twake/organizationGroups.json"
|
|
670
|
+
},
|
|
663
671
|
"./schema-twake-organizations": {
|
|
664
672
|
"import": "./static/schemas/twake/organizations.json",
|
|
665
673
|
"require": "./static/schemas/twake/organizations.json"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"strict": true,
|
|
3
|
+
"attributes": {
|
|
4
|
+
"objectClass": {
|
|
5
|
+
"type": "array",
|
|
6
|
+
"items": {
|
|
7
|
+
"type": "string",
|
|
8
|
+
"test": "^[a-zA-Z][a-zA-Z0-9-]*$"
|
|
9
|
+
},
|
|
10
|
+
"default": ["top", "groupOfNames", "twakeGroup"],
|
|
11
|
+
"required": true,
|
|
12
|
+
"fixed": true
|
|
13
|
+
},
|
|
14
|
+
"cn": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"test": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
|
|
17
|
+
"required": true
|
|
18
|
+
},
|
|
19
|
+
"member": {
|
|
20
|
+
"type": "array",
|
|
21
|
+
"items": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"test": "^[a-zA-Z]+=.*,__LDAP_BASE__$"
|
|
24
|
+
},
|
|
25
|
+
"required": false
|
|
26
|
+
},
|
|
27
|
+
"description": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"required": false
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|