@boxyhq/saml-jackson 0.2.2-beta.176 → 0.2.3-beta.207
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/ nodemon.json +12 -0
- package/.nyc_output/522d751d-0cf8-42cc-9e6b-7c4f2c2ab0d4.json +1 -0
- package/.nyc_output/93c45454-d3b6-48a7-9885-209592dc290a.json +1 -0
- package/.nyc_output/da9b997e-732d-4bf2-a4e8-4b0568635c06.json +1 -0
- package/.nyc_output/processinfo/522d751d-0cf8-42cc-9e6b-7c4f2c2ab0d4.json +1 -0
- package/.nyc_output/processinfo/93c45454-d3b6-48a7-9885-209592dc290a.json +1 -0
- package/.nyc_output/processinfo/da9b997e-732d-4bf2-a4e8-4b0568635c06.json +1 -0
- package/.nyc_output/processinfo/index.json +1 -0
- package/package.json +23 -15
- package/.eslintrc.js +0 -13
- package/prettier.config.js +0 -4
- package/src/controller/api.js +0 -167
- package/src/controller/error.js +0 -12
- package/src/controller/oauth/allowed.js +0 -19
- package/src/controller/oauth/code-verifier.js +0 -16
- package/src/controller/oauth/redirect.js +0 -18
- package/src/controller/oauth.js +0 -321
- package/src/controller/utils.js +0 -19
- package/src/db/db.js +0 -81
- package/src/db/db.test.js +0 -302
- package/src/db/encrypter.js +0 -36
- package/src/db/mem.js +0 -111
- package/src/db/mongo.js +0 -89
- package/src/db/redis.js +0 -88
- package/src/db/sql/entity/JacksonIndex.js +0 -42
- package/src/db/sql/entity/JacksonStore.js +0 -42
- package/src/db/sql/entity/JacksonTTL.js +0 -23
- package/src/db/sql/model/JacksonIndex.js +0 -9
- package/src/db/sql/model/JacksonStore.js +0 -10
- package/src/db/sql/model/JacksonTTL.js +0 -8
- package/src/db/sql/sql.js +0 -153
- package/src/db/store.js +0 -42
- package/src/db/utils.js +0 -30
- package/src/env.js +0 -39
- package/src/index.js +0 -67
- package/src/jackson.js +0 -161
- package/src/read-config.js +0 -24
- package/src/saml/claims.js +0 -40
- package/src/saml/saml.js +0 -223
- package/src/saml/x509.js +0 -48
- package/src/test/api.test.js +0 -186
- package/src/test/data/metadata/boxyhq.js +0 -6
- package/src/test/data/metadata/boxyhq.xml +0 -30
- package/src/test/data/saml_response +0 -1
- package/src/test/oauth.test.js +0 -342
package/ nodemon.json
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
{}
|
@@ -0,0 +1 @@
|
|
1
|
+
{}
|
@@ -0,0 +1 @@
|
|
1
|
+
{}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"parent":"93c45454-d3b6-48a7-9885-209592dc290a","pid":3596,"argv":["/opt/hostedtoolcache/node/16.13.1/x64/bin/node","/home/runner/work/jackson/jackson/src/test/api.test.ts"],"execArgv":["-r","/home/runner/work/jackson/jackson/node_modules/ts-node/register/index.js"],"cwd":"/home/runner/work/jackson/jackson","time":1640694328676,"ppid":3579,"coverageFilename":"/home/runner/work/jackson/jackson/.nyc_output/522d751d-0cf8-42cc-9e6b-7c4f2c2ab0d4.json","externalId":"src/test/api.test.ts","uuid":"522d751d-0cf8-42cc-9e6b-7c4f2c2ab0d4","files":[]}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"parent":null,"pid":3579,"argv":["/opt/hostedtoolcache/node/16.13.1/x64/bin/node","/home/runner/work/jackson/jackson/node_modules/.bin/tap","--ts","--timeout=100","src/test/api.test.ts","src/test/oauth.test.ts"],"execArgv":[],"cwd":"/home/runner/work/jackson/jackson","time":1640694328360,"ppid":3568,"coverageFilename":"/home/runner/work/jackson/jackson/.nyc_output/93c45454-d3b6-48a7-9885-209592dc290a.json","externalId":"","uuid":"93c45454-d3b6-48a7-9885-209592dc290a","files":[]}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"parent":"93c45454-d3b6-48a7-9885-209592dc290a","pid":3590,"argv":["/opt/hostedtoolcache/node/16.13.1/x64/bin/node","/home/runner/work/jackson/jackson/src/test/oauth.test.ts"],"execArgv":["-r","/home/runner/work/jackson/jackson/node_modules/ts-node/register/index.js"],"cwd":"/home/runner/work/jackson/jackson","time":1640694328650,"ppid":3579,"coverageFilename":"/home/runner/work/jackson/jackson/.nyc_output/da9b997e-732d-4bf2-a4e8-4b0568635c06.json","externalId":"src/test/oauth.test.ts","uuid":"da9b997e-732d-4bf2-a4e8-4b0568635c06","files":[]}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"processes":{"522d751d-0cf8-42cc-9e6b-7c4f2c2ab0d4":{"parent":"93c45454-d3b6-48a7-9885-209592dc290a","externalId":"src/test/api.test.ts","children":[]},"93c45454-d3b6-48a7-9885-209592dc290a":{"parent":null,"children":["522d751d-0cf8-42cc-9e6b-7c4f2c2ab0d4","da9b997e-732d-4bf2-a4e8-4b0568635c06"]},"da9b997e-732d-4bf2-a4e8-4b0568635c06":{"parent":"93c45454-d3b6-48a7-9885-209592dc290a","externalId":"src/test/oauth.test.ts","children":[]}},"files":{},"externalIds":{"src/test/api.test.ts":{"root":"522d751d-0cf8-42cc-9e6b-7c4f2c2ab0d4","children":[]},"src/test/oauth.test.ts":{"root":"da9b997e-732d-4bf2-a4e8-4b0568635c06","children":[]}}}
|
package/package.json
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
{
|
2
2
|
"name": "@boxyhq/saml-jackson",
|
3
|
-
"version": "0.2.
|
3
|
+
"version": "0.2.3-beta.207",
|
4
4
|
"license": "Apache 2.0",
|
5
5
|
"description": "SAML 2.0 service",
|
6
|
-
"main": "
|
6
|
+
"main": "dist/index.js",
|
7
|
+
"types": "dist/types.d.ts",
|
7
8
|
"engines": {
|
8
9
|
"node": ">=14.18.1"
|
9
10
|
},
|
@@ -15,12 +16,14 @@
|
|
15
16
|
"SAML 2.0"
|
16
17
|
],
|
17
18
|
"scripts": {
|
19
|
+
"build": "tsc",
|
18
20
|
"start": "cross-env IDP_ENABLED=true node src/jackson.js",
|
19
21
|
"dev": "cross-env IDP_ENABLED=true nodemon src/jackson.js",
|
20
|
-
"mongo": "cross-env JACKSON_API_KEYS=secret DB_ENGINE=mongo DB_URL=mongodb://localhost:27017/jackson nodemon src/jackson.
|
22
|
+
"mongo": "cross-env JACKSON_API_KEYS=secret DB_ENGINE=mongo DB_URL=mongodb://localhost:27017/jackson DB_ENCRYPTION_KEY=RiVoTxDoLUUoIUOp224abMxK6PGGfFuF nodemon --config nodemon.json src/jackson.ts",
|
23
|
+
"sql": "cross-env JACKSON_API_KEYS=secret DB_ENGINE=sql DB_TYPE=postgres DB_URL=postgres://postgres:postgres@localhost:5432/jackson DB_ENCRYPTION_KEY=RiVoTxDoLUUoIUOp224abMxK6PGGfFuF nodemon src/jackson.js",
|
21
24
|
"pre-loaded": "cross-env JACKSON_API_KEYS=secret DB_ENGINE=mem PRE_LOADED_CONFIG='./_config' nodemon src/jackson.js",
|
22
25
|
"pre-loaded-db": "cross-env JACKSON_API_KEYS=secret PRE_LOADED_CONFIG='./_config' nodemon src/jackson.js",
|
23
|
-
"test": "tap --timeout=100 src/**/*.test.
|
26
|
+
"test": "tap --ts --timeout=100 src/**/*.test.ts",
|
24
27
|
"dev-dbs": "docker-compose -f ./_dev/docker-compose.yml up -d",
|
25
28
|
"dev-dbs-destroy": "docker-compose -f ./_dev/docker-compose.yml down --volumes --remove-orphans"
|
26
29
|
},
|
@@ -33,15 +36,15 @@
|
|
33
36
|
},
|
34
37
|
"dependencies": {
|
35
38
|
"@boxyhq/saml20": "0.2.0",
|
36
|
-
"@peculiar/webcrypto": "1.2.
|
37
|
-
"@peculiar/x509": "1.6.
|
39
|
+
"@peculiar/webcrypto": "1.2.3",
|
40
|
+
"@peculiar/x509": "1.6.1",
|
38
41
|
"cors": "2.8.5",
|
39
|
-
"express": "4.17.
|
40
|
-
"mongodb": "4.2.
|
42
|
+
"express": "4.17.2",
|
43
|
+
"mongodb": "4.2.2",
|
41
44
|
"mysql2": "2.3.3",
|
42
45
|
"pg": "8.7.1",
|
43
46
|
"rambda": "6.9.0",
|
44
|
-
"redis": "4.0.
|
47
|
+
"redis": "4.0.1",
|
45
48
|
"reflect-metadata": "0.1.13",
|
46
49
|
"ripemd160": "2.0.2",
|
47
50
|
"thumbprint": "0.0.1",
|
@@ -51,17 +54,22 @@
|
|
51
54
|
"xmlbuilder": "15.1.1"
|
52
55
|
},
|
53
56
|
"devDependencies": {
|
57
|
+
"@types/redis": "4.0.11",
|
58
|
+
"@types/sinon": "10.0.6",
|
59
|
+
"@types/tap": "15.0.5",
|
54
60
|
"cross-env": "7.0.3",
|
55
|
-
"eslint": "8.
|
61
|
+
"eslint": "8.5.0",
|
56
62
|
"husky": "7.0.4",
|
57
|
-
"lint-staged": "12.1.
|
63
|
+
"lint-staged": "12.1.4",
|
58
64
|
"nodemon": "2.0.15",
|
59
65
|
"prettier": "2.5.1",
|
60
66
|
"sinon": "12.0.1",
|
61
|
-
"tap": "15.1.5"
|
67
|
+
"tap": "15.1.5",
|
68
|
+
"ts-node": "10.4.0",
|
69
|
+
"typescript": "4.5.4"
|
62
70
|
},
|
63
71
|
"lint-staged": {
|
64
|
-
"*.js": "eslint --cache --fix",
|
65
|
-
"*.{js,css,md}": "prettier --write"
|
72
|
+
"*.{js,ts}": "eslint --cache --fix",
|
73
|
+
"*.{js,ts,css,md}": "prettier --write"
|
66
74
|
}
|
67
|
-
}
|
75
|
+
}
|
package/.eslintrc.js
DELETED
package/prettier.config.js
DELETED
package/src/controller/api.js
DELETED
@@ -1,167 +0,0 @@
|
|
1
|
-
const saml = require('../saml/saml.js');
|
2
|
-
const x509 = require('../saml/x509.js');
|
3
|
-
const dbutils = require('../db/utils.js');
|
4
|
-
const { indexNames } = require('./utils.js');
|
5
|
-
const { JacksonError } = require('./error.js');
|
6
|
-
|
7
|
-
const crypto = require('crypto');
|
8
|
-
|
9
|
-
let configStore;
|
10
|
-
|
11
|
-
const extractHostName = (url) => {
|
12
|
-
try {
|
13
|
-
const pUrl = new URL(url);
|
14
|
-
if (pUrl.hostname.startsWith('www.')) {
|
15
|
-
return pUrl.hostname.substring(4);
|
16
|
-
}
|
17
|
-
return pUrl.hostname;
|
18
|
-
} catch (err) {
|
19
|
-
return null;
|
20
|
-
}
|
21
|
-
};
|
22
|
-
|
23
|
-
const config = async (body) => {
|
24
|
-
const { rawMetadata, defaultRedirectUrl, redirectUrl, tenant, product } =
|
25
|
-
body;
|
26
|
-
|
27
|
-
if (!rawMetadata) {
|
28
|
-
throw new JacksonError('Please provide rawMetadata', 400);
|
29
|
-
}
|
30
|
-
|
31
|
-
if (!defaultRedirectUrl) {
|
32
|
-
throw new JacksonError('Please provide a defaultRedirectUrl', 400);
|
33
|
-
}
|
34
|
-
|
35
|
-
if (!redirectUrl) {
|
36
|
-
throw new JacksonError('Please provide redirectUrl', 400);
|
37
|
-
}
|
38
|
-
|
39
|
-
if (!tenant) {
|
40
|
-
throw new JacksonError('Please provide tenant', 400);
|
41
|
-
}
|
42
|
-
|
43
|
-
if (!product) {
|
44
|
-
throw new JacksonError('Please provide product', 400);
|
45
|
-
}
|
46
|
-
|
47
|
-
const idpMetadata = await saml.parseMetadataAsync(rawMetadata);
|
48
|
-
|
49
|
-
// extract provider
|
50
|
-
let providerName = extractHostName(idpMetadata.entityID);
|
51
|
-
if (!providerName) {
|
52
|
-
providerName = extractHostName(
|
53
|
-
idpMetadata.sso.redirectUrl || idpMetadata.sso.postUrl
|
54
|
-
);
|
55
|
-
}
|
56
|
-
|
57
|
-
idpMetadata.provider = providerName ? providerName : 'Unknown';
|
58
|
-
|
59
|
-
let clientID = dbutils.keyDigest(
|
60
|
-
dbutils.keyFromParts(tenant, product, idpMetadata.entityID)
|
61
|
-
);
|
62
|
-
let clientSecret;
|
63
|
-
|
64
|
-
let exists = await configStore.get(clientID);
|
65
|
-
if (exists) {
|
66
|
-
clientSecret = exists.clientSecret;
|
67
|
-
} else {
|
68
|
-
clientSecret = crypto.randomBytes(24).toString('hex');
|
69
|
-
}
|
70
|
-
|
71
|
-
const certs = await x509.generate();
|
72
|
-
if (!certs) {
|
73
|
-
throw new Error('Error generating x59 certs');
|
74
|
-
}
|
75
|
-
|
76
|
-
await configStore.put(
|
77
|
-
clientID,
|
78
|
-
{
|
79
|
-
idpMetadata,
|
80
|
-
defaultRedirectUrl,
|
81
|
-
redirectUrl: JSON.parse(redirectUrl), // redirectUrl is a stringified array
|
82
|
-
tenant,
|
83
|
-
product,
|
84
|
-
clientID,
|
85
|
-
clientSecret,
|
86
|
-
certs,
|
87
|
-
},
|
88
|
-
{
|
89
|
-
// secondary index on entityID
|
90
|
-
name: indexNames.entityID,
|
91
|
-
value: idpMetadata.entityID,
|
92
|
-
},
|
93
|
-
{
|
94
|
-
// secondary index on tenant + product
|
95
|
-
name: indexNames.tenantProduct,
|
96
|
-
value: dbutils.keyFromParts(tenant, product),
|
97
|
-
}
|
98
|
-
);
|
99
|
-
|
100
|
-
return {
|
101
|
-
client_id: clientID,
|
102
|
-
client_secret: clientSecret,
|
103
|
-
provider: idpMetadata.provider,
|
104
|
-
};
|
105
|
-
};
|
106
|
-
|
107
|
-
const getConfig = async (body) => {
|
108
|
-
const { clientID, tenant, product } = body;
|
109
|
-
|
110
|
-
if (clientID) {
|
111
|
-
const samlConfig = await configStore.get(clientID);
|
112
|
-
if (!samlConfig) {
|
113
|
-
return {};
|
114
|
-
}
|
115
|
-
|
116
|
-
return { provider: samlConfig.idpMetadata.provider };
|
117
|
-
} else {
|
118
|
-
const samlConfigs = await configStore.getByIndex({
|
119
|
-
name: indexNames.tenantProduct,
|
120
|
-
value: dbutils.keyFromParts(tenant, product),
|
121
|
-
});
|
122
|
-
if (!samlConfigs || !samlConfigs.length) {
|
123
|
-
return {};
|
124
|
-
}
|
125
|
-
|
126
|
-
return { provider: samlConfigs[0].idpMetadata.provider };
|
127
|
-
}
|
128
|
-
};
|
129
|
-
|
130
|
-
const deleteConfig = async (body) => {
|
131
|
-
const { clientID, clientSecret, tenant, product } = body;
|
132
|
-
|
133
|
-
if (clientID) {
|
134
|
-
if (!clientSecret) {
|
135
|
-
throw new JacksonError('Please provide clientSecret', 400);
|
136
|
-
}
|
137
|
-
const samlConfig = await configStore.get(clientID);
|
138
|
-
if (!samlConfig) {
|
139
|
-
return;
|
140
|
-
}
|
141
|
-
if (samlConfig.clientSecret === clientSecret) {
|
142
|
-
await configStore.delete(clientID);
|
143
|
-
} else {
|
144
|
-
throw new JacksonError('clientSecret mismatch', 400);
|
145
|
-
}
|
146
|
-
} else {
|
147
|
-
const samlConfigs = await configStore.getByIndex({
|
148
|
-
name: indexNames.tenantProduct,
|
149
|
-
value: dbutils.keyFromParts(tenant, product),
|
150
|
-
});
|
151
|
-
if (!samlConfigs || !samlConfigs.length) {
|
152
|
-
return;
|
153
|
-
}
|
154
|
-
for (const conf of samlConfigs) {
|
155
|
-
await configStore.delete(conf.clientID);
|
156
|
-
}
|
157
|
-
}
|
158
|
-
};
|
159
|
-
|
160
|
-
module.exports = (opts) => {
|
161
|
-
configStore = opts.configStore;
|
162
|
-
return {
|
163
|
-
config,
|
164
|
-
getConfig,
|
165
|
-
deleteConfig,
|
166
|
-
};
|
167
|
-
};
|
package/src/controller/error.js
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
class JacksonError extends Error {
|
2
|
-
constructor(message, statusCode = 500) {
|
3
|
-
super(message);
|
4
|
-
|
5
|
-
this.name = this.constructor.name;
|
6
|
-
this.statusCode = statusCode;
|
7
|
-
|
8
|
-
Error.captureStackTrace(this, this.constructor);
|
9
|
-
}
|
10
|
-
}
|
11
|
-
|
12
|
-
module.exports = { JacksonError };
|
@@ -1,19 +0,0 @@
|
|
1
|
-
module.exports = {
|
2
|
-
redirect: (redirectUrl, redirectUrls) => {
|
3
|
-
const url = new URL(redirectUrl);
|
4
|
-
|
5
|
-
for (const idx in redirectUrls) {
|
6
|
-
const rUrl = new URL(redirectUrls[idx]);
|
7
|
-
// TODO: Check pathname, for now pathname is ignored
|
8
|
-
if (
|
9
|
-
rUrl.protocol === url.protocol &&
|
10
|
-
rUrl.hostname === url.hostname &&
|
11
|
-
rUrl.port === url.port
|
12
|
-
) {
|
13
|
-
return true;
|
14
|
-
}
|
15
|
-
}
|
16
|
-
|
17
|
-
return false;
|
18
|
-
},
|
19
|
-
};
|
@@ -1,16 +0,0 @@
|
|
1
|
-
const crypto = require('crypto');
|
2
|
-
|
3
|
-
const transformBase64 = (input) => {
|
4
|
-
return input.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
|
5
|
-
};
|
6
|
-
|
7
|
-
const encode = (code_challenge) => {
|
8
|
-
return transformBase64(
|
9
|
-
crypto.createHash('sha256').update(code_challenge).digest('base64')
|
10
|
-
);
|
11
|
-
};
|
12
|
-
|
13
|
-
module.exports = {
|
14
|
-
encode,
|
15
|
-
transformBase64,
|
16
|
-
};
|
@@ -1,18 +0,0 @@
|
|
1
|
-
module.exports = {
|
2
|
-
error: (res, redirectUrl, err) => {
|
3
|
-
var url = new URL(redirectUrl);
|
4
|
-
url.searchParams.set('error', err);
|
5
|
-
|
6
|
-
res.redirect(url);
|
7
|
-
},
|
8
|
-
|
9
|
-
success: (redirectUrl, params) => {
|
10
|
-
const url = new URL(redirectUrl);
|
11
|
-
|
12
|
-
for (const [key, value] of Object.entries(params)) {
|
13
|
-
url.searchParams.set(key, value);
|
14
|
-
}
|
15
|
-
|
16
|
-
return url.href;
|
17
|
-
},
|
18
|
-
};
|