ldap-rest 0.7.0 → 0.8.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/abstract/plugin.js +1 -1
- package/dist/bin/index.js +1 -1
- package/dist/config/args.js +1 -1
- package/dist/config/schema.js +1 -0
- package/dist/lib/expressFormatedResponses.js +1 -1
- package/dist/lib/ldapActions.js +1 -1
- package/dist/lib/utils.js +1 -1
- package/dist/plugins/auth/authzScope.js +1 -0
- package/dist/plugins/auth/llng.js +1 -1
- package/dist/plugins/ldap/accountLifecycle.js +1 -0
- package/dist/plugins/ldap/bulkImport.js +1 -1
- package/dist/plugins/ldap/departmentSync.js +1 -1
- package/dist/plugins/ldap/enterpriseRules.js +1 -0
- package/dist/plugins/ldap/externalUsersInGroups.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/scim/groups.js +1 -1
- package/dist/plugins/twake/calendar.js +1 -0
- package/dist/plugins/twake/calendarResources.js +1 -1
- package/dist/plugins/twake/james.js +1 -1
- package/dist/src/abstract/ldapFlat.d.ts +159 -1
- package/dist/src/abstract/plugin.d.ts +13 -0
- package/dist/src/config/args.d.ts +2 -0
- package/dist/src/config/schema.d.ts +382 -12
- package/dist/src/lib/expressFormatedResponses.d.ts +14 -0
- package/dist/src/lib/ldapActions.d.ts +33 -6
- package/dist/src/lib/utils.d.ts +65 -0
- package/dist/src/plugins/auth/authzScope.d.ts +53 -0
- package/dist/src/plugins/auth/llng.d.ts +30 -1
- package/dist/src/plugins/ldap/accountLifecycle.d.ts +56 -0
- package/dist/src/plugins/ldap/departmentSync.d.ts +43 -0
- package/dist/src/plugins/ldap/enterpriseRules.d.ts +436 -0
- package/dist/src/plugins/ldap/flatGeneric.d.ts +29 -0
- package/dist/src/plugins/ldap/groups.d.ts +22 -0
- package/dist/src/plugins/ldap/organizations.d.ts +25 -4
- package/dist/src/plugins/twake/calendar.d.ts +113 -0
- package/dist/src/plugins/twake/calendarResources.d.ts +9 -58
- package/docs/README.md +1 -0
- package/docs/client-development/api/openapi.md +1 -1
- package/docs/client-development/browser/libraries.md +1 -1
- package/docs/plugin-development/dependencies.md +10 -7
- package/docs/presentations/en.md +1 -1
- package/docs/presentations/fr.md +1 -1
- package/docs/usage/README.md +1 -0
- package/docs/usage/configuration.md +35 -15
- package/docs/usage/directory-audit.md +105 -0
- package/docs/usage/plugins/README.md +6 -6
- package/docs/usage/plugins/auth/README.md +6 -5
- package/docs/usage/plugins/auth/authz-scope.md +103 -0
- package/docs/usage/plugins/auth/llng.md +17 -0
- package/docs/usage/plugins/integrations/README.md +5 -5
- package/docs/usage/plugins/integrations/{calendar-resources.md → calendar.md} +70 -13
- package/docs/usage/plugins/ldap/README.md +13 -11
- package/docs/usage/plugins/ldap/account-lifecycle.md +129 -0
- package/docs/usage/plugins/ldap/bulk-import.md +8 -1
- package/docs/usage/plugins/ldap/enterprise-rules.md +167 -0
- package/docs/usage/plugins/ldap/flat-generic.md +172 -0
- package/docs/usage/plugins/ldap/groups.md +10 -4
- package/docs/usage/plugins/ldap/organizations.md +59 -33
- package/docs/usage/upgrading.md +322 -0
- package/package.json +50 -5
- package/static/schemas/example/README.md +36 -0
- package/static/schemas/example/groups.json +94 -0
- package/static/schemas/example/nomenclature/domains.json +49 -0
- package/static/schemas/example/organizations.json +106 -0
- package/static/schemas/example/positions.json +35 -0
- package/static/schemas/example/users.json +246 -0
- package/static/schemas/twake/groups.json +81 -15
- package/static/schemas/twake/nomenclature/twakeAccountStatus.json +26 -0
- package/static/schemas/twake/nomenclature/twakeDeliveryMode.json +22 -0
- package/static/schemas/twake/nomenclature/twakeDomain.json +60 -0
- package/static/schemas/twake/nomenclature/twakeListType.json +22 -0
- package/static/schemas/twake/nomenclature/twakeMailboxType.json +22 -0
- package/static/schemas/twake/nomenclature/twakeTitle.json +42 -0
- package/static/schemas/twake/organizations.json +92 -12
- package/static/schemas/twake/positions.json +22 -4
- package/static/schemas/twake/users.json +269 -32
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import TwakePlugin from '../../abstract/twakePlugin';
|
|
2
|
+
import { type Role } from '../../abstract/plugin';
|
|
3
|
+
import { Hooks } from '../../hooks';
|
|
4
|
+
/**
|
|
5
|
+
* Plugin to sync LDAP resources and users with Twake Calendar
|
|
6
|
+
*
|
|
7
|
+
* Monitors a LDAP branch for resources (meeting rooms, equipment, etc.)
|
|
8
|
+
* and automatically creates/updates/deletes them in Twake Calendar via WebAdmin API.
|
|
9
|
+
*
|
|
10
|
+
* Also propagates user identity changes (email, first name, last name) to the
|
|
11
|
+
* Twake Calendar "registered users" via the WebAdmin API.
|
|
12
|
+
*/
|
|
13
|
+
export default class Calendar extends TwakePlugin {
|
|
14
|
+
name: string;
|
|
15
|
+
roles: Role[];
|
|
16
|
+
dependencies: {
|
|
17
|
+
onLdapChange: string;
|
|
18
|
+
};
|
|
19
|
+
private resourceBase;
|
|
20
|
+
private resourceObjectClass;
|
|
21
|
+
private resourceCreator;
|
|
22
|
+
private resourceDomain;
|
|
23
|
+
private firstnameAttr;
|
|
24
|
+
private lastnameAttr;
|
|
25
|
+
constructor(server: import('../../bin').DM);
|
|
26
|
+
hooks: Hooks;
|
|
27
|
+
/**
|
|
28
|
+
* Check if a LDAP entry is a calendar resource
|
|
29
|
+
*/
|
|
30
|
+
private isResource;
|
|
31
|
+
/**
|
|
32
|
+
* Whether a DN is the configured resource branch or sits below it.
|
|
33
|
+
*
|
|
34
|
+
* Compared RDN by RDN ({@link isDnInBranch}), not as text: a substring test
|
|
35
|
+
* took `cn=Salle,ou=resourcesArchive,…` for a resource when the branch was
|
|
36
|
+
* given as `ou=resources`, and missed a DN written `cn=Salle, ou=resources,
|
|
37
|
+
* …` — the spaces a client puts after its commas are not part of the DN.
|
|
38
|
+
*
|
|
39
|
+
* No configured branch means no branch restriction, as before.
|
|
40
|
+
*/
|
|
41
|
+
private isInResourceBranch;
|
|
42
|
+
/**
|
|
43
|
+
* URL of one resource in the WebAdmin API.
|
|
44
|
+
*
|
|
45
|
+
* The id is a raw RDN value, so it can carry anything a directory accepts:
|
|
46
|
+
* `cn=Salle A/B` interpolated as such builds `/resources/Salle A/B`, a path
|
|
47
|
+
* naming another resource or none. Percent-encoding keeps it one segment.
|
|
48
|
+
*/
|
|
49
|
+
private resourceUrl;
|
|
50
|
+
/**
|
|
51
|
+
* Build resource data for Calendar API from LDAP attributes
|
|
52
|
+
*/
|
|
53
|
+
private buildResourceData;
|
|
54
|
+
/**
|
|
55
|
+
* The name a resource is known by in Calendar: the value of the entry's own
|
|
56
|
+
* RDN, escapes removed.
|
|
57
|
+
*
|
|
58
|
+
* Taken from the first RDN, whatever its attribute type, so that an entity
|
|
59
|
+
* whose mainAttribute is neither `cn` nor `uid` gets an id of its own. The
|
|
60
|
+
* previous derivation looked for `cn=`/`uid=` anywhere in the DN, so
|
|
61
|
+
* `o=Room 12,cn=zone,ou=resources,…` answered `zone`, its parent's id — a
|
|
62
|
+
* modify on that entry then patched another resource. It also cut the value
|
|
63
|
+
* at the first comma, escaped or not, so `cn=Salle\, 2` answered `Salle\`,
|
|
64
|
+
* an id two rooms could share.
|
|
65
|
+
*
|
|
66
|
+
* A DN with `cn=` or `uid=` as its own first RDN and no escape in its value
|
|
67
|
+
* — the shape a deployment has — answers exactly what it answered before.
|
|
68
|
+
*/
|
|
69
|
+
private getResourceId;
|
|
70
|
+
/**
|
|
71
|
+
* Find a Calendar registered user by email.
|
|
72
|
+
*
|
|
73
|
+
* `GET /registeredUsers?email=…` answers the one user, or 404. Calendar
|
|
74
|
+
* lower-cases the address before matching it (James's `Username` folds both
|
|
75
|
+
* parts), which is also how it stores every address, so a case difference
|
|
76
|
+
* between LDAP and Calendar does not matter. The one record this misses is
|
|
77
|
+
* a legacy one whose stored address kept upper case, written without going
|
|
78
|
+
* through `Username`; the full-list lookup used before did find it.
|
|
79
|
+
*
|
|
80
|
+
* Calendar releases before 1.0.0.1 ignore the `email` parameter and answer
|
|
81
|
+
* the full list; the user is then picked from it, case-insensitively.
|
|
82
|
+
*
|
|
83
|
+
* @param email Address Calendar holds for the user
|
|
84
|
+
* @param log Log context of the calling sync
|
|
85
|
+
* @returns The registered user, or null when it is not registered or the
|
|
86
|
+
* lookup failed (both logged)
|
|
87
|
+
*/
|
|
88
|
+
private findRegisteredUser;
|
|
89
|
+
/**
|
|
90
|
+
* Synchronize an LDAP user's identity (email, first and last name) to the
|
|
91
|
+
* Twake Calendar registered users via the WebAdmin API.
|
|
92
|
+
*
|
|
93
|
+
* Registered users are keyed by an internal id: the user is looked up with
|
|
94
|
+
* `GET /registeredUsers?email=…` (see findRegisteredUser), then
|
|
95
|
+
* `PATCH /registeredUsers?id={id}` with the LDAP values.
|
|
96
|
+
*
|
|
97
|
+
* @param event Hook name, used for logging
|
|
98
|
+
* @param dn LDAP DN of the user
|
|
99
|
+
* @param lookupEmail Email used to locate the existing registered user.
|
|
100
|
+
* Defaults to the user's current mail; pass the OLD mail when the email
|
|
101
|
+
* itself is changing (Calendar still holds the previous address).
|
|
102
|
+
*/
|
|
103
|
+
syncRegisteredUser(event: string, dn: string, lookupEmail?: string): Promise<void>;
|
|
104
|
+
/**
|
|
105
|
+
* Delete user data from Twake Calendar WebAdmin API
|
|
106
|
+
* Calls POST /users/{mail}?action=deleteData
|
|
107
|
+
* @param mail - The user's email address
|
|
108
|
+
* @returns Task information or null on error
|
|
109
|
+
*/
|
|
110
|
+
deleteUserData(mail: string): Promise<{
|
|
111
|
+
taskId: string;
|
|
112
|
+
} | null>;
|
|
113
|
+
}
|
|
@@ -1,63 +1,14 @@
|
|
|
1
|
-
import TwakePlugin from '../../abstract/twakePlugin';
|
|
2
|
-
import { type Role } from '../../abstract/plugin';
|
|
3
|
-
import { Hooks } from '../../hooks';
|
|
4
1
|
/**
|
|
5
|
-
*
|
|
2
|
+
* @deprecated Use `core/twake/calendar` instead. This file is a
|
|
3
|
+
* backwards-compatibility shim for setups that still load the plugin under
|
|
4
|
+
* its historical name, which undersold it: besides resources, it propagates
|
|
5
|
+
* user identity changes (email, first and last name) to Twake Calendar. It
|
|
6
|
+
* will be removed in a future major release.
|
|
6
7
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* Also propagates user identity changes (email, first name, last name) to the
|
|
11
|
-
* Twake Calendar "registered users" via the WebAdmin API.
|
|
8
|
+
* The instance keeps registering as `calendarResources`, so code looking it
|
|
9
|
+
* up by that name keeps finding it.
|
|
12
10
|
*/
|
|
13
|
-
|
|
11
|
+
import Calendar from './calendar';
|
|
12
|
+
export default class CalendarResources extends Calendar {
|
|
14
13
|
name: string;
|
|
15
|
-
roles: Role[];
|
|
16
|
-
dependencies: {
|
|
17
|
-
onLdapChange: string;
|
|
18
|
-
};
|
|
19
|
-
private resourceBase;
|
|
20
|
-
private resourceObjectClass;
|
|
21
|
-
private resourceCreator;
|
|
22
|
-
private resourceDomain;
|
|
23
|
-
private firstnameAttr;
|
|
24
|
-
private lastnameAttr;
|
|
25
|
-
constructor(server: import('../../bin').DM);
|
|
26
|
-
hooks: Hooks;
|
|
27
|
-
/**
|
|
28
|
-
* Check if a LDAP entry is a calendar resource
|
|
29
|
-
*/
|
|
30
|
-
private isResource;
|
|
31
|
-
/**
|
|
32
|
-
* Build resource data for Calendar API from LDAP attributes
|
|
33
|
-
*/
|
|
34
|
-
private buildResourceData;
|
|
35
|
-
/**
|
|
36
|
-
* Extract resource ID from DN
|
|
37
|
-
*/
|
|
38
|
-
private getResourceId;
|
|
39
|
-
/**
|
|
40
|
-
* Synchronize an LDAP user's identity (email, first and last name) to the
|
|
41
|
-
* Twake Calendar registered users via the WebAdmin API.
|
|
42
|
-
*
|
|
43
|
-
* Registered users are keyed by an internal id, and `GET /registeredUsers`
|
|
44
|
-
* exposes no filter, so we list all registered users, locate the entry by
|
|
45
|
-
* email, then `PATCH /registeredUsers?id={id}` with the LDAP values.
|
|
46
|
-
*
|
|
47
|
-
* @param event Hook name, used for logging
|
|
48
|
-
* @param dn LDAP DN of the user
|
|
49
|
-
* @param lookupEmail Email used to locate the existing registered user.
|
|
50
|
-
* Defaults to the user's current mail; pass the OLD mail when the email
|
|
51
|
-
* itself is changing (Calendar still holds the previous address).
|
|
52
|
-
*/
|
|
53
|
-
syncRegisteredUser(event: string, dn: string, lookupEmail?: string): Promise<void>;
|
|
54
|
-
/**
|
|
55
|
-
* Delete user data from Twake Calendar WebAdmin API
|
|
56
|
-
* Calls POST /users/{mail}?action=deleteData
|
|
57
|
-
* @param mail - The user's email address
|
|
58
|
-
* @returns Task information or null on error
|
|
59
|
-
*/
|
|
60
|
-
deleteUserData(mail: string): Promise<{
|
|
61
|
-
taskId: string;
|
|
62
|
-
} | null>;
|
|
63
14
|
}
|
package/docs/README.md
CHANGED
|
@@ -11,6 +11,7 @@ Installation, configuration and plugin usage.
|
|
|
11
11
|
- **[Getting Started](usage/README.md)** - Quick start guide
|
|
12
12
|
- **[Configuration](usage/configuration.md)** - CLI options and environment variables
|
|
13
13
|
- **[Upgrading](usage/upgrading.md)** - What to check before deploying a new version
|
|
14
|
+
- **[Directory audit](usage/directory-audit.md)** - What a schema would refuse in an existing directory
|
|
14
15
|
- **[Plugins](usage/plugins/README.md)** - Documentation for all available plugins
|
|
15
16
|
|
|
16
17
|
### [Plugin Development](plugin-development/README.md)
|
|
@@ -220,7 +220,7 @@ private pluginTags: Map<string, string> = new Map([
|
|
|
220
220
|
['ldapFlatGeneric', 'Entities'],
|
|
221
221
|
['ldapBulkImport', 'Bulk Import'],
|
|
222
222
|
['james', 'Apache James Integration'],
|
|
223
|
-
['
|
|
223
|
+
['calendar', 'Twake Calendar'],
|
|
224
224
|
['configApi', 'Configuration'],
|
|
225
225
|
['static', 'Static Files'],
|
|
226
226
|
]);
|
|
@@ -34,7 +34,7 @@ This guide covers LDAP-Rest's browser libraries for building LDAP management int
|
|
|
34
34
|
|
|
35
35
|
## Overview
|
|
36
36
|
|
|
37
|
-
LDAP-Rest provides
|
|
37
|
+
LDAP-Rest provides ready-to-use browser libraries for building LDAP management interfaces:
|
|
38
38
|
|
|
39
39
|
- **LdapTreeViewer** - Interactive hierarchical tree view of LDAP organizations
|
|
40
40
|
- **LdapUserEditor** - Complete user management interface with organization tree, user list, and edit form
|
|
@@ -190,15 +190,18 @@ dependencies = {
|
|
|
190
190
|
- **Consumes Hooks**: (Hooks provided by `onLdapChange`)
|
|
191
191
|
- **Notes**: Synchronizes LDAP users/groups with Apache James mail server
|
|
192
192
|
|
|
193
|
-
#### `
|
|
193
|
+
#### `calendar` (twake/calendar)
|
|
194
194
|
|
|
195
|
-
- **Dependencies**:
|
|
195
|
+
- **Dependencies**:
|
|
196
|
+
- `onLdapChange: 'core/ldap/onChange'` ⚠️ **Required**
|
|
196
197
|
- **Provides Hooks**:
|
|
197
198
|
- `ldapcalendarResourceadddone` - After calendar resource added
|
|
198
199
|
- `ldapcalendarResourcemodifydone` - After calendar resource modified
|
|
199
200
|
- `ldapcalendarResourcedeletedone` - After calendar resource deleted
|
|
200
|
-
-
|
|
201
|
-
- **
|
|
201
|
+
- `onLdapChange` - Propagates user email / name changes
|
|
202
|
+
- **Consumes Hooks**: (Hooks provided by `onLdapChange`)
|
|
203
|
+
- **Notes**: Synchronizes calendar resources and registered users with Twake
|
|
204
|
+
Calendar. Formerly `calendarResources`, still loadable under that name
|
|
202
205
|
|
|
203
206
|
#### `appAccountsConsistency` (twake/appAccountsConsistency)
|
|
204
207
|
|
|
@@ -361,7 +364,7 @@ ldapOrganizations (core/ldap/organization)
|
|
|
361
364
|
├─────────────────────────────────────────────────────────────────────────────┤
|
|
362
365
|
│ │
|
|
363
366
|
│ ┌────────────────────────────┐ ┌──────────────────────────┐ │
|
|
364
|
-
│ │ james │ │
|
|
367
|
+
│ │ james │ │ calendar │ │
|
|
365
368
|
│ │ (Apache James sync) │ │ (Twake Calendar sync) │ │
|
|
366
369
|
│ │ │ │ │ │
|
|
367
370
|
│ │ Requires: │ │ │ │
|
|
@@ -466,7 +469,7 @@ graph TB
|
|
|
466
469
|
|
|
467
470
|
%% Twake Integration
|
|
468
471
|
james[james]
|
|
469
|
-
calendar[
|
|
472
|
+
calendar[calendar]
|
|
470
473
|
|
|
471
474
|
%% Utility
|
|
472
475
|
static[static]
|
|
@@ -521,7 +524,7 @@ graph TB
|
|
|
521
524
|
### 4. Integration Plugins
|
|
522
525
|
|
|
523
526
|
13. `james` - After `onChange` and `groups`
|
|
524
|
-
14. `
|
|
527
|
+
14. `calendar` - Twake Calendar sync (optional)
|
|
525
528
|
|
|
526
529
|
### 5. Utility Plugins (can load anytime)
|
|
527
530
|
|
package/docs/presentations/en.md
CHANGED
|
@@ -100,7 +100,7 @@ export default class MyPlugin extends DmPlugin {
|
|
|
100
100
|
## Integrations
|
|
101
101
|
|
|
102
102
|
- **twake/james** - Apache James Synchronization (mail)
|
|
103
|
-
- **twake/
|
|
103
|
+
- **twake/calendar** - Twake Calendar resources and users
|
|
104
104
|
|
|
105
105
|
<!-- end_slide -->
|
|
106
106
|
|
package/docs/presentations/fr.md
CHANGED
|
@@ -100,7 +100,7 @@ export default class MyPlugin extends DmPlugin {
|
|
|
100
100
|
## Intégrations
|
|
101
101
|
|
|
102
102
|
- **twake/james** - Synchronisation Apache James (mail)
|
|
103
|
-
- **twake/
|
|
103
|
+
- **twake/calendar** - Ressources et utilisateurs Twake Calendar
|
|
104
104
|
|
|
105
105
|
<!-- end_slide -->
|
|
106
106
|
|
package/docs/usage/README.md
CHANGED
|
@@ -87,4 +87,5 @@ The system will:
|
|
|
87
87
|
- **[Configuration](configuration.md)** - CLI options and environment variables
|
|
88
88
|
- **[Plugins](plugins/README.md)** - Choose and configure plugins
|
|
89
89
|
- **[Upgrading](upgrading.md)** - What to check before deploying a new version
|
|
90
|
+
- **[Directory audit](directory-audit.md)** - What a schema would refuse in an existing directory
|
|
90
91
|
- **[Troubleshooting](troubleshooting.md)** - Problem resolution
|
|
@@ -35,7 +35,7 @@ All LDAP-Rest configuration options.
|
|
|
35
35
|
- [core/auth/trustedProxy](#coreauthtrustedproxy)
|
|
36
36
|
- [Twake Integration Plugins](#twake-integration-plugins)
|
|
37
37
|
- [core/twake/james](#coretwakejames)
|
|
38
|
-
- [core/twake/
|
|
38
|
+
- [core/twake/calendar](#coretwakecalendar)
|
|
39
39
|
- [core/twake/applicativeAccounts](#coretwakeapplicativeaccounts)
|
|
40
40
|
- [core/twake/appAccountsConsistency](#coretwakeappaccountsconsistency)
|
|
41
41
|
- [Utility Plugins](#utility-plugins)
|
|
@@ -92,18 +92,34 @@ export DM_PLUGINS="core/auth/token,core/ldap/flatGeneric,core/ldap/groups"
|
|
|
92
92
|
|
|
93
93
|
## LDAP Connection
|
|
94
94
|
|
|
95
|
-
| CLI | Plural | Env | Default | Description
|
|
96
|
-
| ---------------------------- | ---------------- | ------------------------ | ---------------------------------- |
|
|
97
|
-
| `--ldap-url` | `--ldap-urls` | `DM_LDAP_URL` | `ldap://localhost` | LDAP server URL(s)
|
|
98
|
-
| `--ldap-dn` | | `DM_LDAP_DN` | `cn=admin,dc=example,dc=com` | Bind DN
|
|
99
|
-
| `--ldap-pwd` | | `DM_LDAP_PWD` | `admin` | Password
|
|
100
|
-
| `--ldap-base` | | `DM_LDAP_BASE` | | Base DN for searches
|
|
101
|
-
| `--ldap-user-main-attribute` | | `DM_LDAP_USER_ATTRIBUTE` | `uid` | User identifier attribute
|
|
102
|
-
| `--ldap-cache-max` | | `DM_LDAP_CACHE_MAX` | `1000` | Max cache entries
|
|
103
|
-
| `--ldap-cache-ttl` | | `DM_LDAP_CACHE_TTL` | `
|
|
104
|
-
| `--ldap-pool-size` | | `DM_LDAP_POOL_SIZE` | `5` | Connection pool size
|
|
105
|
-
| `--ldap-connection-ttl` | | `DM_LDAP_CONNECTION_TTL` | `60` | Connection TTL (seconds)
|
|
106
|
-
| `--user-class` | `--user-classes` | `DM_USER_CLASSES` | `top,twakeAccount,twakeWhitePages` | Default user objectClasses
|
|
95
|
+
| CLI | Plural | Env | Default | Description |
|
|
96
|
+
| ---------------------------- | ---------------- | ------------------------ | ---------------------------------- | ------------------------------------------- |
|
|
97
|
+
| `--ldap-url` | `--ldap-urls` | `DM_LDAP_URL` | `ldap://localhost` | LDAP server URL(s) |
|
|
98
|
+
| `--ldap-dn` | | `DM_LDAP_DN` | `cn=admin,dc=example,dc=com` | Bind DN |
|
|
99
|
+
| `--ldap-pwd` | | `DM_LDAP_PWD` | `admin` | Password |
|
|
100
|
+
| `--ldap-base` | | `DM_LDAP_BASE` | | Base DN for searches |
|
|
101
|
+
| `--ldap-user-main-attribute` | | `DM_LDAP_USER_ATTRIBUTE` | `uid` | User identifier attribute |
|
|
102
|
+
| `--ldap-cache-max` | | `DM_LDAP_CACHE_MAX` | `1000` | Max cache entries |
|
|
103
|
+
| `--ldap-cache-ttl` | | `DM_LDAP_CACHE_TTL` | `0` | Search cache TTL (seconds), `0` disables it |
|
|
104
|
+
| `--ldap-pool-size` | | `DM_LDAP_POOL_SIZE` | `5` | Connection pool size |
|
|
105
|
+
| `--ldap-connection-ttl` | | `DM_LDAP_CONNECTION_TTL` | `60` | Connection TTL (seconds) |
|
|
106
|
+
| `--user-class` | `--user-classes` | `DM_USER_CLASSES` | `top,twakeAccount,twakeWhitePages` | Default user objectClasses |
|
|
107
|
+
|
|
108
|
+
### The search cache
|
|
109
|
+
|
|
110
|
+
`--ldap-cache-ttl` holds the answers of non-paginated, base-scope searches —
|
|
111
|
+
single-entry lookups by DN — for that many seconds. It is **off by default**:
|
|
112
|
+
until the branch storing a result was repaired, nothing was ever cached, so no
|
|
113
|
+
deployment has run with it on, and a cache that silently serves stale entries
|
|
114
|
+
is not something to switch on for everyone at once.
|
|
115
|
+
|
|
116
|
+
Writes made through this service (add, modify, rename, move, delete) drop what
|
|
117
|
+
they change, the moved subtree included. Writes made anywhere else do not:
|
|
118
|
+
another replica of this service, an LSC synchronisation, a hand-run
|
|
119
|
+
`ldapmodify`. Each process caches on its own, and only its own writes drop what
|
|
120
|
+
it cached. Turn the cache on when this service is the only writer, or when
|
|
121
|
+
serving an entry up to `--ldap-cache-ttl` seconds old is acceptable; leave it
|
|
122
|
+
at `0` otherwise.
|
|
107
123
|
|
|
108
124
|
## Special Attributes
|
|
109
125
|
|
|
@@ -188,7 +204,7 @@ Monitors LDAP modifications and triggers hooks for attribute changes. No configu
|
|
|
188
204
|
|
|
189
205
|
#### `core/ldap/departmentSync`
|
|
190
206
|
|
|
191
|
-
Maintains consistency of department links when organizations are renamed/moved. No configuration options - uses [core/ldap/organizations](#coreldaporganizations) settings.
|
|
207
|
+
Maintains consistency of department links when organizations are renamed/moved: it recomputes the path of the organization and of its sub-organizations (those already holding one), then updates the link and path of the entries linked to any of them. The attributes are those the loaded schemas declare through the `organizationPath` and `organizationLink` roles, then the configured `--ldap-organization-path-attribute` and `--ldap-organization-link-attribute`. No configuration options of its own - uses [core/ldap/organizations](#coreldaporganizations) settings.
|
|
192
208
|
|
|
193
209
|
#### `core/ldap/raw`
|
|
194
210
|
|
|
@@ -308,7 +324,9 @@ Empty means the plugin guards every path. Scoping several instances to different
|
|
|
308
324
|
| `--james-mailbox-type-attribute` | | `DM_JAMES_MAILBOX_TYPE_ATTRIBUTE` | `twakeMailboxType` | Mailbox type attribute |
|
|
309
325
|
| `--ldap-concurrency` | | `DM_LDAP_CONCURRENCY` | `10` | LDAP operations concurrency |
|
|
310
326
|
|
|
311
|
-
#### `core/twake/
|
|
327
|
+
#### `core/twake/calendar`
|
|
328
|
+
|
|
329
|
+
Formerly `core/twake/calendarResources`, still accepted as a deprecated alias.
|
|
312
330
|
|
|
313
331
|
| CLI | Env | Default | Description |
|
|
314
332
|
| --------------------------------- | ---------------------------------- | ----------------------- | ----------------------------- |
|
|
@@ -319,6 +337,8 @@ Empty means the plugin guards every path. Scoping several instances to different
|
|
|
319
337
|
| `--calendar-resource-objectclass` | `DM_CALENDAR_RESOURCE_OBJECTCLASS` | | Resource objectClass |
|
|
320
338
|
| `--calendar-resource-creator` | `DM_CALENDAR_RESOURCE_CREATOR` | | Resource creator |
|
|
321
339
|
| `--calendar-resource-domain` | `DM_CALENDAR_RESOURCE_DOMAIN` | | Resource domain |
|
|
340
|
+
| `--calendar-firstname-attribute` | `DM_CALENDAR_FIRSTNAME_ATTRIBUTE` | `givenName` | Registered user first name |
|
|
341
|
+
| `--calendar-lastname-attribute` | `DM_CALENDAR_LASTNAME_ATTRIBUTE` | `sn` | Registered user last name |
|
|
322
342
|
|
|
323
343
|
#### `core/twake/applicativeAccounts`
|
|
324
344
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Auditing a directory before a migration
|
|
2
|
+
|
|
3
|
+
Tightening a validation pattern changes what the server accepts **from now
|
|
4
|
+
on**. It says nothing about the entries already stored: a directory whose
|
|
5
|
+
addresses were never anchored, or whose organization names predate the rule
|
|
6
|
+
that now governs them, loads fine and then refuses the first update of every
|
|
7
|
+
offending entry — which is discovered one support ticket at a time.
|
|
8
|
+
|
|
9
|
+
`npm run audit:directory` reads a branch as it is and reports what the schema
|
|
10
|
+
would refuse, so the work is known before the switch rather than after it.
|
|
11
|
+
|
|
12
|
+
## Running it
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
export DM_LDAP_URL=ldap://directory.example.org
|
|
16
|
+
export DM_LDAP_DN='cn=admin,dc=example,dc=com'
|
|
17
|
+
export DM_LDAP_PWD='…'
|
|
18
|
+
export DM_LDAP_BASE='dc=example,dc=com'
|
|
19
|
+
|
|
20
|
+
npm run audit:directory -- --schema static/schemas/twake/users.json \
|
|
21
|
+
--plugin core/ldap/enterpriseRules
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
| Option | Default | Purpose |
|
|
25
|
+
| ----------------- | ---------------------------- | ----------------------------------- |
|
|
26
|
+
| `--schema` | _(required)_ | Schema to check against |
|
|
27
|
+
| `--base` | the schema's own entity base | Branch to read |
|
|
28
|
+
| `--filter` | `(objectClass=*)` | Narrows what is audited |
|
|
29
|
+
| `--url` | `DM_LDAP_URL` | Directory to read |
|
|
30
|
+
| `--bind-dn` | `DM_LDAP_DN` | Identity to read with |
|
|
31
|
+
| `--bind-password` | `DM_LDAP_PWD` | Its password |
|
|
32
|
+
| `--samples` | `5` | Offending entries named per finding |
|
|
33
|
+
| `--plugin` | _(none)_ | A plugin the server loads, repeated |
|
|
34
|
+
|
|
35
|
+
`--plugin` matters for the attributes a schema marks both `required` and
|
|
36
|
+
`generated`. The server exempts one from its check only when something fills
|
|
37
|
+
it: the entity itself (`generatedFrom`), or a loaded plugin. Name the plugins
|
|
38
|
+
the server loads and the audit exempts what they fill; without them it reports
|
|
39
|
+
those attributes as `missing, and no --plugin fills it` — which is what every
|
|
40
|
+
creation would be refused for on a server that does not load them.
|
|
41
|
+
|
|
42
|
+
It exits `0` when the branch is clean, `1` when the schema would refuse
|
|
43
|
+
something, and `2` when the audit itself could not run — an unreadable schema,
|
|
44
|
+
a directory that would not answer — so a pipeline can tell "dirty" from
|
|
45
|
+
"broken" rather than gating on both alike.
|
|
46
|
+
|
|
47
|
+
`--bind-password` puts the password in `ps` and in the shell history of
|
|
48
|
+
whoever runs it. `DM_LDAP_PWD` is the path to prefer, and the flag is there
|
|
49
|
+
for parity with the server's own `--ldap-pwd`.
|
|
50
|
+
|
|
51
|
+
## What it checks, and what only the server can
|
|
52
|
+
|
|
53
|
+
The audit reads a schema and an entry, so it answers what an entry alone can
|
|
54
|
+
answer: required attributes, the `test` pattern of a value and of an array's
|
|
55
|
+
elements, and the branch a DN must land in. It replaces `__KEY__` placeholders
|
|
56
|
+
and `{config_key}` in `entity.base` from the `DM_*` environment exactly as the
|
|
57
|
+
server does, leaving a placeholder the configuration does not name.
|
|
58
|
+
|
|
59
|
+
What it does not answer needs the rest of the directory, and belongs to a dry
|
|
60
|
+
run rather than here: uniqueness across a namespace, the mail domains an
|
|
61
|
+
organization owns, and anything a plugin computes after validation. A clean
|
|
62
|
+
audit is not a promise that every entry will survive every rule — it is a
|
|
63
|
+
promise that none of them fails on its own contents.
|
|
64
|
+
|
|
65
|
+
## Reading the report
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
12632 entries read, 47 value(s) the schema would refuse:
|
|
69
|
+
|
|
70
|
+
mail: does not match — 41
|
|
71
|
+
expected: Expected an address in the example.org domain, at most 64 characters before the @
|
|
72
|
+
uid=jean.dupont,ou=users,dc=example,dc=com → "jean.dupont@old-domain.example"
|
|
73
|
+
…and 36 more
|
|
74
|
+
|
|
75
|
+
postalCode: does not match — 6
|
|
76
|
+
expected: Expected pattern 9999, A9999 or R9999
|
|
77
|
+
uid=marie.martin,ou=users,dc=example,dc=com → "1234"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Each finding names the attribute, why it was refused, and — from the schema's
|
|
81
|
+
`hint` — what a valid value looks like. The same wording reaches the person
|
|
82
|
+
filling the form, so the fix and the rule are described identically.
|
|
83
|
+
|
|
84
|
+
## What it checks, and what it cannot
|
|
85
|
+
|
|
86
|
+
Checked, because an entry answers for itself:
|
|
87
|
+
|
|
88
|
+
- `test` patterns, on single and multi-valued attributes
|
|
89
|
+
- `required` attributes that are absent — except the ones the server computes
|
|
90
|
+
(`generated`), which an entry is not expected to carry yet
|
|
91
|
+
- the `branch` a `pointer` must land in
|
|
92
|
+
|
|
93
|
+
Not checked, because it takes the whole directory or a live server:
|
|
94
|
+
|
|
95
|
+
- uniqueness across a shared namespace
|
|
96
|
+
- mail addresses against the domains an organization owns
|
|
97
|
+
- anything a hook computes rather than validates
|
|
98
|
+
|
|
99
|
+
For those, run the target configuration against a copy of the directory and
|
|
100
|
+
replay the writes.
|
|
101
|
+
|
|
102
|
+
## See also
|
|
103
|
+
|
|
104
|
+
- [flat-generic](plugins/ldap/flat-generic.md) — where `test` and `hint` live
|
|
105
|
+
- [enterprise-rules](plugins/ldap/enterprise-rules.md) — the rules a dry run covers
|
|
@@ -52,12 +52,12 @@ Protection and rate limiting:
|
|
|
52
52
|
|
|
53
53
|
Connect to external systems:
|
|
54
54
|
|
|
55
|
-
| Plugin
|
|
56
|
-
|
|
|
57
|
-
| [james-mail](integrations/james-mail.md)
|
|
58
|
-
| [james-mailboxes](integrations/james-mailboxes.md)
|
|
59
|
-
| [calendar
|
|
60
|
-
| [app-accounts](integrations/app-accounts.md)
|
|
55
|
+
| Plugin | Description |
|
|
56
|
+
| -------------------------------------------------- | ---------------------------------- |
|
|
57
|
+
| [james-mail](integrations/james-mail.md) | Apache James synchronization |
|
|
58
|
+
| [james-mailboxes](integrations/james-mailboxes.md) | Apache James team mailboxes |
|
|
59
|
+
| [calendar](integrations/calendar.md) | Twake Calendar resources and users |
|
|
60
|
+
| [app-accounts](integrations/app-accounts.md) | Applicative accounts API |
|
|
61
61
|
|
|
62
62
|
## Utility Plugins
|
|
63
63
|
|
|
@@ -14,11 +14,12 @@ LDAP-Rest provides multiple authentication plugins to secure API access. These p
|
|
|
14
14
|
|
|
15
15
|
## Authorization Plugins
|
|
16
16
|
|
|
17
|
-
| Method | Plugin | Description
|
|
18
|
-
| ----------------------------------------------- | -------------------------- |
|
|
19
|
-
| [Authorization Per Branch](authz-per-branch.md) | `core/auth/authzPerBranch` | Branch-level access control
|
|
20
|
-
| [Authorization Per Route](authz-per-route.md) | `core/auth/authzPerRoute` | HTTP route-level ACL
|
|
21
|
-
| [Authorization LinID 1.x](authz-linid1.md) | `core/auth/authzLinid1` | LinID 1.x integration
|
|
17
|
+
| Method | Plugin | Description |
|
|
18
|
+
| ----------------------------------------------- | -------------------------- | ---------------------------- |
|
|
19
|
+
| [Authorization Per Branch](authz-per-branch.md) | `core/auth/authzPerBranch` | Branch-level access control |
|
|
20
|
+
| [Authorization Per Route](authz-per-route.md) | `core/auth/authzPerRoute` | HTTP route-level ACL |
|
|
21
|
+
| [Authorization LinID 1.x](authz-linid1.md) | `core/auth/authzLinid1` | LinID 1.x integration |
|
|
22
|
+
| [Authorization Scope](authz-scope.md) | `core/auth/authzScope` | What the current user may do |
|
|
22
23
|
|
|
23
24
|
## Security Plugins
|
|
24
25
|
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Authorization Scope Plugin
|
|
2
|
+
|
|
3
|
+
Tells a client what the signed-in administrator may actually do, before it
|
|
4
|
+
offers them a button that will fail.
|
|
5
|
+
|
|
6
|
+
In a local-administration model the scope _is_ the interface: a manager
|
|
7
|
+
administers a few branches of the tree and nothing else, and an application
|
|
8
|
+
that cannot name those branches leaves them guessing. This endpoint answers
|
|
9
|
+
both halves — which branches, and which entities can be created — by asking
|
|
10
|
+
whichever authorization plugin is in force.
|
|
11
|
+
|
|
12
|
+
## Configuration
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
--plugin core/auth/authzScope
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
It has no options. It answers through whichever loaded plugin carries the
|
|
19
|
+
`authz` role _and_ can say who may do what where — one implementing
|
|
20
|
+
`resolveUser`, `getAuthorizedBranches` and `getUserPermissions`. Both
|
|
21
|
+
[authz-linid1](authz-linid1.md) and [authz-per-branch](authz-per-branch.md)
|
|
22
|
+
do, and this endpoint works with either without knowing which.
|
|
23
|
+
|
|
24
|
+
The role alone is not enough. [authz-per-route](authz-per-route.md) gates URLs
|
|
25
|
+
and [authz-dynamic](authz-dynamic.md) reads a token: both carry the `authz`
|
|
26
|
+
role and implement none of those three methods, so this endpoint passes them
|
|
27
|
+
over — loading one beside a branch-level plugin changes the answer not at all.
|
|
28
|
+
A server whose only authorization plugin is one of those has nothing to
|
|
29
|
+
describe a scope with, and the answer is the unrestricted one shown below: a
|
|
30
|
+
client built on it shows every button, and a refusal, when it comes, comes from
|
|
31
|
+
the route or the token rather than from the scope.
|
|
32
|
+
|
|
33
|
+
## Endpoint
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
GET /api/v1/authz/scope
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"user": "uid=alice,ou=users,dc=example,dc=com",
|
|
42
|
+
"unrestricted": false,
|
|
43
|
+
"branches": [
|
|
44
|
+
{
|
|
45
|
+
"dn": "ou=Sales,ou=organization,dc=example,dc=com",
|
|
46
|
+
"name": "Sales",
|
|
47
|
+
"path": "Acme / Sales",
|
|
48
|
+
"read": true,
|
|
49
|
+
"write": true,
|
|
50
|
+
"delete": true
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"entities": [
|
|
54
|
+
{ "name": "users", "base": "ou=users,dc=example,dc=com", "create": true },
|
|
55
|
+
{ "name": "groups", "base": "ou=groups,dc=example,dc=com", "create": true },
|
|
56
|
+
{
|
|
57
|
+
"name": "organizations",
|
|
58
|
+
"base": "ou=organization,dc=example,dc=com",
|
|
59
|
+
"create": false
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`name` and `path` come from the branch entry itself, so an interface can show
|
|
66
|
+
the scope in the directory's own words rather than as a raw DN.
|
|
67
|
+
|
|
68
|
+
`create` answers "may I add one of these?", on the rule the add hook enforces.
|
|
69
|
+
An entry that can carry the organization link (its schema declares the
|
|
70
|
+
configured link attribute) is scoped by the organization it is attached to, so
|
|
71
|
+
the answer is yes as soon as the caller may write in a branch they administer.
|
|
72
|
+
One that cannot — a position, a nomenclature row — is checked against the
|
|
73
|
+
branch it lands in, so the answer is whether the caller may write there.
|
|
74
|
+
Organizations are the other exception, since they live in the tree itself and
|
|
75
|
+
need write permission on the node they hang from — the top of the tree, which
|
|
76
|
+
is where a new organization goes when the client names no parent. A local administrator of one branch therefore reads
|
|
77
|
+
`create: false` for organizations, and creates sub-organizations under their own
|
|
78
|
+
node by naming it as `parentDn`.
|
|
79
|
+
|
|
80
|
+
With no authorization plugin loaded the server grants everything, and the
|
|
81
|
+
answer says so:
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"user": "alice",
|
|
86
|
+
"unrestricted": true,
|
|
87
|
+
"branches": [],
|
|
88
|
+
"entities": [
|
|
89
|
+
{ "name": "users", "base": "ou=users,dc=example,dc=com", "create": true }
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Errors
|
|
95
|
+
|
|
96
|
+
| Status | When |
|
|
97
|
+
| ------ | ------------------------------------------------------------- |
|
|
98
|
+
| `401` | No authenticated user, or a user the directory cannot resolve |
|
|
99
|
+
|
|
100
|
+
## See also
|
|
101
|
+
|
|
102
|
+
- [authz-linid1](authz-linid1.md) — the local-administrator model this serves
|
|
103
|
+
- [authz-per-branch](authz-per-branch.md) — static per-branch permissions
|
|
@@ -21,6 +21,23 @@ DM_LLNG_INI="/etc/lemonldap-ng/lemonldap-ng.ini"
|
|
|
21
21
|
2. **LLNG Configuration**: Valid `lemonldap-ng.ini` file
|
|
22
22
|
3. **Virtual Host Configuration**: LDAP-Rest must be configured as a protected application in LLNG
|
|
23
23
|
|
|
24
|
+
The handler runs inside LDAP-Rest and reads `lemonldap-ng.ini` when the server
|
|
25
|
+
starts. The file tells it where the LLNG configuration is, and which virtual
|
|
26
|
+
hosts it protects — a Node.js handler serves only those listed in
|
|
27
|
+
`nodeVhosts`:
|
|
28
|
+
|
|
29
|
+
```ini
|
|
30
|
+
[configuration]
|
|
31
|
+
type = REST
|
|
32
|
+
baseConfigUrl = https://auth.example.com/index.fcgi/config
|
|
33
|
+
|
|
34
|
+
[node-handler]
|
|
35
|
+
nodeVhosts = api.example.com
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
A file that cannot be read, a configuration that cannot be reached or a
|
|
39
|
+
missing `nodeVhosts` stops the server at startup, with the reason.
|
|
40
|
+
|
|
24
41
|
## How It Works
|
|
25
42
|
|
|
26
43
|
1. Uses the LemonLDAP::NG Handler to validate requests
|