ldap-rest 0.9.0 → 0.10.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 +1 -1
- package/dist/abstract/ldapFlat.js +1 -1
- package/dist/lib/authz/base.js +1 -1
- package/dist/lib/changeContext.js +1 -0
- package/dist/lib/errors.js +1 -1
- package/dist/lib/ldapActions.js +1 -1
- package/dist/plugins/auth/authzLinid1.js +1 -1
- package/dist/plugins/auth/authzPerBranch.js +1 -1
- package/dist/plugins/ldap/departmentSync.js +1 -1
- package/dist/plugins/ldap/groups.js +1 -1
- package/dist/plugins/ldap/onChange.js +1 -1
- package/dist/plugins/ldap/organizations.js +1 -1
- package/dist/plugins/ldap/trash.js +1 -1
- package/dist/plugins/scim/scim.js +1 -1
- package/dist/plugins/twake/appAccountsApi.js +1 -1
- package/dist/plugins/twake/appAccountsConsistency.js +1 -1
- package/dist/plugins/twake/clouderyProvision.js +1 -1
- package/dist/plugins/twake/cozyProvision.js +1 -1
- package/dist/src/abstract/plugin.d.ts +6 -0
- package/dist/src/hooks.d.ts +15 -6
- package/dist/src/lib/authz/base.d.ts +26 -0
- package/dist/src/lib/changeContext.d.ts +24 -0
- package/dist/src/lib/errors.d.ts +15 -0
- package/dist/src/lib/ldapActions.d.ts +2 -1
- package/dist/src/plugins/auth/authzLinid1.d.ts +6 -0
- package/dist/src/plugins/auth/authzPerBranch.d.ts +35 -0
- package/dist/src/plugins/ldap/groups.d.ts +7 -5
- package/dist/src/plugins/ldap/onChange.d.ts +17 -8
- package/dist/src/plugins/ldap/organizations.d.ts +2 -2
- package/docs/plugin-development/README.md +1 -18
- package/docs/plugin-development/hooks.md +6 -0
- package/docs/plugin-development/testing.md +1 -17
- package/docs/usage/configuration.md +1 -1
- package/docs/usage/plugins/auth/authz-linid1.md +8 -7
- package/docs/usage/plugins/auth/authz-per-branch.md +33 -11
- package/docs/usage/plugins/auth/authz-scope.md +5 -0
- package/docs/usage/plugins/ldap/on-change.md +51 -284
- package/docs/usage/troubleshooting.md +1 -9
- package/docs/usage/upgrading.md +52 -0
- package/package.json +1 -1
|
@@ -174,10 +174,20 @@ Modifies the organization tree API:
|
|
|
174
174
|
|
|
175
175
|
Groups are resolved dynamically:
|
|
176
176
|
|
|
177
|
-
1.
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
177
|
+
1. Resolves the caller to its DN, searching
|
|
178
|
+
`(<ldap_user_main_attribute>=<uid>)` under the LDAP base (`--ldap-base`)
|
|
179
|
+
2. Searches for all groups where that DN is a member
|
|
180
|
+
3. Matches each group found against the `groups` keys **as DNs**: case and
|
|
181
|
+
the spaces around `,` and `=` do not matter, so
|
|
182
|
+
`CN=Editors, OU=Groups,dc=example,dc=com` names the same group as
|
|
183
|
+
`cn=editors,ou=groups,dc=example,dc=com`
|
|
184
|
+
4. Caches results (see [Group Caching](#group-caching)); concurrent
|
|
185
|
+
requests for the same user share one lookup
|
|
186
|
+
|
|
187
|
+
A uid that names **more than one** entry gets **no group rule**, since its
|
|
188
|
+
groups cannot be told apart from its homonym's; a warning is logged, and the
|
|
189
|
+
uid's own `users` rule still applies. A lookup that fails answers `500` and
|
|
190
|
+
is not cached.
|
|
181
191
|
|
|
182
192
|
## Sub-branch Inheritance
|
|
183
193
|
|
|
@@ -379,6 +389,10 @@ Group memberships are cached to reduce LDAP queries:
|
|
|
379
389
|
- **Configurable**: `--authz-per-branch-cache-ttl`
|
|
380
390
|
- **Per-user cache**: Each user's groups cached separately
|
|
381
391
|
- **Automatic expiry**: Cache entries expire after TTL
|
|
392
|
+
- **Dropped on writes**: any add, delete, rename or move made through
|
|
393
|
+
ldap-rest empties the cache, and so does a modify touching the group member
|
|
394
|
+
attribute or `--ldap-user-main-attribute`. A change made directly in the
|
|
395
|
+
directory waits for the TTL
|
|
382
396
|
|
|
383
397
|
Cache hit/miss logging:
|
|
384
398
|
|
|
@@ -420,7 +434,6 @@ names, this plugin lets them read and refuses every write. Give it an
|
|
|
420
434
|
|
|
421
435
|
- Group DNs must be fully qualified
|
|
422
436
|
- Group resolution uses LDAP search - ensure proper indexing
|
|
423
|
-
- Cache can delay permission revocation (up to TTL duration)
|
|
424
437
|
|
|
425
438
|
### Authentication Required
|
|
426
439
|
|
|
@@ -531,7 +544,8 @@ Changed permissions don't take effect immediately.
|
|
|
531
544
|
|
|
532
545
|
**Solutions:**
|
|
533
546
|
|
|
534
|
-
1.
|
|
547
|
+
1. A membership changed directly in the directory waits for the
|
|
548
|
+
[group cache](#group-caching) TTL
|
|
535
549
|
2. Restart server to clear all caches
|
|
536
550
|
3. Reduce `--authz-per-branch-cache-ttl` for testing
|
|
537
551
|
|
|
@@ -542,17 +556,25 @@ User should inherit group permissions but doesn't.
|
|
|
542
556
|
|
|
543
557
|
**Solutions:**
|
|
544
558
|
|
|
545
|
-
1. Verify user is member of group:
|
|
559
|
+
1. Verify the user's DN is a member of the group:
|
|
546
560
|
|
|
547
561
|
```bash
|
|
548
|
-
ldapsearch -x -b "
|
|
562
|
+
ldapsearch -x -b "dc=example,dc=com" \
|
|
563
|
+
"(member=uid=jdoe,ou=users,dc=example,dc=com)"
|
|
549
564
|
```
|
|
550
565
|
|
|
551
|
-
2. Check group DN in config
|
|
566
|
+
2. Check the group DN in config names the group: it is compared as a DN
|
|
567
|
+
(case and spaces are ignored), but every RDN must be there
|
|
552
568
|
|
|
553
|
-
3.
|
|
569
|
+
3. Check the uid names a single entry:
|
|
554
570
|
|
|
555
|
-
|
|
571
|
+
```bash
|
|
572
|
+
ldapsearch -x -b "dc=example,dc=com" "(uid=jdoe)" dn
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
4. Ensure group membership uses correct attribute (default: `member`)
|
|
576
|
+
|
|
577
|
+
5. Configure custom member attribute if needed:
|
|
556
578
|
```bash
|
|
557
579
|
--ldap-group-member-attribute uniqueMember
|
|
558
580
|
```
|
|
@@ -150,6 +150,11 @@ identified caller of the same server is told. A server loading no
|
|
|
150
150
|
authorization plugin at all answers `unrestricted` to anyone, anonymous
|
|
151
151
|
included, which is what it does.
|
|
152
152
|
|
|
153
|
+
An identity that names **several** entries — the same `uid` in two branches of
|
|
154
|
+
a directory without the `unique` overlay, which `authzLinid1` refuses with
|
|
155
|
+
`AmbiguousIdentityError` — is answered `403`, not `401`: the caller cannot be
|
|
156
|
+
told apart from the homonym, so no scope can be described for them.
|
|
157
|
+
|
|
153
158
|
## See also
|
|
154
159
|
|
|
155
160
|
- [authz-linid1](authz-linid1.md) — the local-administrator model this serves
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
# LDAP onChange Plugin
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
The `onChange` plugin watches for LDAP modifications and generates specialized hooks when configured attributes change. This enables reactive integrations with external systems (mail servers, quota managers, etc.).
|
|
3
|
+
Publish the state of an entry before and after each write made through
|
|
4
|
+
LDAP-Rest, and hooks for the attributes other plugins follow.
|
|
8
5
|
|
|
9
6
|
## Configuration
|
|
10
7
|
|
|
@@ -14,305 +11,75 @@ The `onChange` plugin watches for LDAP modifications and generates specialized h
|
|
|
14
11
|
--quota-attribute mailQuota
|
|
15
12
|
```
|
|
16
13
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
DM_MAIL_ATTRIBUTE="mail"
|
|
21
|
-
DM_QUOTA_ATTRIBUTE="mailQuota"
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Generated Hooks
|
|
25
|
-
|
|
26
|
-
The plugin generates hooks based on configured attributes:
|
|
27
|
-
|
|
28
|
-
| Config Parameter | Generated Hook | Parameters |
|
|
29
|
-
| ------------------- | ------------------- | -------------------------------- |
|
|
30
|
-
| `--mail-attribute` | `onLdapMailChange` | `(dn, oldMail, newMail)` |
|
|
31
|
-
| `--quota-attribute` | `onLdapQuotaChange` | `(dn, mail, oldQuota, newQuota)` |
|
|
32
|
-
|
|
33
|
-
Generic hook for any change:
|
|
34
|
-
|
|
35
|
-
- `onLdapChange` - `(dn, changes)` where `changes` is `Record<attr, [oldValue, newValue]>`
|
|
36
|
-
|
|
37
|
-
## How It Works
|
|
38
|
-
|
|
39
|
-
1. **Hooks into LDAP modify operations** via `ldapUsersmodify` and `ldapGroupsmodify` hooks
|
|
40
|
-
2. **Detects attribute changes** by comparing old and new values
|
|
41
|
-
3. **Triggers specialized hooks** for configured attributes
|
|
42
|
-
4. **Provides old and new values** to downstream hooks
|
|
43
|
-
|
|
44
|
-
## Use Cases
|
|
45
|
-
|
|
46
|
-
### Mail Server Synchronization
|
|
47
|
-
|
|
48
|
-
When user email changes, update external mail server:
|
|
49
|
-
|
|
50
|
-
```javascript
|
|
51
|
-
// In another plugin
|
|
52
|
-
hooks: {
|
|
53
|
-
onLdapMailChange: async (dn, oldMail, newMail) => {
|
|
54
|
-
await mailServer.renameAccount(oldMail, newMail);
|
|
55
|
-
console.log(`Renamed mail account: ${oldMail} → ${newMail}`);
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
### Quota Management
|
|
61
|
-
|
|
62
|
-
When quota changes, update mail server quota:
|
|
63
|
-
|
|
64
|
-
```javascript
|
|
65
|
-
hooks: {
|
|
66
|
-
onLdapQuotaChange: async (dn, mail, oldQuota, newQuota) => {
|
|
67
|
-
await mailServer.setQuota(mail, newQuota);
|
|
68
|
-
console.log(`Updated quota for ${mail}: ${oldQuota} → ${newQuota}`);
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
### Generic Change Tracking
|
|
74
|
-
|
|
75
|
-
Track all attribute changes:
|
|
76
|
-
|
|
77
|
-
```javascript
|
|
78
|
-
hooks: {
|
|
79
|
-
onLdapChange: async (dn, changes) => {
|
|
80
|
-
for (const [attr, [oldVal, newVal]] of Object.entries(changes)) {
|
|
81
|
-
console.log(`${dn}: ${attr} changed from ${oldVal} to ${newVal}`);
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
## Examples
|
|
88
|
-
|
|
89
|
-
### Example 1: Mail Attribute Monitoring
|
|
90
|
-
|
|
91
|
-
```bash
|
|
92
|
-
--plugin core/ldap/onChange \
|
|
93
|
-
--plugin core/ldap/flatGeneric \
|
|
94
|
-
--ldap-flat-schema ./schemas/users.json \
|
|
95
|
-
--mail-attribute mail
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
When a user's mail attribute changes via API:
|
|
99
|
-
|
|
100
|
-
```bash
|
|
101
|
-
PUT /api/v1/ldap/users/jdoe
|
|
102
|
-
{
|
|
103
|
-
"replace": {
|
|
104
|
-
"mail": "john.doe@newdomain.com"
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
The `onLdapMailChange` hook fires with:
|
|
110
|
-
|
|
111
|
-
- `dn`: `"uid=jdoe,ou=users,dc=example,dc=com"`
|
|
112
|
-
- `oldMail`: `"jdoe@olddomain.com"`
|
|
113
|
-
- `newMail`: `"john.doe@newdomain.com"`
|
|
114
|
-
|
|
115
|
-
### Example 2: Multiple Attributes
|
|
116
|
-
|
|
117
|
-
```bash
|
|
118
|
-
--plugin core/ldap/onChange \
|
|
119
|
-
--mail-attribute mail \
|
|
120
|
-
--quota-attribute mailQuota
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
When both attributes change:
|
|
14
|
+
## Hooks
|
|
124
15
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
"replace": {
|
|
129
|
-
"mail": "jdoe@company.com",
|
|
130
|
-
"mailQuota": "5000000000"
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
```
|
|
16
|
+
`onLdapEntryChange(dn, before, after, context)` fires after every add,
|
|
17
|
+
modify, rename and delete, with the entry as the directory held it on each
|
|
18
|
+
side:
|
|
134
19
|
|
|
135
|
-
|
|
20
|
+
| Operation | `before` | `after` |
|
|
21
|
+
| --------- | ------------------------ | ------------------------ |
|
|
22
|
+
| add | `null` | the new entry |
|
|
23
|
+
| modify | the entry before | the entry after |
|
|
24
|
+
| rename | the entry, at its old DN | the entry, at its new DN |
|
|
25
|
+
| delete | the entry before | `null` |
|
|
136
26
|
|
|
137
|
-
|
|
138
|
-
|
|
27
|
+
`dn` is the entry's DN after the write, its old one on a delete. `context`
|
|
28
|
+
says who made the write, and through which door:
|
|
139
29
|
|
|
140
|
-
|
|
30
|
+
- `actor`: the caller's `userName`, or its `user` when it has none;
|
|
31
|
+
- `requestId`: generated, the same for every write of one request;
|
|
32
|
+
- `source`: `scim` for the SCIM API, `rest` otherwise.
|
|
141
33
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
```
|
|
34
|
+
A write no request is behind, such as a scheduled task's, gets `{}`. The LDAP
|
|
35
|
+
`ldap*done` hooks receive the same context after their arguments.
|
|
145
36
|
|
|
146
|
-
|
|
37
|
+
The other hooks are derived from it:
|
|
147
38
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
```
|
|
39
|
+
| Hook | Fires when | Parameters |
|
|
40
|
+
| ------------------------- | ---------------------------------------------------------- | -------------------------------------- |
|
|
41
|
+
| `onLdapChange` | any attribute changed | `(dn, changes)` |
|
|
42
|
+
| `onLdapMailChange` | `--mail-attribute` changed | `(dn, oldMail, newMail)` |
|
|
43
|
+
| `onLdapQuotaChange` | `--quota-attribute` changed | `(dn, mail, oldQuota, newQuota)` |
|
|
44
|
+
| `onLdapAliasChange` | `--alias-attribute` changed | `(dn, mail, oldAliases, newAliases)` |
|
|
45
|
+
| `onLdapForwardChange` | `--forward-attribute` changed | `(dn, mail, oldForwards, newForwards)` |
|
|
46
|
+
| `onLdapDriveQuotaChange` | `--drive-quota-attribute` changed | `(dn, oldQuota, newQuota)` |
|
|
47
|
+
| `onLdapDisplayNameChange` | the name built from `cn`, or `givenName` and `sn`, changed | `(dn, oldName, newName)` |
|
|
158
48
|
|
|
159
|
-
|
|
49
|
+
`changes` maps each attribute that changed to `[oldValues, newValues]`, the
|
|
50
|
+
full values on each side, `null` where the attribute is absent:
|
|
160
51
|
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
"telephoneNumber": [null, "+1234567890"],
|
|
165
|
-
"description": ["Old description", null]
|
|
166
|
-
}
|
|
52
|
+
```text
|
|
53
|
+
member was [a, b], the request added c:
|
|
54
|
+
{ member: [['a', 'b'], ['a', 'b', 'c']] }
|
|
167
55
|
```
|
|
168
56
|
|
|
169
|
-
##
|
|
170
|
-
|
|
171
|
-
### With Twake James Mail Server
|
|
172
|
-
|
|
173
|
-
```bash
|
|
174
|
-
--plugin core/ldap/onChange \
|
|
175
|
-
--plugin twake/james \
|
|
176
|
-
--plugin core/ldap/flatGeneric \
|
|
177
|
-
--ldap-flat-schema ./schemas/twake/users.json \
|
|
178
|
-
--mail-attribute mail \
|
|
179
|
-
--quota-attribute mailQuota \
|
|
180
|
-
--james-webadmin-url http://james:8000
|
|
181
|
-
```
|
|
57
|
+
## Operational attributes
|
|
182
58
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
Create a custom plugin that reacts to changes:
|
|
59
|
+
A search returns no operational attribute unless asked by name, so neither
|
|
60
|
+
side holds `pwdAccountLockedTime` or its kind by default, and a write changing
|
|
61
|
+
only such an attribute fires no hook. A plugin that follows some declares them:
|
|
188
62
|
|
|
189
63
|
```typescript
|
|
190
|
-
|
|
191
|
-
import { Hooks } from '../hooks';
|
|
192
|
-
|
|
193
|
-
export default class CustomSync extends DmPlugin {
|
|
194
|
-
name = 'customSync';
|
|
195
|
-
|
|
196
|
-
dependencies = {
|
|
197
|
-
onChange: 'core/ldap/onChange',
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
hooks: Hooks = {
|
|
201
|
-
onLdapMailChange: async (dn, oldMail, newMail) => {
|
|
202
|
-
this.logger.info(`Mail changed: ${oldMail} → ${newMail}`);
|
|
203
|
-
|
|
204
|
-
try {
|
|
205
|
-
await fetch('https://api.example.com/update-email', {
|
|
206
|
-
method: 'POST',
|
|
207
|
-
headers: { 'Content-Type': 'application/json' },
|
|
208
|
-
body: JSON.stringify({ dn, oldMail, newMail }),
|
|
209
|
-
});
|
|
210
|
-
} catch (err) {
|
|
211
|
-
this.logger.error(`Failed to sync mail change: ${err}`);
|
|
212
|
-
}
|
|
213
|
-
},
|
|
214
|
-
};
|
|
215
|
-
}
|
|
64
|
+
followedOperationalAttributes = ['pwdAccountLockedTime'];
|
|
216
65
|
```
|
|
217
66
|
|
|
218
|
-
|
|
67
|
+
The entry is then read with `*` and every attribute a loaded plugin declares.
|
|
219
68
|
|
|
220
|
-
|
|
69
|
+
## What counts as a change
|
|
221
70
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
replace: {
|
|
226
|
-
mail: 'new@example.com';
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
// Triggers: onLdapMailChange("uid=user,ou=users,dc=example,dc=com", "old@example.com", "new@example.com")
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
### Add Operations
|
|
71
|
+
Values are compared as sets: a single value and a one-element array are equal,
|
|
72
|
+
and so are two orderings of the same values. A write that leaves every value
|
|
73
|
+
as it was, such as a `replace` with the current value, fires no hook.
|
|
233
74
|
|
|
234
|
-
|
|
235
|
-
// Before: mail = undefined
|
|
236
|
-
{
|
|
237
|
-
add: {
|
|
238
|
-
mail: 'new@example.com';
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
// Triggers: onLdapMailChange("uid=user,ou=users,dc=example,dc=com", null, "new@example.com")
|
|
242
|
-
```
|
|
75
|
+
## Timing and errors
|
|
243
76
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
```javascript
|
|
247
|
-
// Before: mail = "old@example.com"
|
|
248
|
-
{ delete: ["mail"] }
|
|
249
|
-
// Triggers: onLdapMailChange("uid=user,ou=users,dc=example,dc=com", "old@example.com", null)
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
## Performance Considerations
|
|
253
|
-
|
|
254
|
-
### Hook Execution
|
|
255
|
-
|
|
256
|
-
- Hooks run **synchronously** within the modify operation
|
|
257
|
-
- Slow hooks delay the LDAP response
|
|
258
|
-
- Consider async operations with fire-and-forget for non-critical updates
|
|
259
|
-
|
|
260
|
-
### Optimization Tips
|
|
261
|
-
|
|
262
|
-
1. **Keep hooks fast**: Defer heavy work to background jobs
|
|
263
|
-
2. **Use error handling**: Don't let hook failures block LDAP operations
|
|
264
|
-
3. **Batch updates**: If possible, batch multiple hook calls
|
|
265
|
-
4. **Cache external state**: Avoid redundant external API calls
|
|
266
|
-
|
|
267
|
-
## Error Handling
|
|
268
|
-
|
|
269
|
-
Hooks can throw errors to abort the LDAP modification:
|
|
270
|
-
|
|
271
|
-
```javascript
|
|
272
|
-
hooks: {
|
|
273
|
-
onLdapMailChange: async (dn, oldMail, newMail) => {
|
|
274
|
-
// Validate mail domain
|
|
275
|
-
if (!newMail.endsWith('@company.com')) {
|
|
276
|
-
throw new Error('Mail must be @company.com domain');
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// Update mail server
|
|
280
|
-
try {
|
|
281
|
-
await mailServer.renameAccount(oldMail, newMail);
|
|
282
|
-
} catch (err) {
|
|
283
|
-
throw new Error(`Mail server update failed: ${err.message}`);
|
|
284
|
-
}
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
If the hook throws, the LDAP modification is rolled back (if supported by LDAP server).
|
|
290
|
-
|
|
291
|
-
## Debugging
|
|
292
|
-
|
|
293
|
-
Enable debug logging to see change detection:
|
|
294
|
-
|
|
295
|
-
```bash
|
|
296
|
-
--log-level debug
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
Output:
|
|
300
|
-
|
|
301
|
-
```
|
|
302
|
-
[debug] Detected mail change for uid=jdoe,ou=users,dc=example,dc=com: old@domain.com → new@domain.com
|
|
303
|
-
[debug] Triggering onLdapMailChange hook
|
|
304
|
-
[info] onLdapMailChange: Mail account renamed successfully
|
|
305
|
-
```
|
|
77
|
+
Hooks run after the directory has accepted the write, and the API answers
|
|
78
|
+
without waiting for them. A hook that throws is logged; the write stays.
|
|
306
79
|
|
|
307
80
|
## Limitations
|
|
308
81
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
## See Also
|
|
315
|
-
|
|
316
|
-
- [Twake James Plugin](twakeJames.md) - Mail server integration using onChange
|
|
317
|
-
- [ldapFlatGeneric.md](ldapFlatGeneric.md) - Generic LDAP entity management
|
|
318
|
-
- [Hooks Documentation](../src/hooks.ts) - All available hooks
|
|
82
|
+
- Only writes made through LDAP-Rest are seen; a direct LDAP client's are not.
|
|
83
|
+
- Entries moved by the [trash](trash.md) plugin are not seen, nor the entries
|
|
84
|
+
under a renamed container, which move with it.
|
|
85
|
+
- Each write reads the entry before and after it: one search on each side.
|
|
@@ -89,15 +89,7 @@ DM_LOG_LEVEL=debug ldap-rest
|
|
|
89
89
|
|
|
90
90
|
## Testing
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
```bash
|
|
95
|
-
# All tests
|
|
96
|
-
source ~/.test-env && npm run test:dev
|
|
97
|
-
|
|
98
|
-
# Single file
|
|
99
|
-
source ~/.test-env && npm run test:one test/path/to/file.test.ts
|
|
100
|
-
```
|
|
92
|
+
See [Tests and checks](../../CONTRIBUTING.md#tests-and-checks).
|
|
101
93
|
|
|
102
94
|
## Support
|
|
103
95
|
|
package/docs/usage/upgrading.md
CHANGED
|
@@ -4,6 +4,58 @@ 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.10.0
|
|
8
|
+
|
|
9
|
+
### LDAP base is now required
|
|
10
|
+
|
|
11
|
+
**Who is affected:** a deployment that starts `ldap-rest` without
|
|
12
|
+
`--ldap-base` (or `DM_LDAP_BASE`).
|
|
13
|
+
|
|
14
|
+
The server refuses to start without it. It used to take the second RDN of
|
|
15
|
+
`--ldap-dn` — `dc=example` for `cn=admin,dc=example,dc=com` — so subtree
|
|
16
|
+
searches failed or found nothing. Set `--ldap-base` to the DN under which
|
|
17
|
+
the entries are searched.
|
|
18
|
+
|
|
19
|
+
### Group rules now apply
|
|
20
|
+
|
|
21
|
+
**Who is affected:** a deployment whose `--authz-per-branch-config` declares
|
|
22
|
+
a `groups` section.
|
|
23
|
+
|
|
24
|
+
That section granted nothing: permissions came from `users` and `default`
|
|
25
|
+
alone. A member of a configured group now also gets what its rule grants.
|
|
26
|
+
**Check the `groups` rules before upgrading.**
|
|
27
|
+
|
|
28
|
+
### An identity naming several entries is refused
|
|
29
|
+
|
|
30
|
+
**Who is affected:** a directory where the same `uid` appears twice — one
|
|
31
|
+
without a `unique` overlay, or one where a homonym was left in the trash
|
|
32
|
+
while the uid was reused.
|
|
33
|
+
|
|
34
|
+
`authzLinid1` refuses every request of such a caller with a `403`.
|
|
35
|
+
`authzPerBranch` keeps the uid's `users` rules and withholds the `groups`
|
|
36
|
+
rules. Both log a warning naming the identity and the number of entries it
|
|
37
|
+
matched.
|
|
38
|
+
|
|
39
|
+
**Check your directory before upgrading:**
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
ldapsearch -x -b "<base>" "(uid=<uid>)" dn
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
must answer one entry. Where it answers two, remove the duplicate — the
|
|
46
|
+
trash included — or restore the uniqueness the `unique` overlay enforces.
|
|
47
|
+
|
|
48
|
+
### `onLdapChange` gives full values
|
|
49
|
+
|
|
50
|
+
**Who is affected:** plugins listening to `onLdapChange` that read the values
|
|
51
|
+
of an `add`, or of a `delete` naming values, as the values added or removed.
|
|
52
|
+
|
|
53
|
+
Each attribute now maps to all its values before and after the write. Adding
|
|
54
|
+
`c` to `member: [a, b]` gave `[null, [c]]` and gives `[[a, b], [a, b, c]]`.
|
|
55
|
+
Compute what was added or removed as the difference of the two sides, as the
|
|
56
|
+
plugins shipped with LDAP-Rest do. A `replace` with the current value no
|
|
57
|
+
longer fires the hook.
|
|
58
|
+
|
|
7
59
|
## To 0.9.0
|
|
8
60
|
|
|
9
61
|
### Two authorization plugins judging the same requests no longer start
|