@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
@@ -1,8 +1,9 @@
|
|
1
|
-
import type { OAuthErrorHandlerParams } from '../typings';
|
1
|
+
import type { ConnectionType, OAuthErrorHandlerParams, OIDCSSOConnection, SAMLSSOConnectionWithEncodedMetadata, SAMLSSOConnectionWithRawMetadata } from '../typings';
|
2
2
|
import * as jose from 'jose';
|
3
3
|
export declare enum IndexNames {
|
4
4
|
EntityID = "entityID",
|
5
|
-
TenantProduct = "tenantProduct"
|
5
|
+
TenantProduct = "tenantProduct",
|
6
|
+
OIDCProviderClientID = "OIDCProviderClientID"
|
6
7
|
}
|
7
8
|
export declare const storeNamespacePrefix: {
|
8
9
|
dsync: {
|
@@ -29,3 +30,10 @@ export declare function isJWSKeyPairLoaded(jwsKeyPair: {
|
|
29
30
|
export declare const importJWTPublicKey: (key: string, jwsAlg: string) => Promise<jose.KeyLike>;
|
30
31
|
export declare const exportPublicKeyJWK: (key: jose.KeyLike) => Promise<jose.JWK>;
|
31
32
|
export declare const generateJwkThumbprint: (jwk: jose.JWK) => Promise<string>;
|
33
|
+
export declare const validateSSOConnection: (body: SAMLSSOConnectionWithRawMetadata | SAMLSSOConnectionWithEncodedMetadata | OIDCSSOConnection, strategy: ConnectionType) => void;
|
34
|
+
export declare const validateRedirectUrl: ({ redirectUrlList, defaultRedirectUrl }: {
|
35
|
+
redirectUrlList: any;
|
36
|
+
defaultRedirectUrl: any;
|
37
|
+
}) => void;
|
38
|
+
export declare const extractRedirectUrls: (urls: string[] | string) => string[];
|
39
|
+
export declare const extractHostName: (url: string) => string | null;
|
package/dist/controller/utils.js
CHANGED
@@ -35,7 +35,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
35
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
36
36
|
};
|
37
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
38
|
-
exports.generateJwkThumbprint = exports.exportPublicKeyJWK = exports.importJWTPublicKey = exports.isJWSKeyPairLoaded = exports.loadJWSPrivateKey = exports.createRandomSecret = exports.getErrorMessage = exports.OAuthErrorResponse = exports.validateAbsoluteUrl = exports.relayStatePrefix = exports.storeNamespacePrefix = exports.IndexNames = void 0;
|
38
|
+
exports.extractHostName = exports.extractRedirectUrls = exports.validateRedirectUrl = exports.validateSSOConnection = exports.generateJwkThumbprint = exports.exportPublicKeyJWK = exports.importJWTPublicKey = exports.isJWSKeyPairLoaded = exports.loadJWSPrivateKey = exports.createRandomSecret = exports.getErrorMessage = exports.OAuthErrorResponse = exports.validateAbsoluteUrl = exports.relayStatePrefix = exports.storeNamespacePrefix = exports.IndexNames = void 0;
|
39
39
|
const error_1 = require("./error");
|
40
40
|
const redirect = __importStar(require("./oauth/redirect"));
|
41
41
|
const crypto_1 = __importDefault(require("crypto"));
|
@@ -44,6 +44,7 @@ var IndexNames;
|
|
44
44
|
(function (IndexNames) {
|
45
45
|
IndexNames["EntityID"] = "entityID";
|
46
46
|
IndexNames["TenantProduct"] = "tenantProduct";
|
47
|
+
IndexNames["OIDCProviderClientID"] = "OIDCProviderClientID";
|
47
48
|
})(IndexNames = exports.IndexNames || (exports.IndexNames = {}));
|
48
49
|
// The namespace prefix for the database store
|
49
50
|
exports.storeNamespacePrefix = {
|
@@ -120,3 +121,89 @@ const generateJwkThumbprint = (jwk) => __awaiter(void 0, void 0, void 0, functio
|
|
120
121
|
return thumbprint;
|
121
122
|
});
|
122
123
|
exports.generateJwkThumbprint = generateJwkThumbprint;
|
124
|
+
const validateSSOConnection = (body, strategy) => {
|
125
|
+
const { defaultRedirectUrl, redirectUrl, tenant, product, description } = body;
|
126
|
+
const encodedRawMetadata = 'encodedRawMetadata' in body ? body.encodedRawMetadata : undefined;
|
127
|
+
const rawMetadata = 'rawMetadata' in body ? body.rawMetadata : undefined;
|
128
|
+
const oidcDiscoveryUrl = 'oidcDiscoveryUrl' in body ? body.oidcDiscoveryUrl : undefined;
|
129
|
+
const oidcClientId = 'oidcClientId' in body ? body.oidcClientId : undefined;
|
130
|
+
const oidcClientSecret = 'oidcClientSecret' in body ? body.oidcClientSecret : undefined;
|
131
|
+
if (strategy !== 'saml' && strategy !== 'oidc') {
|
132
|
+
throw new error_1.JacksonError(`Strategy: ${strategy} not supported`, 400);
|
133
|
+
}
|
134
|
+
if (strategy === 'saml') {
|
135
|
+
if (!rawMetadata && !encodedRawMetadata) {
|
136
|
+
throw new error_1.JacksonError('Please provide rawMetadata or encodedRawMetadata', 400);
|
137
|
+
}
|
138
|
+
}
|
139
|
+
if (strategy === 'oidc') {
|
140
|
+
if (!oidcClientId) {
|
141
|
+
throw new error_1.JacksonError('Please provide the clientId from OpenID Provider', 400);
|
142
|
+
}
|
143
|
+
if (!oidcClientSecret) {
|
144
|
+
throw new error_1.JacksonError('Please provide the clientSecret from OpenID Provider', 400);
|
145
|
+
}
|
146
|
+
if (!oidcDiscoveryUrl) {
|
147
|
+
throw new error_1.JacksonError('Please provide the discoveryUrl for the OpenID Provider', 400);
|
148
|
+
}
|
149
|
+
}
|
150
|
+
if (!defaultRedirectUrl) {
|
151
|
+
throw new error_1.JacksonError('Please provide a defaultRedirectUrl', 400);
|
152
|
+
}
|
153
|
+
if (!redirectUrl) {
|
154
|
+
throw new error_1.JacksonError('Please provide redirectUrl', 400);
|
155
|
+
}
|
156
|
+
if (!tenant) {
|
157
|
+
throw new error_1.JacksonError('Please provide tenant', 400);
|
158
|
+
}
|
159
|
+
if (!product) {
|
160
|
+
throw new error_1.JacksonError('Please provide product', 400);
|
161
|
+
}
|
162
|
+
if (description && description.length > 100) {
|
163
|
+
throw new error_1.JacksonError('Description should not exceed 100 characters', 400);
|
164
|
+
}
|
165
|
+
};
|
166
|
+
exports.validateSSOConnection = validateSSOConnection;
|
167
|
+
const validateRedirectUrl = ({ redirectUrlList, defaultRedirectUrl }) => {
|
168
|
+
if (redirectUrlList) {
|
169
|
+
if (redirectUrlList.length > 100) {
|
170
|
+
throw new error_1.JacksonError('Exceeded maximum number of allowed redirect urls', 400);
|
171
|
+
}
|
172
|
+
for (const url of redirectUrlList) {
|
173
|
+
(0, exports.validateAbsoluteUrl)(url, 'redirectUrl is invalid');
|
174
|
+
}
|
175
|
+
}
|
176
|
+
if (defaultRedirectUrl) {
|
177
|
+
(0, exports.validateAbsoluteUrl)(defaultRedirectUrl, 'defaultRedirectUrl is invalid');
|
178
|
+
}
|
179
|
+
};
|
180
|
+
exports.validateRedirectUrl = validateRedirectUrl;
|
181
|
+
const extractRedirectUrls = (urls) => {
|
182
|
+
if (!urls) {
|
183
|
+
return [];
|
184
|
+
}
|
185
|
+
if (typeof urls === 'string') {
|
186
|
+
if (urls.startsWith('[')) {
|
187
|
+
// redirectUrl is a stringified array
|
188
|
+
return JSON.parse(urls);
|
189
|
+
}
|
190
|
+
// redirectUrl is a single URL
|
191
|
+
return [urls];
|
192
|
+
}
|
193
|
+
// redirectUrl is an array of URLs
|
194
|
+
return urls;
|
195
|
+
};
|
196
|
+
exports.extractRedirectUrls = extractRedirectUrls;
|
197
|
+
const extractHostName = (url) => {
|
198
|
+
try {
|
199
|
+
const pUrl = new URL(url);
|
200
|
+
if (pUrl.hostname.startsWith('www.')) {
|
201
|
+
return pUrl.hostname.substring(4);
|
202
|
+
}
|
203
|
+
return pUrl.hostname;
|
204
|
+
}
|
205
|
+
catch (err) {
|
206
|
+
return null;
|
207
|
+
}
|
208
|
+
};
|
209
|
+
exports.extractHostName = extractHostName;
|
package/dist/index.d.ts
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
import type { DirectorySync, JacksonOption } from './typings';
|
2
2
|
import { AdminController } from './controller/admin';
|
3
|
-
import {
|
3
|
+
import { ConnectionAPIController } from './controller/api';
|
4
4
|
import { OAuthController } from './controller/oauth';
|
5
5
|
import { HealthCheckController } from './controller/health-check';
|
6
6
|
import { LogoutController } from './controller/logout';
|
7
7
|
import { OidcDiscoveryController } from './controller/oidc-discovery';
|
8
8
|
import { SPSAMLConfig } from './controller/sp-config';
|
9
9
|
export declare const controllers: (opts: JacksonOption) => Promise<{
|
10
|
-
apiController:
|
10
|
+
apiController: ConnectionAPIController;
|
11
|
+
connectionAPIController: ConnectionAPIController;
|
11
12
|
oauthController: OAuthController;
|
12
13
|
adminController: AdminController;
|
13
14
|
logoutController: LogoutController;
|
package/dist/index.js
CHANGED
@@ -29,7 +29,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.controllers = void 0;
|
30
30
|
const db_1 = __importDefault(require("./db/db"));
|
31
31
|
const defaultDb_1 = __importDefault(require("./db/defaultDb"));
|
32
|
-
const
|
32
|
+
const loadConnection_1 = __importDefault(require("./loadConnection"));
|
33
33
|
const admin_1 = require("./controller/admin");
|
34
34
|
const api_1 = require("./controller/api");
|
35
35
|
const oauth_1 = require("./controller/oauth");
|
@@ -47,8 +47,13 @@ const defaultOpts = (opts) => {
|
|
47
47
|
throw new Error('samlPath is required');
|
48
48
|
}
|
49
49
|
newOpts.scimPath = newOpts.scimPath || '/api/scim/v2.0';
|
50
|
+
if (!newOpts.oidcPath) {
|
51
|
+
throw new Error('oidcPath is required');
|
52
|
+
}
|
50
53
|
newOpts.samlAudience = newOpts.samlAudience || 'https://saml.boxyhq.com';
|
51
|
-
|
54
|
+
// path to folder containing static IdP connections that will be preloaded. This is useful for self-hosted deployments that only have to support a single tenant (or small number of known tenants).
|
55
|
+
newOpts.preLoadedConnection = newOpts.preLoadedConnection || '';
|
56
|
+
newOpts.preLoadedConfig = newOpts.preLoadedConfig || ''; // for backwards compatibility
|
52
57
|
newOpts.idpEnabled = newOpts.idpEnabled === true;
|
53
58
|
(0, defaultDb_1.default)(newOpts);
|
54
59
|
newOpts.clientSecretVerifier = newOpts.clientSecretVerifier || 'dummy';
|
@@ -60,43 +65,50 @@ const defaultOpts = (opts) => {
|
|
60
65
|
const controllers = (opts) => __awaiter(void 0, void 0, void 0, function* () {
|
61
66
|
opts = defaultOpts(opts);
|
62
67
|
const db = yield db_1.default.new(opts.db);
|
63
|
-
const
|
68
|
+
const connectionStore = db.store('saml:config');
|
64
69
|
const sessionStore = db.store('oauth:session', opts.db.ttl);
|
65
70
|
const codeStore = db.store('oauth:code', opts.db.ttl);
|
66
71
|
const tokenStore = db.store('oauth:token', opts.db.ttl);
|
67
72
|
const healthCheckStore = db.store('_health:check');
|
68
|
-
const
|
69
|
-
const adminController = new admin_1.AdminController({
|
73
|
+
const connectionAPIController = new api_1.ConnectionAPIController({ connectionStore });
|
74
|
+
const adminController = new admin_1.AdminController({ connectionStore });
|
70
75
|
const healthCheckController = new health_check_1.HealthCheckController({ healthCheckStore });
|
71
76
|
yield healthCheckController.init();
|
72
77
|
const oauthController = new oauth_1.OAuthController({
|
73
|
-
|
78
|
+
connectionStore,
|
74
79
|
sessionStore,
|
75
80
|
codeStore,
|
76
81
|
tokenStore,
|
77
82
|
opts,
|
78
83
|
});
|
79
84
|
const logoutController = new logout_1.LogoutController({
|
80
|
-
|
85
|
+
connectionStore,
|
81
86
|
sessionStore,
|
82
87
|
opts,
|
83
88
|
});
|
84
89
|
const directorySync = yield (0, directory_sync_1.default)({ db, opts });
|
85
90
|
const oidcDiscoveryController = new oidc_discovery_1.OidcDiscoveryController({ opts });
|
86
91
|
const spConfig = new sp_config_1.SPSAMLConfig(opts);
|
87
|
-
// write pre-loaded
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
92
|
+
// write pre-loaded connections if present
|
93
|
+
const preLoadedConnection = opts.preLoadedConnection || opts.preLoadedConfig;
|
94
|
+
if (preLoadedConnection && preLoadedConnection.length > 0) {
|
95
|
+
const connections = yield (0, loadConnection_1.default)(preLoadedConnection);
|
96
|
+
for (const connection of connections) {
|
97
|
+
if ('oidcDiscoveryUrl' in connection) {
|
98
|
+
yield connectionAPIController.createOIDCConnection(connection);
|
99
|
+
}
|
100
|
+
else {
|
101
|
+
yield connectionAPIController.createSAMLConnection(connection);
|
102
|
+
}
|
103
|
+
console.log(`loaded connection for tenant "${connection.tenant}" and product "${connection.product}"`);
|
93
104
|
}
|
94
105
|
}
|
95
106
|
const type = opts.db.engine === 'sql' && opts.db.type ? ' Type: ' + opts.db.type : '';
|
96
107
|
console.log(`Using engine: ${opts.db.engine}.${type}`);
|
97
108
|
return {
|
98
109
|
spConfig,
|
99
|
-
apiController,
|
110
|
+
apiController: connectionAPIController,
|
111
|
+
connectionAPIController,
|
100
112
|
oauthController,
|
101
113
|
adminController,
|
102
114
|
logoutController,
|
@@ -0,0 +1,3 @@
|
|
1
|
+
import { OIDCSSOConnection, SAMLSSOConnectionWithEncodedMetadata, SAMLSSOConnectionWithRawMetadata } from './typings';
|
2
|
+
declare const loadConnection: (preLoadedConnection: string) => Promise<(SAMLSSOConnectionWithEncodedMetadata | SAMLSSOConnectionWithRawMetadata | OIDCSSOConnection)[]>;
|
3
|
+
export default loadConnection;
|
@@ -34,22 +34,23 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
34
34
|
Object.defineProperty(exports, "__esModule", { value: true });
|
35
35
|
const fs = __importStar(require("fs"));
|
36
36
|
const path = __importStar(require("path"));
|
37
|
-
const
|
38
|
-
if (
|
39
|
-
|
37
|
+
const loadConnection = (preLoadedConnection) => __awaiter(void 0, void 0, void 0, function* () {
|
38
|
+
if (preLoadedConnection.startsWith('./')) {
|
39
|
+
preLoadedConnection = path.resolve(process.cwd(), preLoadedConnection);
|
40
40
|
}
|
41
|
-
const files = yield fs.promises.readdir(
|
42
|
-
const
|
41
|
+
const files = yield fs.promises.readdir(preLoadedConnection);
|
42
|
+
const connections = [];
|
43
43
|
for (const idx in files) {
|
44
44
|
const file = files[idx];
|
45
45
|
if (file.endsWith('.js')) {
|
46
|
-
const { default:
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
46
|
+
const { default: connection, } = yield Promise.resolve().then(() => __importStar(require(/* webpackIgnore: true */ path.join(preLoadedConnection, file))));
|
47
|
+
if (!('oidcDiscoveryUrl' in connection)) {
|
48
|
+
const rawMetadata = yield fs.promises.readFile(path.join(preLoadedConnection, path.parse(file).name + '.xml'), 'utf8');
|
49
|
+
connection.encodedRawMetadata = Buffer.from(rawMetadata, 'utf8').toString('base64');
|
50
|
+
}
|
51
|
+
connections.push(connection);
|
51
52
|
}
|
52
53
|
}
|
53
|
-
return
|
54
|
+
return connections;
|
54
55
|
});
|
55
|
-
exports.default =
|
56
|
+
exports.default = loadConnection;
|
@@ -3,29 +3,29 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.increment = void 0;
|
4
4
|
const api_metrics_1 = require("@opentelemetry/api-metrics");
|
5
5
|
const counters = {
|
6
|
-
|
7
|
-
name: 'jackson.
|
8
|
-
description: 'Number of
|
6
|
+
createConnection: {
|
7
|
+
name: 'jackson.connection.create',
|
8
|
+
description: 'Number of IdP connection create requests',
|
9
9
|
},
|
10
|
-
|
11
|
-
name: 'jackson.
|
12
|
-
description: 'Number of
|
10
|
+
getConnections: {
|
11
|
+
name: 'jackson.connections.get',
|
12
|
+
description: 'Number of IdP connections get requests',
|
13
13
|
},
|
14
|
-
|
15
|
-
name: 'jackson.
|
16
|
-
description: 'Number of
|
14
|
+
deleteConnections: {
|
15
|
+
name: 'jackson.connections.delete',
|
16
|
+
description: 'Number of IdP connections delete requests',
|
17
17
|
},
|
18
18
|
oauthAuthorize: {
|
19
19
|
name: 'jackson.oauth.authorize',
|
20
|
-
description: 'Number of
|
20
|
+
description: 'Number of oauth authorize requests',
|
21
21
|
},
|
22
22
|
oauthToken: {
|
23
23
|
name: 'jackson.oauth.token',
|
24
|
-
description: 'Number of
|
24
|
+
description: 'Number of oauth token requests',
|
25
25
|
},
|
26
26
|
oauthUserInfo: {
|
27
27
|
name: 'jackson.oauth.userinfo',
|
28
|
-
description: 'Number of
|
28
|
+
description: 'Number of oauth user info requests',
|
29
29
|
},
|
30
30
|
};
|
31
31
|
const createCounter = (action) => {
|
package/dist/typings.d.ts
CHANGED
@@ -1,32 +1,68 @@
|
|
1
1
|
import { type JWK } from 'jose';
|
2
|
-
|
2
|
+
interface SSOConnection {
|
3
3
|
defaultRedirectUrl: string;
|
4
4
|
redirectUrl: string[] | string;
|
5
5
|
tenant: string;
|
6
6
|
product: string;
|
7
7
|
name?: string;
|
8
8
|
description?: string;
|
9
|
-
|
10
|
-
|
11
|
-
forceAuthn
|
9
|
+
}
|
10
|
+
export interface SAMLSSOConnection extends SSOConnection {
|
11
|
+
forceAuthn?: boolean | string;
|
12
|
+
}
|
13
|
+
export interface SAMLSSOConnectionWithRawMetadata extends SAMLSSOConnection {
|
14
|
+
rawMetadata: string;
|
15
|
+
encodedRawMetadata?: never;
|
16
|
+
}
|
17
|
+
export interface SAMLSSOConnectionWithEncodedMetadata extends SAMLSSOConnection {
|
18
|
+
rawMetadata?: never;
|
19
|
+
encodedRawMetadata: string;
|
20
|
+
}
|
21
|
+
export interface OIDCSSOConnection extends SSOConnection {
|
22
|
+
oidcDiscoveryUrl: string;
|
23
|
+
oidcClientId: string;
|
24
|
+
oidcClientSecret: string;
|
25
|
+
}
|
26
|
+
export declare type ConnectionType = 'saml' | 'oidc';
|
27
|
+
declare type ClientIDQuery = {
|
28
|
+
clientID: string;
|
12
29
|
};
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
30
|
+
declare type TenantQuery = {
|
31
|
+
tenant: string;
|
32
|
+
product: string;
|
33
|
+
strategy?: ConnectionType;
|
34
|
+
};
|
35
|
+
export declare type GetConnectionsQuery = ClientIDQuery | TenantQuery;
|
36
|
+
export declare type DelConnectionsQuery = (ClientIDQuery & {
|
37
|
+
clientSecret: string;
|
38
|
+
}) | TenantQuery;
|
39
|
+
export declare type GetConfigQuery = ClientIDQuery | Omit<TenantQuery, 'strategy'>;
|
40
|
+
export declare type DelConfigQuery = (ClientIDQuery & {
|
41
|
+
clientSecret: string;
|
42
|
+
}) | Omit<TenantQuery, 'strategy'>;
|
43
|
+
export interface IConnectionAPIController {
|
44
|
+
config(body: SAMLSSOConnection): Promise<any>;
|
45
|
+
createSAMLConnection(body: SAMLSSOConnectionWithRawMetadata | SAMLSSOConnectionWithEncodedMetadata): Promise<any>;
|
46
|
+
createOIDCConnection(body: OIDCSSOConnection): Promise<any>;
|
47
|
+
updateConfig(body: SAMLSSOConnection & {
|
48
|
+
clientID: string;
|
49
|
+
clientSecret: string;
|
50
|
+
}): Promise<any>;
|
51
|
+
updateSAMLConnection(body: (SAMLSSOConnectionWithRawMetadata | SAMLSSOConnectionWithEncodedMetadata) & {
|
52
|
+
clientID: string;
|
53
|
+
clientSecret: string;
|
54
|
+
}): Promise<any>;
|
55
|
+
updateOIDCConnection(body: OIDCSSOConnection & {
|
56
|
+
clientID: string;
|
57
|
+
clientSecret: string;
|
20
58
|
}): Promise<any>;
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
product?: string;
|
26
|
-
}): Promise<void>;
|
59
|
+
getConnections(body: GetConnectionsQuery): Promise<Array<any>>;
|
60
|
+
getConfig(body: GetConfigQuery): Promise<any>;
|
61
|
+
deleteConnections(body: DelConnectionsQuery): Promise<void>;
|
62
|
+
deleteConfig(body: DelConfigQuery): Promise<void>;
|
27
63
|
}
|
28
64
|
export interface IOAuthController {
|
29
|
-
authorize(body:
|
65
|
+
authorize(body: OAuthReq): Promise<{
|
30
66
|
redirect_url?: string;
|
31
67
|
authorize_form?: string;
|
32
68
|
}>;
|
@@ -34,11 +70,14 @@ export interface IOAuthController {
|
|
34
70
|
redirect_url?: string;
|
35
71
|
app_select_form?: string;
|
36
72
|
}>;
|
73
|
+
oidcAuthzResponse(body: OIDCAuthzResponsePayload): Promise<{
|
74
|
+
redirect_url?: string;
|
75
|
+
}>;
|
37
76
|
token(body: OAuthTokenReq): Promise<OAuthTokenRes>;
|
38
77
|
userInfo(token: string): Promise<Profile>;
|
39
78
|
}
|
40
79
|
export interface IAdminController {
|
41
|
-
|
80
|
+
getAllConnection(pageOffset?: number, pageLimit?: number): any;
|
42
81
|
}
|
43
82
|
export interface IHealthCheckController {
|
44
83
|
status(): Promise<{
|
@@ -71,35 +110,67 @@ export interface IOidcDiscoveryController {
|
|
71
110
|
}>;
|
72
111
|
}
|
73
112
|
export interface OAuthReqBody {
|
113
|
+
state: string;
|
74
114
|
response_type: 'code';
|
75
|
-
client_id: string;
|
76
115
|
redirect_uri: string;
|
77
|
-
state: string;
|
78
|
-
tenant?: string;
|
79
|
-
product?: string;
|
80
|
-
access_type?: string;
|
81
|
-
resource?: string;
|
82
|
-
scope?: string;
|
83
|
-
nonce?: string;
|
84
116
|
code_challenge: string;
|
85
117
|
code_challenge_method: 'plain' | 'S256' | '';
|
86
|
-
|
118
|
+
scope?: string;
|
119
|
+
nonce?: string;
|
87
120
|
idp_hint?: string;
|
88
121
|
prompt?: string;
|
89
122
|
}
|
123
|
+
export interface OAuthReqBodyWithClientId extends OAuthReqBody {
|
124
|
+
client_id: string;
|
125
|
+
}
|
126
|
+
export interface OAuthReqBodyWithTenantProduct extends OAuthReqBody {
|
127
|
+
client_id: 'dummy';
|
128
|
+
tenant: string;
|
129
|
+
product: string;
|
130
|
+
}
|
131
|
+
export interface OAuthReqBodyWithAccessType extends OAuthReqBody {
|
132
|
+
client_id: 'dummy';
|
133
|
+
access_type: string;
|
134
|
+
}
|
135
|
+
export interface OAuthReqBodyWithResource extends OAuthReqBody {
|
136
|
+
client_id: 'dummy';
|
137
|
+
resource: string;
|
138
|
+
}
|
139
|
+
export declare type OAuthReq = OAuthReqBodyWithClientId | OAuthReqBodyWithTenantProduct | OAuthReqBodyWithAccessType | OAuthReqBodyWithResource;
|
90
140
|
export interface SAMLResponsePayload {
|
91
141
|
SAMLResponse: string;
|
92
142
|
RelayState: string;
|
93
143
|
idp_hint?: string;
|
94
144
|
}
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
145
|
+
interface OIDCAuthzResponseSuccess {
|
146
|
+
code: string;
|
147
|
+
state: string;
|
148
|
+
error?: never;
|
149
|
+
error_description?: never;
|
150
|
+
}
|
151
|
+
interface OIDCAuthzResponseError {
|
152
|
+
code?: never;
|
153
|
+
state: string;
|
154
|
+
error: OAuthErrorHandlerParams['error'] | OIDCErrorCodes;
|
155
|
+
error_description?: string;
|
156
|
+
}
|
157
|
+
export declare type OIDCAuthzResponsePayload = OIDCAuthzResponseSuccess | OIDCAuthzResponseError;
|
158
|
+
interface OAuthTokenReqBody {
|
99
159
|
code: string;
|
100
160
|
grant_type: 'authorization_code';
|
101
|
-
redirect_uri
|
161
|
+
redirect_uri: string;
|
162
|
+
}
|
163
|
+
export interface OAuthTokenReqWithCodeVerifier extends OAuthTokenReqBody {
|
164
|
+
code_verifier: string;
|
165
|
+
client_id?: never;
|
166
|
+
client_secret?: never;
|
167
|
+
}
|
168
|
+
export interface OAuthTokenReqWithCredentials extends OAuthTokenReqBody {
|
169
|
+
code_verifier?: never;
|
170
|
+
client_id: string;
|
171
|
+
client_secret: string;
|
102
172
|
}
|
173
|
+
export declare type OAuthTokenReq = OAuthTokenReqWithCodeVerifier | OAuthTokenReqWithCredentials;
|
103
174
|
export interface OAuthTokenRes {
|
104
175
|
access_token: string;
|
105
176
|
id_token?: string;
|
@@ -156,8 +227,10 @@ export interface DatabaseOption {
|
|
156
227
|
export interface JacksonOption {
|
157
228
|
externalUrl: string;
|
158
229
|
samlPath: string;
|
230
|
+
oidcPath: string;
|
159
231
|
samlAudience?: string;
|
160
232
|
preLoadedConfig?: string;
|
233
|
+
preLoadedConnection?: string;
|
161
234
|
idpEnabled?: boolean;
|
162
235
|
db: DatabaseOption;
|
163
236
|
clientSecretVerifier?: string;
|
@@ -191,7 +264,7 @@ interface Metadata {
|
|
191
264
|
loginType: 'idp' | 'sp';
|
192
265
|
provider: string;
|
193
266
|
}
|
194
|
-
export interface
|
267
|
+
export interface SAMLConnection {
|
195
268
|
idpMetadata: Metadata;
|
196
269
|
certs: {
|
197
270
|
privateKey: string;
|
@@ -200,11 +273,12 @@ export interface SAMLConfig {
|
|
200
273
|
defaultRedirectUrl: string;
|
201
274
|
}
|
202
275
|
export interface OAuthErrorHandlerParams {
|
203
|
-
error: 'invalid_request' | 'access_denied' | 'unauthorized_client' | 'unsupported_response_type' | 'invalid_scope' | 'server_error' | 'temporarily_unavailable';
|
276
|
+
error: 'invalid_request' | 'access_denied' | 'unauthorized_client' | 'unsupported_response_type' | 'invalid_scope' | 'server_error' | 'temporarily_unavailable' | OIDCErrorCodes;
|
204
277
|
error_description: string;
|
205
278
|
redirect_uri: string;
|
206
279
|
state?: string;
|
207
280
|
}
|
281
|
+
export declare 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';
|
208
282
|
export interface ISPSAMLConfig {
|
209
283
|
get(): {
|
210
284
|
acsUrl: string;
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@boxyhq/saml-jackson",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.3.0",
|
4
4
|
"description": "SAML Jackson library",
|
5
5
|
"keywords": [
|
6
6
|
"SAML 2.0"
|
@@ -27,7 +27,7 @@
|
|
27
27
|
"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
28
|
"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",
|
29
29
|
"prepublishOnly": "npm run build",
|
30
|
-
"test": "tap --ts --timeout=100 --coverage test/**/*.test.ts",
|
30
|
+
"test": "tap --ts --timeout=100 --coverage-map=map.js test/**/*.test.ts",
|
31
31
|
"sort": "npx sort-package-json"
|
32
32
|
},
|
33
33
|
"tap": {
|
@@ -46,6 +46,7 @@
|
|
46
46
|
"marked": "4.1.0",
|
47
47
|
"mongodb": "4.10.0",
|
48
48
|
"mysql2": "2.3.3",
|
49
|
+
"openid-client": "5.1.9",
|
49
50
|
"node-forge": "1.3.1",
|
50
51
|
"pg": "8.8.0",
|
51
52
|
"redis": "4.3.1",
|
package/dist/read-config.d.ts
DELETED