ldap-rest 0.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 (296) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +48 -0
  3. package/bin/cleanup-external-users.mjs +219 -0
  4. package/bin/index.mjs +54 -0
  5. package/bin/sync-james.mjs +190 -0
  6. package/dist/abstract/ldapFlat.js +1 -0
  7. package/dist/abstract/plugin.js +1 -0
  8. package/dist/abstract/twakePlugin.js +1 -0
  9. package/dist/bin/index.js +1 -0
  10. package/dist/config/args.js +1 -0
  11. package/dist/lib/auth/base.js +1 -0
  12. package/dist/lib/authz/base.js +1 -0
  13. package/dist/lib/expressFormatedResponses.js +1 -0
  14. package/dist/lib/ldapActions.js +1 -0
  15. package/dist/lib/parseConfig.js +1 -0
  16. package/dist/lib/utils.js +1 -0
  17. package/dist/logger/winston.js +1 -0
  18. package/dist/plugins/auth/authzLinid1.js +1 -0
  19. package/dist/plugins/auth/authzPerBranch.js +1 -0
  20. package/dist/plugins/auth/crowdsec.js +1 -0
  21. package/dist/plugins/auth/llng.js +1 -0
  22. package/dist/plugins/auth/openidconnect.js +1 -0
  23. package/dist/plugins/auth/rateLimit.js +1 -0
  24. package/dist/plugins/auth/token.js +1 -0
  25. package/dist/plugins/configApi.js +1 -0
  26. package/dist/plugins/demo/helloworld.js +1 -0
  27. package/dist/plugins/ldap/bulkImport.js +1 -0
  28. package/dist/plugins/ldap/departmentSync.js +1 -0
  29. package/dist/plugins/ldap/externalUsersInGroups.js +1 -0
  30. package/dist/plugins/ldap/flatGeneric.js +1 -0
  31. package/dist/plugins/ldap/groups.js +1 -0
  32. package/dist/plugins/ldap/onChange.js +1 -0
  33. package/dist/plugins/ldap/organization.js +1 -0
  34. package/dist/plugins/ldap/trash.js +1 -0
  35. package/dist/plugins/priority.json.js +1 -0
  36. package/dist/plugins/static.js +1 -0
  37. package/dist/plugins/twake/calendarResources.js +1 -0
  38. package/dist/plugins/twake/james.js +1 -0
  39. package/dist/plugins/weblogs.js +1 -0
  40. package/dist/src/abstract/ldapFlat.d.ts +94 -0
  41. package/dist/src/abstract/plugin.d.ts +43 -0
  42. package/dist/src/abstract/twakePlugin.d.ts +90 -0
  43. package/dist/src/bin/index.d.ts +43 -0
  44. package/dist/src/browser/ldap-group-editor/LdapGroupEditor.d.ts +31 -0
  45. package/dist/src/browser/ldap-group-editor/api/GroupApiClient.d.ts +23 -0
  46. package/dist/src/browser/ldap-group-editor/components/CreateGroupModal.d.ts +19 -0
  47. package/dist/src/browser/ldap-group-editor/components/GroupPropertyEditor.d.ts +30 -0
  48. package/dist/src/browser/ldap-group-editor/components/GroupTree.d.ts +17 -0
  49. package/dist/src/browser/ldap-group-editor/components/MoveGroupModal.d.ts +20 -0
  50. package/dist/src/browser/ldap-group-editor/index.d.ts +6 -0
  51. package/dist/src/browser/ldap-group-editor/types.d.ts +58 -0
  52. package/dist/src/browser/ldap-resource-editor/api/ResourceApiClient.d.ts +53 -0
  53. package/dist/src/browser/ldap-resource-editor/cache/CacheManager.d.ts +65 -0
  54. package/dist/src/browser/ldap-resource-editor/index.d.ts +6 -0
  55. package/dist/src/browser/ldap-resource-editor/types.d.ts +78 -0
  56. package/dist/src/browser/ldap-tree-viewer/LdapTreeViewer.d.ts +26 -0
  57. package/dist/src/browser/ldap-tree-viewer/api/LdapApiClient.d.ts +30 -0
  58. package/dist/src/browser/ldap-tree-viewer/components/TreeNode.d.ts +17 -0
  59. package/dist/src/browser/ldap-tree-viewer/components/TreeRoot.d.ts +14 -0
  60. package/dist/src/browser/ldap-tree-viewer/index.d.ts +7 -0
  61. package/dist/src/browser/ldap-tree-viewer/store/Store.d.ts +18 -0
  62. package/dist/src/browser/ldap-tree-viewer/store/actions.d.ts +28 -0
  63. package/dist/src/browser/ldap-tree-viewer/store/reducers.d.ts +7 -0
  64. package/dist/src/browser/ldap-tree-viewer/types.d.ts +34 -0
  65. package/dist/src/browser/ldap-unit-editor/LdapUnitEditor.d.ts +27 -0
  66. package/dist/src/browser/ldap-unit-editor/api/UnitApiClient.d.ts +24 -0
  67. package/dist/src/browser/ldap-unit-editor/components/MoveUnitModal.d.ts +28 -0
  68. package/dist/src/browser/ldap-unit-editor/components/UnitPropertyEditor.d.ts +28 -0
  69. package/dist/src/browser/ldap-unit-editor/components/UnitTree.d.ts +18 -0
  70. package/dist/src/browser/ldap-unit-editor/index.d.ts +6 -0
  71. package/dist/src/browser/ldap-unit-editor/types.d.ts +55 -0
  72. package/dist/src/browser/ldap-user-editor/LdapUserEditor.d.ts +32 -0
  73. package/dist/src/browser/ldap-user-editor/api/UserApiClient.d.ts +55 -0
  74. package/dist/src/browser/ldap-user-editor/cache/CacheManager.d.ts +65 -0
  75. package/dist/src/browser/ldap-user-editor/components/MoveUserModal.d.ts +28 -0
  76. package/dist/src/browser/ldap-user-editor/components/PointerField.d.ts +22 -0
  77. package/dist/src/browser/ldap-user-editor/components/UserEditor.d.ts +46 -0
  78. package/dist/src/browser/ldap-user-editor/components/UserList.d.ts +24 -0
  79. package/dist/src/browser/ldap-user-editor/components/UserTree.d.ts +24 -0
  80. package/dist/src/browser/ldap-user-editor/index.d.ts +7 -0
  81. package/dist/src/browser/ldap-user-editor/types.d.ts +67 -0
  82. package/dist/src/browser/shared/components/Modal.d.ts +38 -0
  83. package/dist/src/browser/shared/components/StatusMessage.d.ts +48 -0
  84. package/dist/src/browser/shared/index.d.ts +10 -0
  85. package/dist/src/browser/shared/types/index.d.ts +65 -0
  86. package/dist/src/browser/shared/utils/dom.d.ts +33 -0
  87. package/dist/src/browser/shared/utils/form.d.ts +28 -0
  88. package/dist/src/browser/shared/utils/schema.d.ts +29 -0
  89. package/dist/src/config/args.d.ts +128 -0
  90. package/dist/src/config/schema.d.ts +18 -0
  91. package/dist/src/hooks.d.ts +76 -0
  92. package/dist/src/lib/auth/base.d.ts +9 -0
  93. package/dist/src/lib/authz/base.d.ts +63 -0
  94. package/dist/src/lib/expressFormatedResponses.d.ts +26 -0
  95. package/dist/src/lib/ldapActions.d.ts +91 -0
  96. package/dist/src/lib/parseConfig.d.ts +23 -0
  97. package/dist/src/lib/utils.d.ts +73 -0
  98. package/dist/src/logger/winston.d.ts +3 -0
  99. package/dist/src/plugins/auth/authzLinid1.d.ts +46 -0
  100. package/dist/src/plugins/auth/authzPerBranch.d.ts +59 -0
  101. package/dist/src/plugins/auth/crowdsec.d.ts +29 -0
  102. package/dist/src/plugins/auth/llng.d.ts +8 -0
  103. package/dist/src/plugins/auth/openidconnect.d.ts +11 -0
  104. package/dist/src/plugins/auth/rateLimit.d.ts +24 -0
  105. package/dist/src/plugins/auth/token.d.ts +17 -0
  106. package/dist/src/plugins/configApi.d.ts +24 -0
  107. package/dist/src/plugins/demo/helloworld.d.ts +12 -0
  108. package/dist/src/plugins/ldap/bulkImport.d.ts +48 -0
  109. package/dist/src/plugins/ldap/departmentSync.d.ts +35 -0
  110. package/dist/src/plugins/ldap/externalUsersInGroups.d.ts +21 -0
  111. package/dist/src/plugins/ldap/flatGeneric.d.ts +31 -0
  112. package/dist/src/plugins/ldap/groups.d.ts +95 -0
  113. package/dist/src/plugins/ldap/onChange.d.ts +32 -0
  114. package/dist/src/plugins/ldap/organization.d.ts +65 -0
  115. package/dist/src/plugins/ldap/trash.d.ts +52 -0
  116. package/dist/src/plugins/static.d.ts +7 -0
  117. package/dist/src/plugins/twake/calendarResources.d.ts +31 -0
  118. package/dist/src/plugins/twake/james.d.ts +83 -0
  119. package/dist/src/plugins/weblogs.d.ts +8 -0
  120. package/docs/DEVELOPER_GUIDE.md +298 -0
  121. package/docs/OPENAPI.md +440 -0
  122. package/docs/PLUGIN_DEPENDENCIES.md +612 -0
  123. package/docs/README.md +466 -0
  124. package/docs/api/REFERENCE.md +983 -0
  125. package/docs/api/REST_API.md +1237 -0
  126. package/docs/authentication.md +469 -0
  127. package/docs/authzLinid1.md +521 -0
  128. package/docs/authzPerBranch.md +596 -0
  129. package/docs/browser/LIBRARIES.md +1196 -0
  130. package/docs/examples/EXAMPLES.md +1659 -0
  131. package/docs/examples/twake-mailbox-type-nomenclature.ldif +37 -0
  132. package/docs/examples/twake-mailbox-type-schema-amendment.ldif +30 -0
  133. package/docs/jamesTeamMailboxes.md +343 -0
  134. package/docs/ldapBulkImport.md +722 -0
  135. package/docs/ldapExternalUsersInGroups.md +325 -0
  136. package/docs/ldapFlatGeneric.md +444 -0
  137. package/docs/ldapGroups.md +589 -0
  138. package/docs/ldapOrganizations.md +659 -0
  139. package/docs/ldapTrash.md +260 -0
  140. package/docs/linagora.png +0 -0
  141. package/docs/onChange.md +318 -0
  142. package/docs/plugins/DEVELOPMENT.md +1219 -0
  143. package/docs/presenterm-fr.md +721 -0
  144. package/docs/presenterm.md +721 -0
  145. package/docs/schemas/SCHEMAS.md +1212 -0
  146. package/docs/static.md +410 -0
  147. package/docs/twakeCalendarResources.md +148 -0
  148. package/docs/twakeJames.md +661 -0
  149. package/docs/weblogs.md +399 -0
  150. package/examples/web/ldap-group-editor.html +113 -0
  151. package/examples/web/ldap-tree-viewer.html +368 -0
  152. package/examples/web/ldap-unit-editor.html +108 -0
  153. package/examples/web/ldap-user-editor.html +412 -0
  154. package/package.json +458 -0
  155. package/static/browser/common-demo.css +450 -0
  156. package/static/browser/ldap-group-editor/LdapGroupEditor.js +207 -0
  157. package/static/browser/ldap-group-editor/LdapGroupEditor.js.map +1 -0
  158. package/static/browser/ldap-group-editor/api/GroupApiClient.js +112 -0
  159. package/static/browser/ldap-group-editor/api/GroupApiClient.js.map +1 -0
  160. package/static/browser/ldap-group-editor/components/CreateGroupModal.js +212 -0
  161. package/static/browser/ldap-group-editor/components/CreateGroupModal.js.map +1 -0
  162. package/static/browser/ldap-group-editor/components/GroupPropertyEditor.js +497 -0
  163. package/static/browser/ldap-group-editor/components/GroupPropertyEditor.js.map +1 -0
  164. package/static/browser/ldap-group-editor/components/GroupTree.js +153 -0
  165. package/static/browser/ldap-group-editor/components/GroupTree.js.map +1 -0
  166. package/static/browser/ldap-group-editor/components/MoveGroupModal.js +235 -0
  167. package/static/browser/ldap-group-editor/components/MoveGroupModal.js.map +1 -0
  168. package/static/browser/ldap-group-editor/index.js +2 -0
  169. package/static/browser/ldap-group-editor/index.js.map +1 -0
  170. package/static/browser/ldap-group-editor/types.js +2 -0
  171. package/static/browser/ldap-group-editor/types.js.map +1 -0
  172. package/static/browser/ldap-group-editor.esm.js +1399 -0
  173. package/static/browser/ldap-group-editor.esm.js.map +1 -0
  174. package/static/browser/ldap-group-editor.js +1407 -0
  175. package/static/browser/ldap-group-editor.js.map +1 -0
  176. package/static/browser/ldap-group-editor.min.js +2 -0
  177. package/static/browser/ldap-group-editor.min.js.map +1 -0
  178. package/static/browser/ldap-resource-editor/api/ResourceApiClient.js +226 -0
  179. package/static/browser/ldap-resource-editor/api/ResourceApiClient.js.map +1 -0
  180. package/static/browser/ldap-resource-editor/cache/CacheManager.js +123 -0
  181. package/static/browser/ldap-resource-editor/cache/CacheManager.js.map +1 -0
  182. package/static/browser/ldap-resource-editor/index.js +2 -0
  183. package/static/browser/ldap-resource-editor/index.js.map +1 -0
  184. package/static/browser/ldap-resource-editor/types.js +2 -0
  185. package/static/browser/ldap-resource-editor/types.js.map +1 -0
  186. package/static/browser/ldap-tree-viewer/LdapTreeViewer.js +187 -0
  187. package/static/browser/ldap-tree-viewer/LdapTreeViewer.js.map +1 -0
  188. package/static/browser/ldap-tree-viewer/api/LdapApiClient.js +50 -0
  189. package/static/browser/ldap-tree-viewer/api/LdapApiClient.js.map +1 -0
  190. package/static/browser/ldap-tree-viewer/components/TreeNode.js +140 -0
  191. package/static/browser/ldap-tree-viewer/components/TreeNode.js.map +1 -0
  192. package/static/browser/ldap-tree-viewer/components/TreeRoot.js +98 -0
  193. package/static/browser/ldap-tree-viewer/components/TreeRoot.js.map +1 -0
  194. package/static/browser/ldap-tree-viewer/index.js +2 -0
  195. package/static/browser/ldap-tree-viewer/index.js.map +1 -0
  196. package/static/browser/ldap-tree-viewer/store/Store.js +29 -0
  197. package/static/browser/ldap-tree-viewer/store/Store.js.map +1 -0
  198. package/static/browser/ldap-tree-viewer/store/actions.js +53 -0
  199. package/static/browser/ldap-tree-viewer/store/actions.js.map +1 -0
  200. package/static/browser/ldap-tree-viewer/store/reducers.js +79 -0
  201. package/static/browser/ldap-tree-viewer/store/reducers.js.map +1 -0
  202. package/static/browser/ldap-tree-viewer/types.js +2 -0
  203. package/static/browser/ldap-tree-viewer/types.js.map +1 -0
  204. package/static/browser/ldap-tree-viewer.css +2 -0
  205. package/static/browser/ldap-tree-viewer.css.map +1 -0
  206. package/static/browser/ldap-tree-viewer.esm.js +606 -0
  207. package/static/browser/ldap-tree-viewer.esm.js.map +1 -0
  208. package/static/browser/ldap-tree-viewer.js +614 -0
  209. package/static/browser/ldap-tree-viewer.js.map +1 -0
  210. package/static/browser/ldap-tree-viewer.min.js +2 -0
  211. package/static/browser/ldap-tree-viewer.min.js.map +1 -0
  212. package/static/browser/ldap-unit-editor/LdapUnitEditor.js +119 -0
  213. package/static/browser/ldap-unit-editor/LdapUnitEditor.js.map +1 -0
  214. package/static/browser/ldap-unit-editor/api/UnitApiClient.js +95 -0
  215. package/static/browser/ldap-unit-editor/api/UnitApiClient.js.map +1 -0
  216. package/static/browser/ldap-unit-editor/components/MoveUnitModal.js +295 -0
  217. package/static/browser/ldap-unit-editor/components/MoveUnitModal.js.map +1 -0
  218. package/static/browser/ldap-unit-editor/components/UnitPropertyEditor.js +321 -0
  219. package/static/browser/ldap-unit-editor/components/UnitPropertyEditor.js.map +1 -0
  220. package/static/browser/ldap-unit-editor/components/UnitTree.js +197 -0
  221. package/static/browser/ldap-unit-editor/components/UnitTree.js.map +1 -0
  222. package/static/browser/ldap-unit-editor/index.js +2 -0
  223. package/static/browser/ldap-unit-editor/index.js.map +1 -0
  224. package/static/browser/ldap-unit-editor/types.js +2 -0
  225. package/static/browser/ldap-unit-editor/types.js.map +1 -0
  226. package/static/browser/ldap-unit-editor.esm.js +1013 -0
  227. package/static/browser/ldap-unit-editor.esm.js.map +1 -0
  228. package/static/browser/ldap-unit-editor.js +1021 -0
  229. package/static/browser/ldap-unit-editor.js.map +1 -0
  230. package/static/browser/ldap-unit-editor.min.js +2 -0
  231. package/static/browser/ldap-unit-editor.min.js.map +1 -0
  232. package/static/browser/ldap-user-editor/LdapUserEditor.js +184 -0
  233. package/static/browser/ldap-user-editor/LdapUserEditor.js.map +1 -0
  234. package/static/browser/ldap-user-editor/api/UserApiClient.js +209 -0
  235. package/static/browser/ldap-user-editor/api/UserApiClient.js.map +1 -0
  236. package/static/browser/ldap-user-editor/cache/CacheManager.js +123 -0
  237. package/static/browser/ldap-user-editor/cache/CacheManager.js.map +1 -0
  238. package/static/browser/ldap-user-editor/components/MoveUserModal.js +302 -0
  239. package/static/browser/ldap-user-editor/components/MoveUserModal.js.map +1 -0
  240. package/static/browser/ldap-user-editor/components/PointerField.js +152 -0
  241. package/static/browser/ldap-user-editor/components/PointerField.js.map +1 -0
  242. package/static/browser/ldap-user-editor/components/UserEditor.js +608 -0
  243. package/static/browser/ldap-user-editor/components/UserEditor.js.map +1 -0
  244. package/static/browser/ldap-user-editor/components/UserList.js +181 -0
  245. package/static/browser/ldap-user-editor/components/UserList.js.map +1 -0
  246. package/static/browser/ldap-user-editor/components/UserTree.js +164 -0
  247. package/static/browser/ldap-user-editor/components/UserTree.js.map +1 -0
  248. package/static/browser/ldap-user-editor/index.js +2 -0
  249. package/static/browser/ldap-user-editor/index.js.map +1 -0
  250. package/static/browser/ldap-user-editor/types.js +2 -0
  251. package/static/browser/ldap-user-editor/types.js.map +1 -0
  252. package/static/browser/ldap-user-editor.css +2 -0
  253. package/static/browser/ldap-user-editor.css.map +1 -0
  254. package/static/browser/ldap-user-editor.esm.js +1897 -0
  255. package/static/browser/ldap-user-editor.esm.js.map +1 -0
  256. package/static/browser/ldap-user-editor.js +1905 -0
  257. package/static/browser/ldap-user-editor.js.map +1 -0
  258. package/static/browser/ldap-user-editor.min.js +2 -0
  259. package/static/browser/ldap-user-editor.min.js.map +1 -0
  260. package/static/browser/shared/components/Modal.js +121 -0
  261. package/static/browser/shared/components/Modal.js.map +1 -0
  262. package/static/browser/shared/components/StatusMessage.js +119 -0
  263. package/static/browser/shared/components/StatusMessage.js.map +1 -0
  264. package/static/browser/shared/index.js +7 -0
  265. package/static/browser/shared/index.js.map +1 -0
  266. package/static/browser/shared/types/index.js +37 -0
  267. package/static/browser/shared/types/index.js.map +1 -0
  268. package/static/browser/shared/utils/dom.js +78 -0
  269. package/static/browser/shared/utils/dom.js.map +1 -0
  270. package/static/browser/shared/utils/form.js +234 -0
  271. package/static/browser/shared/utils/form.js.map +1 -0
  272. package/static/browser/shared/utils/schema.js +121 -0
  273. package/static/browser/shared/utils/schema.js.map +1 -0
  274. package/static/browser/shared.esm.js +694 -0
  275. package/static/browser/shared.esm.js.map +1 -0
  276. package/static/browser/shared.js +723 -0
  277. package/static/browser/shared.js.map +1 -0
  278. package/static/browser/shared.min.js +2 -0
  279. package/static/browser/shared.min.js.map +1 -0
  280. package/static/schemas/ad/computers.json +92 -0
  281. package/static/schemas/ad/groups.json +55 -0
  282. package/static/schemas/ad/organizations.json +66 -0
  283. package/static/schemas/ad/users.json +116 -0
  284. package/static/schemas/standard/devices.json +72 -0
  285. package/static/schemas/standard/groups.json +54 -0
  286. package/static/schemas/standard/organizations.json +49 -0
  287. package/static/schemas/standard/users.json +86 -0
  288. package/static/schemas/twake/groups.json +75 -0
  289. package/static/schemas/twake/nomenclature/twakeAccountStatus.json +31 -0
  290. package/static/schemas/twake/nomenclature/twakeDeliveryMode.json +31 -0
  291. package/static/schemas/twake/nomenclature/twakeListType.json +31 -0
  292. package/static/schemas/twake/nomenclature/twakeMailboxType.json +31 -0
  293. package/static/schemas/twake/nomenclature/twakeTitle.json +31 -0
  294. package/static/schemas/twake/organizations.json +52 -0
  295. package/static/schemas/twake/positions.json +32 -0
  296. package/static/schemas/twake/users.json +112 -0
@@ -0,0 +1,260 @@
1
+ # LDAP Trash Plugin
2
+
3
+ Plugin to intercept LDAP delete operations and move entries to a trash branch instead of permanently deleting them.
4
+
5
+ ## Features
6
+
7
+ - **Soft Delete**: Moves entries to trash instead of permanent deletion
8
+ - **Configurable Branches**: Watch specific LDAP branches or all branches
9
+ - **Metadata Tracking**: Automatically adds deletion timestamp and original DN
10
+ - **Auto-create Trash**: Creates trash branch automatically if it doesn't exist
11
+ - **Atomic Move**: Uses LDAP modifyDN for safe, atomic operations
12
+ - **Overwrite Protection**: Automatically removes old trash entries when moving new ones
13
+
14
+ ## Configuration
15
+
16
+ ### Environment Variables
17
+
18
+ - `DM_TRASH_BASE`: LDAP base DN for trash (default: `ou=trash,dc=example,dc=com`)
19
+ - `DM_TRASH_WATCHED_BASES`: Comma-separated list of branches to watch (default: all branches except trash)
20
+ - `DM_TRASH_ADD_METADATA`: Add metadata to trashed entries (default: `true`)
21
+ - `DM_TRASH_AUTO_CREATE`: Auto-create trash branch if missing (default: `true`)
22
+
23
+ ### Command Line
24
+
25
+ ```bash
26
+ --plugin core/ldap/trash \
27
+ --trash-base "ou=trash,dc=example,dc=com" \
28
+ --trash-watched-bases "ou=users,dc=example,dc=com,ou=groups,dc=example,dc=com" \
29
+ --trash-add-metadata true \
30
+ --trash-auto-create true
31
+ ```
32
+
33
+ ## How It Works
34
+
35
+ When a delete operation occurs:
36
+
37
+ 1. **Check if DN is watched**: Plugin checks if the DN is in a configured watched branch
38
+ 2. **Ensure trash exists**: Creates trash branch if needed (when `auto-create` is enabled)
39
+ 3. **Remove old trash entry**: If an entry with the same RDN exists in trash, it's deleted first
40
+ 4. **Atomic move**: Uses LDAP `modifyDN` to move the entry to trash
41
+ 5. **Add metadata**: Adds deletion timestamp and original DN as `description` attribute
42
+ 6. **Cancel native delete**: The original delete operation is cancelled
43
+
44
+ ### DN Transformation
45
+
46
+ Original DN is transformed to trash DN by replacing the parent branch:
47
+
48
+ ```
49
+ Before: uid=john,ou=users,dc=example,dc=com
50
+ After: uid=john,ou=trash,dc=example,dc=com
51
+ ```
52
+
53
+ ## Usage Examples
54
+
55
+ ### Watch All Branches (Default)
56
+
57
+ ```bash
58
+ ldap-rest \
59
+ --plugin core/ldap/trash \
60
+ --trash-base "ou=trash,dc=example,dc=com"
61
+ ```
62
+
63
+ This watches all LDAP branches except the trash branch itself.
64
+
65
+ ### Watch Specific Branches Only
66
+
67
+ ```bash
68
+ ldap-rest \
69
+ --plugin core/ldap/trash \
70
+ --trash-base "ou=trash,dc=example,dc=com" \
71
+ --trash-watched-bases "ou=users,dc=example,dc=com,ou=groups,dc=example,dc=com"
72
+ ```
73
+
74
+ This only intercepts deletes from `ou=users` and `ou=groups`. Deletes from other branches proceed normally.
75
+
76
+ ### Disable Metadata
77
+
78
+ ```bash
79
+ ldap-rest \
80
+ --plugin core/ldap/trash \
81
+ --trash-base "ou=trash,dc=example,dc=com" \
82
+ --trash-add-metadata false
83
+ ```
84
+
85
+ Entries are moved to trash without adding deletion metadata.
86
+
87
+ ### Manual Trash Branch
88
+
89
+ If you want to create the trash branch manually:
90
+
91
+ ```bash
92
+ # Create trash branch manually
93
+ ldapadd -x -D "cn=admin,dc=example,dc=com" -W <<EOF
94
+ dn: ou=trash,dc=example,dc=com
95
+ objectClass: top
96
+ objectClass: organizationalUnit
97
+ ou: trash
98
+ description: LDAP Trash - Deleted entries are moved here
99
+ EOF
100
+
101
+ # Configure plugin to not auto-create
102
+ ldap-rest \
103
+ --plugin core/ldap/trash \
104
+ --trash-base "ou=trash,dc=example,dc=com" \
105
+ --trash-auto-create false
106
+ ```
107
+
108
+ ## Metadata Format
109
+
110
+ When `trash-add-metadata` is enabled, the plugin adds a `description` attribute to trashed entries:
111
+
112
+ ```
113
+ description: Deleted on 2025-10-15T10:30:45.123Z from uid=john,ou=users,dc=example,dc=com
114
+ ```
115
+
116
+ This helps track:
117
+
118
+ - When the entry was deleted
119
+ - Where it originally existed
120
+
121
+ ## Recovering from Trash
122
+
123
+ To restore an entry from trash, manually move it back using LDAP tools:
124
+
125
+ ```bash
126
+ # List entries in trash
127
+ ldapsearch -x -b "ou=trash,dc=example,dc=com" "(objectClass=*)"
128
+
129
+ # Restore user (move back)
130
+ ldapmodrdn -x -D "cn=admin,dc=example,dc=com" -W \
131
+ "uid=john,ou=trash,dc=example,dc=com" \
132
+ "uid=john" \
133
+ -s "ou=users,dc=example,dc=com"
134
+ ```
135
+
136
+ Or use a script:
137
+
138
+ ```javascript
139
+ // Restore from trash
140
+ await dm.ldap.move(
141
+ 'uid=john,ou=trash,dc=example,dc=com',
142
+ 'uid=john,ou=users,dc=example,dc=com'
143
+ );
144
+
145
+ // Clean up metadata (optional)
146
+ await dm.ldap.modify('uid=john,ou=users,dc=example,dc=com', {
147
+ delete: { description: [] },
148
+ });
149
+ ```
150
+
151
+ ## Emptying Trash
152
+
153
+ To permanently delete entries from trash:
154
+
155
+ ```bash
156
+ # Delete specific entry from trash
157
+ ldapdelete -x -D "cn=admin,dc=example,dc=com" -W \
158
+ "uid=john,ou=trash,dc=example,dc=com"
159
+
160
+ # Empty entire trash (careful!)
161
+ ldapsearch -x -b "ou=trash,dc=example,dc=com" -LLL dn | \
162
+ grep '^dn:' | cut -d' ' -f2 | \
163
+ while read dn; do
164
+ if [ "$dn" != "ou=trash,dc=example,dc=com" ]; then
165
+ ldapdelete -x -D "cn=admin,dc=example,dc=com" -W "$dn"
166
+ fi
167
+ done
168
+ ```
169
+
170
+ Note: Deleting from trash itself is NOT intercepted by the plugin (prevents infinite loops).
171
+
172
+ ## LDAP Permissions
173
+
174
+ The plugin requires `modifyDN` permission to move entries. Ensure your LDAP bind DN has sufficient permissions:
175
+
176
+ ```ldif
177
+ # Example ACL for OpenLDAP
178
+ olcAccess: to dn.subtree="dc=example,dc=com"
179
+ by dn="cn=admin,dc=example,dc=com" write
180
+ by * read
181
+ ```
182
+
183
+ If you get permission errors, check your LDAP ACLs and ensure the bind DN can:
184
+
185
+ - Read entries from watched branches
186
+ - Move entries to trash branch (modifyDN)
187
+ - Modify entries in trash (to add metadata)
188
+
189
+ ## Hooks
190
+
191
+ This plugin uses the `ldapdeleterequest` hook to intercept delete operations before they occur.
192
+
193
+ ## Limitations
194
+
195
+ - Only works with flat entries (RDN is preserved, parent DN is changed)
196
+ - Entries with the same RDN will overwrite previous trash entries
197
+ - Tree structures (entries with children) must be deleted leaf-first
198
+ - Does not track history (only keeps the latest deleted version)
199
+
200
+ ## Troubleshooting
201
+
202
+ ### Trash not being created
203
+
204
+ 1. Check `auto-create` is enabled (default)
205
+ 2. Verify bind DN has permission to create `ou=trash`
206
+ 3. Check logs for error messages
207
+
208
+ ### Entries not moving to trash
209
+
210
+ 1. Check if DN matches `watched-bases` configuration
211
+ 2. Verify bind DN has `modifyDN` permission
212
+ 3. Check that trash branch exists
213
+ 4. Review logs for specific error messages
214
+
215
+ ### Permission errors
216
+
217
+ ```
218
+ Error: Trash plugin: Insufficient LDAP permissions to move uid=john,ou=users,dc=example,dc=com to trash
219
+ ```
220
+
221
+ Solution: Grant `modifyDN` permission to the bind DN in LDAP ACLs.
222
+
223
+ ### Overwrite warnings
224
+
225
+ If you see messages about removing old trash entries, this is normal behavior. The plugin ensures only one version of each entry exists in trash.
226
+
227
+ ## Best Practices
228
+
229
+ 1. **Regular cleanup**: Schedule periodic trash cleanup to prevent unlimited growth
230
+ 2. **Backup first**: Always backup LDAP before emptying trash
231
+ 3. **Monitor trash size**: Track the number of entries in trash
232
+ 4. **Document recovery**: Document the recovery process for your team
233
+ 5. **Test permissions**: Verify LDAP permissions before deploying to production
234
+ 6. **Watch selectively**: Only watch branches that need trash protection
235
+
236
+ ## Example Configuration
237
+
238
+ Full production setup:
239
+
240
+ ```bash
241
+ ldap-rest \
242
+ --plugin core/auth/token \
243
+ --plugin core/ldap/trash \
244
+ --plugin core/ldap/flatGeneric \
245
+ --plugin core/ldap/groups \
246
+ --ldap-url "ldap://localhost:389" \
247
+ --ldap-dn "cn=admin,dc=example,dc=com" \
248
+ --ldap-pwd "admin" \
249
+ --ldap-base "dc=example,dc=com" \
250
+ --trash-base "ou=trash,dc=example,dc=com" \
251
+ --trash-watched-bases "ou=users,dc=example,dc=com,ou=groups,dc=example,dc=com" \
252
+ --trash-add-metadata true \
253
+ --auth-token "secret-token"
254
+ ```
255
+
256
+ ## License
257
+
258
+ [![Powered by LINAGORA](./linagora.png)](https://linagora.com)
259
+
260
+ License: [AGPL-3.0](../LICENSE), copyright 2025-present LINAGORA.
Binary file
@@ -0,0 +1,318 @@
1
+ # LDAP onChange Plugin
2
+
3
+ Monitor LDAP attribute changes and trigger hooks for specific attributes.
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.).
8
+
9
+ ## Configuration
10
+
11
+ ```bash
12
+ --plugin core/ldap/onChange \
13
+ --mail-attribute mail \
14
+ --quota-attribute mailQuota
15
+ ```
16
+
17
+ **Environment Variables:**
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:
124
+
125
+ ```bash
126
+ PUT /api/v1/ldap/users/jdoe
127
+ {
128
+ "replace": {
129
+ "mail": "jdoe@company.com",
130
+ "mailQuota": "5000000000"
131
+ }
132
+ }
133
+ ```
134
+
135
+ Both hooks fire:
136
+
137
+ 1. `onLdapMailChange(dn, "old@mail.com", "jdoe@company.com")`
138
+ 2. `onLdapQuotaChange(dn, "jdoe@company.com", "1000000000", "5000000000")`
139
+
140
+ ### Example 3: Generic Change Listener
141
+
142
+ ```bash
143
+ --plugin core/ldap/onChange
144
+ ```
145
+
146
+ All modifications trigger `onLdapChange`:
147
+
148
+ ```bash
149
+ PUT /api/v1/ldap/users/jdoe
150
+ {
151
+ "replace": {
152
+ "cn": "John A. Doe",
153
+ "telephoneNumber": "+1234567890"
154
+ },
155
+ "delete": ["description"]
156
+ }
157
+ ```
158
+
159
+ Hook receives:
160
+
161
+ ```javascript
162
+ {
163
+ "cn": ["John Doe", "John A. Doe"],
164
+ "telephoneNumber": [null, "+1234567890"],
165
+ "description": ["Old description", null]
166
+ }
167
+ ```
168
+
169
+ ## Integration Examples
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
+ ```
182
+
183
+ The James plugin listens to `onLdapMailChange` and `onLdapQuotaChange` hooks and automatically updates the James mail server.
184
+
185
+ ### Custom Integration Plugin
186
+
187
+ Create a custom plugin that reacts to changes:
188
+
189
+ ```typescript
190
+ import DmPlugin from '../abstract/plugin';
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
+ }
216
+ ```
217
+
218
+ ## Change Detection
219
+
220
+ ### Replace Operations
221
+
222
+ ```javascript
223
+ // Before: mail = "old@example.com"
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
233
+
234
+ ```javascript
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
+ ```
243
+
244
+ ### Delete Operations
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
+ ```
306
+
307
+ ## Limitations
308
+
309
+ 1. **Only monitors modify operations**: Does not detect changes from direct LDAP clients
310
+ 2. **Requires old value lookup**: Fetches entry before modification for comparison
311
+ 3. **Single-valued attributes**: Best suited for single-valued attributes like mail
312
+ 4. **Synchronous execution**: Hooks block the LDAP response
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