ldap-rest 0.3.0 → 0.3.2

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.
@@ -0,0 +1,155 @@
1
+ import type { Express, Request, Response } from 'express';
2
+ import DmPlugin, { type Role } from '../../abstract/plugin';
3
+ import { DM } from '../../bin';
4
+ import { Hooks } from '../../hooks';
5
+ import { AttributesList, AttributeValue, ModifyRequest } from '../../lib/ldapActions';
6
+ import type { Schema } from '../../config/schema';
7
+ /**
8
+ * Shared OpenAPI schemas surfaced by this plugin. Picked up by
9
+ * scripts/generate-openapi.ts and merged into `components.schemas`.
10
+ *
11
+ * @openapi-component
12
+ * Organization:
13
+ * type: object
14
+ * description: An LDAP organizational unit entry.
15
+ * required: [dn, ou]
16
+ * properties:
17
+ * dn:
18
+ * type: string
19
+ * description: Fully-qualified distinguished name of the entry.
20
+ * example: ou=Engineering,ou=organizations,dc=example,dc=com
21
+ * ou:
22
+ * type: string
23
+ * description: Organizational unit name (RDN attribute).
24
+ * example: Engineering
25
+ * o:
26
+ * type: string
27
+ * description: Organization display name.
28
+ * example: Engineering Department
29
+ * l:
30
+ * type: string
31
+ * description: Locality / city.
32
+ * example: Paris
33
+ * description:
34
+ * type: string
35
+ * example: Software engineering division
36
+ * organizationLink:
37
+ * type: string
38
+ * description: DN of the parent organization (link attribute).
39
+ * example: ou=organizations,dc=example,dc=com
40
+ * organizationPath:
41
+ * type: string
42
+ * description: |
43
+ * Human-readable slash-separated path to this node, used by the
44
+ * UI tree. Set automatically on creation and move.
45
+ * example: Engineering / Backend
46
+ * member:
47
+ * type: array
48
+ * items: { type: string }
49
+ * description: DNs of entries linked to this organization.
50
+ * example:
51
+ * - uid=alice,ou=users,dc=example,dc=com
52
+ * OrgSummary:
53
+ * type: object
54
+ * description: Lightweight organization reference (used in node lists).
55
+ * required: [dn, ou]
56
+ * properties:
57
+ * dn: { type: string, example: ou=HR,ou=organizations,dc=example,dc=com }
58
+ * ou: { type: string, example: HR }
59
+ * description: { type: string }
60
+ * objectClass:
61
+ * type: array
62
+ * items: { type: string }
63
+ * example: [top, organizationalUnit]
64
+ * OrganizationCreate:
65
+ * type: object
66
+ * required: [ou]
67
+ * properties:
68
+ * ou:
69
+ * type: string
70
+ * description: Name of the new organizational unit.
71
+ * example: Marketing
72
+ * parentDn:
73
+ * type: string
74
+ * description: |
75
+ * DN of the parent organizational unit. Defaults to the configured
76
+ * top organization when omitted.
77
+ * example: ou=organizations,dc=example,dc=com
78
+ * description: { type: string }
79
+ * l: { type: string }
80
+ * example:
81
+ * ou: Marketing
82
+ * parentDn: ou=organizations,dc=example,dc=com
83
+ * description: Marketing division
84
+ * OrganizationModify:
85
+ * type: object
86
+ * description: |
87
+ * Partial update. Any provided attribute is replaced wholesale.
88
+ * `ou` cannot be changed via this endpoint — use the move endpoint
89
+ * to relocate the node within the tree.
90
+ * properties:
91
+ * description: { type: string }
92
+ * l: { type: string }
93
+ * o: { type: string }
94
+ * example:
95
+ * description: Updated description for Marketing
96
+ */
97
+ export default class LdapOrganizations extends DmPlugin {
98
+ name: string;
99
+ roles: Role[];
100
+ pathAttr: string;
101
+ linkAttr: string;
102
+ schema?: Schema;
103
+ constructor(dm: DM);
104
+ /**
105
+ * API routes for LDAP organizations
106
+ * @param app Express application
107
+ */
108
+ api(app: Express): void;
109
+ apiAdd(req: Request, res: Response): Promise<void>;
110
+ apiModify(req: Request, res: Response): Promise<void>;
111
+ apiDelete(req: Request, res: Response): Promise<void>;
112
+ apiMove(req: Request, res: Response): Promise<void>;
113
+ /**
114
+ * Consistency checks on any entry
115
+ */
116
+ hooks: Hooks;
117
+ /**
118
+ * Check if the department link is valid
119
+ * @param entry LDAP entry to check
120
+ */
121
+ checkDeptLink(entry: AttributesList): Promise<void>;
122
+ /**
123
+ * Check if the department path is valid
124
+ * @param entry LDAP entry to check
125
+ */
126
+ checkDeptPath(entry: AttributesList): Promise<void>;
127
+ isEmptyOrganization(dn: string): Promise<void>;
128
+ /**
129
+ * Check if entry is an organisation
130
+ * @param entry LDAP entry to check
131
+ * @returns True if entry is an organisation, false otherwise
132
+ */
133
+ isOu(entry: AttributesList): boolean;
134
+ getOrganisationTop(req?: Request): Promise<AttributesList | AttributesList[]>;
135
+ getOrganisationByDn(dn: string, req?: Request): Promise<AttributesList>;
136
+ getOrganisationSubnodes(dn: string, req?: Request): Promise<AttributesList[]>;
137
+ addOrganization(dn: string, entry: AttributesList, req?: Request): Promise<boolean>;
138
+ modifyOrganization(dn: string, changes: ModifyRequest): Promise<boolean>;
139
+ validateNewOrganization(dn: string, entry: AttributesList): boolean;
140
+ validateChanges(dn: string, changes: ModifyRequest): boolean;
141
+ _validateOneChange(field: string, value: AttributeValue | null): boolean;
142
+ /**
143
+ * Move an organization to a different parent organization
144
+ * Uses LDAP modifyDN to change the DN hierarchy
145
+ */
146
+ moveOrganization(dn: string, targetOrgDn: string, req?: Request): Promise<{
147
+ newDn: string;
148
+ }>;
149
+ deleteOrganization(dn: string): Promise<boolean>;
150
+ searchOrganisationSubnodes(dn: string, query: string): Promise<AttributesList[]>;
151
+ /**
152
+ * Provide configuration for config API
153
+ */
154
+ getConfigApiData(): Record<string, unknown>;
155
+ }
@@ -11,6 +11,184 @@
11
11
  */
12
12
  import type { Express } from 'express';
13
13
  import DmPlugin, { type Role } from '../../abstract/plugin';
14
+ /**
15
+ * Shared OpenAPI schemas surfaced by this plugin. Picked up by
16
+ * scripts/generate-openapi.ts and merged into `components.schemas`.
17
+ *
18
+ * @openapi-component
19
+ * PasswordPolicy:
20
+ * type: object
21
+ * description: |
22
+ * Active OpenLDAP ppolicy configuration. All duration fields are in
23
+ * **seconds**. Absent fields mean the policy attribute is not set.
24
+ * properties:
25
+ * dn:
26
+ * type: string
27
+ * description: DN of the ppolicy entry.
28
+ * example: cn=default,ou=policies,dc=example,dc=com
29
+ * pwdMaxAge:
30
+ * type: integer
31
+ * description: Maximum password age in seconds (0 = never expires).
32
+ * example: 7776000
33
+ * pwdMinAge:
34
+ * type: integer
35
+ * description: Minimum password age in seconds before it may be changed.
36
+ * example: 0
37
+ * pwdInHistory:
38
+ * type: integer
39
+ * description: Number of previous passwords stored.
40
+ * example: 5
41
+ * pwdCheckQuality:
42
+ * type: integer
43
+ * description: Password quality enforcement level (0-2).
44
+ * example: 1
45
+ * pwdMinLength:
46
+ * type: integer
47
+ * description: Minimum password length.
48
+ * example: 12
49
+ * pwdMaxFailure:
50
+ * type: integer
51
+ * description: Maximum bind failures before lockout.
52
+ * example: 5
53
+ * pwdLockout:
54
+ * type: boolean
55
+ * description: Whether account lockout is enabled.
56
+ * example: true
57
+ * pwdLockoutDuration:
58
+ * type: integer
59
+ * description: Lockout duration in seconds (0 = permanent until admin reset).
60
+ * example: 300
61
+ * pwdGraceAuthNLimit:
62
+ * type: integer
63
+ * description: Number of grace logins allowed after password expires.
64
+ * example: 0
65
+ * pwdExpireWarning:
66
+ * type: integer
67
+ * description: Seconds before expiry at which a warning is issued.
68
+ * example: 1209600
69
+ * pwdMustChange:
70
+ * type: boolean
71
+ * description: If true, users must change their password after an admin reset.
72
+ * example: true
73
+ * pwdAllowUserChange:
74
+ * type: boolean
75
+ * description: Whether users are allowed to change their own password.
76
+ * example: true
77
+ * PasswordStatus:
78
+ * type: object
79
+ * description: Current password status for a specific user account.
80
+ * required: [dn, passwordSet, isExpired, isExpiringSoon, mustChange, isLocked, failureCount, graceLoginsUsed]
81
+ * properties:
82
+ * dn:
83
+ * type: string
84
+ * description: Fully-qualified DN of the user.
85
+ * example: uid=alice,ou=users,dc=example,dc=com
86
+ * passwordSet:
87
+ * type: boolean
88
+ * description: Whether a userPassword attribute is present.
89
+ * example: true
90
+ * lastChanged:
91
+ * type: string
92
+ * format: date-time
93
+ * nullable: true
94
+ * description: ISO-8601 timestamp of last password change, or null if never set.
95
+ * example: '2026-01-15T10:00:00.000Z'
96
+ * expiresAt:
97
+ * type: string
98
+ * format: date-time
99
+ * nullable: true
100
+ * description: ISO-8601 expiry timestamp, or null if no max age is configured.
101
+ * example: '2026-04-15T10:00:00.000Z'
102
+ * daysUntilExpiration:
103
+ * type: integer
104
+ * nullable: true
105
+ * description: Remaining days until expiry (negative means already expired).
106
+ * example: 80
107
+ * isExpired:
108
+ * type: boolean
109
+ * example: false
110
+ * isExpiringSoon:
111
+ * type: boolean
112
+ * description: True when expiry is within the configured warning window.
113
+ * example: false
114
+ * mustChange:
115
+ * type: boolean
116
+ * description: True when `pwdReset` is set (admin forced change).
117
+ * example: false
118
+ * isLocked:
119
+ * type: boolean
120
+ * description: True when the account is currently locked.
121
+ * example: false
122
+ * lockedAt:
123
+ * type: string
124
+ * format: date-time
125
+ * nullable: true
126
+ * description: ISO-8601 timestamp of lockout, or null.
127
+ * example: null
128
+ * failureCount:
129
+ * type: integer
130
+ * description: Number of recorded bind failures still within the window.
131
+ * example: 0
132
+ * graceLoginsUsed:
133
+ * type: integer
134
+ * description: Number of grace logins already consumed.
135
+ * example: 0
136
+ * ExpiringAccount:
137
+ * type: object
138
+ * description: User whose password is expiring within the warning window.
139
+ * required: [dn, expiresAt, daysUntilExpiration]
140
+ * properties:
141
+ * dn: { type: string, example: uid=bob,ou=users,dc=example,dc=com }
142
+ * uid: { type: string, example: bob }
143
+ * displayName: { type: string, example: Bob Builder }
144
+ * mail: { type: string, example: bob@example.com }
145
+ * expiresAt:
146
+ * type: string
147
+ * format: date-time
148
+ * example: '2026-05-01T08:00:00.000Z'
149
+ * daysUntilExpiration: { type: integer, example: 6 }
150
+ * LockedAccount:
151
+ * type: object
152
+ * description: User account that is currently locked.
153
+ * required: [dn, failureCount]
154
+ * properties:
155
+ * dn: { type: string, example: uid=charlie,ou=users,dc=example,dc=com }
156
+ * uid: { type: string, example: charlie }
157
+ * displayName: { type: string, example: Charlie Chaplin }
158
+ * mail: { type: string, example: charlie@example.com }
159
+ * lockedAt:
160
+ * type: string
161
+ * format: date-time
162
+ * nullable: true
163
+ * example: '2026-04-24T14:30:00.000Z'
164
+ * failureCount: { type: integer, example: 5 }
165
+ * PasswordValidationRequest:
166
+ * type: object
167
+ * required: [password]
168
+ * properties:
169
+ * password:
170
+ * type: string
171
+ * format: password
172
+ * description: The candidate password to validate.
173
+ * example: 'S3cur3P@ss!'
174
+ * dn:
175
+ * type: string
176
+ * description: Optional user DN for context (not used in local validation).
177
+ * example: uid=alice,ou=users,dc=example,dc=com
178
+ * PasswordValidationResponse:
179
+ * type: object
180
+ * required: [valid, errors]
181
+ * properties:
182
+ * valid:
183
+ * type: boolean
184
+ * description: True when the password meets all complexity rules.
185
+ * example: true
186
+ * errors:
187
+ * type: array
188
+ * items: { type: string }
189
+ * description: List of failed rule descriptions (empty when valid).
190
+ * example: []
191
+ */
14
192
  export default class PasswordPolicy extends DmPlugin {
15
193
  name: string;
16
194
  roles: Role[];