@boxyhq/saml-jackson 0.2.3-beta.230 → 0.2.3-beta.231
Sign up to get free protection for your applications and to get access to all the features.
- package/package.json +1 -1
- package/src/controller/api.ts +2 -2
- package/src/controller/error.ts +1 -1
- package/src/controller/oauth.ts +4 -7
- package/src/db/db.ts +11 -11
- package/src/db/mem.ts +2 -2
- package/src/db/mongo.ts +2 -2
- package/src/db/redis.ts +3 -3
- package/src/db/store.ts +2 -2
- package/src/env.ts +1 -1
- package/src/jackson.ts +0 -1
- package/src/saml/saml.ts +8 -9
- package/src/test/api.test.ts +1 -1
- package/src/typings.ts +2 -2
package/package.json
CHANGED
package/src/controller/api.ts
CHANGED
@@ -56,13 +56,13 @@ export class SAMLConfig implements ISAMLConfig {
|
|
56
56
|
|
57
57
|
idpMetadata.provider = providerName ? providerName : 'Unknown';
|
58
58
|
|
59
|
-
|
59
|
+
const clientID = dbutils.keyDigest(
|
60
60
|
dbutils.keyFromParts(tenant, product, idpMetadata.entityID)
|
61
61
|
);
|
62
62
|
|
63
63
|
let clientSecret;
|
64
64
|
|
65
|
-
|
65
|
+
const exists = await this.configStore.get(clientID);
|
66
66
|
|
67
67
|
if (exists) {
|
68
68
|
clientSecret = exists.clientSecret;
|
package/src/controller/error.ts
CHANGED
package/src/controller/oauth.ts
CHANGED
@@ -66,7 +66,7 @@ export class OAuthController implements IOAuthController {
|
|
66
66
|
product,
|
67
67
|
code_challenge,
|
68
68
|
code_challenge_method = '',
|
69
|
-
// eslint-disable-next-line no-unused-vars
|
69
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
70
70
|
provider = 'saml',
|
71
71
|
} = body;
|
72
72
|
|
@@ -134,7 +134,6 @@ export class OAuthController implements IOAuthController {
|
|
134
134
|
}
|
135
135
|
|
136
136
|
const samlReq = saml.request({
|
137
|
-
// @ts-ignore
|
138
137
|
entityID: this.opts.samlAudience,
|
139
138
|
callbackUrl: this.opts.externalUrl + this.opts.samlPath,
|
140
139
|
signingKey: samlConfig.certs.privateKey,
|
@@ -190,8 +189,6 @@ export class OAuthController implements IOAuthController {
|
|
190
189
|
|
191
190
|
const samlConfigs = await this.configStore.getByIndex({
|
192
191
|
name: IndexNames.EntityID,
|
193
|
-
|
194
|
-
// @ts-ignore
|
195
192
|
value: parsedResp?.issuer,
|
196
193
|
});
|
197
194
|
|
@@ -214,7 +211,7 @@ export class OAuthController implements IOAuthController {
|
|
214
211
|
}
|
215
212
|
}
|
216
213
|
|
217
|
-
|
214
|
+
const validateOpts: Record<string, string> = {
|
218
215
|
thumbprint: samlConfig.idpMetadata.thumbprint,
|
219
216
|
audience: this.opts.samlAudience,
|
220
217
|
};
|
@@ -228,7 +225,7 @@ export class OAuthController implements IOAuthController {
|
|
228
225
|
// store details against a code
|
229
226
|
const code = crypto.randomBytes(20).toString('hex');
|
230
227
|
|
231
|
-
|
228
|
+
const codeVal: Record<string, unknown> = {
|
232
229
|
profile,
|
233
230
|
clientID: samlConfig.clientID,
|
234
231
|
clientSecret: samlConfig.clientSecret,
|
@@ -248,7 +245,7 @@ export class OAuthController implements IOAuthController {
|
|
248
245
|
throw new JacksonError('Redirect URL is not allowed.', 403);
|
249
246
|
}
|
250
247
|
|
251
|
-
|
248
|
+
const params: Record<string, string> = {
|
252
249
|
code,
|
253
250
|
};
|
254
251
|
|
package/src/db/db.ts
CHANGED
@@ -13,7 +13,7 @@ import redis from './redis';
|
|
13
13
|
import sql from './sql/sql';
|
14
14
|
import store from './store';
|
15
15
|
|
16
|
-
const decrypt = (res: Encrypted, encryptionKey: EncryptionKey):
|
16
|
+
const decrypt = (res: Encrypted, encryptionKey: EncryptionKey): unknown => {
|
17
17
|
if (res.iv && res.tag) {
|
18
18
|
return JSON.parse(
|
19
19
|
encrypter.decrypt(res.value, res.iv, res.tag, encryptionKey)
|
@@ -24,15 +24,15 @@ const decrypt = (res: Encrypted, encryptionKey: EncryptionKey): any => {
|
|
24
24
|
};
|
25
25
|
|
26
26
|
class DB implements DatabaseDriver {
|
27
|
-
private db:
|
27
|
+
private db: DatabaseDriver;
|
28
28
|
private encryptionKey: EncryptionKey;
|
29
29
|
|
30
|
-
constructor(db:
|
30
|
+
constructor(db: DatabaseDriver, encryptionKey: EncryptionKey) {
|
31
31
|
this.db = db;
|
32
32
|
this.encryptionKey = encryptionKey;
|
33
33
|
}
|
34
34
|
|
35
|
-
async get(namespace: string, key: string): Promise<
|
35
|
+
async get(namespace: string, key: string): Promise<unknown> {
|
36
36
|
const res = await this.db.get(namespace, key);
|
37
37
|
|
38
38
|
if (!res) {
|
@@ -42,7 +42,7 @@ class DB implements DatabaseDriver {
|
|
42
42
|
return decrypt(res, this.encryptionKey);
|
43
43
|
}
|
44
44
|
|
45
|
-
async getByIndex(namespace: string, idx: Index): Promise<
|
45
|
+
async getByIndex(namespace: string, idx: Index): Promise<unknown[]> {
|
46
46
|
const res = await this.db.getByIndex(namespace, idx);
|
47
47
|
const encryptionKey = this.encryptionKey;
|
48
48
|
return res.map((r) => {
|
@@ -54,10 +54,10 @@ class DB implements DatabaseDriver {
|
|
54
54
|
async put(
|
55
55
|
namespace: string,
|
56
56
|
key: string,
|
57
|
-
val:
|
58
|
-
ttl
|
59
|
-
...indexes:
|
60
|
-
): Promise<
|
57
|
+
val: unknown,
|
58
|
+
ttl = 0,
|
59
|
+
...indexes: Index[]
|
60
|
+
): Promise<unknown> {
|
61
61
|
if (ttl > 0 && indexes && indexes.length > 0) {
|
62
62
|
throw new Error('secondary indexes not allow on a store with ttl');
|
63
63
|
}
|
@@ -69,11 +69,11 @@ class DB implements DatabaseDriver {
|
|
69
69
|
return await this.db.put(namespace, key, dbVal, ttl, ...indexes);
|
70
70
|
}
|
71
71
|
|
72
|
-
async delete(namespace: string, key: string): Promise<
|
72
|
+
async delete(namespace: string, key: string): Promise<unknown> {
|
73
73
|
return await this.db.delete(namespace, key);
|
74
74
|
}
|
75
75
|
|
76
|
-
store(namespace: string, ttl
|
76
|
+
store(namespace: string, ttl = 0): Storable {
|
77
77
|
return store.new(namespace, this, ttl);
|
78
78
|
}
|
79
79
|
}
|
package/src/db/mem.ts
CHANGED
@@ -43,7 +43,7 @@ class Mem implements DatabaseDriver {
|
|
43
43
|
}
|
44
44
|
|
45
45
|
async get(namespace: string, key: string): Promise<any> {
|
46
|
-
|
46
|
+
const res = this.store[dbutils.key(namespace, key)];
|
47
47
|
if (res) {
|
48
48
|
return res;
|
49
49
|
}
|
@@ -66,7 +66,7 @@ class Mem implements DatabaseDriver {
|
|
66
66
|
namespace: string,
|
67
67
|
key: string,
|
68
68
|
val: Encrypted,
|
69
|
-
ttl
|
69
|
+
ttl = 0,
|
70
70
|
...indexes: any[]
|
71
71
|
): Promise<any> {
|
72
72
|
const k = dbutils.key(namespace, key);
|
package/src/db/mongo.ts
CHANGED
@@ -36,7 +36,7 @@ class Mongo implements DatabaseDriver {
|
|
36
36
|
}
|
37
37
|
|
38
38
|
async get(namespace: string, key: string): Promise<any> {
|
39
|
-
|
39
|
+
const res = await this.collection.findOne({
|
40
40
|
_id: dbutils.key(namespace, key),
|
41
41
|
});
|
42
42
|
if (res && res.value) {
|
@@ -65,7 +65,7 @@ class Mongo implements DatabaseDriver {
|
|
65
65
|
namespace: string,
|
66
66
|
key: string,
|
67
67
|
val: Encrypted,
|
68
|
-
ttl
|
68
|
+
ttl = 0,
|
69
69
|
...indexes: any[]
|
70
70
|
): Promise<void> {
|
71
71
|
const doc = <Document>{
|
package/src/db/redis.ts
CHANGED
@@ -11,7 +11,7 @@ class Redis implements DatabaseDriver {
|
|
11
11
|
}
|
12
12
|
|
13
13
|
async init(): Promise<Redis> {
|
14
|
-
|
14
|
+
const opts = {};
|
15
15
|
|
16
16
|
if (this.options && this.options.url) {
|
17
17
|
opts['socket'] = {
|
@@ -30,7 +30,7 @@ class Redis implements DatabaseDriver {
|
|
30
30
|
}
|
31
31
|
|
32
32
|
async get(namespace: string, key: string): Promise<any> {
|
33
|
-
|
33
|
+
const res = await this.client.get(dbutils.key(namespace, key));
|
34
34
|
if (res) {
|
35
35
|
return JSON.parse(res);
|
36
36
|
}
|
@@ -55,7 +55,7 @@ class Redis implements DatabaseDriver {
|
|
55
55
|
namespace: string,
|
56
56
|
key: string,
|
57
57
|
val: Encrypted,
|
58
|
-
ttl
|
58
|
+
ttl = 0,
|
59
59
|
...indexes: any[]
|
60
60
|
): Promise<void> {
|
61
61
|
let tx = this.client.multi();
|
package/src/db/store.ts
CHANGED
@@ -6,7 +6,7 @@ class Store implements Storable {
|
|
6
6
|
private db: any;
|
7
7
|
private ttl: number;
|
8
8
|
|
9
|
-
constructor(namespace: string, db: any, ttl
|
9
|
+
constructor(namespace: string, db: any, ttl = 0) {
|
10
10
|
this.namespace = namespace;
|
11
11
|
this.db = db;
|
12
12
|
this.ttl = ttl;
|
@@ -43,7 +43,7 @@ class Store implements Storable {
|
|
43
43
|
}
|
44
44
|
|
45
45
|
export default {
|
46
|
-
new: (namespace: string, db: any, ttl
|
46
|
+
new: (namespace: string, db: any, ttl = 0): Storable => {
|
47
47
|
return new Store(namespace, db, ttl);
|
48
48
|
},
|
49
49
|
};
|
package/src/env.ts
CHANGED
@@ -9,7 +9,7 @@ const internalHostPort = +(process.env.INTERNAL_HOST_PORT || '6000');
|
|
9
9
|
|
10
10
|
const apiKeys = (process.env.JACKSON_API_KEYS || '').split(',');
|
11
11
|
|
12
|
-
const samlAudience = process.env.SAML_AUDIENCE;
|
12
|
+
const samlAudience = process.env.SAML_AUDIENCE || 'https://saml.boxyhq.com';
|
13
13
|
const preLoadedConfig = process.env.PRE_LOADED_CONFIG;
|
14
14
|
|
15
15
|
const idpEnabled = process.env.IDP_ENABLED;
|
package/src/jackson.ts
CHANGED
package/src/saml/saml.ts
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
import saml from '@boxyhq/saml20';
|
2
|
+
import xml2js from 'xml2js';
|
3
|
+
import thumbprint from 'thumbprint';
|
4
|
+
import xmlcrypto from 'xml-crypto';
|
5
5
|
import * as rambda from 'rambda';
|
6
6
|
import xmlbuilder from 'xmlbuilder';
|
7
7
|
import crypto from 'crypto';
|
@@ -53,7 +53,8 @@ const request = ({
|
|
53
53
|
const id = idPrefix + crypto.randomBytes(10).toString('hex');
|
54
54
|
const date = new Date().toISOString();
|
55
55
|
|
56
|
-
|
56
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
57
|
+
const samlReq: Record<string, any> = {
|
57
58
|
'samlp:AuthnRequest': {
|
58
59
|
'@xmlns:samlp': 'urn:oasis:names:tc:SAML:2.0:protocol',
|
59
60
|
'@ID': id,
|
@@ -97,9 +98,7 @@ const request = ({
|
|
97
98
|
};
|
98
99
|
};
|
99
100
|
|
100
|
-
const parseAsync = async (
|
101
|
-
rawAssertion: string
|
102
|
-
): Promise<SAMLProfile | void> => {
|
101
|
+
const parseAsync = async (rawAssertion: string): Promise<SAMLProfile> => {
|
103
102
|
return new Promise((resolve, reject) => {
|
104
103
|
saml.parse(
|
105
104
|
rawAssertion,
|
@@ -118,7 +117,7 @@ const parseAsync = async (
|
|
118
117
|
const validateAsync = async (
|
119
118
|
rawAssertion: string,
|
120
119
|
options
|
121
|
-
): Promise<SAMLProfile
|
120
|
+
): Promise<SAMLProfile> => {
|
122
121
|
return new Promise((resolve, reject) => {
|
123
122
|
saml.validate(
|
124
123
|
rawAssertion,
|
package/src/test/api.test.ts
CHANGED
@@ -144,7 +144,7 @@ tap.test('controller/api', async (t) => {
|
|
144
144
|
t.equal(response.client_id, CLIENT_ID);
|
145
145
|
t.equal(response.provider, PROVIDER);
|
146
146
|
|
147
|
-
|
147
|
+
const savedConf = await apiController.getConfig({
|
148
148
|
clientID: CLIENT_ID,
|
149
149
|
});
|
150
150
|
|
package/src/typings.ts
CHANGED
@@ -104,7 +104,7 @@ declare module 'saml-jackson' {
|
|
104
104
|
key: string,
|
105
105
|
val: any,
|
106
106
|
ttl: number,
|
107
|
-
indexes: Index[]
|
107
|
+
...indexes: Index[]
|
108
108
|
): Promise<any>;
|
109
109
|
delete(namespace: string, key: string): Promise<any>;
|
110
110
|
getByIndex(namespace: string, idx: Index): Promise<any>;
|
@@ -159,7 +159,7 @@ declare module 'saml-jackson' {
|
|
159
159
|
export interface JacksonOption {
|
160
160
|
externalUrl: string;
|
161
161
|
samlPath: string;
|
162
|
-
samlAudience
|
162
|
+
samlAudience: string;
|
163
163
|
preLoadedConfig?: string;
|
164
164
|
idpEnabled?: boolean;
|
165
165
|
db: DatabaseOption;
|