@boxyhq/saml-jackson 1.2.1 → 1.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.
- package/dist/controller/admin.d.ts +4 -4
- package/dist/controller/admin.js +6 -6
- package/dist/controller/api.d.ts +448 -204
- package/dist/controller/api.js +547 -376
- package/dist/controller/connection/oidc.d.ts +18 -0
- package/dist/controller/connection/oidc.js +145 -0
- package/dist/controller/connection/saml.d.ts +14 -0
- package/dist/controller/connection/saml.js +168 -0
- package/dist/controller/logout.d.ts +3 -3
- package/dist/controller/logout.js +14 -14
- package/dist/controller/oauth.d.ts +26 -8
- package/dist/controller/oauth.js +368 -118
- package/dist/controller/utils.d.ts +10 -2
- package/dist/controller/utils.js +88 -1
- package/dist/directory-sync/DirectoryUsers.js +4 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +26 -14
- package/dist/loadConnection.d.ts +3 -0
- package/dist/{read-config.js → loadConnection.js} +13 -12
- package/dist/opentelemetry/metrics.js +12 -12
- package/dist/saml/x509.d.ts +4 -4
- package/dist/saml/x509.js +38 -42
- package/dist/typings.d.ts +110 -34
- package/package.json +14 -14
- package/dist/read-config.d.ts +0 -3
@@ -0,0 +1,18 @@
|
|
1
|
+
import { IConnectionAPIController, OIDCSSOConnection, Storable } from '../../typings';
|
2
|
+
declare const oidc: {
|
3
|
+
create: (body: OIDCSSOConnection, connectionStore: Storable) => Promise<Partial<OIDCSSOConnection> & {
|
4
|
+
clientID: string;
|
5
|
+
clientSecret: string;
|
6
|
+
oidcProvider?: {
|
7
|
+
provider?: string | undefined;
|
8
|
+
discoveryUrl?: string | undefined;
|
9
|
+
clientId?: string | undefined;
|
10
|
+
clientSecret?: string | undefined;
|
11
|
+
} | undefined;
|
12
|
+
}>;
|
13
|
+
update: (body: OIDCSSOConnection & {
|
14
|
+
clientID: string;
|
15
|
+
clientSecret: string;
|
16
|
+
}, connectionStore: Storable, connectionsGetter: IConnectionAPIController['getConnections']) => Promise<void>;
|
17
|
+
};
|
18
|
+
export default oidc;
|
@@ -0,0 +1,145 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
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
|
+
};
|
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 __rest = (this && this.__rest) || function (s, e) {
|
35
|
+
var t = {};
|
36
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
37
|
+
t[p] = s[p];
|
38
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
39
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
40
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
41
|
+
t[p[i]] = s[p[i]];
|
42
|
+
}
|
43
|
+
return t;
|
44
|
+
};
|
45
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
46
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
47
|
+
};
|
48
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
49
|
+
const crypto_1 = __importDefault(require("crypto"));
|
50
|
+
const dbutils = __importStar(require("../../db/utils"));
|
51
|
+
const utils_1 = require("../utils");
|
52
|
+
const error_1 = require("../error");
|
53
|
+
const oidc = {
|
54
|
+
create: (body, connectionStore) => __awaiter(void 0, void 0, void 0, function* () {
|
55
|
+
const { defaultRedirectUrl, redirectUrl, tenant, product, name, description, oidcDiscoveryUrl = '', oidcClientId = '', oidcClientSecret = '', } = body;
|
56
|
+
let connectionClientSecret;
|
57
|
+
(0, utils_1.validateSSOConnection)(body, 'oidc');
|
58
|
+
const redirectUrlList = (0, utils_1.extractRedirectUrls)(redirectUrl);
|
59
|
+
(0, utils_1.validateRedirectUrl)({ defaultRedirectUrl, redirectUrlList });
|
60
|
+
const record = {
|
61
|
+
defaultRedirectUrl,
|
62
|
+
redirectUrl: redirectUrlList,
|
63
|
+
tenant,
|
64
|
+
product,
|
65
|
+
name,
|
66
|
+
description,
|
67
|
+
clientID: '',
|
68
|
+
clientSecret: '',
|
69
|
+
};
|
70
|
+
// from OpenID Provider
|
71
|
+
record.oidcProvider = {
|
72
|
+
discoveryUrl: oidcDiscoveryUrl,
|
73
|
+
clientId: oidcClientId,
|
74
|
+
clientSecret: oidcClientSecret,
|
75
|
+
};
|
76
|
+
// extract provider
|
77
|
+
const providerName = (0, utils_1.extractHostName)(oidcDiscoveryUrl);
|
78
|
+
record.oidcProvider.provider = providerName ? providerName : 'Unknown';
|
79
|
+
// Use the clientId from the OpenID Provider to generate the clientID hash for the connection
|
80
|
+
record.clientID = dbutils.keyDigest(dbutils.keyFromParts(tenant, product, oidcClientId));
|
81
|
+
const exists = yield connectionStore.get(record.clientID);
|
82
|
+
if (exists) {
|
83
|
+
connectionClientSecret = exists.clientSecret;
|
84
|
+
}
|
85
|
+
else {
|
86
|
+
connectionClientSecret = crypto_1.default.randomBytes(24).toString('hex');
|
87
|
+
}
|
88
|
+
record.clientSecret = connectionClientSecret;
|
89
|
+
yield connectionStore.put(record.clientID, record, {
|
90
|
+
// secondary index on tenant + product
|
91
|
+
name: utils_1.IndexNames.TenantProduct,
|
92
|
+
value: dbutils.keyFromParts(tenant, product),
|
93
|
+
});
|
94
|
+
return record;
|
95
|
+
}),
|
96
|
+
update: (body, connectionStore, connectionsGetter) => __awaiter(void 0, void 0, void 0, function* () {
|
97
|
+
const { defaultRedirectUrl, redirectUrl, name, description, oidcDiscoveryUrl, oidcClientId, oidcClientSecret } = body, clientInfo = __rest(body, ["defaultRedirectUrl", "redirectUrl", "name", "description", "oidcDiscoveryUrl", "oidcClientId", "oidcClientSecret"]);
|
98
|
+
if (!(clientInfo === null || clientInfo === void 0 ? void 0 : clientInfo.clientID)) {
|
99
|
+
throw new error_1.JacksonError('Please provide clientID', 400);
|
100
|
+
}
|
101
|
+
if (!(clientInfo === null || clientInfo === void 0 ? void 0 : clientInfo.clientSecret)) {
|
102
|
+
throw new error_1.JacksonError('Please provide clientSecret', 400);
|
103
|
+
}
|
104
|
+
if (!(clientInfo === null || clientInfo === void 0 ? void 0 : clientInfo.tenant)) {
|
105
|
+
throw new error_1.JacksonError('Please provide tenant', 400);
|
106
|
+
}
|
107
|
+
if (!(clientInfo === null || clientInfo === void 0 ? void 0 : clientInfo.product)) {
|
108
|
+
throw new error_1.JacksonError('Please provide product', 400);
|
109
|
+
}
|
110
|
+
if (description && description.length > 100) {
|
111
|
+
throw new error_1.JacksonError('Description should not exceed 100 characters', 400);
|
112
|
+
}
|
113
|
+
const redirectUrlList = redirectUrl ? (0, utils_1.extractRedirectUrls)(redirectUrl) : null;
|
114
|
+
(0, utils_1.validateRedirectUrl)({ defaultRedirectUrl, redirectUrlList });
|
115
|
+
const _savedConnection = (yield connectionsGetter(clientInfo))[0];
|
116
|
+
if (_savedConnection.clientSecret !== (clientInfo === null || clientInfo === void 0 ? void 0 : clientInfo.clientSecret)) {
|
117
|
+
throw new error_1.JacksonError('clientSecret mismatch', 400);
|
118
|
+
}
|
119
|
+
let oidcProvider;
|
120
|
+
if (_savedConnection && typeof _savedConnection.oidcProvider === 'object') {
|
121
|
+
oidcProvider = Object.assign({}, _savedConnection.oidcProvider);
|
122
|
+
if (oidcClientId && typeof oidcClientId === 'string') {
|
123
|
+
const clientID = dbutils.keyDigest(dbutils.keyFromParts(clientInfo.tenant, clientInfo.product, oidcClientId));
|
124
|
+
if (clientID !== (clientInfo === null || clientInfo === void 0 ? void 0 : clientInfo.clientID)) {
|
125
|
+
throw new error_1.JacksonError('Tenant/Product config mismatch with OIDC Provider metadata', 400);
|
126
|
+
}
|
127
|
+
}
|
128
|
+
if (oidcClientSecret && typeof oidcClientSecret === 'string') {
|
129
|
+
oidcProvider.clientSecret = oidcClientSecret;
|
130
|
+
}
|
131
|
+
if (oidcDiscoveryUrl && typeof oidcDiscoveryUrl === 'string') {
|
132
|
+
oidcProvider.discoveryUrl = oidcDiscoveryUrl;
|
133
|
+
const providerName = (0, utils_1.extractHostName)(oidcDiscoveryUrl);
|
134
|
+
oidcProvider.provider = providerName ? providerName : 'Unknown';
|
135
|
+
}
|
136
|
+
}
|
137
|
+
const record = Object.assign(Object.assign({}, _savedConnection), { name: name ? name : _savedConnection.name, description: description ? description : _savedConnection.description, defaultRedirectUrl: defaultRedirectUrl ? defaultRedirectUrl : _savedConnection.defaultRedirectUrl, redirectUrl: redirectUrlList ? redirectUrlList : _savedConnection.redirectUrl, oidcProvider: oidcProvider ? oidcProvider : _savedConnection.oidcProvider });
|
138
|
+
yield connectionStore.put(clientInfo === null || clientInfo === void 0 ? void 0 : clientInfo.clientID, record, {
|
139
|
+
// secondary index on tenant + product
|
140
|
+
name: utils_1.IndexNames.TenantProduct,
|
141
|
+
value: dbutils.keyFromParts(_savedConnection.tenant, _savedConnection.product),
|
142
|
+
});
|
143
|
+
}),
|
144
|
+
};
|
145
|
+
exports.default = oidc;
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import { IConnectionAPIController, SAMLSSOConnection, SAMLSSOConnectionWithEncodedMetadata, SAMLSSOConnectionWithRawMetadata, Storable } from '../../typings';
|
2
|
+
declare const saml: {
|
3
|
+
create: (body: SAMLSSOConnectionWithRawMetadata | SAMLSSOConnectionWithEncodedMetadata, connectionStore: Storable) => Promise<Partial<SAMLSSOConnection> & {
|
4
|
+
clientID: string;
|
5
|
+
clientSecret: string;
|
6
|
+
idpMetadata?: Record<string, any> | undefined;
|
7
|
+
certs?: Record<"publicKey" | "privateKey", string> | undefined;
|
8
|
+
}>;
|
9
|
+
update: (body: (SAMLSSOConnectionWithRawMetadata | SAMLSSOConnectionWithEncodedMetadata) & {
|
10
|
+
clientID: string;
|
11
|
+
clientSecret: string;
|
12
|
+
}, connectionStore: Storable, connectionsGetter: IConnectionAPIController['getConnections']) => Promise<void>;
|
13
|
+
};
|
14
|
+
export default saml;
|
@@ -0,0 +1,168 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
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
|
+
};
|
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 __rest = (this && this.__rest) || function (s, e) {
|
35
|
+
var t = {};
|
36
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
37
|
+
t[p] = s[p];
|
38
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
39
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
40
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
41
|
+
t[p[i]] = s[p[i]];
|
42
|
+
}
|
43
|
+
return t;
|
44
|
+
};
|
45
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
46
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
47
|
+
};
|
48
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
49
|
+
const crypto_1 = __importDefault(require("crypto"));
|
50
|
+
const dbutils = __importStar(require("../../db/utils"));
|
51
|
+
const utils_1 = require("../utils");
|
52
|
+
const saml20_1 = __importDefault(require("@boxyhq/saml20"));
|
53
|
+
const x509_1 = __importDefault(require("../../saml/x509"));
|
54
|
+
const error_1 = require("../error");
|
55
|
+
const saml = {
|
56
|
+
create: (body, connectionStore) => __awaiter(void 0, void 0, void 0, function* () {
|
57
|
+
const { encodedRawMetadata, rawMetadata, defaultRedirectUrl, redirectUrl, tenant, product, name, description, } = body;
|
58
|
+
const forceAuthn = body.forceAuthn == 'true' || body.forceAuthn == true;
|
59
|
+
let connectionClientSecret;
|
60
|
+
(0, utils_1.validateSSOConnection)(body, 'saml');
|
61
|
+
const redirectUrlList = (0, utils_1.extractRedirectUrls)(redirectUrl);
|
62
|
+
(0, utils_1.validateRedirectUrl)({ defaultRedirectUrl, redirectUrlList });
|
63
|
+
const record = {
|
64
|
+
defaultRedirectUrl,
|
65
|
+
redirectUrl: redirectUrlList,
|
66
|
+
tenant,
|
67
|
+
product,
|
68
|
+
name,
|
69
|
+
description,
|
70
|
+
clientID: '',
|
71
|
+
clientSecret: '',
|
72
|
+
forceAuthn,
|
73
|
+
};
|
74
|
+
let metaData = rawMetadata;
|
75
|
+
if (encodedRawMetadata) {
|
76
|
+
metaData = Buffer.from(encodedRawMetadata, 'base64').toString();
|
77
|
+
}
|
78
|
+
const idpMetadata = yield saml20_1.default.parseMetadata(metaData, {});
|
79
|
+
// extract provider
|
80
|
+
let providerName = (0, utils_1.extractHostName)(idpMetadata.entityID);
|
81
|
+
if (!providerName) {
|
82
|
+
providerName = (0, utils_1.extractHostName)(idpMetadata.sso.redirectUrl || idpMetadata.sso.postUrl);
|
83
|
+
}
|
84
|
+
idpMetadata.provider = providerName ? providerName : 'Unknown';
|
85
|
+
record.clientID = dbutils.keyDigest(dbutils.keyFromParts(tenant, product, idpMetadata.entityID));
|
86
|
+
const certs = yield x509_1.default.generate();
|
87
|
+
if (!certs) {
|
88
|
+
throw new Error('Error generating x509 certs');
|
89
|
+
}
|
90
|
+
record.idpMetadata = idpMetadata;
|
91
|
+
record.certs = certs;
|
92
|
+
const exists = yield connectionStore.get(record.clientID);
|
93
|
+
if (exists) {
|
94
|
+
connectionClientSecret = exists.clientSecret;
|
95
|
+
}
|
96
|
+
else {
|
97
|
+
connectionClientSecret = crypto_1.default.randomBytes(24).toString('hex');
|
98
|
+
}
|
99
|
+
record.clientSecret = connectionClientSecret;
|
100
|
+
yield connectionStore.put(record.clientID, record, {
|
101
|
+
name: utils_1.IndexNames.EntityID,
|
102
|
+
value: idpMetadata.entityID,
|
103
|
+
}, {
|
104
|
+
// secondary index on tenant + product
|
105
|
+
name: utils_1.IndexNames.TenantProduct,
|
106
|
+
value: dbutils.keyFromParts(tenant, product),
|
107
|
+
});
|
108
|
+
return record;
|
109
|
+
}),
|
110
|
+
update: (body, connectionStore, connectionsGetter) => __awaiter(void 0, void 0, void 0, function* () {
|
111
|
+
const { encodedRawMetadata, // could be empty
|
112
|
+
rawMetadata, // could be empty
|
113
|
+
defaultRedirectUrl, redirectUrl, name, description, forceAuthn = false } = body, clientInfo = __rest(body, ["encodedRawMetadata", "rawMetadata", "defaultRedirectUrl", "redirectUrl", "name", "description", "forceAuthn"]);
|
114
|
+
if (!(clientInfo === null || clientInfo === void 0 ? void 0 : clientInfo.clientID)) {
|
115
|
+
throw new error_1.JacksonError('Please provide clientID', 400);
|
116
|
+
}
|
117
|
+
if (!(clientInfo === null || clientInfo === void 0 ? void 0 : clientInfo.clientSecret)) {
|
118
|
+
throw new error_1.JacksonError('Please provide clientSecret', 400);
|
119
|
+
}
|
120
|
+
if (!(clientInfo === null || clientInfo === void 0 ? void 0 : clientInfo.tenant)) {
|
121
|
+
throw new error_1.JacksonError('Please provide tenant', 400);
|
122
|
+
}
|
123
|
+
if (!(clientInfo === null || clientInfo === void 0 ? void 0 : clientInfo.product)) {
|
124
|
+
throw new error_1.JacksonError('Please provide product', 400);
|
125
|
+
}
|
126
|
+
if (description && description.length > 100) {
|
127
|
+
throw new error_1.JacksonError('Description should not exceed 100 characters', 400);
|
128
|
+
}
|
129
|
+
const redirectUrlList = redirectUrl ? (0, utils_1.extractRedirectUrls)(redirectUrl) : null;
|
130
|
+
(0, utils_1.validateRedirectUrl)({ defaultRedirectUrl, redirectUrlList });
|
131
|
+
const _savedConnection = (yield connectionsGetter(clientInfo))[0];
|
132
|
+
if (_savedConnection.clientSecret !== (clientInfo === null || clientInfo === void 0 ? void 0 : clientInfo.clientSecret)) {
|
133
|
+
throw new error_1.JacksonError('clientSecret mismatch', 400);
|
134
|
+
}
|
135
|
+
let metaData = rawMetadata;
|
136
|
+
if (encodedRawMetadata) {
|
137
|
+
metaData = Buffer.from(encodedRawMetadata, 'base64').toString();
|
138
|
+
}
|
139
|
+
let newMetadata;
|
140
|
+
if (metaData) {
|
141
|
+
newMetadata = yield saml20_1.default.parseMetadata(metaData, {});
|
142
|
+
// extract provider
|
143
|
+
let providerName = (0, utils_1.extractHostName)(newMetadata.entityID);
|
144
|
+
if (!providerName) {
|
145
|
+
providerName = (0, utils_1.extractHostName)(newMetadata.sso.redirectUrl || newMetadata.sso.postUrl);
|
146
|
+
}
|
147
|
+
newMetadata.provider = providerName ? providerName : 'Unknown';
|
148
|
+
}
|
149
|
+
if (newMetadata) {
|
150
|
+
// check if clientID matches with new metadata payload
|
151
|
+
const clientID = dbutils.keyDigest(dbutils.keyFromParts(clientInfo.tenant, clientInfo.product, newMetadata.entityID));
|
152
|
+
if (clientID !== (clientInfo === null || clientInfo === void 0 ? void 0 : clientInfo.clientID)) {
|
153
|
+
throw new error_1.JacksonError('Tenant/Product config mismatch with IdP metadata', 400);
|
154
|
+
}
|
155
|
+
}
|
156
|
+
const record = Object.assign(Object.assign({}, _savedConnection), { name: name ? name : _savedConnection.name, description: description ? description : _savedConnection.description, idpMetadata: newMetadata ? newMetadata : _savedConnection.idpMetadata, defaultRedirectUrl: defaultRedirectUrl ? defaultRedirectUrl : _savedConnection.defaultRedirectUrl, redirectUrl: redirectUrlList ? redirectUrlList : _savedConnection.redirectUrl, forceAuthn });
|
157
|
+
yield connectionStore.put(clientInfo === null || clientInfo === void 0 ? void 0 : clientInfo.clientID, record, {
|
158
|
+
// secondary index on entityID
|
159
|
+
name: utils_1.IndexNames.EntityID,
|
160
|
+
value: _savedConnection.idpMetadata.entityID,
|
161
|
+
}, {
|
162
|
+
// secondary index on tenant + product
|
163
|
+
name: utils_1.IndexNames.TenantProduct,
|
164
|
+
value: dbutils.keyFromParts(_savedConnection.tenant, _savedConnection.product),
|
165
|
+
});
|
166
|
+
}),
|
167
|
+
};
|
168
|
+
exports.default = saml;
|
@@ -1,10 +1,10 @@
|
|
1
1
|
import { SAMLResponsePayload, SLORequestParams } from '../typings';
|
2
2
|
export declare class LogoutController {
|
3
|
-
private
|
3
|
+
private connectionStore;
|
4
4
|
private sessionStore;
|
5
5
|
private opts;
|
6
|
-
constructor({
|
7
|
-
|
6
|
+
constructor({ connectionStore, sessionStore, opts }: {
|
7
|
+
connectionStore: any;
|
8
8
|
sessionStore: any;
|
9
9
|
opts: any;
|
10
10
|
});
|
@@ -50,29 +50,29 @@ const deflateRawAsync = (0, util_1.promisify)(zlib_1.deflateRaw);
|
|
50
50
|
const relayStatePrefix = 'boxyhq_jackson_';
|
51
51
|
const logoutXPath = "/*[local-name(.)='LogoutRequest']";
|
52
52
|
class LogoutController {
|
53
|
-
constructor({
|
53
|
+
constructor({ connectionStore, sessionStore, opts }) {
|
54
54
|
this.opts = opts;
|
55
|
-
this.
|
55
|
+
this.connectionStore = connectionStore;
|
56
56
|
this.sessionStore = sessionStore;
|
57
57
|
}
|
58
58
|
// Create SLO Request
|
59
59
|
createRequest({ nameId, tenant, product, redirectUrl }) {
|
60
60
|
return __awaiter(this, void 0, void 0, function* () {
|
61
|
-
let
|
61
|
+
let samlConnection = null;
|
62
62
|
if (tenant && product) {
|
63
|
-
const
|
63
|
+
const samlConnections = yield this.connectionStore.getByIndex({
|
64
64
|
name: utils_1.IndexNames.TenantProduct,
|
65
65
|
value: dbutils.keyFromParts(tenant, product),
|
66
66
|
});
|
67
|
-
if (!
|
68
|
-
throw new error_1.JacksonError('SAML
|
67
|
+
if (!samlConnections || samlConnections.length === 0) {
|
68
|
+
throw new error_1.JacksonError('SAML connection not found.', 403);
|
69
69
|
}
|
70
|
-
|
70
|
+
samlConnection = samlConnections[0];
|
71
71
|
}
|
72
|
-
if (!
|
73
|
-
throw new error_1.JacksonError('SAML
|
72
|
+
if (!samlConnection) {
|
73
|
+
throw new error_1.JacksonError('SAML connection not found.', 403);
|
74
74
|
}
|
75
|
-
const { idpMetadata: { slo, provider }, certs: { privateKey, publicKey }, } =
|
75
|
+
const { idpMetadata: { slo, provider }, certs: { privateKey, publicKey }, } = samlConnection;
|
76
76
|
if ('redirectUrl' in slo === false && 'postUrl' in slo === false) {
|
77
77
|
throw new error_1.JacksonError(`${provider} doesn't support SLO or disabled by IdP.`, 400);
|
78
78
|
}
|
@@ -126,14 +126,14 @@ class LogoutController {
|
|
126
126
|
if (parsedResponse.inResponseTo !== session.id) {
|
127
127
|
throw new error_1.JacksonError(`SLO failed with mismatched request ID.`, 400);
|
128
128
|
}
|
129
|
-
const
|
129
|
+
const samlConnections = yield this.connectionStore.getByIndex({
|
130
130
|
name: utils_1.IndexNames.EntityID,
|
131
131
|
value: parsedResponse.issuer,
|
132
132
|
});
|
133
|
-
if (!
|
134
|
-
throw new error_1.JacksonError('SAML
|
133
|
+
if (!samlConnections || samlConnections.length === 0) {
|
134
|
+
throw new error_1.JacksonError('SAML connection not found.', 403);
|
135
135
|
}
|
136
|
-
const { idpMetadata, defaultRedirectUrl } =
|
136
|
+
const { idpMetadata, defaultRedirectUrl } = samlConnections[0];
|
137
137
|
if (!(yield saml20_1.default.validateSignature(rawResponse, null, idpMetadata.thumbprint))) {
|
138
138
|
throw new error_1.JacksonError('Invalid signature.', 403);
|
139
139
|
}
|
@@ -1,19 +1,19 @@
|
|
1
|
-
import { IOAuthController,
|
1
|
+
import type { OIDCAuthzResponsePayload, IOAuthController, OAuthReq, OAuthTokenReq, OAuthTokenRes, Profile, SAMLResponsePayload } from '../typings';
|
2
2
|
export declare class OAuthController implements IOAuthController {
|
3
|
-
private
|
3
|
+
private connectionStore;
|
4
4
|
private sessionStore;
|
5
5
|
private codeStore;
|
6
6
|
private tokenStore;
|
7
7
|
private opts;
|
8
|
-
constructor({
|
9
|
-
|
8
|
+
constructor({ connectionStore, sessionStore, codeStore, tokenStore, opts }: {
|
9
|
+
connectionStore: any;
|
10
10
|
sessionStore: any;
|
11
11
|
codeStore: any;
|
12
12
|
tokenStore: any;
|
13
13
|
opts: any;
|
14
14
|
});
|
15
|
-
private
|
16
|
-
authorize(body:
|
15
|
+
private resolveMultipleConnectionMatches;
|
16
|
+
authorize(body: OAuthReq): Promise<{
|
17
17
|
redirect_url?: string;
|
18
18
|
authorize_form?: string;
|
19
19
|
}>;
|
@@ -21,6 +21,10 @@ export declare class OAuthController implements IOAuthController {
|
|
21
21
|
redirect_url?: string;
|
22
22
|
app_select_form?: string;
|
23
23
|
}>;
|
24
|
+
private extractOIDCUserProfile;
|
25
|
+
oidcAuthzResponse(body: OIDCAuthzResponsePayload): Promise<{
|
26
|
+
redirect_url?: string;
|
27
|
+
}>;
|
24
28
|
/**
|
25
29
|
* @swagger
|
26
30
|
*
|
@@ -42,13 +46,17 @@ export declare class OAuthController implements IOAuthController {
|
|
42
46
|
* - name: client_id
|
43
47
|
* in: formData
|
44
48
|
* type: string
|
45
|
-
* description: Use the client_id returned by the SAML
|
49
|
+
* description: Use the client_id returned by the SAML connection API
|
46
50
|
* required: true
|
47
51
|
* - name: client_secret
|
48
52
|
* in: formData
|
49
53
|
* type: string
|
50
|
-
* description: Use the client_secret returned by the SAML
|
54
|
+
* description: Use the client_secret returned by the SAML connection API
|
51
55
|
* required: true
|
56
|
+
* - name: code_verifier
|
57
|
+
* in: formData
|
58
|
+
* type: string
|
59
|
+
* description: code_verifier against the code_challenge in the authz request (relevant to PKCE flow)
|
52
60
|
* - name: redirect_uri
|
53
61
|
* in: formData
|
54
62
|
* type: string
|
@@ -100,11 +108,21 @@ export declare class OAuthController implements IOAuthController {
|
|
100
108
|
* type: string
|
101
109
|
* lastName:
|
102
110
|
* type: string
|
111
|
+
* raw:
|
112
|
+
* type: object
|
113
|
+
* requested:
|
114
|
+
* type: object
|
103
115
|
* example:
|
104
116
|
* id: 32b5af58fdf
|
105
117
|
* email: jackson@coolstartup.com
|
106
118
|
* firstName: SAML
|
107
119
|
* lastName: Jackson
|
120
|
+
* raw: {
|
121
|
+
*
|
122
|
+
* }
|
123
|
+
* requested: {
|
124
|
+
*
|
125
|
+
* }
|
108
126
|
*/
|
109
127
|
userInfo(token: string): Promise<Profile>;
|
110
128
|
}
|