@boxyhq/saml-jackson 1.3.5 → 1.3.7
Sign up to get free protection for your applications and to get access to all the features.
- 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"
|