@boxyhq/saml-jackson 1.2.2 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 -378
- 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 +361 -140
- package/dist/controller/utils.d.ts +10 -2
- package/dist/controller/utils.js +88 -1
- 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/typings.d.ts +109 -35
- package/package.json +3 -2
- 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
|
}
|