@boxyhq/saml-jackson 1.3.5 → 1.3.7
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/api.d.ts +14 -11
- package/dist/controller/api.js +14 -11
- package/dist/controller/connection/saml.js +26 -15
- package/dist/controller/logout.js +3 -1
- package/dist/controller/oauth.js +9 -24
- package/dist/controller/sp-config.d.ts +6 -5
- package/dist/controller/sp-config.js +29 -15
- package/dist/controller/utils.js +3 -2
- package/dist/db/db.js +17 -5
- package/dist/db/redis.js +17 -10
- package/dist/db/sql/mssql/entity/JacksonIndex.d.ts +7 -0
- package/dist/db/sql/mssql/entity/JacksonIndex.js +41 -0
- package/dist/db/sql/mssql/entity/JacksonStore.d.ts +8 -0
- package/dist/db/sql/mssql/entity/JacksonStore.js +55 -0
- package/dist/db/sql/mssql/entity/JacksonTTL.d.ts +4 -0
- package/dist/db/sql/mssql/entity/JacksonTTL.js +29 -0
- package/dist/db/sql/mssql.d.ts +1 -0
- package/dist/db/sql/mssql.js +46 -0
- package/dist/db/sql/sql.js +12 -6
- package/dist/index.js +19 -3
- package/dist/loadConnection.js +2 -1
- package/dist/saml/x509.d.ts +12 -6
- package/dist/saml/x509.js +46 -5
- package/dist/typings.d.ts +31 -34
- package/migration/mssql/1667949639424-mss_Initial.ts +26 -0
- package/package.json +14 -11
@@ -0,0 +1,55 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
7
|
+
};
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
9
|
+
exports.JacksonStore = void 0;
|
10
|
+
const typeorm_1 = require("typeorm");
|
11
|
+
let JacksonStore = class JacksonStore {
|
12
|
+
};
|
13
|
+
__decorate([
|
14
|
+
(0, typeorm_1.Column)({
|
15
|
+
primary: true,
|
16
|
+
type: 'varchar',
|
17
|
+
length: 1500,
|
18
|
+
})
|
19
|
+
], JacksonStore.prototype, "key", void 0);
|
20
|
+
__decorate([
|
21
|
+
(0, typeorm_1.Column)({
|
22
|
+
type: 'text',
|
23
|
+
})
|
24
|
+
], JacksonStore.prototype, "value", void 0);
|
25
|
+
__decorate([
|
26
|
+
(0, typeorm_1.Column)({
|
27
|
+
type: 'varchar',
|
28
|
+
length: 64,
|
29
|
+
nullable: true,
|
30
|
+
})
|
31
|
+
], JacksonStore.prototype, "iv", void 0);
|
32
|
+
__decorate([
|
33
|
+
(0, typeorm_1.Column)({
|
34
|
+
type: 'varchar',
|
35
|
+
length: 64,
|
36
|
+
nullable: true,
|
37
|
+
})
|
38
|
+
], JacksonStore.prototype, "tag", void 0);
|
39
|
+
__decorate([
|
40
|
+
(0, typeorm_1.Column)({
|
41
|
+
type: 'datetime',
|
42
|
+
default: () => 'CURRENT_TIMESTAMP',
|
43
|
+
nullable: false,
|
44
|
+
})
|
45
|
+
], JacksonStore.prototype, "createdAt", void 0);
|
46
|
+
__decorate([
|
47
|
+
(0, typeorm_1.Column)({
|
48
|
+
type: 'datetime',
|
49
|
+
nullable: true,
|
50
|
+
})
|
51
|
+
], JacksonStore.prototype, "modifiedAt", void 0);
|
52
|
+
JacksonStore = __decorate([
|
53
|
+
(0, typeorm_1.Entity)()
|
54
|
+
], JacksonStore);
|
55
|
+
exports.JacksonStore = JacksonStore;
|
@@ -0,0 +1,29 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
7
|
+
};
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
9
|
+
exports.JacksonTTL = void 0;
|
10
|
+
const typeorm_1 = require("typeorm");
|
11
|
+
let JacksonTTL = class JacksonTTL {
|
12
|
+
};
|
13
|
+
__decorate([
|
14
|
+
(0, typeorm_1.Column)({
|
15
|
+
primary: true,
|
16
|
+
type: 'varchar',
|
17
|
+
length: 1500,
|
18
|
+
})
|
19
|
+
], JacksonTTL.prototype, "key", void 0);
|
20
|
+
__decorate([
|
21
|
+
(0, typeorm_1.Index)('_jackson_ttl_expires_at'),
|
22
|
+
(0, typeorm_1.Column)({
|
23
|
+
type: 'bigint',
|
24
|
+
})
|
25
|
+
], JacksonTTL.prototype, "expiresAt", void 0);
|
26
|
+
JacksonTTL = __decorate([
|
27
|
+
(0, typeorm_1.Entity)()
|
28
|
+
], JacksonTTL);
|
29
|
+
exports.JacksonTTL = JacksonTTL;
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare const parseURL: (url?: string) => any;
|
@@ -0,0 +1,46 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.parseURL = void 0;
|
4
|
+
const parseURL = (url) => {
|
5
|
+
if (!url) {
|
6
|
+
throw new Error('URL is required');
|
7
|
+
}
|
8
|
+
const parts = url.split('://');
|
9
|
+
if (parts.length != 2) {
|
10
|
+
throw new Error('Invalid connection string');
|
11
|
+
}
|
12
|
+
//const scheme = parts[0];
|
13
|
+
const connectionString = parts[1];
|
14
|
+
const connParts = connectionString.split(';');
|
15
|
+
if (connParts.length == 0) {
|
16
|
+
throw new Error('Invalid connection string');
|
17
|
+
}
|
18
|
+
// sqlserver://[serverName[\instanceName][:portNumber]][;property=value[;property=value]]
|
19
|
+
const hostPort = connParts[0];
|
20
|
+
const hostPortParts = hostPort.split(':');
|
21
|
+
const host = hostPortParts[0];
|
22
|
+
const port = hostPortParts.length > 1 ? parseInt(hostPortParts[1], 10) : 1433;
|
23
|
+
const options = {};
|
24
|
+
connParts.slice(1).map((p) => {
|
25
|
+
const ps = p.split('=');
|
26
|
+
options[ps[0]] = ps[1];
|
27
|
+
});
|
28
|
+
const username = options.username || options.user;
|
29
|
+
const password = options.password || options.pass;
|
30
|
+
const database = options.database;
|
31
|
+
delete options.username;
|
32
|
+
delete options.user;
|
33
|
+
delete options.password;
|
34
|
+
delete options.pass;
|
35
|
+
delete options.database;
|
36
|
+
options.encrypt = Boolean(options.encrypt || false);
|
37
|
+
return {
|
38
|
+
host,
|
39
|
+
port,
|
40
|
+
database,
|
41
|
+
username,
|
42
|
+
password,
|
43
|
+
options,
|
44
|
+
};
|
45
|
+
};
|
46
|
+
exports.parseURL = parseURL;
|
package/dist/db/sql/sql.js
CHANGED
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
require('reflect-metadata');
|
37
37
|
const typeorm_1 = require("typeorm");
|
38
38
|
const dbutils = __importStar(require("../utils"));
|
39
|
+
const mssql = __importStar(require("./mssql"));
|
39
40
|
class Sql {
|
40
41
|
constructor(options) {
|
41
42
|
this.options = options;
|
@@ -45,15 +46,20 @@ class Sql {
|
|
45
46
|
const sqlType = this.options.engine === 'planetscale' ? 'mysql' : this.options.type;
|
46
47
|
while (true) {
|
47
48
|
try {
|
48
|
-
|
49
|
+
const baseOpts = {
|
49
50
|
type: sqlType,
|
50
|
-
url: this.options.url,
|
51
51
|
synchronize: this.options.engine !== 'planetscale',
|
52
52
|
migrationsTableName: '_jackson_migrations',
|
53
53
|
logging: ['error'],
|
54
54
|
entities: [JacksonStore, JacksonIndex, JacksonTTL],
|
55
|
-
|
56
|
-
|
55
|
+
};
|
56
|
+
if (sqlType === 'mssql') {
|
57
|
+
const mssqlOpts = mssql.parseURL(this.options.url);
|
58
|
+
this.dataSource = new typeorm_1.DataSource(Object.assign({ host: mssqlOpts.host, port: mssqlOpts.port, database: mssqlOpts.database, username: mssqlOpts.username, password: mssqlOpts.password, options: mssqlOpts.options }, baseOpts));
|
59
|
+
}
|
60
|
+
else {
|
61
|
+
this.dataSource = new typeorm_1.DataSource(Object.assign({ url: this.options.url, ssl: this.options.ssl }, baseOpts));
|
62
|
+
}
|
57
63
|
yield this.dataSource.initialize();
|
58
64
|
break;
|
59
65
|
}
|
@@ -94,7 +100,7 @@ class Sql {
|
|
94
100
|
this.timerId = setTimeout(this.ttlCleanup, this.options.ttl * 1000);
|
95
101
|
}
|
96
102
|
else {
|
97
|
-
console.
|
103
|
+
console.warn('Warning: ttl cleanup not enabled, set both "ttl" and "cleanupLimit" options to enable it!');
|
98
104
|
}
|
99
105
|
return this;
|
100
106
|
});
|
@@ -173,7 +179,7 @@ class Sql {
|
|
173
179
|
// no ttl support for secondary indexes
|
174
180
|
for (const idx of indexes || []) {
|
175
181
|
const key = dbutils.keyForIndex(namespace, idx);
|
176
|
-
const rec = yield
|
182
|
+
const rec = yield transactionalEntityManager.findOneBy(this.JacksonIndex, {
|
177
183
|
key,
|
178
184
|
storeKey: store.key,
|
179
185
|
});
|
package/dist/index.js
CHANGED
@@ -10,6 +10,18 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
|
|
10
10
|
if (k2 === undefined) k2 = k;
|
11
11
|
o[k2] = m[k];
|
12
12
|
}));
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
15
|
+
}) : function(o, v) {
|
16
|
+
o["default"] = v;
|
17
|
+
});
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
19
|
+
if (mod && mod.__esModule) return mod;
|
20
|
+
var result = {};
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
22
|
+
__setModuleDefault(result, mod);
|
23
|
+
return result;
|
24
|
+
};
|
13
25
|
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
14
26
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
15
27
|
};
|
@@ -38,6 +50,7 @@ const logout_1 = require("./controller/logout");
|
|
38
50
|
const directory_sync_1 = __importDefault(require("./directory-sync"));
|
39
51
|
const oidc_discovery_1 = require("./controller/oidc-discovery");
|
40
52
|
const sp_config_1 = require("./controller/sp-config");
|
53
|
+
const x509 = __importStar(require("./saml/x509"));
|
41
54
|
const defaultOpts = (opts) => {
|
42
55
|
const newOpts = Object.assign({}, opts);
|
43
56
|
if (!newOpts.externalUrl) {
|
@@ -67,10 +80,13 @@ const controllers = (opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
67
80
|
const codeStore = db.store('oauth:code', opts.db.ttl);
|
68
81
|
const tokenStore = db.store('oauth:token', opts.db.ttl);
|
69
82
|
const healthCheckStore = db.store('_health:check');
|
83
|
+
const certificateStore = db.store('x509:certificates');
|
70
84
|
const connectionAPIController = new api_1.ConnectionAPIController({ connectionStore, opts });
|
71
85
|
const adminController = new admin_1.AdminController({ connectionStore });
|
72
86
|
const healthCheckController = new health_check_1.HealthCheckController({ healthCheckStore });
|
73
87
|
yield healthCheckController.init();
|
88
|
+
// Create default certificate if it doesn't exist.
|
89
|
+
yield x509.init(certificateStore);
|
74
90
|
const oauthController = new oauth_1.OAuthController({
|
75
91
|
connectionStore,
|
76
92
|
sessionStore,
|
@@ -85,7 +101,7 @@ const controllers = (opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
85
101
|
});
|
86
102
|
const directorySync = yield (0, directory_sync_1.default)({ db, opts });
|
87
103
|
const oidcDiscoveryController = new oidc_discovery_1.OidcDiscoveryController({ opts });
|
88
|
-
const spConfig = new sp_config_1.SPSAMLConfig(opts);
|
104
|
+
const spConfig = new sp_config_1.SPSAMLConfig(opts, x509.getDefaultCertificate);
|
89
105
|
// write pre-loaded connections if present
|
90
106
|
const preLoadedConnection = opts.preLoadedConnection || opts.preLoadedConfig;
|
91
107
|
if (preLoadedConnection && preLoadedConnection.length > 0) {
|
@@ -97,11 +113,11 @@ const controllers = (opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
97
113
|
else {
|
98
114
|
yield connectionAPIController.createSAMLConnection(connection);
|
99
115
|
}
|
100
|
-
console.
|
116
|
+
console.info(`loaded connection for tenant "${connection.tenant}" and product "${connection.product}"`);
|
101
117
|
}
|
102
118
|
}
|
103
119
|
const type = opts.db.engine === 'sql' && opts.db.type ? ' Type: ' + opts.db.type : '';
|
104
|
-
console.
|
120
|
+
console.info(`Using engine: ${opts.db.engine}.${type}`);
|
105
121
|
return {
|
106
122
|
spConfig,
|
107
123
|
apiController: connectionAPIController,
|
package/dist/loadConnection.js
CHANGED
@@ -36,6 +36,7 @@ const fs = __importStar(require("fs"));
|
|
36
36
|
const path = __importStar(require("path"));
|
37
37
|
const url = __importStar(require("url"));
|
38
38
|
const loadConnection = (preLoadedConnection) => __awaiter(void 0, void 0, void 0, function* () {
|
39
|
+
var _a;
|
39
40
|
if (preLoadedConnection.startsWith('./')) {
|
40
41
|
preLoadedConnection = path.resolve(process.cwd(), preLoadedConnection);
|
41
42
|
}
|
@@ -49,7 +50,7 @@ const loadConnection = (preLoadedConnection) => __awaiter(void 0, void 0, void 0
|
|
49
50
|
if (file.endsWith('.js')) {
|
50
51
|
const filePath = path.join(preLoadedConnection, file);
|
51
52
|
const fileUrl = preLoadedConnection.startsWith('/') ? filePath : url.pathToFileURL(filePath).toString();
|
52
|
-
const { default: connection, } = yield Promise.resolve().then(() => __importStar(require(
|
53
|
+
const { default: connection, } = yield (_a = fileUrl, Promise.resolve().then(() => __importStar(require(_a))));
|
53
54
|
if (!('oidcDiscoveryUrl' in connection)) {
|
54
55
|
const rawMetadata = yield fs.promises.readFile(path.join(preLoadedConnection, path.parse(file).name + '.xml'), 'utf8');
|
55
56
|
connection.encodedRawMetadata = Buffer.from(rawMetadata, 'utf8').toString('base64');
|
package/dist/saml/x509.d.ts
CHANGED
@@ -1,7 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
import type { Storable } from '../typings';
|
2
|
+
export declare const init: (store: Storable) => Promise<{
|
3
|
+
publicKey: string;
|
4
|
+
privateKey: string;
|
5
|
+
}>;
|
6
|
+
export declare const generateCertificate: () => {
|
7
|
+
publicKey: any;
|
8
|
+
privateKey: any;
|
6
9
|
};
|
7
|
-
export
|
10
|
+
export declare const getDefaultCertificate: () => Promise<{
|
11
|
+
publicKey: string;
|
12
|
+
privateKey: string;
|
13
|
+
}>;
|
package/dist/saml/x509.js
CHANGED
@@ -22,17 +22,38 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
22
22
|
__setModuleDefault(result, mod);
|
23
23
|
return result;
|
24
24
|
};
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
32
|
+
});
|
33
|
+
};
|
34
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
35
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
36
|
+
};
|
25
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
38
|
+
exports.getDefaultCertificate = exports.generateCertificate = exports.init = void 0;
|
26
39
|
const forge = __importStar(require("node-forge"));
|
40
|
+
const crypto_1 = __importDefault(require("crypto"));
|
27
41
|
const pki = forge.pki;
|
28
|
-
|
42
|
+
let certificateStore;
|
43
|
+
let cachedCertificate;
|
44
|
+
const init = (store) => __awaiter(void 0, void 0, void 0, function* () {
|
45
|
+
certificateStore = store;
|
46
|
+
return yield (0, exports.getDefaultCertificate)();
|
47
|
+
});
|
48
|
+
exports.init = init;
|
49
|
+
const generateCertificate = () => {
|
29
50
|
const today = new Date();
|
30
51
|
const keys = pki.rsa.generateKeyPair(2048);
|
31
52
|
const cert = pki.createCertificate();
|
32
53
|
cert.publicKey = keys.publicKey;
|
33
54
|
cert.serialNumber = '01';
|
34
55
|
cert.validity.notBefore = new Date();
|
35
|
-
cert.validity.notAfter = new Date(today.setFullYear(today.getFullYear() +
|
56
|
+
cert.validity.notAfter = new Date(today.setFullYear(today.getFullYear() + 30));
|
36
57
|
const attrs = [
|
37
58
|
{
|
38
59
|
name: 'commonName',
|
@@ -62,6 +83,26 @@ const generate = () => {
|
|
62
83
|
privateKey: pki.privateKeyToPem(keys.privateKey),
|
63
84
|
};
|
64
85
|
};
|
65
|
-
exports.
|
66
|
-
|
67
|
-
|
86
|
+
exports.generateCertificate = generateCertificate;
|
87
|
+
const getDefaultCertificate = () => __awaiter(void 0, void 0, void 0, function* () {
|
88
|
+
if (cachedCertificate && !(yield isCertificateExpired(cachedCertificate.publicKey))) {
|
89
|
+
return cachedCertificate;
|
90
|
+
}
|
91
|
+
if (!certificateStore) {
|
92
|
+
throw new Error('Certificate store not initialized');
|
93
|
+
}
|
94
|
+
cachedCertificate = yield certificateStore.get('default');
|
95
|
+
// If certificate is expired let it drop through so it creates a new cert
|
96
|
+
if (cachedCertificate && !(yield isCertificateExpired(cachedCertificate.publicKey))) {
|
97
|
+
return cachedCertificate;
|
98
|
+
}
|
99
|
+
// If default certificate is not found or has expired, create one and store it.
|
100
|
+
cachedCertificate = (0, exports.generateCertificate)();
|
101
|
+
yield certificateStore.put('default', cachedCertificate);
|
102
|
+
return cachedCertificate;
|
103
|
+
});
|
104
|
+
exports.getDefaultCertificate = getDefaultCertificate;
|
105
|
+
const isCertificateExpired = (publicKey) => __awaiter(void 0, void 0, void 0, function* () {
|
106
|
+
const { validTo } = new crypto_1.default.X509Certificate(publicKey);
|
107
|
+
return !(validTo != 'Bad time value' && new Date(validTo) > new Date());
|
108
|
+
});
|
package/dist/typings.d.ts
CHANGED
@@ -13,10 +13,12 @@ export interface SAMLSSOConnection extends SSOConnection {
|
|
13
13
|
export interface SAMLSSOConnectionWithRawMetadata extends SAMLSSOConnection {
|
14
14
|
rawMetadata: string;
|
15
15
|
encodedRawMetadata?: never;
|
16
|
+
metadataUrl?: string;
|
16
17
|
}
|
17
18
|
export interface SAMLSSOConnectionWithEncodedMetadata extends SAMLSSOConnection {
|
18
19
|
rawMetadata?: never;
|
19
20
|
encodedRawMetadata: string;
|
21
|
+
metadataUrl?: string;
|
20
22
|
}
|
21
23
|
export interface OIDCSSOConnection extends SSOConnection {
|
22
24
|
oidcDiscoveryUrl: string;
|
@@ -26,6 +28,7 @@ export interface OIDCSSOConnection extends SSOConnection {
|
|
26
28
|
export interface SAMLSSORecord extends SAMLSSOConnection {
|
27
29
|
clientID: string;
|
28
30
|
clientSecret: string;
|
31
|
+
metadataUrl?: string;
|
29
32
|
idpMetadata: {
|
30
33
|
entityID: string;
|
31
34
|
loginType?: string;
|
@@ -41,10 +44,6 @@ export interface SAMLSSORecord extends SAMLSSOConnection {
|
|
41
44
|
thumbprint?: string;
|
42
45
|
validTo?: string;
|
43
46
|
};
|
44
|
-
certs: {
|
45
|
-
privateKey: string;
|
46
|
-
publicKey: string;
|
47
|
-
};
|
48
47
|
}
|
49
48
|
export interface OIDCSSORecord extends SSOConnection {
|
50
49
|
clientID: string;
|
@@ -56,21 +55,21 @@ export interface OIDCSSORecord extends SSOConnection {
|
|
56
55
|
clientSecret?: string;
|
57
56
|
};
|
58
57
|
}
|
59
|
-
export
|
60
|
-
|
58
|
+
export type ConnectionType = 'saml' | 'oidc';
|
59
|
+
type ClientIDQuery = {
|
61
60
|
clientID: string;
|
62
61
|
};
|
63
|
-
|
62
|
+
type TenantQuery = {
|
64
63
|
tenant: string;
|
65
64
|
product: string;
|
66
65
|
strategy?: ConnectionType;
|
67
66
|
};
|
68
|
-
export
|
69
|
-
export
|
67
|
+
export type GetConnectionsQuery = ClientIDQuery | TenantQuery;
|
68
|
+
export type DelConnectionsQuery = (ClientIDQuery & {
|
70
69
|
clientSecret: string;
|
71
70
|
}) | TenantQuery;
|
72
|
-
export
|
73
|
-
export
|
71
|
+
export type GetConfigQuery = ClientIDQuery | Omit<TenantQuery, 'strategy'>;
|
72
|
+
export type DelConfigQuery = (ClientIDQuery & {
|
74
73
|
clientSecret: string;
|
75
74
|
}) | Omit<TenantQuery, 'strategy'>;
|
76
75
|
export interface IConnectionAPIController {
|
@@ -181,7 +180,7 @@ export interface OAuthReqBodyWithResource extends OAuthReqBody {
|
|
181
180
|
client_id: 'dummy';
|
182
181
|
resource: string;
|
183
182
|
}
|
184
|
-
export
|
183
|
+
export type OAuthReq = OAuthReqBodyWithClientId | OAuthReqBodyWithTenantProduct | OAuthReqBodyWithAccessType | OAuthReqBodyWithResource;
|
185
184
|
export interface SAMLResponsePayload {
|
186
185
|
SAMLResponse: string;
|
187
186
|
RelayState: string;
|
@@ -199,7 +198,7 @@ interface OIDCAuthzResponseError {
|
|
199
198
|
error: OAuthErrorHandlerParams['error'] | OIDCErrorCodes;
|
200
199
|
error_description?: string;
|
201
200
|
}
|
202
|
-
export
|
201
|
+
export type OIDCAuthzResponsePayload = OIDCAuthzResponseSuccess | OIDCAuthzResponseError;
|
203
202
|
interface OAuthTokenReqBody {
|
204
203
|
code: string;
|
205
204
|
grant_type: 'authorization_code';
|
@@ -215,7 +214,7 @@ export interface OAuthTokenReqWithCredentials extends OAuthTokenReqBody {
|
|
215
214
|
client_id: string;
|
216
215
|
client_secret: string;
|
217
216
|
}
|
218
|
-
export
|
217
|
+
export type OAuthTokenReq = OAuthTokenReqWithCodeVerifier | OAuthTokenReqWithCredentials;
|
219
218
|
export interface OAuthTokenRes {
|
220
219
|
access_token: string;
|
221
220
|
id_token?: string;
|
@@ -224,6 +223,7 @@ export interface OAuthTokenRes {
|
|
224
223
|
}
|
225
224
|
export interface Profile {
|
226
225
|
id: string;
|
226
|
+
idHash: string;
|
227
227
|
sub?: string;
|
228
228
|
email: string;
|
229
229
|
firstName: string;
|
@@ -259,9 +259,9 @@ export interface Encrypted {
|
|
259
259
|
tag?: string;
|
260
260
|
value: string;
|
261
261
|
}
|
262
|
-
export
|
263
|
-
export
|
264
|
-
export
|
262
|
+
export type EncryptionKey = any;
|
263
|
+
export type DatabaseEngine = 'redis' | 'sql' | 'mongo' | 'mem' | 'planetscale';
|
264
|
+
export type DatabaseType = 'postgres' | 'mysql' | 'mariadb' | 'mssql';
|
265
265
|
export interface DatabaseOption {
|
266
266
|
engine?: DatabaseEngine;
|
267
267
|
url?: string;
|
@@ -314,10 +314,6 @@ interface Metadata {
|
|
314
314
|
}
|
315
315
|
export interface SAMLConnection {
|
316
316
|
idpMetadata: Metadata;
|
317
|
-
certs: {
|
318
|
-
privateKey: string;
|
319
|
-
publicKey: string;
|
320
|
-
};
|
321
317
|
defaultRedirectUrl: string;
|
322
318
|
}
|
323
319
|
export interface OAuthErrorHandlerParams {
|
@@ -326,20 +322,21 @@ export interface OAuthErrorHandlerParams {
|
|
326
322
|
redirect_uri: string;
|
327
323
|
state?: string;
|
328
324
|
}
|
329
|
-
export
|
325
|
+
export type OIDCErrorCodes = 'interaction_required' | 'login_required' | 'account_selection_required' | 'consent_required' | 'invalid_request_uri' | 'invalid_request_object' | 'request_not_supported' | 'request_uri_not_supported' | 'registration_not_supported';
|
330
326
|
export interface ISPSAMLConfig {
|
331
|
-
get(): {
|
327
|
+
get(): Promise<{
|
332
328
|
acsUrl: string;
|
333
329
|
entityId: string;
|
334
330
|
response: string;
|
335
331
|
assertionSignature: string;
|
336
332
|
signatureAlgorithm: string;
|
337
|
-
|
338
|
-
|
333
|
+
publicKey: string;
|
334
|
+
publicKeyString: string;
|
335
|
+
}>;
|
339
336
|
toMarkdown(): string;
|
340
337
|
toHTML(): string;
|
341
338
|
}
|
342
|
-
export
|
339
|
+
export type DirectorySyncEventType = 'user.created' | 'user.updated' | 'user.deleted' | 'group.created' | 'group.updated' | 'group.deleted' | 'group.user_added' | 'group.user_removed';
|
343
340
|
export interface Base {
|
344
341
|
store(type: 'groups' | 'members' | 'users'): Storable;
|
345
342
|
setTenant(tenant: string): this;
|
@@ -432,7 +429,7 @@ export interface Groups extends Base {
|
|
432
429
|
error: ApiError | null;
|
433
430
|
}>;
|
434
431
|
}
|
435
|
-
export
|
432
|
+
export type User = {
|
436
433
|
id: string;
|
437
434
|
email: string;
|
438
435
|
first_name: string;
|
@@ -440,7 +437,7 @@ export declare type User = {
|
|
440
437
|
active: boolean;
|
441
438
|
raw?: any;
|
442
439
|
};
|
443
|
-
export
|
440
|
+
export type Group = {
|
444
441
|
id: string;
|
445
442
|
name: string;
|
446
443
|
raw?: any;
|
@@ -452,9 +449,9 @@ export declare enum DirectorySyncProviders {
|
|
452
449
|
'jumpcloud-scim-v2' = "JumpCloud v2.0",
|
453
450
|
'generic-scim-v2' = "SCIM Generic v2.0"
|
454
451
|
}
|
455
|
-
export
|
456
|
-
export
|
457
|
-
export
|
452
|
+
export type DirectoryType = keyof typeof DirectorySyncProviders;
|
453
|
+
export type HTTPMethod = 'POST' | 'PUT' | 'DELETE' | 'GET' | 'PATCH';
|
454
|
+
export type Directory = {
|
458
455
|
id: string;
|
459
456
|
name: string;
|
460
457
|
tenant: string;
|
@@ -471,7 +468,7 @@ export declare type Directory = {
|
|
471
468
|
secret: string;
|
472
469
|
};
|
473
470
|
};
|
474
|
-
export
|
471
|
+
export type DirectorySyncGroupMember = {
|
475
472
|
value: string;
|
476
473
|
email?: string;
|
477
474
|
};
|
@@ -544,7 +541,7 @@ export interface IWebhookEventsLogger extends Base {
|
|
544
541
|
delete(id: string): Promise<void>;
|
545
542
|
updateStatus(log: WebhookEventLog, statusCode: number): Promise<WebhookEventLog>;
|
546
543
|
}
|
547
|
-
export
|
544
|
+
export type DirectorySyncResponse = {
|
548
545
|
status: number;
|
549
546
|
data?: any;
|
550
547
|
};
|
@@ -567,7 +564,7 @@ export interface DirectorySyncRequest {
|
|
567
564
|
filter?: string;
|
568
565
|
};
|
569
566
|
}
|
570
|
-
export
|
567
|
+
export type DirectorySync = {
|
571
568
|
requests: DirectorySyncRequestHandler;
|
572
569
|
directories: DirectoryConfig;
|
573
570
|
groups: Groups;
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import { MigrationInterface, QueryRunner } from "typeorm";
|
2
|
+
|
3
|
+
export class mssInitial1667949639424 implements MigrationInterface {
|
4
|
+
name = 'mssInitial1667949639424'
|
5
|
+
|
6
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
7
|
+
await queryRunner.query(`CREATE TABLE "jackson_ttl" ("key" varchar(1500) NOT NULL, "expiresAt" bigint NOT NULL, CONSTRAINT "PK_7c9bcdfb4d82e873e19935ec806" PRIMARY KEY ("key"))`);
|
8
|
+
await queryRunner.query(`CREATE INDEX "_jackson_ttl_expires_at" ON "jackson_ttl" ("expiresAt") `);
|
9
|
+
await queryRunner.query(`CREATE TABLE "jackson_store" ("key" varchar(1500) NOT NULL, "value" text NOT NULL, "iv" varchar(64), "tag" varchar(64), "createdAt" datetime NOT NULL CONSTRAINT "DF_49022ed8c543adefc99ff762200" DEFAULT getdate(), "modifiedAt" datetime, CONSTRAINT "PK_87b6fc1475fbd1228d2f53c6f4a" PRIMARY KEY ("key"))`);
|
10
|
+
await queryRunner.query(`CREATE TABLE "jackson_index" ("id" int NOT NULL IDENTITY(1,1), "key" varchar(1500) NOT NULL, "storeKey" varchar(1500) NOT NULL, CONSTRAINT "PK_a95aa83f01e3c73e126856b7820" PRIMARY KEY ("id"))`);
|
11
|
+
await queryRunner.query(`CREATE INDEX "_jackson_index_key" ON "jackson_index" ("key") `);
|
12
|
+
await queryRunner.query(`CREATE INDEX "_jackson_index_key_store" ON "jackson_index" ("key", "storeKey") `);
|
13
|
+
await queryRunner.query(`ALTER TABLE "jackson_index" ADD CONSTRAINT "FK_937b040fb2592b4671cbde09e83" FOREIGN KEY ("storeKey") REFERENCES "jackson_store"("key") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
14
|
+
}
|
15
|
+
|
16
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
17
|
+
await queryRunner.query(`ALTER TABLE "jackson_index" DROP CONSTRAINT "FK_937b040fb2592b4671cbde09e83"`);
|
18
|
+
await queryRunner.query(`DROP INDEX "_jackson_index_key_store" ON "jackson_index"`);
|
19
|
+
await queryRunner.query(`DROP INDEX "_jackson_index_key" ON "jackson_index"`);
|
20
|
+
await queryRunner.query(`DROP TABLE "jackson_index"`);
|
21
|
+
await queryRunner.query(`DROP TABLE "jackson_store"`);
|
22
|
+
await queryRunner.query(`DROP INDEX "_jackson_ttl_expires_at" ON "jackson_ttl"`);
|
23
|
+
await queryRunner.query(`DROP TABLE "jackson_ttl"`);
|
24
|
+
}
|
25
|
+
|
26
|
+
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@boxyhq/saml-jackson",
|
3
|
-
"version": "1.3.
|
3
|
+
"version": "1.3.7",
|
4
4
|
"description": "SAML Jackson library",
|
5
5
|
"keywords": [
|
6
6
|
"SAML 2.0"
|
@@ -22,10 +22,12 @@
|
|
22
22
|
"db:migration:generate:mysql": "cross-env DB_TYPE=mysql DB_URL=mysql://root:mysql@localhost:3307/mysql ts-node --transpile-only ./node_modules/typeorm/cli.js migration:generate -d typeorm.ts migration/mysql/ms_${MIGRATION_NAME}",
|
23
23
|
"db:migration:generate:planetscale": "cross-env DB_ENGINE=planetscale DB_URL=mysql://root:mysql@localhost:3307/mysql ts-node --transpile-only ./node_modules/typeorm/cli.js migration:generate -d typeorm.ts migration/mysql/ms_${MIGRATION_NAME}",
|
24
24
|
"db:migration:generate:mariadb": "cross-env DB_TYPE=mariadb DB_URL=mariadb://root@localhost:3306/mysql ts-node --transpile-only ./node_modules/typeorm/cli.js migration:generate -d typeorm.ts migration/mariadb/md_${MIGRATION_NAME}",
|
25
|
+
"db:migration:generate:mssql": "cross-env DB_TYPE=mssql DB_URL='sqlserver://localhost:1433;database=master;username=sa;password=123ABabc!' ts-node --transpile-only ./node_modules/typeorm/cli.js migration:generate -d typeorm.ts migration/mssql/mss_${MIGRATION_NAME}",
|
25
26
|
"db:migration:run:postgres": "ts-node --transpile-only ./node_modules/typeorm/cli.js migration:run -d typeorm.ts",
|
26
27
|
"db:migration:run:mysql": "cross-env DB_TYPE=mysql DB_URL=mysql://root:mysql@localhost:3307/mysql ts-node --transpile-only ./node_modules/typeorm/cli.js migration:run -d typeorm.ts",
|
27
28
|
"db:migration:run:planetscale": "cross-env DB_SSL=true DB_ENGINE=planetscale DB_URL=${PLANETSCALE_URL} ts-node --transpile-only ./node_modules/typeorm/cli.js migration:run -d typeorm.ts",
|
28
29
|
"db:migration:run:mariadb": "cross-env DB_TYPE=mariadb DB_URL=mariadb://root@localhost:3306/mysql ts-node --transpile-only ./node_modules/typeorm/cli.js migration:run -d typeorm.ts",
|
30
|
+
"db:migration:run:mssql": "cross-env DB_TYPE=mssql DB_URL='sqlserver://localhost:1433;database=master;username=sa;password=123ABabc!' ts-node --transpile-only ./node_modules/typeorm/cli.js migration:run -d typeorm.ts",
|
29
31
|
"prepublishOnly": "npm run build",
|
30
32
|
"test": "tap --ts --timeout=100 --coverage-map=map.js test/**/*.test.ts",
|
31
33
|
"sort": "npx sort-package-json"
|
@@ -38,18 +40,19 @@
|
|
38
40
|
"statements": 70
|
39
41
|
},
|
40
42
|
"dependencies": {
|
41
|
-
"@boxyhq/saml20": "1.0.
|
43
|
+
"@boxyhq/saml20": "1.0.14",
|
42
44
|
"@opentelemetry/api": "1.0.4",
|
43
45
|
"@opentelemetry/api-metrics": "0.27.0",
|
44
46
|
"axios": "1.1.3",
|
45
|
-
"jose": "4.
|
46
|
-
"marked": "4.2.
|
47
|
+
"jose": "4.11.0",
|
48
|
+
"marked": "4.2.3",
|
47
49
|
"mongodb": "4.11.0",
|
50
|
+
"mssql": "9.0.1",
|
48
51
|
"mysql2": "2.3.3",
|
49
|
-
"openid-client": "5.2.1",
|
50
52
|
"node-forge": "1.3.1",
|
53
|
+
"openid-client": "5.3.0",
|
51
54
|
"pg": "8.8.0",
|
52
|
-
"redis": "4.
|
55
|
+
"redis": "4.5.0",
|
53
56
|
"reflect-metadata": "0.1.13",
|
54
57
|
"ripemd160": "2.0.2",
|
55
58
|
"typeorm": "0.3.10",
|
@@ -61,17 +64,17 @@
|
|
61
64
|
"@types/node": "18.11.9",
|
62
65
|
"@types/sinon": "10.0.13",
|
63
66
|
"@types/tap": "15.0.7",
|
64
|
-
"@typescript-eslint/eslint-plugin": "5.
|
65
|
-
"@typescript-eslint/parser": "5.42.
|
67
|
+
"@typescript-eslint/eslint-plugin": "5.43.0",
|
68
|
+
"@typescript-eslint/parser": "5.42.1",
|
66
69
|
"cross-env": "7.0.3",
|
67
|
-
"eslint": "8.
|
70
|
+
"eslint": "8.28.0",
|
68
71
|
"eslint-config-prettier": "8.5.0",
|
69
72
|
"prettier": "2.7.1",
|
70
|
-
"sinon": "14.0.
|
73
|
+
"sinon": "14.0.2",
|
71
74
|
"tap": "16.3.0",
|
72
75
|
"ts-node": "10.9.1",
|
73
76
|
"tsconfig-paths": "4.1.0",
|
74
|
-
"typescript": "4.
|
77
|
+
"typescript": "4.9.3"
|
75
78
|
},
|
76
79
|
"engines": {
|
77
80
|
"node": ">=14.18.1 <=18.x"
|