ldap-rest 0.4.7 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/sync-james.mjs +6 -2
- package/dist/bin/index.js +1 -1
- package/dist/config/args.js +1 -1
- package/dist/lib/auth/base.js +1 -1
- package/dist/lib/ldapSchema.js +1 -0
- package/dist/lib/utils.js +1 -1
- package/dist/plugins/auth/authzPerRoute.js +1 -1
- package/dist/plugins/auth/rateLimit.js +1 -1
- package/dist/plugins/ldap/groups.js +1 -1
- package/dist/plugins/ldap/organizations.js +1 -1
- package/dist/plugins/ldap/raw.js +1 -0
- package/dist/plugins/twake/appAccountsApi.js +1 -1
- package/dist/plugins/twake/appAccountsConsistency.js +1 -1
- package/dist/src/bin/index.d.ts +112 -0
- package/dist/src/browser/ldap-browser/LdapBrowser.d.ts +52 -0
- package/dist/src/browser/ldap-browser/api/RawApiClient.d.ts +64 -0
- package/dist/src/browser/ldap-browser/components/EntryTree.d.ts +75 -0
- package/dist/src/browser/ldap-browser/components/EntryView.d.ts +56 -0
- package/dist/src/browser/ldap-browser/index.d.ts +9 -0
- package/dist/src/browser/ldap-browser/schema.d.ts +62 -0
- package/dist/src/browser/ldap-browser/types.d.ts +96 -0
- package/dist/src/config/args.d.ts +7 -0
- package/dist/src/lib/auth/base.d.ts +82 -1
- package/dist/src/lib/ldapSchema.d.ts +159 -0
- package/dist/src/lib/utils.d.ts +4 -0
- package/dist/src/plugins/ldap/raw.d.ts +251 -0
- package/dist/src/plugins/twake/appAccountsConsistency.d.ts +40 -2
- package/docs/client-development/browser/libraries.md +142 -1
- package/docs/usage/configuration.md +40 -5
- package/docs/usage/plugins/README.md +10 -9
- package/docs/usage/plugins/auth/README.md +57 -0
- package/docs/usage/plugins/auth/rate-limit.md +9 -0
- package/docs/usage/plugins/integrations/app-accounts.md +35 -2
- package/docs/usage/plugins/ldap/README.md +12 -0
- package/docs/usage/plugins/ldap/raw.md +226 -0
- package/examples/web/README.md +18 -0
- package/examples/web/ldap-browser.html +94 -0
- package/package.json +37 -1
- package/static/browser/ldap-browser/LdapBrowser.js +199 -0
- package/static/browser/ldap-browser/LdapBrowser.js.map +1 -0
- package/static/browser/ldap-browser/api/RawApiClient.js +103 -0
- package/static/browser/ldap-browser/api/RawApiClient.js.map +1 -0
- package/static/browser/ldap-browser/components/EntryTree.js +235 -0
- package/static/browser/ldap-browser/components/EntryTree.js.map +1 -0
- package/static/browser/ldap-browser/components/EntryView.js +183 -0
- package/static/browser/ldap-browser/components/EntryView.js.map +1 -0
- package/static/browser/ldap-browser/index.js +4 -0
- package/static/browser/ldap-browser/index.js.map +1 -0
- package/static/browser/ldap-browser/schema.js +135 -0
- package/static/browser/ldap-browser/schema.js.map +1 -0
- package/static/browser/ldap-browser/types.js +2 -0
- package/static/browser/ldap-browser/types.js.map +1 -0
- package/static/browser/ldap-browser.css +2 -0
- package/static/browser/ldap-browser.css.map +1 -0
- package/static/browser/ldap-browser.esm.js +915 -0
- package/static/browser/ldap-browser.esm.js.map +1 -0
- package/static/browser/ldap-browser.js +925 -0
- package/static/browser/ldap-browser.js.map +1 -0
- package/static/browser/ldap-browser.min.js +2 -0
- package/static/browser/ldap-browser.min.js.map +1 -0
- package/static/browser/ldap-unit-editor/components/UnitTree.js +0 -1
- package/static/browser/ldap-unit-editor/components/UnitTree.js.map +1 -1
- package/static/browser/ldap-unit-editor.esm.js +0 -1
- package/static/browser/ldap-unit-editor.esm.js.map +1 -1
- package/static/browser/ldap-unit-editor.js +0 -1
- package/static/browser/ldap-unit-editor.js.map +1 -1
- package/static/browser/ldap-unit-editor.min.js.map +1 -1
|
@@ -43,8 +43,36 @@ Instead of using a single primary password to access all services that authentic
|
|
|
43
43
|
2. **App accounts consistency plugin** `core/twake/appAccountsConsistency` - **Required**
|
|
44
44
|
- Automatically creates principal accounts (uid=mail@domain.com)
|
|
45
45
|
- Ensures automatic cleanup when users are deleted
|
|
46
|
-
-
|
|
46
|
+
- Moves the principal account on a mail change, and drops the app accounts:
|
|
47
|
+
every MUA has to be reconfigured against the new address anyway
|
|
47
48
|
3. **Applicative accounts base** configured in LDAP (e.g., `ou=applicative,dc=example,dc=com`)
|
|
49
|
+
4. **Read access on `userPassword`** in that branch, for the bind DN
|
|
50
|
+
(`--ldap-dn`) - **Required for deletion**
|
|
51
|
+
|
|
52
|
+
Revoking an app account means removing _its_ value from the principal
|
|
53
|
+
account, which holds one `userPassword` per device. The server must read the
|
|
54
|
+
stored hash to know which value to remove — a salted hash cannot be
|
|
55
|
+
recomputed. Without that access, `DELETE` returns `500` and keeps the
|
|
56
|
+
account rather than reporting a revocation that did not happen.
|
|
57
|
+
|
|
58
|
+
A typical OpenLDAP ACL, scoped to the applicative branch so that the users'
|
|
59
|
+
primary passwords stay unreadable:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
olcAccess: to dn.subtree="ou=applicative,dc=example,dc=com" attrs=userPassword
|
|
63
|
+
by dn.exact="cn=ldap-rest,ou=tech,dc=example,dc=com" read
|
|
64
|
+
by * break
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
It must precede any broader rule on `userPassword`; OpenLDAP stops at the
|
|
68
|
+
first matching directive, and `by * break` lets other identities fall
|
|
69
|
+
through to the following ones.
|
|
70
|
+
|
|
71
|
+
5. **Uniqueness constraints must not cover the applicative branch.** The
|
|
72
|
+
principal account and its app accounts intentionally share the same `mail`,
|
|
73
|
+
so a `slapo-unique` overlay on `mail` has to be scoped to the users branch
|
|
74
|
+
(`olcUniqueURI: ldap:///ou=users,dc=example,dc=com?mail?sub?`) or every app
|
|
75
|
+
account creation is rejected.
|
|
48
76
|
|
|
49
77
|
## Configuration
|
|
50
78
|
|
|
@@ -181,6 +209,8 @@ Content-Type: application/json
|
|
|
181
209
|
- `400 Bad Request` - Max accounts limit reached or user has no mail
|
|
182
210
|
- `401 Unauthorized` - Missing or invalid token
|
|
183
211
|
- `404 Not Found` - User not found
|
|
212
|
+
- `500 Internal Server Error` - The password could not be added to the principal
|
|
213
|
+
account; the app account is rolled back and no password is returned
|
|
184
214
|
|
|
185
215
|
### Delete Applicative Account
|
|
186
216
|
|
|
@@ -202,6 +232,9 @@ Authorization: Bearer {token}
|
|
|
202
232
|
- `200 OK` - Account deleted (or already deleted - idempotent)
|
|
203
233
|
- `401 Unauthorized` - Missing or invalid token
|
|
204
234
|
- `403 Forbidden` - UID does not belong to user
|
|
235
|
+
- `500 Internal Server Error` - The account password could not be read, or could
|
|
236
|
+
not be removed from the principal account; the app account is kept so the
|
|
237
|
+
request stays replayable
|
|
205
238
|
|
|
206
239
|
## Password Generation
|
|
207
240
|
|
|
@@ -263,7 +296,7 @@ sync-app-accounts --help
|
|
|
263
296
|
- Secure random password
|
|
264
297
|
4. Plugin creates applicative account in LDAP:
|
|
265
298
|
- `uid=alice_c12345678,ou=applicative,dc=example,dc=com`
|
|
266
|
-
- Copies attributes from user (
|
|
299
|
+
- Copies the allowlisted attributes from the user (`--applicative-account-attribute`)
|
|
267
300
|
- Sets generated password
|
|
268
301
|
5. Plugin adds password to principal account:
|
|
269
302
|
- `uid=alice@example.com,ou=applicative,dc=example,dc=com`
|
|
@@ -14,6 +14,7 @@ Plugins for LDAP entity management.
|
|
|
14
14
|
| [external-users](external-users.md) | Contacts | Automatic creation |
|
|
15
15
|
| [on-change](on-change.md) | All | Change detection |
|
|
16
16
|
| [password-policy](password-policy.md) | Password management | Expiration, Lockout, Unlock |
|
|
17
|
+
| [raw](raw.md) | Whole directory (read) | Root DSE, Schema, Tree, Raw search |
|
|
17
18
|
|
|
18
19
|
## API Endpoints
|
|
19
20
|
|
|
@@ -62,6 +63,17 @@ GET /api/v1/password-policy/locked-accounts # List locked accounts
|
|
|
62
63
|
POST /api/v1/password/validate # Validate complexity (optional)
|
|
63
64
|
```
|
|
64
65
|
|
|
66
|
+
### Low-level browsing (ldapRaw)
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
GET /api/v1/ldap/raw/bases # Exposed subtrees
|
|
70
|
+
GET /api/v1/ldap/raw/rootdse # Server capabilities
|
|
71
|
+
GET /api/v1/ldap/raw/schema # Parsed directory schema
|
|
72
|
+
GET /api/v1/ldap/raw/entry/{dn} # Read one entry
|
|
73
|
+
GET /api/v1/ldap/raw/children/{dn} # Direct children of an entry
|
|
74
|
+
GET /api/v1/ldap/raw/search # Raw search (base, scope, filter)
|
|
75
|
+
```
|
|
76
|
+
|
|
65
77
|
### Bulk Import (ldapBulkImport)
|
|
66
78
|
|
|
67
79
|
```
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# LDAP Raw Plugin (low-level browsing)
|
|
2
|
+
|
|
3
|
+
Read-only, low-level access to the directory itself: root DSE, schema, and entries addressed by their DN. Where the other LDAP plugins expose business objects (users, groups, organizations), this one exposes the tree as it is stored — the server side of a phpLDAPadmin-like interface.
|
|
4
|
+
|
|
5
|
+
The companion browser library is [`ldap-browser`](../../../client-development/browser/libraries.md#ldapbrowser).
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Root DSE**: naming contexts, supported controls and extensions
|
|
10
|
+
- **Schema**: object classes, attribute types, syntaxes and matching rules, parsed from the subschema entry (RFC 4512) and cached
|
|
11
|
+
- **Entry read**: every attribute, operational ones included, binary values base64-encoded
|
|
12
|
+
- **Tree navigation**: direct children of a DN, with an optional "has children" probe
|
|
13
|
+
- **Raw search**: arbitrary base, scope and LDAP filter
|
|
14
|
+
- **Read-only**: this plugin registers no write route
|
|
15
|
+
|
|
16
|
+
## Configuration
|
|
17
|
+
|
|
18
|
+
### Environment Variables
|
|
19
|
+
|
|
20
|
+
- `DM_LDAP_RAW_BASE`: comma-separated subtrees to expose (default: `--ldap-base`)
|
|
21
|
+
- `DM_LDAP_RAW_HIDDEN_ATTRIBUTES`: comma-separated attributes never returned, on top of the credential ones (default: none)
|
|
22
|
+
- `DM_LDAP_RAW_SHOW_SECRETS`: serve credential attributes instead of hiding them (default: `false`)
|
|
23
|
+
- `DM_LDAP_RAW_MAX_RESULTS`: maximum entries returned by a search or a children listing (default: `200`)
|
|
24
|
+
- `DM_LDAP_RAW_SCHEMA_CACHE_TTL`: schema cache lifetime in seconds (default: `3600`)
|
|
25
|
+
|
|
26
|
+
### Command Line
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
ldap-rest \
|
|
30
|
+
--plugin core/ldap/raw \
|
|
31
|
+
--ldap-raw-base "ou=users,dc=example,dc=com" \
|
|
32
|
+
--ldap-raw-base "ou=groups,dc=example,dc=com" \
|
|
33
|
+
--ldap-raw-hidden-attribute employeeNumber \
|
|
34
|
+
--ldap-raw-max-results 500
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
With no `--ldap-raw-base`, the plugin exposes `--ldap-base`.
|
|
38
|
+
|
|
39
|
+
## API Endpoints
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
GET /api/v1/ldap/raw/bases # Exposed subtrees (roots of the tree)
|
|
43
|
+
GET /api/v1/ldap/raw/rootdse # Server capabilities
|
|
44
|
+
GET /api/v1/ldap/raw/schema # Parsed directory schema
|
|
45
|
+
GET /api/v1/ldap/raw/entry/{dn} # One entry, operational attributes included
|
|
46
|
+
GET /api/v1/ldap/raw/children/{dn} # Direct children of an entry
|
|
47
|
+
GET /api/v1/ldap/raw/search # Arbitrary search
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`{dn}` is the URL-encoded fully-qualified DN.
|
|
51
|
+
|
|
52
|
+
### Entry format
|
|
53
|
+
|
|
54
|
+
Attribute values are always arrays. A `binary` flag tells whether the values are base64-encoded octets rather than text:
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"dn": "uid=alice,ou=users,dc=example,dc=com",
|
|
59
|
+
"attributes": {
|
|
60
|
+
"objectClass": { "values": ["top", "inetOrgPerson"], "binary": false },
|
|
61
|
+
"uid": { "values": ["alice"], "binary": false },
|
|
62
|
+
"cn": { "values": ["Alice Smith"], "binary": false },
|
|
63
|
+
"jpegPhoto": { "values": ["/9j/4AAQSkZJRg…"], "binary": true }
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
A value is flagged binary when the directory returned octets that are not valid UTF-8, or when the attribute type is binary.
|
|
69
|
+
|
|
70
|
+
Credential attributes are **not** part of the response by default — see [Hidden attributes](#hidden-attributes).
|
|
71
|
+
|
|
72
|
+
### Children
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
curl "$URL/api/v1/ldap/raw/children/$(urlencode 'dc=example,dc=com')?children=1"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"children": [
|
|
81
|
+
{
|
|
82
|
+
"dn": "ou=users,dc=example,dc=com",
|
|
83
|
+
"rdn": "ou=users",
|
|
84
|
+
"objectClass": ["organizationalUnit"],
|
|
85
|
+
"hasChildren": true
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
"truncated": false
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`hasChildren` is only computed when the `children` query parameter is set: it costs one extra search per child.
|
|
93
|
+
|
|
94
|
+
At most `--ldap-raw-max-results` children are returned. `truncated` is true when the branch holds more, so a browsing UI can say so instead of silently showing a partial list — a branch of 5000 users must not look like a branch of 200.
|
|
95
|
+
|
|
96
|
+
### Search
|
|
97
|
+
|
|
98
|
+
| Parameter | Default | Description |
|
|
99
|
+
| ------------ | ------------------------ | ---------------------------------------------- |
|
|
100
|
+
| `base` | first exposed base | Search base, must be inside an exposed subtree |
|
|
101
|
+
| `scope` | `sub` | `base`, `one` or `sub` |
|
|
102
|
+
| `filter` | `(objectClass=*)` | LDAP filter |
|
|
103
|
+
| `attributes` | `*` | Comma-separated attribute list |
|
|
104
|
+
| `limit` | `--ldap-raw-max-results` | Capped by `--ldap-raw-max-results` |
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
curl "$URL/api/v1/ldap/raw/search?base=ou=users,dc=example,dc=com&filter=(mail=*@example.com)&attributes=uid,mail"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{ "entries": [...], "truncated": false }
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`truncated` is true when the limit cut the result set short.
|
|
115
|
+
|
|
116
|
+
The filter is parsed before the search runs, so a malformed one comes back as a 400 naming it rather than as a server error — a search box receives whatever the user typed, and `gov` is a typo, not a server fault:
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
{
|
|
120
|
+
"error": "Invalid LDAP filter \"gov\": Invalid expression: gov. A filter must be parenthesised, e.g. (cn=foo) or (|(cn=*foo*)(ou=*foo*))"
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Schema
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"objectClasses": [
|
|
129
|
+
{
|
|
130
|
+
"oid": "2.5.6.6",
|
|
131
|
+
"names": ["person"],
|
|
132
|
+
"desc": "RFC2256: a person",
|
|
133
|
+
"kind": "STRUCTURAL",
|
|
134
|
+
"sup": ["top"],
|
|
135
|
+
"must": ["sn", "cn"],
|
|
136
|
+
"may": ["userPassword", "telephoneNumber", "seeAlso", "description"],
|
|
137
|
+
"obsolete": false
|
|
138
|
+
}
|
|
139
|
+
],
|
|
140
|
+
"attributeTypes": [
|
|
141
|
+
{
|
|
142
|
+
"oid": "2.5.4.3",
|
|
143
|
+
"names": ["cn", "commonName"],
|
|
144
|
+
"sup": "name",
|
|
145
|
+
"singleValue": false,
|
|
146
|
+
"noUserModification": false,
|
|
147
|
+
"usage": "userApplications",
|
|
148
|
+
"obsolete": false,
|
|
149
|
+
"collective": false
|
|
150
|
+
}
|
|
151
|
+
],
|
|
152
|
+
"syntaxes": [...],
|
|
153
|
+
"matchingRules": [...]
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Inheritance is **not** flattened: a client resolving the attributes of an entry must walk the `sup` chains. `SchemaView` (browser) and `SchemaIndex` (`src/lib/ldapSchema.ts`, server) do it for you.
|
|
158
|
+
|
|
159
|
+
## Hidden attributes
|
|
160
|
+
|
|
161
|
+
Attributes holding credential material are stripped from **every** response — entry reads and searches alike — before it leaves the server. Asking for one explicitly (`?attributes=uid,userPassword`) does not get around the filter: the removal happens when the entry is serialised, not when the query is built.
|
|
162
|
+
|
|
163
|
+
The built-in list covers the usual OpenLDAP, Samba, Kerberos and Active Directory spellings:
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
userPassword, authPassword, pwdHistory, sambaNTPassword, sambaLMPassword,
|
|
167
|
+
sambaPasswordHistory, krbPrincipalKey, krbExtraData, krbPwdHistory,
|
|
168
|
+
unicodePwd, dbcsPwd, lmPwdHistory, ntPwdHistory, supplementalCredentials,
|
|
169
|
+
userPKCS12
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
A password hash served over HTTP is an offline cracking target, and browsing a directory does not require reading one — hence hidden by default, visible only on request:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
--ldap-raw-show-secrets true # logs a warning at startup
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Site-specific attributes are added with `--ldap-raw-hidden-attribute`, which stacks on top of the built-in list rather than replacing it:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
--ldap-raw-hidden-attribute twakeApiKey --ldap-raw-hidden-attribute employeeNumber
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Note that hiding an attribute here keeps it out of the API, not out of the directory: an account able to bind to LDAP directly still reads it. This is a guard against casual exposure through the browsing UI, not an access control — use [authz-per-branch](../auth/authz-per-branch.md) or directory ACLs for that.
|
|
185
|
+
|
|
186
|
+
## Security
|
|
187
|
+
|
|
188
|
+
Access is restricted in three independent layers:
|
|
189
|
+
|
|
190
|
+
1. **Exposed bases** — any DN outside `--ldap-raw-base` is refused with a 403, whatever the caller's rights.
|
|
191
|
+
2. **Authorization hooks** — every entry read, children listing and search goes through `server.ldap`, so the authorization plugins ([authz-per-branch](../auth/authz-per-branch.md), authz-dynamic, …) apply exactly as on the high-level APIs.
|
|
192
|
+
3. **Hidden attributes** — credential attributes, plus anything in `--ldap-raw-hidden-attribute`, are removed from every response, including searches. See [Hidden attributes](#hidden-attributes).
|
|
193
|
+
|
|
194
|
+
Two exceptions, both deliberate: the **root DSE** and the **schema** are read with the service account, not with the caller's rights. They are directory metadata and carry no user data; reading them with a restricted account would leave the UI unable to name and type attributes. Do not expose this plugin publicly if your directory publishes sensitive information in its root DSE.
|
|
195
|
+
|
|
196
|
+
Combine with an authentication plugin ([token](../auth/token.md), [oidc](../auth/oidc.md), …) — this plugin adds no authentication of its own.
|
|
197
|
+
|
|
198
|
+
## How It Works
|
|
199
|
+
|
|
200
|
+
- **Schema fetch**: the root DSE is read for `subschemaSubentry` (falling back to `cn=Subschema`), then the subschema entry is fetched and parsed once per `--ldap-raw-schema-cache-ttl`. Concurrent callers share a single fetch.
|
|
201
|
+
- **Operational attributes**: entries are read with `*` and `+`. When the server rejects `+`, the read is retried with `*` alone.
|
|
202
|
+
- **Missing entries**: the LDAP "no such object" result (code 32) is mapped to a 404.
|
|
203
|
+
|
|
204
|
+
## Limitations
|
|
205
|
+
|
|
206
|
+
- **Read-only.** Creating, modifying, renaming and deleting entries is not exposed yet.
|
|
207
|
+
- **No LDIF** import or export.
|
|
208
|
+
- **No paging**: searches and children listings are capped by `--ldap-raw-max-results` and flagged as `truncated`; there is no cursor to fetch the rest. Use a narrower search to reach entries beyond the cap.
|
|
209
|
+
|
|
210
|
+
## Usage Example
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
ldap-rest \
|
|
214
|
+
--plugin core/auth/token --auth-token "$TOKEN" \
|
|
215
|
+
--plugin core/ldap/raw \
|
|
216
|
+
--plugin core/static
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
The demo page ([`examples/web/ldap-browser.html`](../../../../examples/web/ldap-browser.html)) is then served at
|
|
220
|
+
`/static/examples/web/ldap-browser.html`.
|
|
221
|
+
|
|
222
|
+
## See Also
|
|
223
|
+
|
|
224
|
+
- [ldap-browser client library](../../../client-development/browser/libraries.md#ldapbrowser)
|
|
225
|
+
- [organizations plugin](organizations.md) — high-level tree of organizational units
|
|
226
|
+
- [authz-per-branch plugin](../auth/authz-per-branch.md) — branch-level access control
|
package/examples/web/README.md
CHANGED
|
@@ -82,6 +82,23 @@ Manage organizational units.
|
|
|
82
82
|
- Move units
|
|
83
83
|
- Create/delete units
|
|
84
84
|
|
|
85
|
+
### 🗂️ LDAP Browser (`ldap-browser.html`)
|
|
86
|
+
|
|
87
|
+
Low-level, read-only view of the directory, in the spirit of phpLDAPadmin.
|
|
88
|
+
|
|
89
|
+
**Features:**
|
|
90
|
+
|
|
91
|
+
- Lazy tree of the whole directory
|
|
92
|
+
- Raw entry content, operational attributes included
|
|
93
|
+
- Schema annotations: mandatory attributes, descriptions, unknown attributes flagged
|
|
94
|
+
- LDAP filter search with scope selection
|
|
95
|
+
|
|
96
|
+
Requires the `core/ldap/raw` plugin:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
npm start -- --plugin core/ldap/raw
|
|
100
|
+
```
|
|
101
|
+
|
|
85
102
|
## Running Examples
|
|
86
103
|
|
|
87
104
|
1. **Start the server:**
|
|
@@ -109,6 +126,7 @@ Manage organizational units.
|
|
|
109
126
|
http://localhost:8081/static/examples/web/ldap-user-editor.html
|
|
110
127
|
http://localhost:8081/static/examples/web/ldap-group-editor.html
|
|
111
128
|
http://localhost:8081/static/examples/web/ldap-unit-editor.html
|
|
129
|
+
http://localhost:8081/static/examples/web/ldap-browser.html
|
|
112
130
|
```
|
|
113
131
|
|
|
114
132
|
## Using Browser Libraries in Your Application
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>LDAP Browser Demo</title>
|
|
7
|
+
|
|
8
|
+
<!-- Google Fonts -->
|
|
9
|
+
<link
|
|
10
|
+
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap"
|
|
11
|
+
rel="stylesheet"
|
|
12
|
+
/>
|
|
13
|
+
<link
|
|
14
|
+
href="https://fonts.googleapis.com/icon?family=Material+Icons"
|
|
15
|
+
rel="stylesheet"
|
|
16
|
+
/>
|
|
17
|
+
|
|
18
|
+
<!-- Shared CSS -->
|
|
19
|
+
<link rel="stylesheet" href="/static/browser/common-demo.css" />
|
|
20
|
+
<!-- Library CSS -->
|
|
21
|
+
<link rel="stylesheet" href="/static/browser/ldap-browser.css" />
|
|
22
|
+
|
|
23
|
+
<style>
|
|
24
|
+
:root {
|
|
25
|
+
--primary-color: #3949ab;
|
|
26
|
+
--primary-color-dark: #283593;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
body {
|
|
30
|
+
background: linear-gradient(135deg, #8ea7e9 0%, #3949ab 100%);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.demo-header h1 {
|
|
34
|
+
color: #3949ab;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
#ldap-browser {
|
|
38
|
+
height: 70vh;
|
|
39
|
+
min-height: 520px;
|
|
40
|
+
}
|
|
41
|
+
</style>
|
|
42
|
+
</head>
|
|
43
|
+
<body>
|
|
44
|
+
<div class="demo-container">
|
|
45
|
+
<div class="demo-header">
|
|
46
|
+
<h1>🗂️ LDAP Browser</h1>
|
|
47
|
+
<p>
|
|
48
|
+
Low-level, read-only view of the directory: tree, raw entries and
|
|
49
|
+
schema
|
|
50
|
+
</p>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<div id="status-container"></div>
|
|
54
|
+
|
|
55
|
+
<div id="ldap-browser"></div>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<!-- Shared utilities -->
|
|
59
|
+
<script src="/static/browser/shared.js"></script>
|
|
60
|
+
<!-- Library JS -->
|
|
61
|
+
<script src="/static/browser/ldap-browser.js"></script>
|
|
62
|
+
|
|
63
|
+
<script>
|
|
64
|
+
const { LdapBrowser } = window.LdapBrowser;
|
|
65
|
+
const { showStatus } = window.MiniDmShared;
|
|
66
|
+
|
|
67
|
+
async function initBrowser() {
|
|
68
|
+
try {
|
|
69
|
+
const browser = new LdapBrowser({
|
|
70
|
+
containerId: 'ldap-browser',
|
|
71
|
+
apiBaseUrl: window.location.origin,
|
|
72
|
+
onEntrySelected: dn => console.log('Entry selected:', dn),
|
|
73
|
+
onError: error => {
|
|
74
|
+
console.error('Browser error:', error);
|
|
75
|
+
showStatus(
|
|
76
|
+
'status-container',
|
|
77
|
+
`Error: ${error.message}`,
|
|
78
|
+
'error'
|
|
79
|
+
);
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
await browser.init();
|
|
84
|
+
showStatus('status-container', 'LDAP Browser loaded', 'success');
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.error('Failed to initialize browser:', error);
|
|
87
|
+
showStatus('status-container', `Error: ${error.message}`, 'error');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
initBrowser();
|
|
92
|
+
</script>
|
|
93
|
+
</body>
|
|
94
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ldap-rest",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Light directory manager",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Identity-Manager"
|
|
@@ -132,6 +132,10 @@
|
|
|
132
132
|
"types": "./dist/src/plugins/ldap/passwordPolicy.d.ts",
|
|
133
133
|
"import": "./dist/plugins/ldap/passwordPolicy.js"
|
|
134
134
|
},
|
|
135
|
+
"./plugin-ldap-raw": {
|
|
136
|
+
"types": "./dist/src/plugins/ldap/raw.d.ts",
|
|
137
|
+
"import": "./dist/plugins/ldap/raw.js"
|
|
138
|
+
},
|
|
135
139
|
"./plugin-ldap-trash": {
|
|
136
140
|
"types": "./dist/src/plugins/ldap/trash.d.ts",
|
|
137
141
|
"import": "./dist/plugins/ldap/trash.js"
|
|
@@ -232,6 +236,34 @@
|
|
|
232
236
|
"types": "./dist/src/abstract/twakePlugin.d.ts",
|
|
233
237
|
"import": "./dist/abstract/twakePlugin.js"
|
|
234
238
|
},
|
|
239
|
+
"./browser-ldap-browser-ldapbrowser": {
|
|
240
|
+
"types": "./dist/src/browser/ldap-browser/LdapBrowser.d.ts",
|
|
241
|
+
"import": "./static/browser/ldap-browser/LdapBrowser.js"
|
|
242
|
+
},
|
|
243
|
+
"./browser-ldap-browser-api-rawapiclient": {
|
|
244
|
+
"types": "./dist/src/browser/ldap-browser/api/RawApiClient.d.ts",
|
|
245
|
+
"import": "./static/browser/ldap-browser/api/RawApiClient.js"
|
|
246
|
+
},
|
|
247
|
+
"./browser-ldap-browser-components-entrytree": {
|
|
248
|
+
"types": "./dist/src/browser/ldap-browser/components/EntryTree.d.ts",
|
|
249
|
+
"import": "./static/browser/ldap-browser/components/EntryTree.js"
|
|
250
|
+
},
|
|
251
|
+
"./browser-ldap-browser-components-entryview": {
|
|
252
|
+
"types": "./dist/src/browser/ldap-browser/components/EntryView.d.ts",
|
|
253
|
+
"import": "./static/browser/ldap-browser/components/EntryView.js"
|
|
254
|
+
},
|
|
255
|
+
"./browser-ldap-browser-index": {
|
|
256
|
+
"types": "./dist/src/browser/ldap-browser/index.d.ts",
|
|
257
|
+
"import": "./static/browser/ldap-browser/index.js"
|
|
258
|
+
},
|
|
259
|
+
"./browser-ldap-browser-schema": {
|
|
260
|
+
"types": "./dist/src/browser/ldap-browser/schema.d.ts",
|
|
261
|
+
"import": "./static/browser/ldap-browser/schema.js"
|
|
262
|
+
},
|
|
263
|
+
"./browser-ldap-browser-types": {
|
|
264
|
+
"types": "./dist/src/browser/ldap-browser/types.d.ts",
|
|
265
|
+
"import": "./static/browser/ldap-browser/types.js"
|
|
266
|
+
},
|
|
235
267
|
"./browser-ldap-group-editor-ldapgroupeditor": {
|
|
236
268
|
"types": "./dist/src/browser/ldap-group-editor/LdapGroupEditor.d.ts",
|
|
237
269
|
"import": "./static/browser/ldap-group-editor/LdapGroupEditor.js"
|
|
@@ -578,6 +610,8 @@
|
|
|
578
610
|
"check": "npm run check:ts && npm run lint && npm run format:check",
|
|
579
611
|
"check:ts": "tsc --noEmit",
|
|
580
612
|
"clean": "rimraf dist/* static/browser/* coverage",
|
|
613
|
+
"coverage": "c8 --config .c8rc.json mocha",
|
|
614
|
+
"coverage:check": "npm run check:ts && c8 --config .c8rc.json --exclude 'src/browser/**' --check-coverage --statements 84 --lines 84 --branches 75 --functions 86 mocha",
|
|
581
615
|
"dev": "npm run start:dev",
|
|
582
616
|
"fix": "npm run lint:fix && npm run format:fix",
|
|
583
617
|
"format:check": "prettier --check .",
|
|
@@ -626,6 +660,7 @@
|
|
|
626
660
|
"@types/supertest": "^6.0.3",
|
|
627
661
|
"@typescript-eslint/eslint-plugin": "^8.44.0",
|
|
628
662
|
"@typescript-eslint/parser": "^8.44.0",
|
|
663
|
+
"c8": "^10.1.3",
|
|
629
664
|
"chai": "^6.0.1",
|
|
630
665
|
"eslint": "^9.35.0",
|
|
631
666
|
"eslint-config-prettier": "^10.1.8",
|
|
@@ -633,6 +668,7 @@
|
|
|
633
668
|
"eslint-plugin-node": "^11.1.0",
|
|
634
669
|
"eslint-plugin-prettier": "^5.5.4",
|
|
635
670
|
"fast-glob": "^3.3.3",
|
|
671
|
+
"globals": "^14.0.0",
|
|
636
672
|
"js-yaml": "^4.1.1",
|
|
637
673
|
"mocha": "^11.7.2",
|
|
638
674
|
"nock": "^14.0.10",
|