ldap-rest 1.3.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/abstract/ldapFlat.js +1 -1
- package/dist/abstract/plugin.js +1 -1
- package/dist/bin/index.js +1 -1
- package/dist/config/options.js +1 -1
- package/dist/config/schema.js +1 -1
- package/dist/lib/authz/base.js +1 -1
- package/dist/lib/errors.js +1 -1
- package/dist/lib/ldap/callerView.js +1 -0
- package/dist/lib/ldap/pool.js +1 -0
- package/dist/lib/ldap/schema.js +1 -0
- package/dist/lib/ldap/searchCache.js +1 -0
- package/dist/lib/ldapActions.js +1 -1
- package/dist/lib/parseConfig.js +1 -1
- package/dist/lib/services/index.js +1 -0
- package/dist/lib/utils.js +1 -1
- package/dist/plugins/ldap/accountLifecycle.js +1 -1
- package/dist/plugins/ldap/enterpriseRules.js +1 -1
- package/dist/plugins/ldap/groups.js +1 -1
- package/dist/plugins/ldap/organizations.js +1 -1
- package/dist/plugins/ldap/passwordPolicy.js +1 -1
- package/dist/plugins/ldap/raw.js +1 -1
- package/dist/plugins/ldap/trash.js +1 -1
- package/dist/plugins/scim/mapping.js +1 -1
- package/dist/plugins/scim/patch.js +1 -1
- package/dist/plugins/storage/file.js +1 -1
- package/dist/plugins/twake/instances.js +1 -1
- package/dist/plugins/twake/lifecycleAttributes.js +1 -1
- package/dist/plugins/twake/lifecycleEvents.js +1 -1
- package/dist/plugins/twake/tombstone.js +1 -1
- package/dist/src/abstract/ldapFlat.d.ts +13 -0
- package/dist/src/abstract/plugin.d.ts +21 -0
- package/dist/src/bin/index.d.ts +18 -0
- package/dist/src/config/options.d.ts +16 -1
- package/dist/src/lib/errors.d.ts +2 -1
- package/dist/src/lib/ldap/callerView.d.ts +45 -0
- package/dist/src/lib/ldap/pool.d.ts +108 -0
- package/dist/src/lib/ldap/schema.d.ts +157 -0
- package/dist/src/lib/ldap/searchCache.d.ts +112 -0
- package/dist/src/lib/ldapActions.d.ts +25 -262
- package/dist/src/lib/parseConfig.d.ts +26 -2
- package/dist/src/lib/services/index.d.ts +56 -0
- package/dist/src/lib/utils.d.ts +72 -3
- package/dist/src/plugins/ldap/enterpriseRules.d.ts +0 -14
- package/dist/src/plugins/ldap/passwordPolicy.d.ts +3 -2
- package/dist/src/plugins/scim/mapping.d.ts +16 -3
- package/dist/src/plugins/scim/types.d.ts +2 -0
- package/dist/src/plugins/twake/instances.d.ts +31 -0
- package/dist/src/plugins/twake/lifecycleAttributes.d.ts +13 -2
- package/dist/src/plugins/twake/tombstone.d.ts +9 -2
- package/docs/README.md +16 -2
- package/docs/client-development/api/rest-api.md +4 -0
- package/docs/development/contracts.md +109 -0
- package/docs/plugin-development/README.md +8 -1
- package/docs/plugin-development/dependencies.md +13 -2
- package/docs/plugin-development/hooks.md +2 -1
- package/docs/plugin-development/options.md +40 -13
- package/docs/plugin-development/services.md +95 -0
- package/docs/usage/operations.md +9 -0
- package/docs/usage/plugins/integrations/instances.md +11 -3
- package/docs/usage/plugins/integrations/lifecycle-events.md +4 -1
- package/docs/usage/plugins/integrations/scim.md +20 -18
- package/docs/usage/plugins/integrations/tombstone.md +10 -6
- package/docs/usage/plugins/ldap/flat-generic.md +8 -1
- package/docs/usage/plugins/ldap/groups.md +4 -1
- package/docs/usage/plugins/ldap/password-policy.md +7 -0
- package/docs/usage/upgrading.md +59 -0
- package/package.json +17 -12
- package/static/browser/ldap-tree-viewer/LdapTreeViewer.js.map +1 -1
- package/static/browser/ldap-tree-viewer.esm.js.map +1 -1
- package/static/browser/ldap-tree-viewer.js.map +1 -1
- package/static/browser/ldap-tree-viewer.min.js.map +1 -1
|
@@ -42,17 +42,43 @@ export type ExampleOptions = OptionsOf<typeof exampleOptions>;
|
|
|
42
42
|
The key is the `Config` name: `example_timeout` is `--example-timeout`,
|
|
43
43
|
`DM_EXAMPLE_TIMEOUT` when the descriptor names that variable.
|
|
44
44
|
|
|
45
|
+
### Deprecating an option
|
|
46
|
+
|
|
47
|
+
Rename an option by giving the old name as an alias: the parser still reads
|
|
48
|
+
it, and the server warns once at startup. Keep the alias for two minor
|
|
49
|
+
releases, as [CONTRIBUTING.md](../../CONTRIBUTING.md#deprecating-a-published-contract)
|
|
50
|
+
requires.
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
export const exampleOptions = defineOptions({
|
|
54
|
+
example_url: opt.string({
|
|
55
|
+
env: 'DM_EXAMPLE_URL',
|
|
56
|
+
aliases: ['example-uri'],
|
|
57
|
+
envAliases: ['DM_EXAMPLE_URI'],
|
|
58
|
+
}),
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
A CLI alias takes one value per occurrence, as the singular form does, and an
|
|
63
|
+
array option's plural form has no alias: renaming it is a breaking change. An
|
|
64
|
+
environment alias is read when `env` is unset, or empty for a type where an
|
|
65
|
+
empty value means nothing, and only for a non-array option when its canonical
|
|
66
|
+
CLI name is absent; an array option combines the environment value with the
|
|
67
|
+
CLI one, so its alias is still read.
|
|
68
|
+
|
|
45
69
|
Each declaration takes:
|
|
46
70
|
|
|
47
|
-
| Field
|
|
48
|
-
|
|
|
49
|
-
| `env`
|
|
50
|
-
| `default`
|
|
51
|
-
| `required`
|
|
52
|
-
| `plural`
|
|
53
|
-
| `kind`
|
|
54
|
-
| `min/max`
|
|
55
|
-
| `choices`
|
|
71
|
+
| Field | Meaning |
|
|
72
|
+
| ------------ | --------------------------------------------------------------------- |
|
|
73
|
+
| `env` | Environment variable read when the CLI does not set the option |
|
|
74
|
+
| `default` | Value kept when neither the CLI nor the environment sets the option |
|
|
75
|
+
| `required` | Refuse an empty value instead of reading it as unset |
|
|
76
|
+
| `plural` | Array only: CLI name of the plural form, without the leading `--` |
|
|
77
|
+
| `kind` | Array only: how a value splits, see `ArrayKind` in `parseConfig.ts` |
|
|
78
|
+
| `min/max` | Number only: bounds checked when the option is read |
|
|
79
|
+
| `choices` | String only: the values the option accepts |
|
|
80
|
+
| `aliases` | Former CLI names still accepted, without the leading `--` |
|
|
81
|
+
| `envAliases` | Former environment variables still accepted, read when `env` is unset |
|
|
56
82
|
|
|
57
83
|
## Reading options
|
|
58
84
|
|
|
@@ -103,7 +129,8 @@ moved. A migrated plugin no longer reads them: it uses `options()`.
|
|
|
103
129
|
|
|
104
130
|
Plugins outside the repository cannot add to `args.ts` yet, but they can
|
|
105
131
|
declare options the same way and name them in `optionDefinitions`: the startup
|
|
106
|
-
report subtracts those keys, and `options()` reads a declared
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
132
|
+
report subtracts those keys and their aliases, and `options()` reads a declared
|
|
133
|
+
`env` variable or a deprecated CLI alias the parser did not carry, warning at
|
|
134
|
+
startup for the alias as it does for a core option. An option without a
|
|
135
|
+
declaration still reaches `this.config` from an unknown `--key value` pair, and
|
|
136
|
+
the startup report names it.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Plugin services
|
|
2
|
+
|
|
3
|
+
A plugin sometimes needs what another plugin holds: the group operations, the
|
|
4
|
+
entity schemas, the trash. A service is a typed interface a plugin provides
|
|
5
|
+
under a token, and another plugin reaches with `this.service(token)`.
|
|
6
|
+
|
|
7
|
+
The token carries the interface. The compiler checks that an instance bound
|
|
8
|
+
with `with()` answers it, and gives a consumer the type it declared. Whether a
|
|
9
|
+
provider exists is a runtime question: a plugin that stops declaring the token
|
|
10
|
+
still compiles, and its consumers get `null` and a warning. The plugin
|
|
11
|
+
registry name stays what it is for: loading a plugin and naming it in the
|
|
12
|
+
logs.
|
|
13
|
+
|
|
14
|
+
## Declaring a service
|
|
15
|
+
|
|
16
|
+
Put the token and its interface in a module both sides import — a plugin
|
|
17
|
+
family's own service in its own module. A service shared between families is
|
|
18
|
+
declared in `src/lib/services/` and re-exported from `ldap-rest/plugin`, one
|
|
19
|
+
of the package's entry points; a module under `src/lib/` has no export path of
|
|
20
|
+
its own.
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { serviceToken } from 'ldap-rest/plugin';
|
|
24
|
+
|
|
25
|
+
export interface GroupsApi {
|
|
26
|
+
listGroups(): Promise<string[]>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const GroupsService = serviceToken<GroupsApi>('groups');
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Declare a token once. The object is the registry key; calling `serviceToken`
|
|
33
|
+
again under the same name declares another service, not the same one. The name
|
|
34
|
+
only identifies it in the logs.
|
|
35
|
+
|
|
36
|
+
## Providing a service
|
|
37
|
+
|
|
38
|
+
Bind the plugin instance to each token it provides:
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import DmPlugin from 'ldap-rest/plugin';
|
|
42
|
+
|
|
43
|
+
export default class LdapGroups extends DmPlugin {
|
|
44
|
+
name = 'ldapGroups';
|
|
45
|
+
provides = [GroupsService.with(this)];
|
|
46
|
+
|
|
47
|
+
async listGroups(): Promise<string[]> {
|
|
48
|
+
/* … */
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`with(this)` is checked by the compiler: an instance that does not answer the
|
|
54
|
+
interface does not compile. A plugin can provide several services. A service
|
|
55
|
+
is registered once its plugin's registration completes — after `api()` and
|
|
56
|
+
the hooks — so a consumer loaded afterwards finds it, and a provider does not
|
|
57
|
+
find its own service there. A plugin needing another one declares it in
|
|
58
|
+
[`dependencies`](dependencies.md#explicit-dependencies) so that it loads
|
|
59
|
+
first.
|
|
60
|
+
|
|
61
|
+
The first provider to register wins. A second one offering the same token is
|
|
62
|
+
ignored and named in a warning: which one answered would otherwise depend on
|
|
63
|
+
load order. Loading the same module twice under two names gives two instances
|
|
64
|
+
but one module-level token, so the second instance cannot provide it either.
|
|
65
|
+
|
|
66
|
+
When a host registers a plugin after startup, its `assertComposition` runs
|
|
67
|
+
before the service is registered, so a provider does not find its own service
|
|
68
|
+
there; the configuration's plugins are all registered before their
|
|
69
|
+
`assertComposition` runs.
|
|
70
|
+
|
|
71
|
+
## Consuming a service
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
const groups = this.service(GroupsService);
|
|
75
|
+
if (!groups) {
|
|
76
|
+
// Nothing provides it: the plugin skips the feature it would serve
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
await groups.listGroups();
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`service()` answers the provided instance, or `null` when nothing provides the
|
|
83
|
+
token. It logs one warning per plugin and service rather than one per call. A
|
|
84
|
+
plugin that cannot work without a service declares the provider in
|
|
85
|
+
`dependencies`, checks the answer in `assertComposition`, and throws naming the
|
|
86
|
+
service — that stops the server at startup instead of leaving a feature
|
|
87
|
+
silently absent. A constructor runs before the dependencies load, so it cannot
|
|
88
|
+
be the place for that check.
|
|
89
|
+
|
|
90
|
+
The registry belongs to the server and is shared by the views `withConfig`
|
|
91
|
+
builds for plugins loaded with overrides. It has no removal: a plugin
|
|
92
|
+
registers once and keeps its services for the life of the server.
|
|
93
|
+
|
|
94
|
+
`this.requirePlugin(name)` remains for a plugin whose interface is not yet
|
|
95
|
+
declared as a service; new code reaches another plugin through a token.
|
package/docs/usage/operations.md
CHANGED
|
@@ -53,6 +53,15 @@ The image runs as its unprivileged `node` user: with `docker run`, a
|
|
|
53
53
|
`DM_PORT` below 1024 stops the server at startup, where the default 8081
|
|
54
54
|
changes nothing.
|
|
55
55
|
|
|
56
|
+
The image is built in two stages: a builder produces the package and installs
|
|
57
|
+
its production dependencies, the runtime stage copies them and carries no
|
|
58
|
+
compiler nor package manager cache. Its base image is pinned by digest in
|
|
59
|
+
`scripts/buildDockerfile.ts`, so the image built is the one reviewed even if
|
|
60
|
+
the tag moves; the digest follows the tag it names, taken from the
|
|
61
|
+
[Docker Hub tag page](https://hub.docker.com/_/node/tags?name=25-alpine) and
|
|
62
|
+
updated by hand with it. Dependabot ignores the image: it would open a change
|
|
63
|
+
to the generated `Dockerfile`, which the drift check refuses.
|
|
64
|
+
|
|
56
65
|
### What the shipped plugins report
|
|
57
66
|
|
|
58
67
|
| Plugin | `degraded` when |
|
|
@@ -19,7 +19,13 @@ gets no instance.
|
|
|
19
19
|
An entry holding `--twake-instance-skip-value` in
|
|
20
20
|
`--twake-instance-skip-attribute`, a technical account for instance, gets
|
|
21
21
|
none, and neither does a tombstone
|
|
22
|
-
(`--twake-lifecycle-deleted-attribute`) put back in place.
|
|
22
|
+
(`--twake-lifecycle-deleted-attribute`) put back in place. Each expression
|
|
23
|
+
is tried against the canonical DN first, then against the DN as sent: an
|
|
24
|
+
account created under a branch written with other spacing or case is still
|
|
25
|
+
one, and an expression written with the directory's own spelling (`\2C`, a
|
|
26
|
+
doubled space) still matches. An expression naming a value that holds a
|
|
27
|
+
comma writes it `\2C` or `\,`: a value comma never stands in for an RDN
|
|
28
|
+
separator in the form matched.
|
|
23
29
|
- The address (`--twake-instance-fqdn-attribute`) and the mark
|
|
24
30
|
(`--twake-instance-sent-attribute`) are this plugin's to write: an add that
|
|
25
31
|
carries them has them removed, and an address written by a modify is taken
|
|
@@ -80,8 +86,10 @@ before it takes its members' `user.created`. Then `organization.created` is
|
|
|
80
86
|
published on the b2b exchange, and the entry is marked. The message carries
|
|
81
87
|
the organization's id, address, domain, and its name as `organization`, read
|
|
82
88
|
from `--twake-instance-organization-name-attribute`, which
|
|
83
|
-
`ensureOrganization` fills from `name` when the entry has none.
|
|
84
|
-
|
|
89
|
+
`ensureOrganization` fills from `name` when the entry has none. An id captured
|
|
90
|
+
from a `--twake-instance-dn` group is read from the organization entry when
|
|
91
|
+
one exists, so the case a caller spells the branch in is not sent. The mark,
|
|
92
|
+
not the address, says the organization is done.
|
|
85
93
|
|
|
86
94
|
With the Cloudery, a member's `user.created` waits for its organization's: a
|
|
87
95
|
member under an organization entry that is not marked yet gets its address
|
|
@@ -110,7 +110,10 @@ operational one such as `pwdAccountLockedTime` is seen on both sides.
|
|
|
110
110
|
means entries are never tombstones, and only a removal publishes `deleted`.
|
|
111
111
|
- `--twake-lifecycle-deleted-at-attribute`,
|
|
112
112
|
`--twake-lifecycle-deleted-at-format` (`iso8601`, the default, or
|
|
113
|
-
`generalizedTime`): the deletion date. It is
|
|
113
|
+
`generalizedTime`): the deletion date. It is read whether it is written as
|
|
114
|
+
a GeneralizedTime or as an ISO 8601 date, and always published as ISO 8601;
|
|
115
|
+
a value of neither shape is left out. A GeneralizedTime needs its zone; an
|
|
116
|
+
ISO 8601 date and time without one is read in the server's time zone.
|
|
114
117
|
- `--twake-lifecycle-member-attribute` (default `member`): the attribute
|
|
115
118
|
`memberAdded`, `memberRemoved` and member lists read.
|
|
116
119
|
- `--twake-lifecycle-rules`: a JSON file, or the JSON itself.
|
|
@@ -223,16 +223,17 @@ and `--scim-group-mapping`.
|
|
|
223
223
|
|
|
224
224
|
Each element of `entries` is a `MappingEntry` with the following optional fields:
|
|
225
225
|
|
|
226
|
-
| Field | Purpose
|
|
227
|
-
| --------------- |
|
|
228
|
-
| `scim` | **Required.** Top-level SCIM attribute name (`userName`, `displayName`, `emails`, …).
|
|
229
|
-
| `ldap` | Simple 1:1 mapping to an LDAP attribute.
|
|
230
|
-
| `ldapPrimary` | For multi-valued SCIM attributes (`emails`, `phoneNumbers`, …), the LDAP attribute that stores the _primary_ value.
|
|
231
|
-
| `ldapSecondary` | LDAP attribute that stores the _non-primary_ values of the same SCIM attribute (array).
|
|
232
|
-
| `sub` | Object that maps SCIM sub-attributes to LDAP attributes. Used for complex SCIM values like `name.familyName` → `sn`.
|
|
233
|
-
| `
|
|
234
|
-
| `
|
|
235
|
-
| `
|
|
226
|
+
| Field | Purpose |
|
|
227
|
+
| --------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
228
|
+
| `scim` | **Required.** Top-level SCIM attribute name (`userName`, `displayName`, `emails`, …). |
|
|
229
|
+
| `ldap` | Simple 1:1 mapping to an LDAP attribute. |
|
|
230
|
+
| `ldapPrimary` | For multi-valued SCIM attributes (`emails`, `phoneNumbers`, …), the LDAP attribute that stores the _primary_ value. |
|
|
231
|
+
| `ldapSecondary` | LDAP attribute that stores the _non-primary_ values of the same SCIM attribute (array). |
|
|
232
|
+
| `sub` | Object that maps SCIM sub-attributes to LDAP attributes. Used for complex SCIM values like `name.familyName` → `sn`. |
|
|
233
|
+
| `subDn` | Sub-attribute names in `sub` whose value is a DN (for example `["value"]` for `manager`); they are held to RFC 4514 on write. |
|
|
234
|
+
| `multi` | `"array"` or `"single"` (default) — hints array serialization for `ldap`. |
|
|
235
|
+
| `readOnly` | `true` to skip this attribute on write (create/update ignore it). |
|
|
236
|
+
| `operational` | `true` for LDAP operational attributes (e.g. `entryUUID`) — loaded on read only. |
|
|
236
237
|
|
|
237
238
|
### Merging
|
|
238
239
|
|
|
@@ -269,7 +270,8 @@ override only what's different and inherit the rest.
|
|
|
269
270
|
},
|
|
270
271
|
{
|
|
271
272
|
"scim": "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:manager",
|
|
272
|
-
"sub": { "value": "manager" }
|
|
273
|
+
"sub": { "value": "manager" },
|
|
274
|
+
"subDn": ["value"]
|
|
273
275
|
}
|
|
274
276
|
]
|
|
275
277
|
}
|
|
@@ -317,7 +319,11 @@ of them; a complex attribute takes an object whose sub-attributes are scalars
|
|
|
317
319
|
multi-valued complex attribute such as `emails` takes a list of objects whose
|
|
318
320
|
`value` is a scalar. Anything else is answered
|
|
319
321
|
`400 invalidValue`, as is a PATCH operation that is not an object or whose
|
|
320
|
-
`op` is not a string.
|
|
322
|
+
`op` is not a string. A reference the mapping declares a DN (`subDn`) is
|
|
323
|
+
refused with `400 invalidValue` when its value holds an escape RFC 4514 does
|
|
324
|
+
not define, as the flat routes hold a client-written DN. The directory
|
|
325
|
+
refuses such a value itself on an attribute of DN syntax; this names the
|
|
326
|
+
escape in the SCIM answer and applies wherever the mapping declares one.
|
|
321
327
|
|
|
322
328
|
A PATCH `add`, or a `remove` naming values, changes only the values it names:
|
|
323
329
|
values the caller's read did not show, such as group members an
|
|
@@ -715,18 +721,14 @@ Response shape (truncated):
|
|
|
715
721
|
"id",
|
|
716
722
|
"active"
|
|
717
723
|
],
|
|
718
|
-
"mapping": [
|
|
719
|
-
/* same shape as default-mapping.json */
|
|
720
|
-
]
|
|
724
|
+
"mapping": [/* same shape as default-mapping.json */]
|
|
721
725
|
},
|
|
722
726
|
{
|
|
723
727
|
"id": "Group",
|
|
724
728
|
"endpoint": "/scim/v2/Groups",
|
|
725
729
|
"schema": "urn:ietf:params:scim:schemas:core:2.0:Group",
|
|
726
730
|
"rdnAttribute": "cn",
|
|
727
|
-
"mapping": [
|
|
728
|
-
/* ... */
|
|
729
|
-
]
|
|
731
|
+
"mapping": [/* ... */]
|
|
730
732
|
}
|
|
731
733
|
],
|
|
732
734
|
"idStrategy": "rdn",
|
|
@@ -10,10 +10,13 @@ is old enough, or right away when forced.
|
|
|
10
10
|
|
|
11
11
|
## Behaviour
|
|
12
12
|
|
|
13
|
-
- A delete of an entry whose DN matches `--twake-tombstone-dn`
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
- A delete of an entry whose DN matches `--twake-tombstone-dn` — under any
|
|
14
|
+
spelling the directory folds, so spaces, case and escapes do not matter —
|
|
15
|
+
writes, in one modify: the deleted attribute, the deletion date (now), the
|
|
16
|
+
reason, the lock, and removes `--twake-tombstone-clear-attributes`. Other
|
|
17
|
+
entries are deleted as usual. A multi-valued RDN may not match: an
|
|
18
|
+
expression anchored on `uid=` misses a DN written `cn=…+uid=…`, and that
|
|
19
|
+
delete removes the entry for good.
|
|
17
20
|
- A delete of an existing tombstone writes nothing and answers as a delete.
|
|
18
21
|
It fires the `twakedeletionreplay` hook with the tombstone, so
|
|
19
22
|
[lifecycle events](lifecycle-events.md) publishes the deletion again, with
|
|
@@ -62,8 +65,9 @@ Content-Type: application/json
|
|
|
62
65
|
|
|
63
66
|
- `200`: erased.
|
|
64
67
|
- `404`: no tombstone at this DN.
|
|
65
|
-
- `409`: the deletion is younger than
|
|
66
|
-
`
|
|
68
|
+
- `409`: `force` is not true, and either the deletion is younger than
|
|
69
|
+
`--twake-tombstone-erase-min-age` or its date cannot be read as
|
|
70
|
+
[lifecycle events](lifecycle-events.md) reads it.
|
|
67
71
|
|
|
68
72
|
Other plugins call `erase(dn, { force, req })`.
|
|
69
73
|
|
|
@@ -453,7 +453,14 @@ Content-Type: application/json
|
|
|
453
453
|
|
|
454
454
|
The identifier may also be the whole DN of the entry, in the entity's
|
|
455
455
|
branch: `"uid": "uid=Smith\\,John,ou=users,dc=example,dc=com"` creates the
|
|
456
|
-
entry `Smith,John`, whose DN spells the name with its escapes.
|
|
456
|
+
entry `Smith,John`, whose DN spells the name with its escapes. The DN must
|
|
457
|
+
use the escapes RFC 4514 defines; an escape it does not define (`\q`) is
|
|
458
|
+
refused with a `400`. Send the bare value to have the server escape it.
|
|
459
|
+
|
|
460
|
+
The name written is the value the RDN gives under the folding the directory
|
|
461
|
+
applies (Unicode NFKC, and its insignificant spaces): `uid=\ zoë` and
|
|
462
|
+
`uid=zoë` name one entry, written `uid=zoë`, and a name sent decomposed is
|
|
463
|
+
stored composed.
|
|
457
464
|
|
|
458
465
|
### Modify Entry
|
|
459
466
|
|
|
@@ -157,7 +157,10 @@ POST /api/v1/ldap/groups
|
|
|
157
157
|
|
|
158
158
|
**Notes:**
|
|
159
159
|
|
|
160
|
-
- `cn` is required
|
|
160
|
+
- `cn` is required; it is a name, or the group's DN in the groups branch,
|
|
161
|
+
whose first RDN gives the name, folded as the directory folds it. The DN
|
|
162
|
+
form follows the same
|
|
163
|
+
[escape rule as a flat entity's identifier](flat-generic.md#create-entry)
|
|
161
164
|
- `member` can be a string (single member) or array (multiple members)
|
|
162
165
|
- If no members provided, a dummy member is automatically added, and it is
|
|
163
166
|
left out of `member` when the group is read back, on both the list and the
|
|
@@ -155,6 +155,10 @@ curl "http://localhost:8081/api/v1/users/uid%3Djohn.doe%2Cou%3Dusers%2Cdc%3Dexam
|
|
|
155
155
|
}
|
|
156
156
|
```
|
|
157
157
|
|
|
158
|
+
A `pwdMaxAge` large enough to put the expiry beyond the representable date
|
|
159
|
+
range is reported as no expiry: `expiresAt` and `daysUntilExpiration` are
|
|
160
|
+
`null`, and `isExpired` stays `false`.
|
|
161
|
+
|
|
158
162
|
### Unlock User Account
|
|
159
163
|
|
|
160
164
|
```http
|
|
@@ -337,6 +341,9 @@ curl -X PATCH "http://localhost:8081/api/v1/password-policies/default" \
|
|
|
337
341
|
|
|
338
342
|
- `pwdAttribute` and `pwdCheckModule` are read-only. Before OpenLDAP 2.6,
|
|
339
343
|
`pwdCheckModule` is the path of a library slapd loads; set it in slapd.
|
|
344
|
+
- Durations and counts are integers from 0 to 9007199254740991 (2⁵³ − 1),
|
|
345
|
+
the largest a JSON number holds exactly: a larger value, or one sent as an
|
|
346
|
+
exponent such as `1e21`, is refused with a `400`.
|
|
340
347
|
- `pwdCheckModuleArg`, the configuration of the quality-check module (ppm,
|
|
341
348
|
for instance), is a string, usually of several lines. Writing it, or
|
|
342
349
|
`pwdUseCheckModule`, gives the entry the `pwdPolicyChecker` class. Both
|
package/docs/usage/upgrading.md
CHANGED
|
@@ -4,6 +4,65 @@ 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 1.3.0
|
|
8
|
+
|
|
9
|
+
### A plugin with its own `service` member
|
|
10
|
+
|
|
11
|
+
**Who is affected:** a plugin built outside this repository that declares a
|
|
12
|
+
field, getter or method named `service`.
|
|
13
|
+
|
|
14
|
+
`DmPlugin` now has `service(token)`, which returns the instance another plugin
|
|
15
|
+
provides under a service token. Rename the plugin's own `service` member. See
|
|
16
|
+
[plugin services](../plugin-development/services.md).
|
|
17
|
+
|
|
18
|
+
### A plugin with its own `provides` member
|
|
19
|
+
|
|
20
|
+
**Who is affected:** a plugin built outside this repository that declares a
|
|
21
|
+
field named `provides`.
|
|
22
|
+
|
|
23
|
+
`DmPlugin` now has `provides`, the services a plugin offers to others. Rename
|
|
24
|
+
the plugin's own `provides` member, or it becomes the list of services the
|
|
25
|
+
plugin declares. See
|
|
26
|
+
[plugin services](../plugin-development/services.md#providing-a-service).
|
|
27
|
+
|
|
28
|
+
### A path parameter is percent-decoded once
|
|
29
|
+
|
|
30
|
+
**Who is affected:** a client that encoded a path parameter twice to reach an
|
|
31
|
+
identifier holding `%`, sending `/users/100%2525` for the entry `100%`.
|
|
32
|
+
|
|
33
|
+
The parameter is decoded once now, as RFC 3986 spells it: an identifier
|
|
34
|
+
holding `%` goes out as `100%25`. A parameter still encoded twice names the
|
|
35
|
+
escaped text, so `/users/100%2525` addresses the entry `100%25`
|
|
36
|
+
([details](../client-development/api/rest-api.md#url-encoding)).
|
|
37
|
+
|
|
38
|
+
### A paged search opens its connection on the first page
|
|
39
|
+
|
|
40
|
+
**Who is affected:** a plugin calling `ldap.search()` with paging, leaving the
|
|
41
|
+
returned generator unread and expecting a connection to have been opened, or
|
|
42
|
+
expecting a connection or hook error from the call itself.
|
|
43
|
+
|
|
44
|
+
A paged search takes its pooled connection when the first page is read, not
|
|
45
|
+
when `search()` is called. A generator that is never walked holds no
|
|
46
|
+
connection, and the next request can use the slot. A connection or bind
|
|
47
|
+
failure, the 30 s wait for a pooled connection and an `ldapsearchresult` hook
|
|
48
|
+
that refuses are answered on the first page, not by the call; a read that
|
|
49
|
+
must fail when it is made uses `paged: false`.
|
|
50
|
+
|
|
51
|
+
### A deletion date written in another shape
|
|
52
|
+
|
|
53
|
+
**Who is affected:** a deployment whose writer writes the lifecycle deletion
|
|
54
|
+
date as something other than an ISO 8601 date or a GeneralizedTime with its
|
|
55
|
+
zone — for example `date '+%F %T'` (`2025-01-01 12:00:00`), an RFC 2822 date,
|
|
56
|
+
or a US-style `01/02/2025`.
|
|
57
|
+
|
|
58
|
+
The deletion date is read only in those two shapes now, where the default
|
|
59
|
+
`iso8601` mode handed anything else to `new Date()`. An unreadable date makes
|
|
60
|
+
`erase` answer `409` without `force`, leaves `deletedAt` out of the events,
|
|
61
|
+
and a rule whose payload holds only `$changed.<date>` publishes nothing. Write
|
|
62
|
+
an ISO 8601 date, such as with `date -u '+%Y-%m-%dT%H:%M:%SZ'`, or a
|
|
63
|
+
GeneralizedTime with its zone, and see
|
|
64
|
+
[lifecycle events](plugins/integrations/lifecycle-events.md#configuration).
|
|
65
|
+
|
|
7
66
|
## From 1.2.1
|
|
8
67
|
|
|
9
68
|
### A plugin written against the old hooks API
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ldap-rest",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Light directory manager",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Identity-Manager"
|
|
@@ -790,6 +790,7 @@
|
|
|
790
790
|
"dist",
|
|
791
791
|
"static",
|
|
792
792
|
"docs",
|
|
793
|
+
"!docs/usage/options.snapshot.json",
|
|
793
794
|
"examples",
|
|
794
795
|
"LICENSE",
|
|
795
796
|
"package.json"
|
|
@@ -805,11 +806,13 @@
|
|
|
805
806
|
"build:pages": "tsx scripts/build-pages.ts",
|
|
806
807
|
"build:prod": "npm run clean && NODE_ENV=production rollup -c && npm run build:browser && node scripts/moveBrowserLibs.mjs && npm run build:dockerfile",
|
|
807
808
|
"build:watch": "rollup -c --watch",
|
|
808
|
-
"check": "npm run check:ts && npm run lint && npm run format:check && npm run check:hooks && npm run check:no-client-values && npm run check:openapi",
|
|
809
|
+
"check": "npm run check:ts && npm run lint && npm run format:check && npm run check:hooks && npm run check:no-client-values && npm run check:openapi && npm run check:options",
|
|
809
810
|
"check:hooks": "tsx scripts/hooks-doc.ts",
|
|
810
811
|
"check:no-client-values": "sh scripts/check-no-client-values.sh",
|
|
811
812
|
"check:openapi": "tsx scripts/check-openapi.ts",
|
|
812
|
-
"check:
|
|
813
|
+
"check:options": "tsx scripts/options-snapshot.ts --check",
|
|
814
|
+
"check:ts": "node ./node_modules/typescript/bin/tsc --noEmit",
|
|
815
|
+
"check:ts7": "node ./node_modules/typescript7/bin/tsc --noEmit",
|
|
813
816
|
"clean": "rimraf dist/* static/browser/* coverage",
|
|
814
817
|
"coverage": "c8 --config .c8rc.json mocha",
|
|
815
818
|
"coverage:check": "npm run check:ts && c8 --config .c8rc.json --exclude 'src/browser/**' --check-coverage --statements 84 --lines 84 --branches 75 --functions 86 mocha",
|
|
@@ -820,8 +823,9 @@
|
|
|
820
823
|
"format:fix": "prettier --write .",
|
|
821
824
|
"format:fix-diff": "prettier --write $(git checkout|grep -E '^(M|A)'|cut -f2)",
|
|
822
825
|
"generate:openapi": "tsx scripts/generate-openapi.ts",
|
|
823
|
-
"lint": "eslint \"src/**/*.{ts,tsx,js,jsx}\"",
|
|
824
|
-
"lint:fix": "eslint \"src/**/*.{ts,tsx,js,jsx}\" --fix",
|
|
826
|
+
"lint": "eslint \"src/**/*.{ts,tsx,js,jsx}\" \"test/**/*.ts\"",
|
|
827
|
+
"lint:fix": "eslint \"src/**/*.{ts,tsx,js,jsx}\" \"test/**/*.ts\" --fix",
|
|
828
|
+
"snapshot:options": "tsx scripts/options-snapshot.ts",
|
|
825
829
|
"start:dev": "./.dev.mk start",
|
|
826
830
|
"test": "npm run check:ts && mocha",
|
|
827
831
|
"test:dev": "./.dev.mk test",
|
|
@@ -829,9 +833,8 @@
|
|
|
829
833
|
},
|
|
830
834
|
"overrides": {
|
|
831
835
|
"diff": ">=8.0.3",
|
|
832
|
-
"
|
|
833
|
-
"
|
|
834
|
-
"minimatch": "^10.2.1",
|
|
836
|
+
"glob": ">=11.1.0",
|
|
837
|
+
"minimatch": "^10.2.3",
|
|
835
838
|
"postcss-selector-parser": "^7.1.6",
|
|
836
839
|
"serialize-javascript": ">=7.0.3"
|
|
837
840
|
},
|
|
@@ -849,6 +852,7 @@
|
|
|
849
852
|
"winston": "^3.17.0"
|
|
850
853
|
},
|
|
851
854
|
"devDependencies": {
|
|
855
|
+
"@eslint/js": "^10.0.1",
|
|
852
856
|
"@rollup/plugin-commonjs": "^29.0.3",
|
|
853
857
|
"@rollup/plugin-json": "^6.1.0",
|
|
854
858
|
"@rollup/plugin-terser": "^1.0.2",
|
|
@@ -865,15 +869,15 @@
|
|
|
865
869
|
"@typescript-eslint/parser": "^8.44.0",
|
|
866
870
|
"c8": "^12.0.0",
|
|
867
871
|
"chai": "^6.0.1",
|
|
868
|
-
"eslint": "^
|
|
872
|
+
"eslint": "^10.13.0",
|
|
869
873
|
"eslint-config-prettier": "^10.1.8",
|
|
870
|
-
"eslint-plugin-import": "^
|
|
874
|
+
"eslint-plugin-import-x": "^4.17.1",
|
|
871
875
|
"eslint-plugin-prettier": "^5.5.4",
|
|
872
876
|
"globals": "^17.13.0",
|
|
873
877
|
"js-yaml": "^5.5.0",
|
|
874
878
|
"mocha": "^12.0.0",
|
|
875
879
|
"nock": "^14.0.10",
|
|
876
|
-
"prettier": "^3.
|
|
880
|
+
"prettier": "^3.9.10",
|
|
877
881
|
"rimraf": "^6.0.1",
|
|
878
882
|
"rollup": "^4.50.2",
|
|
879
883
|
"rollup-plugin-postcss": "^4.0.2",
|
|
@@ -882,7 +886,8 @@
|
|
|
882
886
|
"tinyglobby": "^0.2.17",
|
|
883
887
|
"tslib": "^2.8.1",
|
|
884
888
|
"tsx": "^4.20.5",
|
|
885
|
-
"typescript": "^
|
|
889
|
+
"typescript": "^6.0.3",
|
|
890
|
+
"typescript7": "npm:typescript@^7.0.2"
|
|
886
891
|
},
|
|
887
892
|
"optionalDependencies": {
|
|
888
893
|
"@linagora/rabbitmq-client": "^0.7.2",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LdapTreeViewer.js","sources":["../../../../src/browser/ldap-tree-viewer/LdapTreeViewer.ts"],"sourcesContent":[null],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"LdapTreeViewer.js","sources":["../../../../src/browser/ldap-tree-viewer/LdapTreeViewer.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|