ldap-rest 0.26.0 → 1.0.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.
Files changed (96) hide show
  1. package/dist/abstract/ldapFlat.js +1 -1
  2. package/dist/abstract/twakePlugin.js +1 -1
  3. package/dist/bin/index.js +1 -1
  4. package/dist/config/args.js +1 -1
  5. package/dist/lib/authz/base.js +1 -1
  6. package/dist/lib/authz/composition.js +1 -1
  7. package/dist/lib/ldapActions.js +1 -1
  8. package/dist/lib/mailDomains.js +1 -0
  9. package/dist/lib/requestContext.js +1 -0
  10. package/dist/lib/utils.js +1 -1
  11. package/dist/plugins/auth/authzDynamic.js +1 -1
  12. package/dist/plugins/auth/authzLinid1.js +1 -1
  13. package/dist/plugins/auth/authzPerBranch.js +1 -1
  14. package/dist/plugins/auth/authzScope.js +1 -1
  15. package/dist/plugins/auth/openidconnect.js +1 -1
  16. package/dist/plugins/bcl.js +1 -1
  17. package/dist/plugins/configApi.js +1 -1
  18. package/dist/plugins/ldap/bulkImport.js +1 -1
  19. package/dist/plugins/ldap/departmentSync.js +1 -1
  20. package/dist/plugins/ldap/enterpriseRules.js +1 -1
  21. package/dist/plugins/ldap/externalUsersInGroups.js +1 -1
  22. package/dist/plugins/ldap/groups.js +1 -1
  23. package/dist/plugins/ldap/onChange.js +1 -1
  24. package/dist/plugins/ldap/organizations.js +1 -1
  25. package/dist/plugins/ldap/passwordPolicy.js +1 -1
  26. package/dist/plugins/ldap/raw.js +1 -1
  27. package/dist/plugins/ldap/trash.js +1 -1
  28. package/dist/plugins/rabbitmq.js +1 -1
  29. package/dist/plugins/scim/groups.js +1 -1
  30. package/dist/plugins/scim/users.js +1 -1
  31. package/dist/plugins/storage/ldap.js +1 -1
  32. package/dist/plugins/storage/postgres.js +1 -1
  33. package/dist/plugins/storage/valkey.js +1 -1
  34. package/dist/plugins/twake/appAccountsApi.js +1 -1
  35. package/dist/plugins/twake/appAccountsConsistency.js +1 -1
  36. package/dist/plugins/twake/clouderyProvision.js +1 -1
  37. package/dist/plugins/twake/groups.js +1 -1
  38. package/dist/plugins/twake/instances.js +1 -1
  39. package/dist/plugins/twake/james.js +1 -1
  40. package/dist/plugins/twake/lifecycleEvents.js +1 -1
  41. package/dist/plugins/twake/spaces.js +1 -1
  42. package/dist/plugins/twake/tombstone.js +1 -1
  43. package/dist/src/abstract/ldapFlat.d.ts +25 -6
  44. package/dist/src/abstract/plugin.d.ts +1 -1
  45. package/dist/src/bin/index.d.ts +12 -0
  46. package/dist/src/hooks.d.ts +12 -3
  47. package/dist/src/lib/authz/base.d.ts +87 -4
  48. package/dist/src/lib/authz/composition.d.ts +21 -0
  49. package/dist/src/lib/ldapActions.d.ts +139 -18
  50. package/dist/src/lib/mailDomains.d.ts +41 -0
  51. package/dist/src/lib/requestContext.d.ts +23 -0
  52. package/dist/src/lib/utils.d.ts +41 -2
  53. package/dist/src/plugins/auth/authzDynamic.d.ts +5 -12
  54. package/dist/src/plugins/auth/authzLinid1.d.ts +3 -1
  55. package/dist/src/plugins/auth/authzPerBranch.d.ts +5 -9
  56. package/dist/src/plugins/auth/openidconnect.d.ts +47 -0
  57. package/dist/src/plugins/bcl.d.ts +2 -1
  58. package/dist/src/plugins/ldap/accountLifecycle.d.ts +2 -2
  59. package/dist/src/plugins/ldap/bulkImport.d.ts +30 -5
  60. package/dist/src/plugins/ldap/enterpriseRules.d.ts +11 -1
  61. package/dist/src/plugins/ldap/externalUsersInGroups.d.ts +20 -3
  62. package/dist/src/plugins/ldap/groups.d.ts +48 -1
  63. package/dist/src/plugins/ldap/organizations.d.ts +4 -4
  64. package/dist/src/plugins/twake/appAccountsApi.d.ts +3 -67
  65. package/dist/src/plugins/twake/groups.d.ts +46 -2
  66. package/dist/src/plugins/twake/james.d.ts +0 -11
  67. package/docs/README.md +25 -0
  68. package/docs/plugin-development/README.md +61 -15
  69. package/docs/plugin-development/dependencies.md +8 -2
  70. package/docs/plugin-development/hooks.md +4 -5
  71. package/docs/usage/configuration.md +11 -8
  72. package/docs/usage/plugins/auth/README.md +22 -3
  73. package/docs/usage/plugins/auth/authz-linid1.md +14 -5
  74. package/docs/usage/plugins/auth/authz-per-branch.md +60 -9
  75. package/docs/usage/plugins/auth/back-channel-logout.md +28 -0
  76. package/docs/usage/plugins/auth/oidc.md +8 -0
  77. package/docs/usage/plugins/integrations/app-accounts.md +5 -0
  78. package/docs/usage/plugins/integrations/groups.md +36 -3
  79. package/docs/usage/plugins/integrations/scim.md +7 -0
  80. package/docs/usage/plugins/integrations/spaces.md +3 -1
  81. package/docs/usage/plugins/ldap/bulk-import.md +20 -0
  82. package/docs/usage/plugins/ldap/enterprise-rules.md +12 -2
  83. package/docs/usage/plugins/ldap/external-users.md +8 -3
  84. package/docs/usage/plugins/ldap/flat-generic.md +3 -0
  85. package/docs/usage/plugins/ldap/groups.md +6 -0
  86. package/docs/usage/plugins/ldap/organizations.md +17 -0
  87. package/docs/usage/plugins/ldap/raw.md +1 -1
  88. package/docs/usage/upgrading.md +228 -0
  89. package/package.json +1 -1
  90. package/static/schemas/example/groups.json +1 -0
  91. package/static/schemas/example/organizations.json +1 -0
  92. package/static/schemas/example/users.json +3 -0
  93. package/static/schemas/twake/groups.json +2 -0
  94. package/static/schemas/twake/organizations.json +1 -0
  95. package/static/schemas/twake/teamMailboxes.json +3 -1
  96. package/static/schemas/twake/users.json +3 -0
@@ -4,6 +4,234 @@ 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 0.26 to 1.0.0
8
+
9
+ Every breaking change since 0.26.0. Authorization fails closed in 1.0.0:
10
+ what used to pass because a call site forgot the request, or because a
11
+ name was spelled otherwise, is now judged, and may be refused.
12
+
13
+ ### Attribute names in a write: one name per attribute, no option
14
+
15
+ **Who is affected:** a client, a CSV of the bulk import or a plugin writing
16
+ an attribute with an option other than `;binary` (`title;lang-fr`,
17
+ `member;x-tag`), or naming one attribute twice in one part of a write
18
+ (`mail` and `MAIL`, `mail` and `rfc822Mailbox`).
19
+
20
+ Every add and modify now names its attributes as this server does before
21
+ it is judged: the name is resolved through the directory schema, so `MAIL`,
22
+ `rfc822Mailbox` and `0.9.2342.19200300.100.1.3` are all written `mail`.
23
+ The spelling kept is the configuration's or a loaded schema's, else the
24
+ first name the directory declares. An option other than `;binary` is
25
+ refused with a 400: a tagged value is one of its own, which the rules
26
+ guarding the attribute would not see. Two names for one attribute in one
27
+ `add`, `replace` or `delete` are refused with a 400 too. Values already
28
+ stored under an option are still read, but cannot be written or deleted
29
+ through ldap-rest: clean them up in the directory.
30
+
31
+ A rename gives the entry one value of the attribute it is already named by
32
+ (`cn=new` for a group named by `cn`): a new RDN holding several values, or
33
+ naming another attribute, is refused with a 400. The directory writes the
34
+ values of the new RDN on the entry, where no check of a write saw them.
35
+
36
+ When the directory schema cannot be read, the names, aliases and OIDs of
37
+ the standard types (`cn`, `mail`, `uid`, `ou`…) are still resolved, as are
38
+ the spellings of the configuration and the schemas. A name given as another
39
+ OID is refused, and another alias is written as given.
40
+
41
+ ### SCIM group members are looked up as the caller
42
+
43
+ **Who is affected:** a SCIM client writing group members by DN, and one
44
+ that tells an absent user from a hidden one by the message of
45
+ `PUT /Users/{id}`.
46
+
47
+ A member given by DN in `POST`, `PUT` or `PATCH /Groups` was taken as it
48
+ stood. It is now looked up as the caller, as a member given by id is: a DN
49
+ the caller cannot read, or that names no entry, is left out of the group,
50
+ and under a model judging by branch a member in a refused branch makes the
51
+ whole write refused. A DN outside the user base is left out, compared RDN by
52
+ RDN. A client that wrote members it may not read asks an administrator
53
+ whose rules cover them.
54
+
55
+ `PUT /Users/{id}` on a user that is not there answered `Resource not found`;
56
+ it now answers `User {id} not found`, as it did for a user the caller may
57
+ not read. The status, `404`, is unchanged.
58
+
59
+ ### The group routes take a DN for a group only
60
+
61
+ **Who is affected:** a client calling `/api/v1/ldap/groups/{cn}` with a
62
+ DN rather than a name.
63
+
64
+ A DN given to these routes, to read, write, delete, create or rename a
65
+ group, must name a group below the groups branch (`--ldap-group-base`),
66
+ named by the groups' main attribute (`--ldap-groups-main-attribute`, `cn`
67
+ by default) and of a group class (`--group-class`, or a standard one) the
68
+ caller reads; anything else answers `404 Group not found`, and a DN the
69
+ directory would refuse `400`. A client that managed the organization
70
+ groups of `core/twake/groups` by DN through these routes, when they lie
71
+ outside `--ldap-group-base`, uses `/api/v1/organizations/{id}/groups`.
72
+ A deployment whose groups carry a class of their own, and none of the
73
+ standard ones, declares it in `--group-class`.
74
+
75
+ ### Reference data still in use is not deleted
76
+
77
+ **Who is affected:** a deployment loading the shipped `twake` or `example`
78
+ schemas with `core/ldap/enterpriseRules`.
79
+
80
+ Deleting a mail domain an organization links, or a nomenclature value an
81
+ entry holds (account status, delivery mode, personal title, list type,
82
+ mailbox type), answers `409 still referenced` instead of leaving the
83
+ reference naming nothing. Change the referrers first. A deployment with
84
+ its own schemas marks its pointers `"referentialIntegrity": "restrict"` to
85
+ get the same. References are looked for under the base each entity is
86
+ configured with; a base the directory does not hold is logged once and
87
+ holds none.
88
+
89
+ ### Plugins: an operation naming no request is judged as the caller
90
+
91
+ **Who is affected:** a third-party plugin calling `this.server.ldap.search`,
92
+ `add`, `modify`, `rename` or `delete` without a request, from a route, while
93
+ an authorization plugin is loaded. `move` is the server's and stays unjudged:
94
+ move an entry for a caller with `rename`.
95
+
96
+ Such an operation used to pass unjudged, as the server's. While an
97
+ authenticated request is being served, it is now judged as that request's
98
+ caller, and refused where the caller may not. Hand the request down
99
+ (`ldap.forRequest(req)`), or, for the server's own work, go through
100
+ `ldap.system`. Hooks run outside the request and keep acting as the server.
101
+
102
+ Under `core/auth/authzDynamic`, a hook's operations that named no request
103
+ used to be judged against the token, through an async context of the
104
+ plugin's own; they now act as the server, as under the other authorization
105
+ plugins. A hook writing on the caller's behalf passes the request it is
106
+ handed. That context, `authzContext`, is no longer exported: read the token
107
+ off the request (`req.authzToken`).
108
+
109
+ ### An authorization plugin needs an authentication plugin
110
+
111
+ **Who is affected:** a deployment loading `core/auth/authzPerBranch`,
112
+ `core/auth/authzLinid1` or `core/auth/authzPerRoute` without any
113
+ authentication plugin.
114
+
115
+ Such a server no longer starts. No request carried an identity, so each of
116
+ these plugins stepped aside and every request passed, whatever the rules
117
+ said. Load the authentication plugin the rules were written for, or remove
118
+ the authorization plugins to serve the directory openly, as it already was.
119
+
120
+ ### Nested branch rules of `authzPerBranch`
121
+
122
+ **Who is affected:** a deployment of `core/auth/authzPerBranch` whose rules
123
+ for one user, or one group, name a branch and a sub-branch of it.
124
+
125
+ The rule of the sub-branch now applies to everything below it, whatever
126
+ order the two are written in. It used to apply only where it matched
127
+ exactly — the sub-branch entry, and writes on its direct children, judged
128
+ on their parent — and below that the first rule written won. A sub-branch rule that
129
+ was ignored, a restriction or a grant, now takes effect in single reads and
130
+ writes and in searches: a search on the parent no longer lists what the
131
+ sub-branch rule refuses, so a listing may now be shorter. Check such rules:
132
+ they now mean what they say.
133
+
134
+ `default` no longer adds to what the rules grant: it applies to a
135
+ permission none of the rules that apply sets. A rule's `read`, `write` or
136
+ `delete` set to `false` now refuses, where `"default": {"read": true}` used
137
+ to grant it anyway. A permission a rule leaves unset is still the
138
+ default's, not the broader rule's.
139
+
140
+ Renaming or moving an entry a rule names, or one holding such an entry, now
141
+ needs read and write permission at each of those rules, and deleting it
142
+ needs delete there; changing the entry itself needs that rule's write
143
+ permission, as does creating it. A write setting the organization link and
144
+ changing anything besides the link and its path needs write where the
145
+ entry stands — its branch, or under `--authz-filter-attached-entries` the
146
+ organization it leaves: it used to need only read there, so the rest of
147
+ the write — a password, say — went through. Moving an entry between
148
+ organizations is unchanged.
149
+
150
+ ### Organization groups need read access to the organization
151
+
152
+ **Who is affected:** a deployment loading an authorization plugin together
153
+ with `core/twake/groups` (and `core/twake/spaces`, which goes through it).
154
+
155
+ The `/organizations/{id}/groups` and `/organizations/{id}/spaces` routes read
156
+ as the caller. A client calling them must be granted read access to the
157
+ organization, its groups and its users, write access to change them and
158
+ delete access to delete one. An organization it cannot read answers `404`,
159
+ and a user it cannot read `404 USER_NOT_FOUND` where it used to get `403`.
160
+
161
+ Under `core/auth/authzLinid1` or `--authz-filter-attached-entries`, groups
162
+ written in an organization's branch now carry its link
163
+ (`--ldap-organization-link-attribute`): creating or changing a group needs
164
+ write on the organization, and a group without a link is read and changed by
165
+ every administrator. Link the groups written before; this script is an
166
+ example to adapt to your patterns, attribute names and organization names
167
+ (it expects plain ones, without spaces or commas):
168
+
169
+ ```sh
170
+ # Connection to the directory, as for any ldapsearch
171
+ OPTS="-H ldap://localhost -D cn=admin,dc=example,dc=com -w secret"
172
+ # --twake-group-organization-dn and --twake-group-base, {org} left out
173
+ ORGS="dc=example,dc=com"
174
+ for org in $(ldapsearch $OPTS -LLL -s one -b "$ORGS" '(ou=*)' ou |
175
+ sed -n 's/^ou: //p'); do
176
+ ldapsearch $OPTS -LLL -o ldif-wrap=no -s one \
177
+ -b "ou=groups,ou=$org,$ORGS" '(!(twakeDepartmentLink=*))' objectClass |
178
+ awk -v link="ou=$org,$ORGS" '
179
+ function flush() {
180
+ if (!dn) return
181
+ print "dn: " dn "\nchangetype: modify"
182
+ # The class is added only to a group lacking one allowing the link
183
+ if (!held) print "add: objectClass\nobjectClass: twakeGroup\n-"
184
+ print "add: twakeDepartmentLink\ntwakeDepartmentLink: " link "\n"
185
+ dn = ""
186
+ }
187
+ /^dn: / { flush(); dn = substr($0, 5); held = 0 }
188
+ tolower($0) ~ /^objectclass: (twakegroup|twakestaticgroup)$/ { held = 1 }
189
+ END { flush() }'
190
+ done | ldapmodify $OPTS
191
+ ```
192
+
193
+ ### The organization link holds one organization
194
+
195
+ **Who is affected:** a client or a CSV writing several organization links on
196
+ one entry, or an empty one.
197
+
198
+ A write giving the organization link (`--ldap-organization-link-attribute`)
199
+ several values, or an empty value, is refused with a 400: only one of them
200
+ was judged. Under any spelling of the attribute, adding a link to an entry
201
+ that had none is judged as a move: write where it goes and, judged by
202
+ branch, read where it stands.
203
+
204
+ ### Smaller changes in answers
205
+
206
+ - `GET /api/v1/ldap/raw/search` below a base the caller may not read
207
+ answers 404, as for a base that is not there; under `authzPerBranch`
208
+ judging by DN it answered 403.
209
+ - Changing only the case of an account's mail is refused (409) while an
210
+ applicative copy holds the old spelling, which the directory takes for
211
+ the same address.
212
+
213
+ ### External members in a domain the directory declares
214
+
215
+ **Who is affected:** a deployment of `core/ldap/externalUsersInGroups`
216
+ adding as external members addresses in a mail domain the directory
217
+ declares, without listing it in `--mail-domain`.
218
+
219
+ Such a member is refused, as one in a `--mail-domain` already was. The
220
+ managed domains are now also those of the directory's domain branches,
221
+ [docs](plugins/ldap/external-users.md#important-notes); `GET /config` lists
222
+ them in `managedDomains`.
223
+
224
+ ### Quota and app accounts need read access to the account
225
+
226
+ **Who is affected:** a deployment loading an authorization plugin
227
+ (`core/auth/authzPerBranch`, `authzLinid1`, `authzDynamic`) together with
228
+ `core/twake/james` or `core/twake/appAccountsApi`.
229
+
230
+ `GET /users/{user}/quota-usage` and the app account routes answer `404` for
231
+ an account the caller cannot read. A client calling them must be granted
232
+ read access to the accounts it asks about, as it already needed write
233
+ access to create or delete an app account.
234
+
7
235
  ## To 0.24.0
8
236
 
9
237
  ### Links to deleted accounts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ldap-rest",
3
- "version": "0.26.0",
3
+ "version": "1.0.1",
4
4
  "description": "Light directory manager",
5
5
  "keywords": [
6
6
  "Identity-Manager"
@@ -50,6 +50,7 @@
50
50
  "businessCategory": {
51
51
  "type": "pointer",
52
52
  "branch": ["ou=twakeListType,ou=nomenclature,__LDAP_BASE__"],
53
+ "referentialIntegrity": "restrict",
53
54
  "required": false,
54
55
  "role": "writePolicy",
55
56
  "label": "List type"
@@ -89,6 +89,7 @@
89
89
  "type": "pointer",
90
90
  "branch": ["ou=domains,ou=nomenclature,__LDAP_BASE__"]
91
91
  },
92
+ "referentialIntegrity": "restrict",
92
93
  "required": false,
93
94
  "role": "domainLink",
94
95
  "label": "Mail domains"
@@ -77,6 +77,7 @@
77
77
  "personalTitle": {
78
78
  "type": "pointer",
79
79
  "branch": ["ou=twakeTitle,ou=nomenclature,__LDAP_BASE__"],
80
+ "referentialIntegrity": "restrict",
80
81
  "required": false,
81
82
  "label": "Title"
82
83
  },
@@ -203,6 +204,7 @@
203
204
  "twakeAccountStatus": {
204
205
  "type": "pointer",
205
206
  "branch": ["ou=twakeAccountStatus,ou=nomenclature,__LDAP_BASE__"],
207
+ "referentialIntegrity": "restrict",
206
208
  "required": true,
207
209
  "generated": true,
208
210
  "role": "accountStatus",
@@ -220,6 +222,7 @@
220
222
  "type": "pointer",
221
223
  "branch": ["ou=twakeDeliveryMode,ou=nomenclature,__LDAP_BASE__"]
222
224
  },
225
+ "referentialIntegrity": "restrict",
223
226
  "required": true,
224
227
  "generated": true,
225
228
  "default": [
@@ -82,6 +82,7 @@
82
82
  "businessCategory": {
83
83
  "type": "pointer",
84
84
  "branch": ["ou=twakeListType,ou=nomenclature,__LDAP_BASE__"],
85
+ "referentialIntegrity": "restrict",
85
86
  "required": false,
86
87
  "role": "writePolicy",
87
88
  "label": {
@@ -98,6 +99,7 @@
98
99
  "twakeMailboxType": {
99
100
  "type": "pointer",
100
101
  "branch": ["ou=twakeMailboxType,ou=nomenclature,__LDAP_BASE__"],
102
+ "referentialIntegrity": "restrict",
101
103
  "group": {
102
104
  "en": "Mailbox Settings",
103
105
  "fr": "Paramètres de messagerie",
@@ -123,6 +123,7 @@
123
123
  "type": "pointer",
124
124
  "branch": ["ou=domains,ou=nomenclature,__LDAP_BASE__"]
125
125
  },
126
+ "referentialIntegrity": "restrict",
126
127
  "required": false,
127
128
  "role": "domainLink",
128
129
  "label": {
@@ -80,7 +80,9 @@
80
80
  }
81
81
  },
82
82
  "twakeMailboxType": {
83
- "type": "string",
83
+ "type": "pointer",
84
+ "branch": ["ou=twakeMailboxType,ou=nomenclature,__LDAP_BASE__"],
85
+ "referentialIntegrity": "restrict",
84
86
  "default": "cn=teamMailbox,ou=twakeMailboxType,ou=nomenclature,__LDAP_BASE__",
85
87
  "fixed": true,
86
88
  "required": true,
@@ -124,6 +124,7 @@
124
124
  "personalTitle": {
125
125
  "type": "pointer",
126
126
  "branch": ["ou=twakeTitle,ou=nomenclature,__LDAP_BASE__"],
127
+ "referentialIntegrity": "restrict",
127
128
  "required": false,
128
129
  "label": {
129
130
  "en": "Title",
@@ -324,6 +325,7 @@
324
325
  "twakeAccountStatus": {
325
326
  "type": "pointer",
326
327
  "branch": ["ou=twakeAccountStatus,ou=nomenclature,__LDAP_BASE__"],
328
+ "referentialIntegrity": "restrict",
327
329
  "required": true,
328
330
  "generated": true,
329
331
  "role": "accountStatus",
@@ -346,6 +348,7 @@
346
348
  "type": "pointer",
347
349
  "branch": ["ou=twakeDeliveryMode,ou=nomenclature,__LDAP_BASE__"]
348
350
  },
351
+ "referentialIntegrity": "restrict",
349
352
  "required": true,
350
353
  "generated": true,
351
354
  "default": [