@boxyhq/saml-jackson 0.2.4-beta.198 → 0.3.0-beta.248
Sign up to get free protection for your applications and to get access to all the features.
- package/Dockerfile +9 -7
- package/README.md +28 -29
- package/dist/controller/api.d.ts +32 -0
- package/dist/controller/api.js +193 -0
- package/dist/controller/error.d.ts +5 -0
- package/dist/controller/error.js +12 -0
- package/dist/controller/oauth/allowed.d.ts +1 -0
- package/dist/controller/oauth/allowed.js +17 -0
- package/dist/controller/oauth/code-verifier.d.ts +2 -0
- package/dist/controller/oauth/code-verifier.js +15 -0
- package/dist/controller/oauth/redirect.d.ts +1 -0
- package/dist/controller/oauth/redirect.js +11 -0
- package/dist/controller/oauth.d.ts +23 -0
- package/dist/controller/oauth.js +263 -0
- package/dist/controller/utils.d.ts +6 -0
- package/dist/controller/utils.js +17 -0
- package/dist/db/db.d.ts +15 -0
- package/dist/db/db.js +107 -0
- package/dist/db/encrypter.d.ts +3 -0
- package/dist/db/encrypter.js +29 -0
- package/dist/db/mem.d.ts +20 -0
- package/dist/db/mem.js +128 -0
- package/dist/db/mongo.d.ts +17 -0
- package/dist/db/mongo.js +106 -0
- package/dist/db/redis.d.ts +15 -0
- package/dist/db/redis.js +107 -0
- package/dist/db/sql/entity/JacksonIndex.d.ts +7 -0
- package/dist/db/sql/entity/JacksonIndex.js +41 -0
- package/dist/db/sql/entity/JacksonStore.d.ts +6 -0
- package/dist/db/sql/entity/JacksonStore.js +42 -0
- package/dist/db/sql/entity/JacksonTTL.d.ts +4 -0
- package/dist/db/sql/entity/JacksonTTL.js +29 -0
- package/dist/db/sql/sql.d.ts +20 -0
- package/dist/db/sql/sql.js +174 -0
- package/dist/db/store.d.ts +5 -0
- package/dist/db/store.js +68 -0
- package/dist/db/utils.d.ts +7 -0
- package/dist/db/utils.js +29 -0
- package/dist/env.d.ts +22 -0
- package/dist/env.js +35 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +82 -0
- package/dist/jackson.d.ts +1 -0
- package/dist/jackson.js +153 -0
- package/dist/read-config.d.ts +3 -0
- package/dist/read-config.js +50 -0
- package/dist/saml/claims.d.ts +6 -0
- package/dist/saml/claims.js +35 -0
- package/dist/saml/saml.d.ts +11 -0
- package/dist/saml/saml.js +200 -0
- package/dist/saml/x509.d.ts +7 -0
- package/dist/saml/x509.js +69 -0
- package/dist/typings.d.ts +137 -0
- package/dist/typings.js +2 -0
- package/package.json +41 -21
- package/.dockerignore +0 -2
- package/.eslintrc.js +0 -13
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -27
- package/.github/ISSUE_TEMPLATE/config.yml +0 -5
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -43
- package/.github/pull_request_template.md +0 -31
- package/.github/workflows/codesee-arch-diagram.yml +0 -81
- package/.github/workflows/main.yml +0 -123
- package/_dev/docker-compose.yml +0 -37
- package/map.js +0 -1
- 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
@@ -1,23 +0,0 @@
|
|
1
|
-
const EntitySchema = require('typeorm').EntitySchema;
|
2
|
-
const JacksonTTL = require('../model/JacksonTTL.js');
|
3
|
-
|
4
|
-
module.exports = new EntitySchema({
|
5
|
-
name: 'JacksonTTL',
|
6
|
-
target: JacksonTTL,
|
7
|
-
columns: {
|
8
|
-
key: {
|
9
|
-
primary: true,
|
10
|
-
type: 'varchar',
|
11
|
-
length: 1500,
|
12
|
-
},
|
13
|
-
expiresAt: {
|
14
|
-
type: 'bigint',
|
15
|
-
},
|
16
|
-
},
|
17
|
-
indices: [
|
18
|
-
{
|
19
|
-
name: '_jackson_ttl_expires_at',
|
20
|
-
columns: ['expiresAt'],
|
21
|
-
},
|
22
|
-
],
|
23
|
-
});
|
package/src/db/sql/sql.js
DELETED
@@ -1,153 +0,0 @@
|
|
1
|
-
/*eslint no-constant-condition: ["error", { "checkLoops": false }]*/
|
2
|
-
|
3
|
-
require('reflect-metadata');
|
4
|
-
const typeorm = require('typeorm');
|
5
|
-
const JacksonStore = require('./model/JacksonStore.js');
|
6
|
-
const JacksonIndex = require('./model/JacksonIndex.js');
|
7
|
-
const JacksonTTL = require('./model/JacksonTTL.js');
|
8
|
-
|
9
|
-
const dbutils = require('../utils.js');
|
10
|
-
|
11
|
-
class Sql {
|
12
|
-
constructor(options) {
|
13
|
-
return (async () => {
|
14
|
-
while (true) {
|
15
|
-
try {
|
16
|
-
this.connection = await typeorm.createConnection({
|
17
|
-
name: options.type + Math.floor(Math.random() * 100000),
|
18
|
-
type: options.type,
|
19
|
-
url: options.url,
|
20
|
-
synchronize: true,
|
21
|
-
migrationsTableName: '_jackson_migrations',
|
22
|
-
logging: false,
|
23
|
-
entities: [
|
24
|
-
require('./entity/JacksonStore.js')(options.type),
|
25
|
-
require('./entity/JacksonIndex.js'),
|
26
|
-
require('./entity/JacksonTTL.js'),
|
27
|
-
],
|
28
|
-
});
|
29
|
-
|
30
|
-
break;
|
31
|
-
} catch (err) {
|
32
|
-
console.error(`error connecting to ${options.type} db: ${err}`);
|
33
|
-
await dbutils.sleep(1000);
|
34
|
-
continue;
|
35
|
-
}
|
36
|
-
}
|
37
|
-
|
38
|
-
this.storeRepository = this.connection.getRepository(JacksonStore);
|
39
|
-
this.indexRepository = this.connection.getRepository(JacksonIndex);
|
40
|
-
this.ttlRepository = this.connection.getRepository(JacksonTTL);
|
41
|
-
|
42
|
-
if (options.ttl && options.cleanupLimit) {
|
43
|
-
this.ttlCleanup = async () => {
|
44
|
-
const now = Date.now();
|
45
|
-
|
46
|
-
while (true) {
|
47
|
-
const ids = await this.ttlRepository
|
48
|
-
.createQueryBuilder('jackson_ttl')
|
49
|
-
.limit(options.cleanupLimit)
|
50
|
-
.where('jackson_ttl.expiresAt <= :expiresAt', { expiresAt: now })
|
51
|
-
.getMany();
|
52
|
-
|
53
|
-
if (ids.length <= 0) {
|
54
|
-
break;
|
55
|
-
}
|
56
|
-
|
57
|
-
const delIds = ids.map((id) => {
|
58
|
-
return id.key;
|
59
|
-
});
|
60
|
-
|
61
|
-
await this.storeRepository.remove(ids);
|
62
|
-
await this.ttlRepository.delete(delIds);
|
63
|
-
}
|
64
|
-
|
65
|
-
this.timerId = setTimeout(this.ttlCleanup, options.ttl * 1000);
|
66
|
-
};
|
67
|
-
|
68
|
-
this.timerId = setTimeout(this.ttlCleanup, options.ttl * 1000);
|
69
|
-
} else {
|
70
|
-
console.log(
|
71
|
-
'Warning: ttl cleanup not enabled, set both "ttl" and "cleanupLimit" options to enable it!'
|
72
|
-
);
|
73
|
-
}
|
74
|
-
|
75
|
-
return this;
|
76
|
-
})();
|
77
|
-
}
|
78
|
-
|
79
|
-
async get(namespace, key) {
|
80
|
-
let res = await this.storeRepository.findOne({
|
81
|
-
key: dbutils.key(namespace, key),
|
82
|
-
});
|
83
|
-
|
84
|
-
if (res && res.value) {
|
85
|
-
return {
|
86
|
-
value: res.value,
|
87
|
-
iv: res.iv,
|
88
|
-
tag: res.tag,
|
89
|
-
};
|
90
|
-
}
|
91
|
-
|
92
|
-
return null;
|
93
|
-
}
|
94
|
-
|
95
|
-
async getByIndex(namespace, idx) {
|
96
|
-
const res = await this.indexRepository.find({
|
97
|
-
key: dbutils.keyForIndex(namespace, idx),
|
98
|
-
});
|
99
|
-
|
100
|
-
const ret = [];
|
101
|
-
|
102
|
-
if (res) {
|
103
|
-
res.forEach((r) => {
|
104
|
-
ret.push({
|
105
|
-
value: r.store.value,
|
106
|
-
iv: r.store.iv,
|
107
|
-
tag: r.store.tag,
|
108
|
-
});
|
109
|
-
});
|
110
|
-
}
|
111
|
-
|
112
|
-
return ret;
|
113
|
-
}
|
114
|
-
|
115
|
-
async put(namespace, key, val, ttl = 0, ...indexes) {
|
116
|
-
await this.connection.transaction(async (transactionalEntityManager) => {
|
117
|
-
const dbKey = dbutils.key(namespace, key);
|
118
|
-
const store = new JacksonStore(dbKey, val.value, val.iv, val.tag);
|
119
|
-
await transactionalEntityManager.save(store);
|
120
|
-
|
121
|
-
if (ttl) {
|
122
|
-
const ttlRec = new JacksonTTL(dbKey, Date.now() + ttl * 1000);
|
123
|
-
await transactionalEntityManager.save(ttlRec);
|
124
|
-
}
|
125
|
-
|
126
|
-
// no ttl support for secondary indexes
|
127
|
-
for (const idx of indexes || []) {
|
128
|
-
const key = dbutils.keyForIndex(namespace, idx);
|
129
|
-
const rec = await this.indexRepository.findOne({
|
130
|
-
key,
|
131
|
-
storeKey: store.key,
|
132
|
-
});
|
133
|
-
if (!rec) {
|
134
|
-
await transactionalEntityManager.save(
|
135
|
-
new JacksonIndex(0, key, store)
|
136
|
-
);
|
137
|
-
}
|
138
|
-
}
|
139
|
-
});
|
140
|
-
}
|
141
|
-
|
142
|
-
async delete(namespace, key) {
|
143
|
-
return await this.storeRepository.remove({
|
144
|
-
key: dbutils.key(namespace, key),
|
145
|
-
});
|
146
|
-
}
|
147
|
-
}
|
148
|
-
|
149
|
-
module.exports = {
|
150
|
-
new: async (options) => {
|
151
|
-
return new Sql(options);
|
152
|
-
},
|
153
|
-
};
|
package/src/db/store.js
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
const dbutils = require('./utils.js');
|
2
|
-
|
3
|
-
class Store {
|
4
|
-
constructor(namespace, db, ttl = 0) {
|
5
|
-
this.namespace = namespace;
|
6
|
-
this.db = db;
|
7
|
-
this.ttl = ttl;
|
8
|
-
}
|
9
|
-
|
10
|
-
async get(key) {
|
11
|
-
return await this.db.get(this.namespace, dbutils.keyDigest(key));
|
12
|
-
}
|
13
|
-
|
14
|
-
async getByIndex(idx) {
|
15
|
-
idx.value = dbutils.keyDigest(idx.value);
|
16
|
-
return await this.db.getByIndex(this.namespace, idx);
|
17
|
-
}
|
18
|
-
|
19
|
-
async put(key, val, ...indexes) {
|
20
|
-
indexes = (indexes || []).map((idx) => {
|
21
|
-
idx.value = dbutils.keyDigest(idx.value);
|
22
|
-
return idx;
|
23
|
-
});
|
24
|
-
return await this.db.put(
|
25
|
-
this.namespace,
|
26
|
-
dbutils.keyDigest(key),
|
27
|
-
val,
|
28
|
-
this.ttl,
|
29
|
-
...indexes
|
30
|
-
);
|
31
|
-
}
|
32
|
-
|
33
|
-
async delete(key) {
|
34
|
-
return await this.db.delete(this.namespace, dbutils.keyDigest(key));
|
35
|
-
}
|
36
|
-
}
|
37
|
-
|
38
|
-
module.exports = {
|
39
|
-
new: (namespace, db, ttl = 0) => {
|
40
|
-
return new Store(namespace, db, ttl);
|
41
|
-
},
|
42
|
-
};
|
package/src/db/utils.js
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
const Ripemd160 = require('ripemd160');
|
2
|
-
|
3
|
-
const key = (namespace, k) => {
|
4
|
-
return namespace + ':' + k;
|
5
|
-
};
|
6
|
-
|
7
|
-
const keyForIndex = (namespace, idx) => {
|
8
|
-
return key(key(namespace, idx.name), idx.value);
|
9
|
-
};
|
10
|
-
|
11
|
-
const keyDigest = (k) => {
|
12
|
-
return new Ripemd160().update(k).digest('hex');
|
13
|
-
};
|
14
|
-
|
15
|
-
const keyFromParts = (...parts) => {
|
16
|
-
return parts.join(':'); // TODO: pick a better strategy, keys can collide now
|
17
|
-
};
|
18
|
-
|
19
|
-
const sleep = (ms) => {
|
20
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
21
|
-
};
|
22
|
-
|
23
|
-
module.exports = {
|
24
|
-
key,
|
25
|
-
keyForIndex,
|
26
|
-
keyDigest,
|
27
|
-
keyFromParts,
|
28
|
-
sleep,
|
29
|
-
indexPrefix: '_index',
|
30
|
-
};
|
package/src/env.js
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
const hostUrl = process.env.HOST_URL || 'localhost';
|
2
|
-
const hostPort = (process.env.HOST_PORT || '5000') * 1;
|
3
|
-
const externalUrl =
|
4
|
-
process.env.EXTERNAL_URL || 'http://' + hostUrl + ':' + hostPort;
|
5
|
-
const samlPath = process.env.SAML_PATH || '/oauth/saml';
|
6
|
-
|
7
|
-
const internalHostUrl = process.env.INTERNAL_HOST_URL || 'localhost';
|
8
|
-
const internalHostPort = (process.env.INTERNAL_HOST_PORT || '6000') * 1;
|
9
|
-
|
10
|
-
const apiKeys = (process.env.JACKSON_API_KEYS || '').split(',');
|
11
|
-
|
12
|
-
const samlAudience = process.env.SAML_AUDIENCE;
|
13
|
-
const preLoadedConfig = process.env.PRE_LOADED_CONFIG;
|
14
|
-
|
15
|
-
const idpEnabled = process.env.IDP_ENABLED;
|
16
|
-
const db = {
|
17
|
-
engine: process.env.DB_ENGINE,
|
18
|
-
url: process.env.DB_URL,
|
19
|
-
type: process.env.DB_TYPE,
|
20
|
-
ttl: process.env.DB_TTL,
|
21
|
-
encryptionKey: process.env.DB_ENCRYPTION_KEY,
|
22
|
-
};
|
23
|
-
|
24
|
-
module.exports = {
|
25
|
-
hostUrl,
|
26
|
-
hostPort,
|
27
|
-
externalUrl,
|
28
|
-
samlPath,
|
29
|
-
samlAudience,
|
30
|
-
preLoadedConfig,
|
31
|
-
internalHostUrl,
|
32
|
-
internalHostPort,
|
33
|
-
apiKeys,
|
34
|
-
idpEnabled,
|
35
|
-
db,
|
36
|
-
useInternalServer: !(
|
37
|
-
hostUrl === internalHostUrl && hostPort === internalHostPort
|
38
|
-
),
|
39
|
-
};
|
package/src/index.js
DELETED
@@ -1,67 +0,0 @@
|
|
1
|
-
const DB = require('./db/db.js');
|
2
|
-
const readConfig = require('./read-config.js');
|
3
|
-
|
4
|
-
const defaultOpts = (opts) => {
|
5
|
-
const newOpts = {
|
6
|
-
...opts,
|
7
|
-
};
|
8
|
-
|
9
|
-
if (!newOpts.externalUrl) {
|
10
|
-
throw new Error('externalUrl is required');
|
11
|
-
}
|
12
|
-
if (!newOpts.samlPath) {
|
13
|
-
throw new Error('samlPath is required');
|
14
|
-
}
|
15
|
-
|
16
|
-
newOpts.samlAudience = newOpts.samlAudience || 'https://saml.boxyhq.com';
|
17
|
-
newOpts.preLoadedConfig = newOpts.preLoadedConfig || ''; // path to folder containing static SAML config 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).
|
18
|
-
newOpts.idpEnabled = newOpts.idpEnabled === true;
|
19
|
-
newOpts.db = newOpts.db || {};
|
20
|
-
newOpts.db.engine = newOpts.db.engine || 'sql'; // Supported values: redis, sql, mongo, mem. Keep comment in sync with db.js
|
21
|
-
newOpts.db.url =
|
22
|
-
newOpts.db.url || 'postgresql://postgres:postgres@localhost:5432/postgres';
|
23
|
-
newOpts.db.type = newOpts.db.type || 'postgres'; // Only needed if DB_ENGINE is sql. Supported values: postgres, cockroachdb, mysql, mariadb
|
24
|
-
newOpts.db.ttl = (newOpts.db.ttl || 300) * 1; // TTL for the code, session and token stores (in seconds)
|
25
|
-
newOpts.db.cleanupLimit = (newOpts.db.cleanupLimit || 1000) * 1; // Limit cleanup of TTL entries to this many items at a time
|
26
|
-
|
27
|
-
return newOpts;
|
28
|
-
};
|
29
|
-
|
30
|
-
module.exports = async function (opts) {
|
31
|
-
opts = defaultOpts(opts);
|
32
|
-
|
33
|
-
const db = await DB.new(opts.db);
|
34
|
-
const configStore = db.store('saml:config');
|
35
|
-
const sessionStore = db.store('oauth:session', opts.db.ttl);
|
36
|
-
const codeStore = db.store('oauth:code', opts.db.ttl);
|
37
|
-
const tokenStore = db.store('oauth:token', opts.db.ttl);
|
38
|
-
|
39
|
-
const apiController = require('./controller/api.js')({ configStore });
|
40
|
-
const oauthController = require('./controller/oauth.js')({
|
41
|
-
configStore,
|
42
|
-
sessionStore,
|
43
|
-
codeStore,
|
44
|
-
tokenStore,
|
45
|
-
opts,
|
46
|
-
});
|
47
|
-
// write pre-loaded config if present
|
48
|
-
if (opts.preLoadedConfig && opts.preLoadedConfig.length > 0) {
|
49
|
-
const configs = await readConfig(opts.preLoadedConfig);
|
50
|
-
|
51
|
-
for (const config of configs) {
|
52
|
-
await apiController.config(config);
|
53
|
-
console.log(
|
54
|
-
`loaded config for tenant "${config.tenant}" and product "${config.product}"`
|
55
|
-
);
|
56
|
-
}
|
57
|
-
}
|
58
|
-
|
59
|
-
const type =
|
60
|
-
opts.db.engine === 'sql' && opts.db.type ? ' Type: ' + opts.db.type : '';
|
61
|
-
console.log(`Using engine: ${opts.db.engine}.${type}`);
|
62
|
-
|
63
|
-
return {
|
64
|
-
apiController,
|
65
|
-
oauthController,
|
66
|
-
};
|
67
|
-
};
|
package/src/jackson.js
DELETED
@@ -1,161 +0,0 @@
|
|
1
|
-
const express = require('express');
|
2
|
-
const cors = require('cors');
|
3
|
-
|
4
|
-
const env = require('./env.js');
|
5
|
-
const { extractAuthToken } = require('./controller/utils.js');
|
6
|
-
|
7
|
-
let apiController;
|
8
|
-
let oauthController;
|
9
|
-
|
10
|
-
const oauthPath = '/oauth';
|
11
|
-
const apiPath = '/api/v1/saml';
|
12
|
-
|
13
|
-
const app = express();
|
14
|
-
|
15
|
-
app.use(express.json());
|
16
|
-
app.use(express.urlencoded({ extended: true }));
|
17
|
-
|
18
|
-
app.get(oauthPath + '/authorize', async (req, res) => {
|
19
|
-
try {
|
20
|
-
const { redirect_url } = await oauthController.authorize(req.query);
|
21
|
-
|
22
|
-
res.redirect(redirect_url);
|
23
|
-
} catch (err) {
|
24
|
-
const { message, statusCode = 500 } = err;
|
25
|
-
|
26
|
-
res.status(statusCode).send(message);
|
27
|
-
}
|
28
|
-
});
|
29
|
-
|
30
|
-
app.post(env.samlPath, async (req, res) => {
|
31
|
-
try {
|
32
|
-
const { redirect_url } = await oauthController.samlResponse(req.body);
|
33
|
-
|
34
|
-
res.redirect(redirect_url);
|
35
|
-
} catch (err) {
|
36
|
-
const { message, statusCode = 500 } = err;
|
37
|
-
|
38
|
-
res.status(statusCode).send(message);
|
39
|
-
}
|
40
|
-
});
|
41
|
-
|
42
|
-
app.post(oauthPath + '/token', cors(), async (req, res) => {
|
43
|
-
try {
|
44
|
-
const result = await oauthController.token(req.body);
|
45
|
-
|
46
|
-
res.json(result);
|
47
|
-
} catch (err) {
|
48
|
-
const { message, statusCode = 500 } = err;
|
49
|
-
|
50
|
-
res.status(statusCode).send(message);
|
51
|
-
}
|
52
|
-
});
|
53
|
-
|
54
|
-
app.get(oauthPath + '/userinfo', async (req, res) => {
|
55
|
-
try {
|
56
|
-
let token = extractAuthToken(req);
|
57
|
-
|
58
|
-
// check for query param
|
59
|
-
if (!token) {
|
60
|
-
token = req.query.access_token;
|
61
|
-
}
|
62
|
-
|
63
|
-
if (!token) {
|
64
|
-
res.status(401).json({ message: 'Unauthorized' });
|
65
|
-
}
|
66
|
-
|
67
|
-
const profile = await oauthController.userInfo(token);
|
68
|
-
|
69
|
-
res.json(profile);
|
70
|
-
} catch (err) {
|
71
|
-
const { message, statusCode = 500 } = err;
|
72
|
-
|
73
|
-
res.status(statusCode).json({ message });
|
74
|
-
}
|
75
|
-
});
|
76
|
-
|
77
|
-
const server = app.listen(env.hostPort, async () => {
|
78
|
-
console.log(
|
79
|
-
`🚀 The path of the righteous server: http://${env.hostUrl}:${env.hostPort}`
|
80
|
-
);
|
81
|
-
|
82
|
-
const ret = await require('./index.js')(env);
|
83
|
-
apiController = ret.apiController;
|
84
|
-
oauthController = ret.oauthController;
|
85
|
-
});
|
86
|
-
|
87
|
-
// Internal routes, recommended not to expose this to the public interface though it would be guarded by API key(s)
|
88
|
-
let internalApp = app;
|
89
|
-
|
90
|
-
if (env.useInternalServer) {
|
91
|
-
internalApp = express();
|
92
|
-
|
93
|
-
internalApp.use(express.json());
|
94
|
-
internalApp.use(express.urlencoded({ extended: true }));
|
95
|
-
}
|
96
|
-
|
97
|
-
const validateApiKey = (token) => {
|
98
|
-
return env.apiKeys.includes(token);
|
99
|
-
};
|
100
|
-
|
101
|
-
internalApp.post(apiPath + '/config', async (req, res) => {
|
102
|
-
try {
|
103
|
-
const apiKey = extractAuthToken(req);
|
104
|
-
if (!validateApiKey(apiKey)) {
|
105
|
-
res.status(401).send('Unauthorized');
|
106
|
-
return;
|
107
|
-
}
|
108
|
-
|
109
|
-
res.json(await apiController.config(req.body));
|
110
|
-
} catch (err) {
|
111
|
-
res.status(500).json({
|
112
|
-
error: err.message,
|
113
|
-
});
|
114
|
-
}
|
115
|
-
});
|
116
|
-
|
117
|
-
internalApp.get(apiPath + '/config', async (req, res) => {
|
118
|
-
try {
|
119
|
-
const apiKey = extractAuthToken(req);
|
120
|
-
if (!validateApiKey(apiKey)) {
|
121
|
-
res.status(401).send('Unauthorized');
|
122
|
-
return;
|
123
|
-
}
|
124
|
-
|
125
|
-
res.json(await apiController.getConfig(req.query));
|
126
|
-
} catch (err) {
|
127
|
-
res.status(500).json({
|
128
|
-
error: err.message,
|
129
|
-
});
|
130
|
-
}
|
131
|
-
});
|
132
|
-
|
133
|
-
internalApp.delete(apiPath + '/config', async (req, res) => {
|
134
|
-
try {
|
135
|
-
const apiKey = extractAuthToken(req);
|
136
|
-
if (!validateApiKey(apiKey)) {
|
137
|
-
res.status(401).send('Unauthorized');
|
138
|
-
return;
|
139
|
-
}
|
140
|
-
await apiController.deleteConfig(req.body);
|
141
|
-
res.status(200).end();
|
142
|
-
} catch (err) {
|
143
|
-
res.status(500).json({
|
144
|
-
error: err.message,
|
145
|
-
});
|
146
|
-
}
|
147
|
-
});
|
148
|
-
|
149
|
-
let internalServer = server;
|
150
|
-
if (env.useInternalServer) {
|
151
|
-
internalServer = internalApp.listen(env.internalHostPort, async () => {
|
152
|
-
console.log(
|
153
|
-
`🚀 The path of the righteous internal server: http://${env.internalHostUrl}:${env.internalHostPort}`
|
154
|
-
);
|
155
|
-
});
|
156
|
-
}
|
157
|
-
|
158
|
-
module.exports = {
|
159
|
-
server,
|
160
|
-
internalServer,
|
161
|
-
};
|
package/src/read-config.js
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
const fs = require('fs');
|
2
|
-
const path = require('path');
|
3
|
-
|
4
|
-
module.exports = async function (preLoadedConfig) {
|
5
|
-
if (preLoadedConfig.startsWith('./')) {
|
6
|
-
preLoadedConfig = path.resolve(process.cwd(), preLoadedConfig);
|
7
|
-
}
|
8
|
-
const files = await fs.promises.readdir(preLoadedConfig);
|
9
|
-
const configs = [];
|
10
|
-
for (let idx in files) {
|
11
|
-
const file = files[idx];
|
12
|
-
if (file.endsWith('.js')) {
|
13
|
-
const config = require(path.join(preLoadedConfig, file));
|
14
|
-
const rawMetadata = await fs.promises.readFile(
|
15
|
-
path.join(preLoadedConfig, path.parse(file).name + '.xml'),
|
16
|
-
'utf8'
|
17
|
-
);
|
18
|
-
config.rawMetadata = rawMetadata;
|
19
|
-
configs.push(config);
|
20
|
-
}
|
21
|
-
}
|
22
|
-
|
23
|
-
return configs;
|
24
|
-
};
|
package/src/saml/claims.js
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
const mapping = [
|
2
|
-
{
|
3
|
-
attribute: 'id',
|
4
|
-
schema:
|
5
|
-
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier',
|
6
|
-
},
|
7
|
-
{
|
8
|
-
attribute: 'email',
|
9
|
-
schema:
|
10
|
-
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress',
|
11
|
-
},
|
12
|
-
{
|
13
|
-
attribute: 'firstName',
|
14
|
-
schema: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname',
|
15
|
-
},
|
16
|
-
{
|
17
|
-
attribute: 'lastName',
|
18
|
-
schema: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname',
|
19
|
-
},
|
20
|
-
];
|
21
|
-
|
22
|
-
const map = (claims) => {
|
23
|
-
const profile = {
|
24
|
-
raw: claims,
|
25
|
-
};
|
26
|
-
|
27
|
-
mapping.forEach((m) => {
|
28
|
-
if (claims[m.attribute]) {
|
29
|
-
profile[m.attribute] = claims[m.attribute];
|
30
|
-
} else if (claims[m.schema]) {
|
31
|
-
profile[m.attribute] = claims[m.schema];
|
32
|
-
}
|
33
|
-
});
|
34
|
-
|
35
|
-
return profile;
|
36
|
-
};
|
37
|
-
|
38
|
-
module.exports = {
|
39
|
-
map,
|
40
|
-
};
|