@boxyhq/saml-jackson 1.1.6 → 1.2.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/controller/error.d.ts +5 -0
- package/dist/controller/error.js +6 -1
- package/dist/controller/utils.d.ts +13 -0
- package/dist/controller/utils.js +27 -1
- package/dist/db/mem.js +7 -3
- package/dist/directory-sync/Base.d.ts +15 -0
- package/dist/directory-sync/Base.js +39 -0
- package/dist/directory-sync/DirectoryConfig.d.ts +43 -0
- package/dist/directory-sync/DirectoryConfig.js +186 -0
- package/dist/directory-sync/DirectoryGroups.d.ts +26 -0
- package/dist/directory-sync/DirectoryGroups.js +254 -0
- package/dist/directory-sync/DirectoryUsers.d.ts +22 -0
- package/dist/directory-sync/DirectoryUsers.js +175 -0
- package/dist/directory-sync/Groups.d.ts +47 -0
- package/dist/directory-sync/Groups.js +195 -0
- package/dist/directory-sync/Users.d.ts +47 -0
- package/dist/directory-sync/Users.js +135 -0
- package/dist/directory-sync/WebhookEventsLogger.d.ts +13 -0
- package/dist/directory-sync/WebhookEventsLogger.js +57 -0
- package/dist/directory-sync/events.d.ts +7 -0
- package/dist/directory-sync/events.js +53 -0
- package/dist/directory-sync/index.d.ts +6 -0
- package/dist/directory-sync/index.js +42 -0
- package/dist/directory-sync/request.d.ts +7 -0
- package/dist/directory-sync/request.js +30 -0
- package/dist/directory-sync/transform.d.ts +7 -0
- package/dist/directory-sync/transform.js +26 -0
- package/dist/directory-sync/utils.d.ts +39 -0
- package/dist/directory-sync/utils.js +140 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +7 -3
- package/dist/typings.d.ts +275 -7
- package/dist/typings.js +9 -0
- package/package.json +3 -1
package/dist/index.js
CHANGED
@@ -27,16 +27,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
27
27
|
};
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
29
29
|
exports.controllers = void 0;
|
30
|
+
const db_1 = __importDefault(require("./db/db"));
|
31
|
+
const defaultDb_1 = __importDefault(require("./db/defaultDb"));
|
32
|
+
const read_config_1 = __importDefault(require("./read-config"));
|
30
33
|
const admin_1 = require("./controller/admin");
|
31
34
|
const api_1 = require("./controller/api");
|
32
35
|
const oauth_1 = require("./controller/oauth");
|
33
36
|
const health_check_1 = require("./controller/health-check");
|
34
37
|
const logout_1 = require("./controller/logout");
|
38
|
+
const directory_sync_1 = __importDefault(require("./directory-sync"));
|
35
39
|
const oidc_discovery_1 = require("./controller/oidc-discovery");
|
36
40
|
const sp_config_1 = require("./controller/sp-config");
|
37
|
-
const db_1 = __importDefault(require("./db/db"));
|
38
|
-
const defaultDb_1 = __importDefault(require("./db/defaultDb"));
|
39
|
-
const read_config_1 = __importDefault(require("./read-config"));
|
40
41
|
const defaultOpts = (opts) => {
|
41
42
|
const newOpts = Object.assign({}, opts);
|
42
43
|
if (!newOpts.externalUrl) {
|
@@ -45,6 +46,7 @@ const defaultOpts = (opts) => {
|
|
45
46
|
if (!newOpts.samlPath) {
|
46
47
|
throw new Error('samlPath is required');
|
47
48
|
}
|
49
|
+
newOpts.scimPath = newOpts.scimPath || '/api/scim/v2.0';
|
48
50
|
newOpts.samlAudience = newOpts.samlAudience || 'https://saml.boxyhq.com';
|
49
51
|
newOpts.preLoadedConfig = newOpts.preLoadedConfig || ''; // path to folder containing static SAML config that will be preloaded. This is useful for self-hosted deployments that only have to support a single tenant (or small number of known tenants).
|
50
52
|
newOpts.idpEnabled = newOpts.idpEnabled === true;
|
@@ -79,6 +81,7 @@ const controllers = (opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
79
81
|
sessionStore,
|
80
82
|
opts,
|
81
83
|
});
|
84
|
+
const directorySync = yield (0, directory_sync_1.default)({ db, opts });
|
82
85
|
const oidcDiscoveryController = new oidc_discovery_1.OidcDiscoveryController({ opts });
|
83
86
|
const spConfig = new sp_config_1.SPSAMLConfig(opts);
|
84
87
|
// write pre-loaded config if present
|
@@ -98,6 +101,7 @@ const controllers = (opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
98
101
|
adminController,
|
99
102
|
logoutController,
|
100
103
|
healthCheckController,
|
104
|
+
directorySync,
|
101
105
|
oidcDiscoveryController,
|
102
106
|
};
|
103
107
|
});
|
package/dist/typings.d.ts
CHANGED
@@ -45,6 +45,13 @@ export interface IHealthCheckController {
|
|
45
45
|
}>;
|
46
46
|
init(): Promise<void>;
|
47
47
|
}
|
48
|
+
export interface ILogoutController {
|
49
|
+
createRequest(body: SLORequestParams): Promise<{
|
50
|
+
logoutUrl: string | null;
|
51
|
+
logoutForm: string | null;
|
52
|
+
}>;
|
53
|
+
handleResponse(body: SAMLResponsePayload): Promise<any>;
|
54
|
+
}
|
48
55
|
export interface IOidcDiscoveryController {
|
49
56
|
openidConfig(): {
|
50
57
|
issuer: string;
|
@@ -123,6 +130,9 @@ export interface Storable {
|
|
123
130
|
delete(key: string): Promise<any>;
|
124
131
|
getByIndex(idx: Index): Promise<any>;
|
125
132
|
}
|
133
|
+
export interface DatabaseStore {
|
134
|
+
store(namespace: string): Storable;
|
135
|
+
}
|
126
136
|
export interface Encrypted {
|
127
137
|
iv?: string;
|
128
138
|
tag?: string;
|
@@ -150,6 +160,7 @@ export interface JacksonOption {
|
|
150
160
|
db: DatabaseOption;
|
151
161
|
clientSecretVerifier?: string;
|
152
162
|
idpDiscoveryPath?: string;
|
163
|
+
scimPath?: string;
|
153
164
|
openid: {
|
154
165
|
jwsAlg?: string;
|
155
166
|
jwtSigningKeys?: {
|
@@ -186,13 +197,6 @@ export interface SAMLConfig {
|
|
186
197
|
};
|
187
198
|
defaultRedirectUrl: string;
|
188
199
|
}
|
189
|
-
export interface ILogoutController {
|
190
|
-
createRequest(body: SLORequestParams): Promise<{
|
191
|
-
logoutUrl: string | null;
|
192
|
-
logoutForm: string | null;
|
193
|
-
}>;
|
194
|
-
handleResponse(body: SAMLResponsePayload): Promise<any>;
|
195
|
-
}
|
196
200
|
export interface OAuthErrorHandlerParams {
|
197
201
|
error: 'invalid_request' | 'access_denied' | 'unauthorized_client' | 'unsupported_response_type' | 'invalid_scope' | 'server_error' | 'temporarily_unavailable';
|
198
202
|
error_description: string;
|
@@ -211,4 +215,268 @@ export interface ISPSAMLConfig {
|
|
211
215
|
toMarkdown(): string;
|
212
216
|
toHTML(): string;
|
213
217
|
}
|
218
|
+
export declare type DirectorySyncEventType = 'user.created' | 'user.updated' | 'user.deleted' | 'group.created' | 'group.updated' | 'group.deleted' | 'group.user_added' | 'group.user_removed';
|
219
|
+
export interface Base {
|
220
|
+
store(type: 'groups' | 'members' | 'users'): Storable;
|
221
|
+
setTenant(tenant: string): this;
|
222
|
+
setProduct(product: string): this;
|
223
|
+
setTenantAndProduct(tenant: string, product: string): this;
|
224
|
+
with(tenant: string, product: string): this;
|
225
|
+
createId(): string;
|
226
|
+
}
|
227
|
+
export interface Users extends Base {
|
228
|
+
list({ pageOffset, pageLimit, }: {
|
229
|
+
pageOffset?: number;
|
230
|
+
pageLimit?: number;
|
231
|
+
}): Promise<{
|
232
|
+
data: User[] | null;
|
233
|
+
error: ApiError | null;
|
234
|
+
}>;
|
235
|
+
get(id: string): Promise<{
|
236
|
+
data: User | null;
|
237
|
+
error: ApiError | null;
|
238
|
+
}>;
|
239
|
+
search(userName: string): Promise<{
|
240
|
+
data: User[] | null;
|
241
|
+
error: ApiError | null;
|
242
|
+
}>;
|
243
|
+
delete(id: string): Promise<{
|
244
|
+
data: null;
|
245
|
+
error: ApiError | null;
|
246
|
+
}>;
|
247
|
+
clear(): Promise<void>;
|
248
|
+
create(param: {
|
249
|
+
first_name: string;
|
250
|
+
last_name: string;
|
251
|
+
email: string;
|
252
|
+
active: boolean;
|
253
|
+
raw: any;
|
254
|
+
}): Promise<{
|
255
|
+
data: User | null;
|
256
|
+
error: ApiError | null;
|
257
|
+
}>;
|
258
|
+
update(id: string, param: {
|
259
|
+
first_name: string;
|
260
|
+
last_name: string;
|
261
|
+
email: string;
|
262
|
+
active: boolean;
|
263
|
+
raw: object;
|
264
|
+
}): Promise<{
|
265
|
+
data: User | null;
|
266
|
+
error: ApiError | null;
|
267
|
+
}>;
|
268
|
+
}
|
269
|
+
export interface Groups extends Base {
|
270
|
+
create(param: {
|
271
|
+
name: string;
|
272
|
+
raw: any;
|
273
|
+
}): Promise<{
|
274
|
+
data: Group | null;
|
275
|
+
error: ApiError | null;
|
276
|
+
}>;
|
277
|
+
removeAllUsers(groupId: string): Promise<void>;
|
278
|
+
list({ pageOffset, pageLimit, }: {
|
279
|
+
pageOffset?: number;
|
280
|
+
pageLimit?: number;
|
281
|
+
}): Promise<{
|
282
|
+
data: Group[] | null;
|
283
|
+
error: ApiError | null;
|
284
|
+
}>;
|
285
|
+
get(id: string): Promise<{
|
286
|
+
data: Group | null;
|
287
|
+
error: ApiError | null;
|
288
|
+
}>;
|
289
|
+
getAllUsers(groupId: string): Promise<{
|
290
|
+
user_id: string;
|
291
|
+
}[]>;
|
292
|
+
delete(id: string): Promise<{
|
293
|
+
data: null;
|
294
|
+
error: ApiError | null;
|
295
|
+
}>;
|
296
|
+
addUserToGroup(groupId: string, userId: string): Promise<void>;
|
297
|
+
isUserInGroup(groupId: string, userId: string): Promise<boolean>;
|
298
|
+
removeUserFromGroup(groupId: string, userId: string): Promise<void>;
|
299
|
+
search(displayName: string): Promise<{
|
300
|
+
data: Group[] | null;
|
301
|
+
error: ApiError | null;
|
302
|
+
}>;
|
303
|
+
update(id: string, param: {
|
304
|
+
name: string;
|
305
|
+
raw: any;
|
306
|
+
}): Promise<{
|
307
|
+
data: Group | null;
|
308
|
+
error: ApiError | null;
|
309
|
+
}>;
|
310
|
+
}
|
311
|
+
export declare type User = {
|
312
|
+
id: string;
|
313
|
+
email: string;
|
314
|
+
first_name: string;
|
315
|
+
last_name: string;
|
316
|
+
active: boolean;
|
317
|
+
raw?: any;
|
318
|
+
};
|
319
|
+
export declare type Group = {
|
320
|
+
id: string;
|
321
|
+
name: string;
|
322
|
+
raw?: any;
|
323
|
+
};
|
324
|
+
export declare enum DirectorySyncProviders {
|
325
|
+
'azure-scim-v2' = "Azure SCIM v2.0",
|
326
|
+
'onelogin-scim-v2' = "OneLogin SCIM v2.0",
|
327
|
+
'okta-scim-v2' = "Okta SCIM v2.0",
|
328
|
+
'jumpcloud-scim-v2' = "JumpCloud v2.0",
|
329
|
+
'generic-scim-v2' = "SCIM Generic v2.0"
|
330
|
+
}
|
331
|
+
export declare type DirectoryType = keyof typeof DirectorySyncProviders;
|
332
|
+
export declare type HTTPMethod = 'POST' | 'PUT' | 'DELETE' | 'GET' | 'PATCH';
|
333
|
+
export declare type Directory = {
|
334
|
+
id: string;
|
335
|
+
name: string;
|
336
|
+
tenant: string;
|
337
|
+
product: string;
|
338
|
+
type: DirectoryType;
|
339
|
+
log_webhook_events: boolean;
|
340
|
+
scim: {
|
341
|
+
path: string;
|
342
|
+
endpoint?: string;
|
343
|
+
secret: string;
|
344
|
+
};
|
345
|
+
webhook: {
|
346
|
+
endpoint: string;
|
347
|
+
secret: string;
|
348
|
+
};
|
349
|
+
};
|
350
|
+
export declare type DirectorySyncGroupMember = {
|
351
|
+
value: string;
|
352
|
+
email?: string;
|
353
|
+
};
|
354
|
+
export interface DirectoryConfig {
|
355
|
+
create({ name, tenant, product, webhook_url, webhook_secret, type, }: {
|
356
|
+
name?: string;
|
357
|
+
tenant: string;
|
358
|
+
product: string;
|
359
|
+
webhook_url?: string;
|
360
|
+
webhook_secret?: string;
|
361
|
+
type?: DirectoryType;
|
362
|
+
}): Promise<{
|
363
|
+
data: Directory | null;
|
364
|
+
error: ApiError | null;
|
365
|
+
}>;
|
366
|
+
update(id: string, param: Omit<Partial<Directory>, 'id' | 'tenant' | 'prodct' | 'scim'>): Promise<{
|
367
|
+
data: Directory | null;
|
368
|
+
error: ApiError | null;
|
369
|
+
}>;
|
370
|
+
get(id: string): Promise<{
|
371
|
+
data: Directory | null;
|
372
|
+
error: ApiError | null;
|
373
|
+
}>;
|
374
|
+
getByTenantAndProduct(tenant: string, product: string): Promise<{
|
375
|
+
data: Directory | null;
|
376
|
+
error: ApiError | null;
|
377
|
+
}>;
|
378
|
+
list({ pageOffset, pageLimit, }: {
|
379
|
+
pageOffset?: number;
|
380
|
+
pageLimit?: number;
|
381
|
+
}): Promise<{
|
382
|
+
data: Directory[] | null;
|
383
|
+
error: ApiError | null;
|
384
|
+
}>;
|
385
|
+
delete(id: string): Promise<void>;
|
386
|
+
}
|
387
|
+
export interface IDirectoryUsers {
|
388
|
+
create(directory: Directory, body: any): Promise<DirectorySyncResponse>;
|
389
|
+
get(user: User): Promise<DirectorySyncResponse>;
|
390
|
+
update(directory: Directory, user: User, body: any): Promise<DirectorySyncResponse>;
|
391
|
+
patch(directory: Directory, user: User, body: any): Promise<DirectorySyncResponse>;
|
392
|
+
delete(directory: Directory, user: User, active: boolean): Promise<DirectorySyncResponse>;
|
393
|
+
getAll(queryParams: {
|
394
|
+
count: number;
|
395
|
+
startIndex: number;
|
396
|
+
filter?: string;
|
397
|
+
}): Promise<DirectorySyncResponse>;
|
398
|
+
handleRequest(request: DirectorySyncRequest, eventCallback?: EventCallback): Promise<DirectorySyncResponse>;
|
399
|
+
}
|
400
|
+
export interface IDirectoryGroups {
|
401
|
+
create(directory: Directory, body: any): Promise<DirectorySyncResponse>;
|
402
|
+
get(group: Group): Promise<DirectorySyncResponse>;
|
403
|
+
updateDisplayName(directory: Directory, group: Group, body: any): Promise<Group>;
|
404
|
+
delete(directory: Directory, group: Group): Promise<DirectorySyncResponse>;
|
405
|
+
getAll(queryParams: {
|
406
|
+
filter?: string;
|
407
|
+
}): Promise<DirectorySyncResponse>;
|
408
|
+
addGroupMembers(directory: Directory, group: Group, members: DirectorySyncGroupMember[] | undefined, sendWebhookEvent: boolean): Promise<void>;
|
409
|
+
removeGroupMembers(directory: Directory, group: Group, members: DirectorySyncGroupMember[], sendWebhookEvent: boolean): Promise<void>;
|
410
|
+
addOrRemoveGroupMembers(directory: Directory, group: Group, members: DirectorySyncGroupMember[]): Promise<void>;
|
411
|
+
update(directory: Directory, group: Group, body: any): Promise<DirectorySyncResponse>;
|
412
|
+
patch(directory: Directory, group: Group, body: any): Promise<DirectorySyncResponse>;
|
413
|
+
handleRequest(request: DirectorySyncRequest, eventCallback?: EventCallback): Promise<DirectorySyncResponse>;
|
414
|
+
}
|
415
|
+
export interface IWebhookEventsLogger extends Base {
|
416
|
+
log(directory: Directory, event: DirectorySyncEvent): Promise<WebhookEventLog>;
|
417
|
+
getAll(): Promise<WebhookEventLog[]>;
|
418
|
+
get(id: string): Promise<WebhookEventLog>;
|
419
|
+
clear(): Promise<void>;
|
420
|
+
delete(id: string): Promise<void>;
|
421
|
+
updateStatus(log: WebhookEventLog, statusCode: number): Promise<WebhookEventLog>;
|
422
|
+
}
|
423
|
+
export declare type DirectorySyncResponse = {
|
424
|
+
status: number;
|
425
|
+
data?: any;
|
426
|
+
};
|
427
|
+
export interface DirectorySyncRequestHandler {
|
428
|
+
handle(request: DirectorySyncRequest, callback?: EventCallback): Promise<DirectorySyncResponse>;
|
429
|
+
}
|
430
|
+
export interface Events {
|
431
|
+
handle(event: DirectorySyncEvent): Promise<void>;
|
432
|
+
}
|
433
|
+
export interface DirectorySyncRequest {
|
434
|
+
method: HTTPMethod;
|
435
|
+
body: any | undefined;
|
436
|
+
directoryId: Directory['id'];
|
437
|
+
resourceType: 'users' | 'groups';
|
438
|
+
resourceId: string | undefined;
|
439
|
+
apiSecret: string | null;
|
440
|
+
query: {
|
441
|
+
count?: number;
|
442
|
+
startIndex?: number;
|
443
|
+
filter?: string;
|
444
|
+
};
|
445
|
+
}
|
446
|
+
export declare type DirectorySync = {
|
447
|
+
requests: DirectorySyncRequestHandler;
|
448
|
+
directories: DirectoryConfig;
|
449
|
+
groups: Groups;
|
450
|
+
users: Users;
|
451
|
+
events: {
|
452
|
+
callback: EventCallback;
|
453
|
+
};
|
454
|
+
webhookLogs: IWebhookEventsLogger;
|
455
|
+
providers: () => {
|
456
|
+
[K in string]: string;
|
457
|
+
};
|
458
|
+
};
|
459
|
+
export interface ApiError {
|
460
|
+
message: string;
|
461
|
+
code: number;
|
462
|
+
}
|
463
|
+
export interface DirectorySyncEvent {
|
464
|
+
directory_id: Directory['id'];
|
465
|
+
event: DirectorySyncEventType;
|
466
|
+
data: User | Group | (User & {
|
467
|
+
group: Group;
|
468
|
+
});
|
469
|
+
tenant: string;
|
470
|
+
product: string;
|
471
|
+
}
|
472
|
+
export interface EventCallback {
|
473
|
+
(event: DirectorySyncEvent): Promise<void>;
|
474
|
+
}
|
475
|
+
export interface WebhookEventLog extends DirectorySyncEvent {
|
476
|
+
id: string;
|
477
|
+
webhook_endpoint: string;
|
478
|
+
created_at: Date;
|
479
|
+
status_code?: number;
|
480
|
+
delivered?: boolean;
|
481
|
+
}
|
214
482
|
export {};
|
package/dist/typings.js
CHANGED
@@ -1,2 +1,11 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.DirectorySyncProviders = void 0;
|
4
|
+
var DirectorySyncProviders;
|
5
|
+
(function (DirectorySyncProviders) {
|
6
|
+
DirectorySyncProviders["azure-scim-v2"] = "Azure SCIM v2.0";
|
7
|
+
DirectorySyncProviders["onelogin-scim-v2"] = "OneLogin SCIM v2.0";
|
8
|
+
DirectorySyncProviders["okta-scim-v2"] = "Okta SCIM v2.0";
|
9
|
+
DirectorySyncProviders["jumpcloud-scim-v2"] = "JumpCloud v2.0";
|
10
|
+
DirectorySyncProviders["generic-scim-v2"] = "SCIM Generic v2.0";
|
11
|
+
})(DirectorySyncProviders = exports.DirectorySyncProviders || (exports.DirectorySyncProviders = {}));
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@boxyhq/saml-jackson",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.2.0",
|
4
4
|
"description": "SAML Jackson library",
|
5
5
|
"keywords": [
|
6
6
|
"SAML 2.0"
|
@@ -42,6 +42,7 @@
|
|
42
42
|
"@opentelemetry/api": "1.0.4",
|
43
43
|
"@opentelemetry/api-metrics": "0.27.0",
|
44
44
|
"@peculiar/webcrypto": "1.4.0",
|
45
|
+
"axios": "^0.27.2",
|
45
46
|
"@peculiar/x509": "1.8.3",
|
46
47
|
"jose": "4.9.2",
|
47
48
|
"marked": "4.1.0",
|
@@ -56,6 +57,7 @@
|
|
56
57
|
"xmlbuilder": "15.1.1"
|
57
58
|
},
|
58
59
|
"devDependencies": {
|
60
|
+
"@faker-js/faker": "7.2.0",
|
59
61
|
"@types/node": "18.7.16",
|
60
62
|
"@types/sinon": "10.0.13",
|
61
63
|
"@types/tap": "15.0.7",
|