ldap-rest 0.2.1 → 0.3.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.
Files changed (41) hide show
  1. package/dist/abstract/ldapFlat.js +1 -1
  2. package/dist/bin/index.js +1 -1
  3. package/dist/config/args.js +1 -1
  4. package/dist/lib/expressFormatedResponses.js +1 -1
  5. package/dist/plugins/auth/authzDynamic.js +1 -0
  6. package/dist/plugins/auth/authzDynamicHash.js +1 -0
  7. package/dist/plugins/scim/baseResolver.js +1 -0
  8. package/dist/plugins/scim/bulk.js +1 -0
  9. package/dist/plugins/scim/discovery.js +1 -0
  10. package/dist/plugins/scim/errors.js +1 -0
  11. package/dist/plugins/scim/filter.js +1 -0
  12. package/dist/plugins/scim/groups.js +1 -0
  13. package/dist/plugins/scim/mapping.js +1 -0
  14. package/dist/plugins/scim/patch.js +1 -0
  15. package/dist/plugins/scim/scim.js +1 -0
  16. package/dist/plugins/scim/types.js +1 -0
  17. package/dist/plugins/scim/users.js +1 -0
  18. package/dist/plugins/twake/drive.js +1 -1
  19. package/dist/src/abstract/ldapFlat.d.ts +20 -0
  20. package/dist/src/config/args.d.ts +24 -0
  21. package/dist/src/plugins/auth/authzDynamic.d.ts +117 -0
  22. package/dist/src/plugins/auth/authzDynamicHash.d.ts +27 -0
  23. package/dist/src/plugins/scim/baseResolver.d.ts +23 -0
  24. package/dist/src/plugins/scim/bulk.d.ts +43 -0
  25. package/dist/src/plugins/scim/discovery.d.ts +27 -0
  26. package/dist/src/plugins/scim/errors.d.ts +37 -0
  27. package/dist/src/plugins/scim/filter.d.ts +13 -0
  28. package/dist/src/plugins/scim/groups.d.ts +61 -0
  29. package/dist/src/plugins/scim/mapping.d.ts +52 -0
  30. package/dist/src/plugins/scim/patch.d.ts +39 -0
  31. package/dist/src/plugins/scim/scim.d.ts +23 -0
  32. package/dist/src/plugins/scim/types.d.ts +222 -0
  33. package/dist/src/plugins/scim/users.d.ts +58 -0
  34. package/dist/src/plugins/twake/drive.d.ts +7 -0
  35. package/docs/usage/plugins/auth/authz-dynamic.md +183 -0
  36. package/docs/usage/plugins/integrations/drive.md +22 -2
  37. package/docs/usage/plugins/integrations/scim.md +567 -0
  38. package/package.json +65 -1
  39. package/static/schemas/scim/Group.json +31 -0
  40. package/static/schemas/scim/User.json +147 -0
  41. package/static/schemas/scim/default-mapping.json +48 -0
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @module plugins/scim/bulk
3
+ * @author Xavier Guimard <xguimard@linagora.com>
4
+ *
5
+ * SCIM 2.0 Bulk operations (RFC 7644 §3.7).
6
+ *
7
+ * Executes operations sequentially. Supports `bulkId` cross-references:
8
+ * a POST with `"bulkId":"abc"` creates a resource; subsequent operations
9
+ * in the same request can reference it as "bulkId:abc" anywhere a SCIM
10
+ * id or member.value is expected (resolved to the concrete id before
11
+ * dispatch).
12
+ */
13
+ import type winston from 'winston';
14
+ import type { Config } from '../../config/args';
15
+ import type { DmRequest } from '../../lib/auth/base';
16
+ import type { ScimUsers } from './users';
17
+ import type { ScimGroups } from './groups';
18
+ import { type BulkRequest, type BulkResponse } from './types';
19
+ import { writeScimErrorFromException } from './errors';
20
+ export interface ScimBulkOptions {
21
+ config: Config;
22
+ logger: winston.Logger;
23
+ users: ScimUsers;
24
+ groups: ScimGroups;
25
+ scimPrefix: string;
26
+ hooks: {
27
+ [K: string]: Function[] | undefined;
28
+ };
29
+ }
30
+ export declare class ScimBulk {
31
+ private readonly config;
32
+ private readonly logger;
33
+ private readonly users;
34
+ private readonly groups;
35
+ private readonly scimPrefix;
36
+ private readonly hooks;
37
+ constructor(opts: ScimBulkOptions);
38
+ execute(req: DmRequest, body: BulkRequest): Promise<BulkResponse>;
39
+ private executeOne;
40
+ private resolveRefs;
41
+ private buildLocation;
42
+ }
43
+ export { writeScimErrorFromException };
@@ -0,0 +1,27 @@
1
+ import type { Config } from '../../config/args';
2
+ import type { DmRequest } from '../../lib/auth/base';
3
+ import { type ResourceTypeDefinition, type ServiceProviderConfig, type SchemaDefinition } from './types';
4
+ export interface DiscoveryOptions {
5
+ config: Config;
6
+ schemaDir: string;
7
+ scimPrefix: string;
8
+ loadedPlugins: {
9
+ [name: string]: unknown;
10
+ };
11
+ }
12
+ export declare class ScimDiscovery {
13
+ private readonly config;
14
+ private readonly schemaDir;
15
+ private readonly scimPrefix;
16
+ private readonly loadedPlugins;
17
+ constructor(opts: DiscoveryOptions);
18
+ private baseUrl;
19
+ private location;
20
+ private authSchemes;
21
+ serviceProviderConfig(req?: DmRequest): ServiceProviderConfig;
22
+ resourceTypes(req?: DmRequest): ResourceTypeDefinition[];
23
+ resourceType(name: string, req?: DmRequest): ResourceTypeDefinition | undefined;
24
+ schemas(req?: DmRequest): SchemaDefinition[];
25
+ schema(id: string, req?: DmRequest): SchemaDefinition | undefined;
26
+ private loadSchema;
27
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * @module plugins/scim/errors
3
+ * @author Xavier Guimard <xguimard@linagora.com>
4
+ *
5
+ * SCIM 2.0 error envelope (RFC 7644 §3.12) and async handler wrapper.
6
+ */
7
+ import type { Request, Response, NextFunction, RequestHandler } from 'express';
8
+ import { HttpError } from '../../lib/errors';
9
+ import { type ScimErrorType } from './types';
10
+ export declare const SCIM_CONTENT_TYPE = "application/scim+json";
11
+ export declare class ScimError extends HttpError {
12
+ scimType?: ScimErrorType;
13
+ constructor(status: number, detail: string, scimType?: ScimErrorType);
14
+ }
15
+ export declare const scimInvalidFilter: (detail?: string) => ScimError;
16
+ export declare const scimInvalidPath: (detail?: string) => ScimError;
17
+ export declare const scimInvalidValue: (detail?: string) => ScimError;
18
+ export declare const scimInvalidSyntax: (detail?: string) => ScimError;
19
+ export declare const scimNoTarget: (detail?: string) => ScimError;
20
+ export declare const scimMutability: (detail?: string) => ScimError;
21
+ export declare const scimUniqueness: (detail?: string) => ScimError;
22
+ export declare const scimTooMany: (detail?: string) => ScimError;
23
+ export declare const scimNotFound: (detail?: string) => ScimError;
24
+ export declare function writeScimError(res: Response, status: number, detail: string, scimType?: ScimErrorType): void;
25
+ /**
26
+ * Extract an LDAP numeric error code from either a thrown ldapts error
27
+ * (has `.code`) or an Error wrapped by ldapActions (message contains the
28
+ * original text). Returns undefined if no code is detectable.
29
+ */
30
+ export declare function extractLdapCode(err: unknown): number | undefined;
31
+ export declare function writeScimErrorFromException(res: Response, err: unknown, fallbackStatus?: number): void;
32
+ /**
33
+ * Express wrapper that catches errors, serializes them as SCIM
34
+ * envelope and short-circuits the default Express error middleware.
35
+ * Accepts both sync and async handlers.
36
+ */
37
+ export declare const scimAsyncHandler: (fn: (req: Request, res: Response, next: NextFunction) => void | Promise<void>) => RequestHandler;
@@ -0,0 +1,13 @@
1
+ import type { ResourceMapping } from './types';
2
+ export interface TranslatedFilter {
3
+ ldapFilter: string;
4
+ /** True if the filter contains `id eq "..."`, which the caller should translate into a DN lookup. */
5
+ touchesId: boolean;
6
+ /** Extracted id value if the filter is a simple `id eq "..."` (single clause). */
7
+ idEquals?: string;
8
+ }
9
+ /**
10
+ * Translate a SCIM filter string into an LDAP filter.
11
+ * Returns metadata enabling the caller to short-circuit id-equals queries.
12
+ */
13
+ export declare function scimFilterToLdap(filter: string, mapping: ResourceMapping): TranslatedFilter;
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @module plugins/scim/groups
3
+ * @author Xavier Guimard <xguimard@linagora.com>
4
+ *
5
+ * SCIM Groups resource handler — direct access via ldapActions.
6
+ */
7
+ import type winston from 'winston';
8
+ import type ldapActions from '../../lib/ldapActions';
9
+ import type { Config } from '../../config/args';
10
+ import type { DmRequest } from '../../lib/auth/base';
11
+ import { BaseResolver } from './baseResolver';
12
+ import { type ResourceMapping, type ScimGroup, type ListResponse, type PatchRequest } from './types';
13
+ import type { ScimUsers } from './users';
14
+ export interface GroupListQuery {
15
+ filter?: string;
16
+ startIndex?: number;
17
+ count?: number;
18
+ sortBy?: string;
19
+ sortOrder?: 'ascending' | 'descending';
20
+ }
21
+ export interface ScimGroupsOptions {
22
+ ldap: ldapActions;
23
+ config: Config;
24
+ logger: winston.Logger;
25
+ baseResolver: BaseResolver;
26
+ users: ScimUsers;
27
+ hooks: {
28
+ [K: string]: Function[] | undefined;
29
+ };
30
+ }
31
+ export declare class ScimGroups {
32
+ private readonly ldap;
33
+ private readonly config;
34
+ private readonly logger;
35
+ private readonly baseResolver;
36
+ private readonly users;
37
+ private readonly hooks;
38
+ private readonly mapping;
39
+ private readonly rdnAttribute;
40
+ private readonly objectClass;
41
+ private readonly idAttribute;
42
+ private readonly maxResults;
43
+ private readonly scimPrefix;
44
+ constructor(opts: ScimGroupsOptions);
45
+ private ctx;
46
+ private dnForId;
47
+ /**
48
+ * Resolve an LDAP member DN back to a SCIM reference (for GET responses).
49
+ * Best-effort: extract the RDN value and a guessed type (User if in user base).
50
+ */
51
+ private buildMemberResolver;
52
+ get(req: DmRequest, id: string): Promise<ScimGroup>;
53
+ list(req: DmRequest, query: GroupListQuery): Promise<ListResponse<ScimGroup>>;
54
+ create(req: DmRequest, resource: ScimGroup): Promise<ScimGroup>;
55
+ replace(req: DmRequest, id: string, resource: ScimGroup): Promise<ScimGroup>;
56
+ patch(req: DmRequest, id: string, patch: PatchRequest): Promise<ScimGroup>;
57
+ delete(req: DmRequest, id: string): Promise<void>;
58
+ /** Used internally and by Bulk to resolve a Group SCIM reference to a DN. */
59
+ resolveRef(req: DmRequest, value: string): Promise<string | undefined>;
60
+ get groupMapping(): ResourceMapping;
61
+ }
@@ -0,0 +1,52 @@
1
+ import type { AttributesList } from '../../lib/ldapActions';
2
+ import { type ScimUser, type ScimGroup, type ResourceMapping, type MultiValued } from './types';
3
+ export declare const DEFAULT_USER_MAPPING: ResourceMapping;
4
+ export declare const DEFAULT_GROUP_MAPPING: ResourceMapping;
5
+ export declare function loadMappingFile(path: string): ResourceMapping | undefined;
6
+ /**
7
+ * Build the mapping used at runtime by merging a user-supplied JSON
8
+ * override on top of the default. Override entries replace default
9
+ * entries with the same `scim` key; new entries are appended.
10
+ */
11
+ export declare function mergeMapping(base: ResourceMapping, override?: ResourceMapping): ResourceMapping;
12
+ export interface MappingContext {
13
+ /** 'rdn' (default), 'entryUUID', or any LDAP attribute name */
14
+ idAttribute: string;
15
+ rdnAttribute: string;
16
+ resourceType: 'User' | 'Group';
17
+ baseUrl?: string;
18
+ scimPrefix: string;
19
+ }
20
+ /** Resolve the SCIM id for an LDAP entry, per configuration. */
21
+ export declare function resolveScimId(entry: AttributesList, ctx: MappingContext): string | undefined;
22
+ export declare function buildLocation(id: string, ctx: MappingContext): string | undefined;
23
+ export declare function ldapToScimUser(entry: AttributesList, mapping: ResourceMapping, ctx: MappingContext): ScimUser;
24
+ /**
25
+ * Convert SCIM User body → LDAP attributes list.
26
+ * The RDN attribute is set from `userName` (or explicit `id`).
27
+ * Returns { rdn, attributes } so the caller can build the DN.
28
+ */
29
+ export declare function scimUserToLdap(user: ScimUser, mapping: ResourceMapping, ctx: MappingContext, objectClass: string[]): {
30
+ rdn: string;
31
+ attributes: AttributesList;
32
+ };
33
+ export declare function ldapToScimGroup(entry: AttributesList, mapping: ResourceMapping, ctx: MappingContext, memberResolver?: (dn: string) => MultiValued | undefined): ScimGroup;
34
+ /**
35
+ * Convert SCIM Group → LDAP attributes (members excluded; they're
36
+ * resolved separately to DNs by the handler).
37
+ */
38
+ export declare function scimGroupToLdap(group: ScimGroup, mapping: ResourceMapping, objectClass: string[]): {
39
+ rdn: string;
40
+ attributes: AttributesList;
41
+ };
42
+ /**
43
+ * List of LDAP attributes to request from the directory so all
44
+ * mapped SCIM attributes can be populated.
45
+ */
46
+ export declare function requiredLdapAttributes(mapping: ResourceMapping): string[];
47
+ /**
48
+ * Given a SCIM attribute path like "emails.value" or "name.familyName",
49
+ * return the corresponding LDAP attribute name (used by filter parser).
50
+ * Returns undefined if the path is not mapped.
51
+ */
52
+ export declare function scimPathToLdapAttribute(path: string, mapping: ResourceMapping): string | undefined;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @module plugins/scim/patch
3
+ * @author Xavier Guimard <xguimard@linagora.com>
4
+ *
5
+ * SCIM PatchOp applicator (RFC 7644 §3.5.2) → ldapts ModifyRequest.
6
+ *
7
+ * Supports:
8
+ * - op: add / remove / replace
9
+ * - simple paths: "displayName", "userName"
10
+ * - sub-attribute paths: "name.familyName"
11
+ * - multi-valued paths: "emails"
12
+ * - Group member ops via filtered path: `members[value eq "alice"]`
13
+ * - implicit path (op.value is an object)
14
+ *
15
+ * Complex filtered paths on multi-valued attributes OTHER than `members`
16
+ * (e.g. `emails[type eq "work"]`) are rejected with `invalidPath`: the
17
+ * plugin only knows how to map them for member-type resolution. Filtered
18
+ * member operations for Groups are handled via the caller-provided
19
+ * `resolveMemberRef` hook (SCIM id → LDAP DN lookup).
20
+ */
21
+ import type { ModifyRequest } from '../../lib/ldapActions';
22
+ import { type ResourceMapping, type PatchRequest } from './types';
23
+ export interface PatchContext {
24
+ mapping: ResourceMapping;
25
+ /** For Groups: resolve SCIM member value (id or $ref) → LDAP DN. Async. */
26
+ resolveMemberRef?: (value: string) => Promise<string | undefined>;
27
+ /** The LDAP attribute holding members, default 'member'. */
28
+ memberAttribute?: string;
29
+ }
30
+ export declare function patchToModifyRequest(patch: PatchRequest, ctx: PatchContext): Promise<ModifyRequest>;
31
+ /**
32
+ * Apply PATCH to a SCIM resource object in-memory (used for PUT-equivalent
33
+ * or when the resource handler prefers object-level manipulation before
34
+ * falling back to full replace).
35
+ *
36
+ * Returns the mutated resource. Used by tests; the main production path
37
+ * is patchToModifyRequest() → ldap.modify().
38
+ */
39
+ export declare function applyPatchToResource<T extends Record<string, unknown>>(resource: T, patch: PatchRequest): T;
@@ -0,0 +1,23 @@
1
+ import type { Express } from 'express';
2
+ import DmPlugin, { type Role } from '../../abstract/plugin';
3
+ import type { DM } from '../../bin';
4
+ import type ldapActions from '../../lib/ldapActions';
5
+ import { writeScimErrorFromException } from './errors';
6
+ export default class Scim extends DmPlugin {
7
+ name: string;
8
+ roles: Role[];
9
+ ldap: ldapActions;
10
+ private readonly scimPrefix;
11
+ private readonly users;
12
+ private readonly groups;
13
+ private readonly bulk;
14
+ private readonly discovery;
15
+ private readonly baseResolver;
16
+ constructor(server: DM);
17
+ private scimJson;
18
+ private readScimBody;
19
+ api(app: Express): void;
20
+ private parseListQuery;
21
+ getConfigApiData(): Record<string, unknown>;
22
+ }
23
+ export { writeScimErrorFromException };
@@ -0,0 +1,222 @@
1
+ /**
2
+ * @module plugins/scim/types
3
+ * @author Xavier Guimard <xguimard@linagora.com>
4
+ *
5
+ * SCIM 2.0 type definitions (RFC 7643 / RFC 7644).
6
+ */
7
+ export declare const SCHEMA_USER = "urn:ietf:params:scim:schemas:core:2.0:User";
8
+ export declare const SCHEMA_GROUP = "urn:ietf:params:scim:schemas:core:2.0:Group";
9
+ export declare const SCHEMA_LIST_RESPONSE = "urn:ietf:params:scim:api:messages:2.0:ListResponse";
10
+ export declare const SCHEMA_ERROR = "urn:ietf:params:scim:api:messages:2.0:Error";
11
+ export declare const SCHEMA_PATCH_OP = "urn:ietf:params:scim:api:messages:2.0:PatchOp";
12
+ export declare const SCHEMA_BULK_REQUEST = "urn:ietf:params:scim:api:messages:2.0:BulkRequest";
13
+ export declare const SCHEMA_BULK_RESPONSE = "urn:ietf:params:scim:api:messages:2.0:BulkResponse";
14
+ export declare const SCHEMA_SERVICE_PROVIDER_CONFIG = "urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig";
15
+ export declare const SCHEMA_RESOURCE_TYPE = "urn:ietf:params:scim:schemas:core:2.0:ResourceType";
16
+ export declare const SCHEMA_SCHEMA = "urn:ietf:params:scim:schemas:core:2.0:Schema";
17
+ export interface Meta {
18
+ resourceType: 'User' | 'Group';
19
+ created?: string;
20
+ lastModified?: string;
21
+ location?: string;
22
+ version?: string;
23
+ }
24
+ export interface MultiValued<T extends string = string> {
25
+ value: T;
26
+ display?: string;
27
+ type?: string;
28
+ primary?: boolean;
29
+ $ref?: string;
30
+ }
31
+ export interface ScimName {
32
+ formatted?: string;
33
+ familyName?: string;
34
+ givenName?: string;
35
+ middleName?: string;
36
+ honorificPrefix?: string;
37
+ honorificSuffix?: string;
38
+ }
39
+ export interface ScimUser {
40
+ schemas: string[];
41
+ id?: string;
42
+ externalId?: string;
43
+ userName?: string;
44
+ name?: ScimName;
45
+ displayName?: string;
46
+ nickName?: string;
47
+ profileUrl?: string;
48
+ title?: string;
49
+ userType?: string;
50
+ preferredLanguage?: string;
51
+ locale?: string;
52
+ timezone?: string;
53
+ active?: boolean;
54
+ password?: string;
55
+ emails?: MultiValued[];
56
+ phoneNumbers?: MultiValued[];
57
+ ims?: MultiValued[];
58
+ photos?: MultiValued[];
59
+ addresses?: ScimAddress[];
60
+ groups?: MultiValued[];
61
+ entitlements?: MultiValued[];
62
+ roles?: MultiValued[];
63
+ x509Certificates?: MultiValued[];
64
+ meta?: Meta;
65
+ [ext: string]: unknown;
66
+ }
67
+ export interface ScimAddress {
68
+ formatted?: string;
69
+ streetAddress?: string;
70
+ locality?: string;
71
+ region?: string;
72
+ postalCode?: string;
73
+ country?: string;
74
+ type?: string;
75
+ primary?: boolean;
76
+ }
77
+ export interface ScimGroup {
78
+ schemas: string[];
79
+ id?: string;
80
+ externalId?: string;
81
+ displayName?: string;
82
+ members?: MultiValued[];
83
+ meta?: Meta;
84
+ [ext: string]: unknown;
85
+ }
86
+ export type ScimResource = ScimUser | ScimGroup;
87
+ export interface ListResponse<T> {
88
+ schemas: [typeof SCHEMA_LIST_RESPONSE];
89
+ totalResults: number;
90
+ startIndex: number;
91
+ itemsPerPage: number;
92
+ Resources: T[];
93
+ }
94
+ export type ScimErrorType = 'invalidFilter' | 'tooMany' | 'uniqueness' | 'mutability' | 'invalidSyntax' | 'invalidPath' | 'noTarget' | 'invalidValue' | 'invalidVers' | 'sensitive';
95
+ export interface ScimErrorResponse {
96
+ schemas: [typeof SCHEMA_ERROR];
97
+ status: string;
98
+ scimType?: ScimErrorType;
99
+ detail?: string;
100
+ }
101
+ export interface PatchOperation {
102
+ op: 'add' | 'remove' | 'replace' | 'Add' | 'Remove' | 'Replace';
103
+ path?: string;
104
+ value?: unknown;
105
+ }
106
+ export interface PatchRequest {
107
+ schemas: string[];
108
+ Operations: PatchOperation[];
109
+ }
110
+ export interface BulkOperationRequest {
111
+ method: 'POST' | 'PUT' | 'PATCH' | 'DELETE';
112
+ bulkId?: string;
113
+ version?: string;
114
+ path: string;
115
+ data?: unknown;
116
+ }
117
+ export interface BulkRequest {
118
+ schemas: string[];
119
+ failOnErrors?: number;
120
+ Operations: BulkOperationRequest[];
121
+ }
122
+ export interface BulkOperationResponse {
123
+ method: 'POST' | 'PUT' | 'PATCH' | 'DELETE';
124
+ bulkId?: string;
125
+ version?: string;
126
+ location?: string;
127
+ status: string;
128
+ response?: ScimErrorResponse;
129
+ }
130
+ export interface BulkResponse {
131
+ schemas: [typeof SCHEMA_BULK_RESPONSE];
132
+ Operations: BulkOperationResponse[];
133
+ }
134
+ /**
135
+ * Internal mapping description: SCIM attribute → LDAP attribute(s).
136
+ *
137
+ * - ldap: one LDAP attribute name (simple mapping)
138
+ * - ldapPrimary/ldapSecondary: primary vs non-primary in multi-valued attr (emails)
139
+ * - sub: nested SCIM attribute name (for name.familyName etc.)
140
+ * - multi: 'single' or 'array' (hint for formatting)
141
+ * - operational: read-only from LDAP operational attribute
142
+ */
143
+ export interface MappingEntry {
144
+ scim: string;
145
+ ldap?: string;
146
+ ldapPrimary?: string;
147
+ ldapSecondary?: string;
148
+ sub?: Record<string, string>;
149
+ multi?: 'single' | 'array';
150
+ readOnly?: boolean;
151
+ operational?: boolean;
152
+ converter?: 'boolean' | 'number' | 'string';
153
+ }
154
+ export interface ResourceMapping {
155
+ resourceType: 'User' | 'Group';
156
+ schemas: string[];
157
+ entries: MappingEntry[];
158
+ }
159
+ export interface ServiceProviderConfig {
160
+ schemas: [typeof SCHEMA_SERVICE_PROVIDER_CONFIG];
161
+ documentationUri?: string;
162
+ patch: {
163
+ supported: boolean;
164
+ };
165
+ bulk: {
166
+ supported: boolean;
167
+ maxOperations: number;
168
+ maxPayloadSize: number;
169
+ };
170
+ filter: {
171
+ supported: boolean;
172
+ maxResults: number;
173
+ };
174
+ changePassword: {
175
+ supported: boolean;
176
+ };
177
+ sort: {
178
+ supported: boolean;
179
+ };
180
+ etag: {
181
+ supported: boolean;
182
+ };
183
+ authenticationSchemes: Array<{
184
+ name: string;
185
+ description: string;
186
+ specUri?: string;
187
+ documentationUri?: string;
188
+ type: string;
189
+ primary?: boolean;
190
+ }>;
191
+ meta?: {
192
+ resourceType: 'ServiceProviderConfig';
193
+ location?: string;
194
+ };
195
+ }
196
+ export interface ResourceTypeDefinition {
197
+ schemas: [typeof SCHEMA_RESOURCE_TYPE];
198
+ id: string;
199
+ name: string;
200
+ endpoint: string;
201
+ description?: string;
202
+ schema: string;
203
+ schemaExtensions?: Array<{
204
+ schema: string;
205
+ required: boolean;
206
+ }>;
207
+ meta?: {
208
+ resourceType: 'ResourceType';
209
+ location?: string;
210
+ };
211
+ }
212
+ export interface SchemaDefinition {
213
+ schemas: [typeof SCHEMA_SCHEMA];
214
+ id: string;
215
+ name: string;
216
+ description?: string;
217
+ attributes: unknown[];
218
+ meta?: {
219
+ resourceType: 'Schema';
220
+ location?: string;
221
+ };
222
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @module plugins/scim/users
3
+ * @author Xavier Guimard <xguimard@linagora.com>
4
+ *
5
+ * SCIM Users resource handler — direct access via ldapActions.
6
+ */
7
+ import type winston from 'winston';
8
+ import type ldapActions from '../../lib/ldapActions';
9
+ import type { Config } from '../../config/args';
10
+ import type { DmRequest } from '../../lib/auth/base';
11
+ import { BaseResolver } from './baseResolver';
12
+ import { type ResourceMapping, type ScimUser, type ListResponse, type PatchRequest } from './types';
13
+ export interface ListQuery {
14
+ filter?: string;
15
+ startIndex?: number;
16
+ count?: number;
17
+ attributes?: string[];
18
+ excludedAttributes?: string[];
19
+ sortBy?: string;
20
+ sortOrder?: 'ascending' | 'descending';
21
+ }
22
+ export interface ScimUsersOptions {
23
+ ldap: ldapActions;
24
+ config: Config;
25
+ logger: winston.Logger;
26
+ baseResolver: BaseResolver;
27
+ hooks: {
28
+ [K: string]: Function[] | undefined;
29
+ };
30
+ }
31
+ export declare class ScimUsers {
32
+ private readonly ldap;
33
+ private readonly config;
34
+ private readonly logger;
35
+ private readonly baseResolver;
36
+ private readonly hooks;
37
+ private readonly mapping;
38
+ private readonly rdnAttribute;
39
+ private readonly objectClass;
40
+ private readonly idAttribute;
41
+ private readonly maxResults;
42
+ private readonly scimPrefix;
43
+ constructor(opts: ScimUsersOptions);
44
+ private ctx;
45
+ private dnForId;
46
+ get(req: DmRequest, id: string): Promise<ScimUser>;
47
+ list(req: DmRequest, query: ListQuery): Promise<ListResponse<ScimUser>>;
48
+ create(req: DmRequest, resource: ScimUser): Promise<ScimUser>;
49
+ replace(req: DmRequest, id: string, resource: ScimUser): Promise<ScimUser>;
50
+ patch(req: DmRequest, id: string, patch: PatchRequest): Promise<ScimUser>;
51
+ delete(req: DmRequest, id: string): Promise<void>;
52
+ /**
53
+ * Given a SCIM member value (typically an id), return the LDAP DN.
54
+ * Used by Groups PATCH and Bulk reference resolution.
55
+ */
56
+ resolveRef(req: DmRequest, value: string): Promise<string | undefined>;
57
+ get userMapping(): ResourceMapping;
58
+ }
@@ -83,4 +83,11 @@ export default class Drive extends TwakePlugin {
83
83
  * @returns true if successful, false otherwise
84
84
  */
85
85
  unblockInstance(dn: string): Promise<boolean>;
86
+ /**
87
+ * Delete a Cozy instance and all its data
88
+ * Calls DELETE /instances/:domain on the Cozy Admin API
89
+ * @param dn User's LDAP DN
90
+ * @returns true if successful, false otherwise
91
+ */
92
+ deleteInstance(dn: string): Promise<boolean>;
86
93
  }