carta-controller 2.0.2 → 2.0.5
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/config/config_schema.json +39 -1
- package/dist/auth/ldap.js +13 -11
- package/dist/auth/ldap.js.map +1 -1
- package/dist/config.js +7 -1
- package/dist/controllerTests.js +59 -34
- package/dist/database.js +6 -6
- package/dist/serverHandlers.js +27 -11
- package/dist/util.js +14 -1
- package/docs/_build/doctrees/configuration.doctree +0 -0
- package/docs/_build/doctrees/environment.pickle +0 -0
- package/docs/_build/doctrees/index.doctree +0 -0
- package/docs/_build/doctrees/introduction.doctree +0 -0
- package/docs/_build/doctrees/schema.doctree +0 -0
- package/docs/_build/doctrees/ubuntu_focal_instructions.doctree +0 -0
- package/docs/_build/html/.buildinfo +1 -1
- package/docs/_build/html/_sources/configuration.rst.txt +4 -1
- package/docs/_build/html/_sources/index.rst.txt +2 -2
- package/docs/_build/html/_sources/introduction.rst.txt +1 -1
- package/docs/_build/html/_sources/ubuntu_focal_instructions.rst.txt +1 -1
- package/docs/_build/html/_static/config/config_schema.json +44 -1
- package/docs/_build/html/_static/config/layout_schema_2.json +17 -86
- package/docs/_build/html/_static/config/snippet_schema.json +44 -0
- package/docs/_build/html/_static/documentation_options.js +1 -1
- package/docs/_build/html/configuration.html +5 -1
- package/docs/_build/html/genindex.html +1 -1
- package/docs/_build/html/index.html +2 -2
- package/docs/_build/html/installation.html +1 -1
- package/docs/_build/html/introduction.html +2 -2
- package/docs/_build/html/schema.html +137 -35
- package/docs/_build/html/search.html +1 -1
- package/docs/_build/html/searchindex.js +1 -1
- package/docs/_build/html/ubuntu_focal_instructions.html +2 -2
- package/docs/src/configuration.rst +4 -1
- package/package.json +1 -1
- package/config/testLayout.json +0 -125
|
@@ -187,7 +187,7 @@
|
|
|
187
187
|
"ldapOptions": {
|
|
188
188
|
"description": "Options to path through to the LDAP auth instance",
|
|
189
189
|
"type": "object",
|
|
190
|
-
"additionalProperties":
|
|
190
|
+
"additionalProperties": true,
|
|
191
191
|
"required": [
|
|
192
192
|
"url",
|
|
193
193
|
"searchBase"
|
|
@@ -217,6 +217,39 @@
|
|
|
217
217
|
"description": "Whether to automatically reconnect to LDAP",
|
|
218
218
|
"type": "boolean",
|
|
219
219
|
"default": true
|
|
220
|
+
},
|
|
221
|
+
"bindProperty": {
|
|
222
|
+
"description": "Property of the LDAP user object to use when binding to verify the password",
|
|
223
|
+
"type": "string",
|
|
224
|
+
"default": "dn"
|
|
225
|
+
},
|
|
226
|
+
"searchScope" : {
|
|
227
|
+
"description": "Scope of the search",
|
|
228
|
+
"type": "string",
|
|
229
|
+
"enum": ["base", "one", "sub"],
|
|
230
|
+
"default": "sub"
|
|
231
|
+
},
|
|
232
|
+
"bindDN": {
|
|
233
|
+
"description": "Admin connection DN, e.g. uid=myapp,ou=users,dc=example,dc=org. If not given at all, admin client is not bound.",
|
|
234
|
+
"type": "string"
|
|
235
|
+
},
|
|
236
|
+
"bindCredentials": {
|
|
237
|
+
"description": "Password for bindDN",
|
|
238
|
+
"type": "string"
|
|
239
|
+
},
|
|
240
|
+
"cache": {
|
|
241
|
+
"description": "If true, then up to 100 credentials at a time will be cached for 5 minutes",
|
|
242
|
+
"type": "boolean",
|
|
243
|
+
"default": false
|
|
244
|
+
},
|
|
245
|
+
"strictDN": {
|
|
246
|
+
"description": "Force strict DN parsing for client methods",
|
|
247
|
+
"type": "boolean",
|
|
248
|
+
"default": true
|
|
249
|
+
},
|
|
250
|
+
"idleTimeout": {
|
|
251
|
+
"description": "Milliseconds after last activity before client emits idle event",
|
|
252
|
+
"type": "number"
|
|
220
253
|
}
|
|
221
254
|
}
|
|
222
255
|
}
|
|
@@ -422,6 +455,11 @@
|
|
|
422
455
|
],
|
|
423
456
|
"default": "/usr/bin/carta_backend"
|
|
424
457
|
},
|
|
458
|
+
"preserveEnv": {
|
|
459
|
+
"description": "Use the --preserve-env argument when calling sudo",
|
|
460
|
+
"type": "boolean",
|
|
461
|
+
"default": true
|
|
462
|
+
},
|
|
425
463
|
"killCommand": {
|
|
426
464
|
"description": "Path to CARTA kill script",
|
|
427
465
|
"type": "string",
|
package/dist/auth/ldap.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.getLdapLoginHandler = void 0;
|
|
|
4
4
|
const userid = require("userid");
|
|
5
5
|
const LdapAuth = require("ldapauth-fork");
|
|
6
6
|
const local_1 = require("./local");
|
|
7
|
+
const util_1 = require("../util");
|
|
7
8
|
let ldap;
|
|
8
9
|
function getLdapLoginHandler(authConf) {
|
|
9
10
|
ldap = new LdapAuth(authConf.ldapOptions);
|
|
@@ -28,19 +29,20 @@ function getLdapLoginHandler(authConf) {
|
|
|
28
29
|
const handleAuth = (err, user) => {
|
|
29
30
|
if (err) {
|
|
30
31
|
console.error(err);
|
|
31
|
-
}
|
|
32
|
-
if (err || (user === null || user === void 0 ? void 0 : user.uid) !== username) {
|
|
33
32
|
return res.status(403).json({ statusCode: 403, message: "Invalid username/password combo" });
|
|
34
33
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
34
|
+
if ((user === null || user === void 0 ? void 0 : user.uid) !== username) {
|
|
35
|
+
console.warn(`Returned user "uid ${user === null || user === void 0 ? void 0 : user.uid}" does not match username "${username}"`);
|
|
36
|
+
util_1.verboseLog(user);
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const uid = userid.uid(username);
|
|
40
|
+
console.log(`Authenticated as user ${username} with uid ${uid} using LDAP`);
|
|
41
|
+
return local_1.addTokensToResponse(authConf, username, res);
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
util_1.verboseError(e);
|
|
45
|
+
return res.status(403).json({ statusCode: 403, message: "User does not exist" });
|
|
44
46
|
}
|
|
45
47
|
};
|
|
46
48
|
ldap.authenticate(username, password, (error, user) => {
|
package/dist/auth/ldap.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ldap.js","sourceRoot":"","sources":["../../src/auth/ldap.ts"],"names":[],"mappings":";;;AACA,iCAAiC;AACjC,0CAA0C;AAE1C,mCAA4C;
|
|
1
|
+
{"version":3,"file":"ldap.js","sourceRoot":"","sources":["../../src/auth/ldap.ts"],"names":[],"mappings":";;;AACA,iCAAiC;AACjC,0CAA0C;AAE1C,mCAA4C;AAC5C,kCAAiD;AAGjD,IAAI,IAAc,CAAC;AAEnB,SAAgB,mBAAmB,CAAC,QAA6B;IAC7D,IAAI,GAAG,IAAI,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IAC1C,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC;IAC1D,UAAU,CAAC,GAAG,EAAE;;QACZ,MAAM,aAAa,GAAG,MAAA,MAAC,IAAY,0CAAE,WAAW,0CAAE,SAAS,CAAC;QAC5D,IAAI,aAAa,EAAE;YACf,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;SAC3C;aAAM;YACH,OAAO,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;SACxC;IACL,CAAC,EAAE,IAAI,CAAC,CAAC;IAET,OAAO,CAAC,GAAoB,EAAE,GAAqB,EAAE,EAAE;;QACnD,IAAI,QAAQ,GAAG,MAAA,GAAG,CAAC,IAAI,0CAAE,QAAQ,CAAC;QAClC,MAAM,QAAQ,GAAG,MAAA,GAAG,CAAC,IAAI,0CAAE,QAAQ,CAAC;QAEpC,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,EAAE;YACxB,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAC,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,yBAAyB,EAAC,CAAC,CAAC;SACtF;QAED,MAAM,UAAU,GAAG,CAAC,GAAmB,EAAE,IAAS,EAAE,EAAE;YAClD,IAAI,GAAG,EAAE;gBACL,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBACnB,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAC,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,iCAAiC,EAAC,CAAC,CAAC;aAC9F;YACD,IAAI,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,GAAG,MAAK,QAAQ,EAAE;gBACxB,OAAO,CAAC,IAAI,CAAC,sBAAsB,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,GAAG,8BAA8B,QAAQ,GAAG,CAAC,CAAC;gBACvF,iBAAU,CAAC,IAAI,CAAC,CAAC;aACpB;YACD,IAAI;gBACA,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACjC,OAAO,CAAC,GAAG,CAAC,yBAAyB,QAAQ,aAAa,GAAG,aAAa,CAAC,CAAC;gBAC5E,OAAO,2BAAmB,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;aACvD;YAAC,OAAO,CAAC,EAAE;gBACR,mBAAY,CAAC,CAAC,CAAC,CAAC;gBAChB,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAC,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,qBAAqB,EAAC,CAAC,CAAC;aAClF;QACL,CAAC,CAAA;QAED,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;;YAClD,MAAM,QAAQ,GAAG,KAAc,CAAC;YAChC,oDAAoD;YACpD,IAAI,MAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,IAAI,0CAAE,QAAQ,CAAC,8BAA8B,CAAC,EAAE;gBAC1D,OAAO,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;gBACvE,IAAI,CAAC,KAAK,EAAE,CAAC;gBACb,IAAI,GAAG,IAAI,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;gBAC1C,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC;gBAC1D,+CAA+C;gBAC/C,UAAU,CAAC,GAAG,EAAE;oBACZ,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;gBACtD,CAAC,EAAE,GAAG,CAAC,CAAC;aACX;iBAAM;gBACH,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;aAC3B;QACL,CAAC,CAAC,CAAC;IACP,CAAC,CAAC;AACN,CAAC;AAxDD,kDAwDC"}
|
package/dist/config.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var _a, _b;
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.testUser = exports.RuntimeConfig = exports.ServerConfig = void 0;
|
|
4
|
+
exports.verboseOutput = exports.testUser = exports.RuntimeConfig = exports.ServerConfig = void 0;
|
|
5
5
|
const yargs = require("yargs");
|
|
6
6
|
const url = require("url");
|
|
7
7
|
const fs = require("fs");
|
|
@@ -23,11 +23,17 @@ const argv = yargs.options({
|
|
|
23
23
|
alias: "t",
|
|
24
24
|
requiresArg: true,
|
|
25
25
|
description: "Test configuration with the provided user"
|
|
26
|
+
},
|
|
27
|
+
verbose: {
|
|
28
|
+
type: "boolean",
|
|
29
|
+
alias: "v"
|
|
26
30
|
}
|
|
27
31
|
}).argv;
|
|
28
32
|
const usingCustomConfig = argv.config !== defaultConfigPath;
|
|
29
33
|
const testUser = argv.test;
|
|
30
34
|
exports.testUser = testUser;
|
|
35
|
+
const verboseOutput = argv.verbose;
|
|
36
|
+
exports.verboseOutput = verboseOutput;
|
|
31
37
|
const configSchema = require("../config/config_schema.json");
|
|
32
38
|
const ajv = new ajv_1.default({ useDefaults: false, allowUnionTypes: true });
|
|
33
39
|
const ajvWithDefaults = new ajv_1.default({ useDefaults: true, allowUnionTypes: true });
|
package/dist/controllerTests.js
CHANGED
|
@@ -40,7 +40,7 @@ function runTests(username) {
|
|
|
40
40
|
}
|
|
41
41
|
yield testDatabase();
|
|
42
42
|
if (config_1.ServerConfig.logFileTemplate) {
|
|
43
|
-
testLog(username);
|
|
43
|
+
yield testLog(username);
|
|
44
44
|
}
|
|
45
45
|
testFrontend();
|
|
46
46
|
const backendProcess = yield testBackendStartup(username);
|
|
@@ -49,20 +49,21 @@ function runTests(username) {
|
|
|
49
49
|
}
|
|
50
50
|
exports.runTests = runTests;
|
|
51
51
|
function testLog(username) {
|
|
52
|
-
|
|
53
|
-
.replace("{username}", username)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
52
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
53
|
+
const logLocation = config_1.ServerConfig.logFileTemplate.replace("{username}", username).replace("{pid}", "9999").replace("{datetime}", moment().format("YYYYMMDD.h_mm_ss"));
|
|
54
|
+
try {
|
|
55
|
+
const logStream = fs.createWriteStream(logLocation, { flags: "a" });
|
|
56
|
+
// Transform callbacks into awaits
|
|
57
|
+
yield new Promise(res => logStream.write("test", res));
|
|
58
|
+
yield new Promise(res => logStream.end(res));
|
|
59
|
+
fs.unlinkSync(logLocation);
|
|
60
|
+
console.log(logSymbols.success, `Checked log writing for user ${username}`);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
util_1.verboseError(err);
|
|
64
|
+
throw new Error(`Could not create log file at ${logLocation} for user ${username}. Please check your config file's logFileTemplate option`);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
66
67
|
}
|
|
67
68
|
function testLdap(authConf, username) {
|
|
68
69
|
return new Promise((resolve, reject) => {
|
|
@@ -72,12 +73,17 @@ function testLdap(authConf, username) {
|
|
|
72
73
|
ldap = new LdapAuth(authConf.ldapOptions);
|
|
73
74
|
setTimeout(() => {
|
|
74
75
|
read({ prompt: `Password for user ${username}:`, silent: true }, (er, password) => {
|
|
75
|
-
ldap.authenticate(username, password, (error,
|
|
76
|
+
ldap.authenticate(username, password, (error, user) => {
|
|
76
77
|
if (error) {
|
|
78
|
+
util_1.verboseError(error);
|
|
77
79
|
reject(new Error(`Could not authenticate as user ${username}. Please check your config file's ldapOptions section!`));
|
|
78
80
|
}
|
|
79
81
|
else {
|
|
80
82
|
console.log(logSymbols.success, `Checked LDAP connection for user ${username}`);
|
|
83
|
+
if ((user === null || user === void 0 ? void 0 : user.uid) !== username) {
|
|
84
|
+
console.warn(logSymbols.warning, `Returned user "uid ${user === null || user === void 0 ? void 0 : user.uid}" does not match username "${username}"`);
|
|
85
|
+
util_1.verboseLog(user);
|
|
86
|
+
}
|
|
81
87
|
resolve();
|
|
82
88
|
}
|
|
83
89
|
});
|
|
@@ -85,6 +91,7 @@ function testLdap(authConf, username) {
|
|
|
85
91
|
}, 5000);
|
|
86
92
|
}
|
|
87
93
|
catch (e) {
|
|
94
|
+
util_1.verboseError(e);
|
|
88
95
|
reject(new Error("Cannot create LDAP object. Please check your config file's ldapOptions section!"));
|
|
89
96
|
}
|
|
90
97
|
}
|
|
@@ -97,10 +104,11 @@ function testPam(authConf, username) {
|
|
|
97
104
|
read({ prompt: `Password for user ${username}:`, silent: true }, (er, password) => {
|
|
98
105
|
pamAuthenticate({ username, password }, (err, code) => {
|
|
99
106
|
if (err) {
|
|
100
|
-
|
|
107
|
+
util_1.verboseError(err);
|
|
108
|
+
reject(new Error(`Could not authenticate as user ${username}. Error code ${code}`));
|
|
101
109
|
}
|
|
102
110
|
else {
|
|
103
|
-
console.log(logSymbols.success, `Checked
|
|
111
|
+
console.log(logSymbols.success, `Checked PAM connection for user ${username}`);
|
|
104
112
|
resolve();
|
|
105
113
|
}
|
|
106
114
|
});
|
|
@@ -116,6 +124,7 @@ function testDatabase() {
|
|
|
116
124
|
yield db.listCollections({}, { nameOnly: true }).hasNext();
|
|
117
125
|
}
|
|
118
126
|
catch (e) {
|
|
127
|
+
util_1.verboseError(e);
|
|
119
128
|
throw new Error("Cannot connect to MongoDB. Please check your config file's database section!");
|
|
120
129
|
}
|
|
121
130
|
console.log(logSymbols.success, "Checked database connection");
|
|
@@ -127,6 +136,7 @@ function testUid(username) {
|
|
|
127
136
|
uid = userid.uid(username);
|
|
128
137
|
}
|
|
129
138
|
catch (e) {
|
|
139
|
+
util_1.verboseError(e);
|
|
130
140
|
throw new Error(`Cannot verify uid of user ${username}`);
|
|
131
141
|
}
|
|
132
142
|
if (!uid) {
|
|
@@ -140,7 +150,7 @@ function testToken(authConf, username) {
|
|
|
140
150
|
token = local_1.generateToken(authConf, username, false);
|
|
141
151
|
}
|
|
142
152
|
catch (e) {
|
|
143
|
-
|
|
153
|
+
util_1.verboseError(e);
|
|
144
154
|
throw new Error(`Cannot generate access token. Please check your config file's ldap auth section!`);
|
|
145
155
|
}
|
|
146
156
|
if (!token) {
|
|
@@ -157,6 +167,7 @@ function testFrontend() {
|
|
|
157
167
|
indexContents = fs.readFileSync(config_1.ServerConfig.frontendPath + "/index.html").toString();
|
|
158
168
|
}
|
|
159
169
|
catch (e) {
|
|
170
|
+
util_1.verboseError(e);
|
|
160
171
|
throw new Error(`Cannot access frontend at ${config_1.ServerConfig.frontendPath}`);
|
|
161
172
|
}
|
|
162
173
|
if (!indexContents) {
|
|
@@ -169,24 +180,36 @@ function testFrontend() {
|
|
|
169
180
|
function testBackendStartup(username) {
|
|
170
181
|
return __awaiter(this, void 0, void 0, function* () {
|
|
171
182
|
const port = config_1.ServerConfig.backendPorts.max - 1;
|
|
172
|
-
let args = [
|
|
173
|
-
|
|
174
|
-
"-
|
|
183
|
+
let args = [];
|
|
184
|
+
if (config_1.ServerConfig.preserveEnv) {
|
|
185
|
+
args.push("--preserve-env=CARTA_AUTH_TOKEN");
|
|
186
|
+
}
|
|
187
|
+
args = args.concat([
|
|
188
|
+
"-n",
|
|
189
|
+
"-u",
|
|
190
|
+
`${username}`,
|
|
175
191
|
config_1.ServerConfig.processCommand,
|
|
176
|
-
"--no_http",
|
|
177
|
-
"--debug_no_auth",
|
|
178
|
-
"--
|
|
179
|
-
|
|
180
|
-
"--top_level_folder",
|
|
181
|
-
config_1.ServerConfig.
|
|
182
|
-
];
|
|
192
|
+
"--no_http",
|
|
193
|
+
"--debug_no_auth",
|
|
194
|
+
"--port",
|
|
195
|
+
`${port}`,
|
|
196
|
+
"--top_level_folder",
|
|
197
|
+
config_1.ServerConfig.rootFolderTemplate.replace("{username}", username)
|
|
198
|
+
]);
|
|
199
|
+
if (config_1.ServerConfig.logFileTemplate) {
|
|
200
|
+
args.push("--no_log");
|
|
201
|
+
}
|
|
183
202
|
if (config_1.ServerConfig.additionalArgs) {
|
|
184
203
|
args = args.concat(config_1.ServerConfig.additionalArgs);
|
|
185
204
|
}
|
|
186
|
-
|
|
205
|
+
// Finally, add the positional argument for the base folder
|
|
206
|
+
args.push(config_1.ServerConfig.baseFolderTemplate.replace("{username}", username));
|
|
207
|
+
util_1.verboseLog(`running sudo ${args.join(" ")}`);
|
|
208
|
+
// Use same stdout and stderr stream for the backend process
|
|
209
|
+
const backendProcess = child_process_1.spawn("sudo", args, { stdio: "inherit" });
|
|
187
210
|
yield util_1.delay(2000);
|
|
188
211
|
if (backendProcess.signalCode) {
|
|
189
|
-
throw new Error(
|
|
212
|
+
throw new Error(`Backend process terminated with code ${backendProcess.signalCode}. Please check your sudoers config, processCommand option and additionalArgs section`);
|
|
190
213
|
}
|
|
191
214
|
else {
|
|
192
215
|
console.log(logSymbols.success, "Backend process started successfully");
|
|
@@ -210,11 +233,13 @@ function testBackendStartup(username) {
|
|
|
210
233
|
function testKillScript(username, existingProcess) {
|
|
211
234
|
return __awaiter(this, void 0, void 0, function* () {
|
|
212
235
|
if (existingProcess.signalCode) {
|
|
213
|
-
throw new Error(
|
|
236
|
+
throw new Error(`Backend process already killed, signal code ${existingProcess.signalCode}`);
|
|
214
237
|
}
|
|
215
|
-
const
|
|
238
|
+
const args = ["-u", `${username}`, config_1.ServerConfig.killCommand, `${existingProcess.pid}`];
|
|
239
|
+
util_1.verboseLog(`running sudo ${args.join(" ")}`);
|
|
240
|
+
const res = child_process_1.spawnSync("sudo", args);
|
|
216
241
|
if (res.status) {
|
|
217
|
-
throw new Error(
|
|
242
|
+
throw new Error(`Cannot execute kill script (error status ${res.status}. Please check your killCommand option`);
|
|
218
243
|
}
|
|
219
244
|
// Delay to allow the parent process to exit
|
|
220
245
|
yield util_1.delay(1000);
|
package/dist/database.js
CHANGED
|
@@ -66,7 +66,7 @@ function initDB() {
|
|
|
66
66
|
console.log(`Connected to server ${config_1.ServerConfig.database.uri} and database ${config_1.ServerConfig.database.databaseName}`);
|
|
67
67
|
}
|
|
68
68
|
catch (err) {
|
|
69
|
-
|
|
69
|
+
util_1.verboseError(err);
|
|
70
70
|
console.error("Error connecting to database");
|
|
71
71
|
process.exit(1);
|
|
72
72
|
}
|
|
@@ -96,7 +96,7 @@ function handleGetPreferences(req, res, next) {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
catch (err) {
|
|
99
|
-
|
|
99
|
+
util_1.verboseError(err);
|
|
100
100
|
return next({ statusCode: 500, message: "Problem retrieving preferences" });
|
|
101
101
|
}
|
|
102
102
|
});
|
|
@@ -131,7 +131,7 @@ function handleSetPreferences(req, res, next) {
|
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
catch (err) {
|
|
134
|
-
|
|
134
|
+
util_1.verboseError(err);
|
|
135
135
|
return next({ statusCode: 500, message: err.errmsg });
|
|
136
136
|
}
|
|
137
137
|
});
|
|
@@ -164,7 +164,7 @@ function handleClearPreferences(req, res, next) {
|
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
catch (err) {
|
|
167
|
-
|
|
167
|
+
util_1.verboseError(err);
|
|
168
168
|
return next({ statusCode: 500, message: "Problem clearing preferences" });
|
|
169
169
|
}
|
|
170
170
|
});
|
|
@@ -188,7 +188,7 @@ function handleGetLayouts(req, res, next) {
|
|
|
188
188
|
res.json({ success: true, layouts });
|
|
189
189
|
}
|
|
190
190
|
catch (err) {
|
|
191
|
-
|
|
191
|
+
util_1.verboseError(err);
|
|
192
192
|
return next({ statusCode: 500, message: "Problem retrieving layouts" });
|
|
193
193
|
}
|
|
194
194
|
});
|
|
@@ -223,7 +223,7 @@ function handleSetLayout(req, res, next) {
|
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
225
|
catch (err) {
|
|
226
|
-
|
|
226
|
+
util_1.verboseError(err);
|
|
227
227
|
return next({ statusCode: 500, message: err.errmsg });
|
|
228
228
|
}
|
|
229
229
|
});
|
package/dist/serverHandlers.js
CHANGED
|
@@ -81,6 +81,7 @@ function nextAvailablePort() {
|
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
catch (err) {
|
|
84
|
+
util_1.verboseError(err);
|
|
84
85
|
console.log(`Error checking status for port ${p}: ${err.message}`);
|
|
85
86
|
}
|
|
86
87
|
}
|
|
@@ -146,6 +147,7 @@ function handleStartServer(req, res, next) {
|
|
|
146
147
|
}
|
|
147
148
|
}
|
|
148
149
|
catch (e) {
|
|
150
|
+
util_1.verboseError(e);
|
|
149
151
|
console.log(`Error killing existing process belonging to user ${username}`);
|
|
150
152
|
return next({ statusCode: 400, message: "Problem killing existing process" });
|
|
151
153
|
}
|
|
@@ -160,6 +162,7 @@ function handleStartServer(req, res, next) {
|
|
|
160
162
|
return res.json({ success: true });
|
|
161
163
|
}
|
|
162
164
|
catch (e) {
|
|
165
|
+
util_1.verboseError(e);
|
|
163
166
|
return next(e);
|
|
164
167
|
}
|
|
165
168
|
}
|
|
@@ -173,19 +176,29 @@ function startServer(username) {
|
|
|
173
176
|
if (port < 0) {
|
|
174
177
|
throw { statusCode: 500, message: "No available ports for the backend process" };
|
|
175
178
|
}
|
|
176
|
-
let args = [
|
|
177
|
-
|
|
178
|
-
"-
|
|
179
|
+
let args = [];
|
|
180
|
+
if (config_1.ServerConfig.preserveEnv) {
|
|
181
|
+
args.push("--preserve-env=CARTA_AUTH_TOKEN");
|
|
182
|
+
}
|
|
183
|
+
args = args.concat([
|
|
184
|
+
"-n",
|
|
185
|
+
"-u",
|
|
186
|
+
`${username}`,
|
|
179
187
|
config_1.ServerConfig.processCommand,
|
|
180
|
-
"--no_http",
|
|
181
|
-
"--
|
|
182
|
-
|
|
183
|
-
"--top_level_folder",
|
|
184
|
-
config_1.ServerConfig.
|
|
185
|
-
];
|
|
188
|
+
"--no_http",
|
|
189
|
+
"--port",
|
|
190
|
+
`${port}`,
|
|
191
|
+
"--top_level_folder",
|
|
192
|
+
config_1.ServerConfig.rootFolderTemplate.replace("{username}", username)
|
|
193
|
+
]);
|
|
194
|
+
if (config_1.ServerConfig.logFileTemplate) {
|
|
195
|
+
args.push("--no_log");
|
|
196
|
+
}
|
|
186
197
|
if (config_1.ServerConfig.additionalArgs) {
|
|
187
198
|
args = args.concat(config_1.ServerConfig.additionalArgs);
|
|
188
199
|
}
|
|
200
|
+
// Finally, add the positional argument for the base folder
|
|
201
|
+
args.push(config_1.ServerConfig.baseFolderTemplate.replace("{username}", username));
|
|
189
202
|
const headerToken = uuid_1.v4();
|
|
190
203
|
const child = child_process_1.spawn("sudo", args, { env: { CARTA_AUTH_TOKEN: headerToken } });
|
|
191
204
|
setPendingProcess(username, port, headerToken, child);
|
|
@@ -209,6 +222,7 @@ function startServer(username) {
|
|
|
209
222
|
});
|
|
210
223
|
}
|
|
211
224
|
catch (err) {
|
|
225
|
+
util_1.verboseError(err);
|
|
212
226
|
console.error(`Could not create log file at ${logLocation}. Please ensure folder exists and permissions are set correctly`);
|
|
213
227
|
}
|
|
214
228
|
}
|
|
@@ -228,7 +242,7 @@ function startServer(username) {
|
|
|
228
242
|
child.on("exit", code => {
|
|
229
243
|
console.log(`Process ${child.pid} exited with code ${code} and signal ${child.signalCode}`);
|
|
230
244
|
deleteProcess(username);
|
|
231
|
-
logStream === null || logStream === void 0 ? void 0 : logStream.
|
|
245
|
+
logStream === null || logStream === void 0 ? void 0 : logStream.end();
|
|
232
246
|
});
|
|
233
247
|
// Check for early exit of backend process
|
|
234
248
|
yield util_1.delay(config_1.ServerConfig.startDelay);
|
|
@@ -242,8 +256,9 @@ function startServer(username) {
|
|
|
242
256
|
}
|
|
243
257
|
}
|
|
244
258
|
catch (e) {
|
|
259
|
+
util_1.verboseError(e);
|
|
245
260
|
console.log(`Problem starting process for user ${username}`);
|
|
246
|
-
logStream === null || logStream === void 0 ? void 0 : logStream.
|
|
261
|
+
logStream === null || logStream === void 0 ? void 0 : logStream.end();
|
|
247
262
|
if (e.statusCode && e.message) {
|
|
248
263
|
throw e;
|
|
249
264
|
}
|
|
@@ -276,6 +291,7 @@ function handleStopServer(req, res, next) {
|
|
|
276
291
|
}
|
|
277
292
|
}
|
|
278
293
|
catch (e) {
|
|
294
|
+
util_1.verboseError(e);
|
|
279
295
|
console.log(`Error killing existing process belonging to user ${req.username}`);
|
|
280
296
|
return next({ statusCode: 500, message: "Problem killing existing process" });
|
|
281
297
|
}
|
package/dist/util.js
CHANGED
|
@@ -9,7 +9,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.noCache = exports.delay = void 0;
|
|
12
|
+
exports.verboseError = exports.verboseLog = exports.noCache = exports.delay = void 0;
|
|
13
|
+
const config_1 = require("./config");
|
|
13
14
|
// Delay for the specified number of milliseconds
|
|
14
15
|
function delay(delay) {
|
|
15
16
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -26,4 +27,16 @@ function noCache(req, res, next) {
|
|
|
26
27
|
next();
|
|
27
28
|
}
|
|
28
29
|
exports.noCache = noCache;
|
|
30
|
+
function verboseLog(...args) {
|
|
31
|
+
if (config_1.verboseOutput) {
|
|
32
|
+
console.log(args);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.verboseLog = verboseLog;
|
|
36
|
+
function verboseError(...args) {
|
|
37
|
+
if (config_1.verboseOutput) {
|
|
38
|
+
console.error(args);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
exports.verboseError = verboseError;
|
|
29
42
|
//# sourceMappingURL=util.js.map
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
# Sphinx build info version 1
|
|
2
2
|
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
|
|
3
|
-
config:
|
|
3
|
+
config: cab4ab9f21bbbaa15a42a39a8e17d156
|
|
4
4
|
tags: 645f666f9bcd5a90fca523b33c5a78b7
|
|
@@ -26,7 +26,10 @@ To provide the ``carta`` user with these privileges, you must make modifications
|
|
|
26
26
|
|
|
27
27
|
.. warning::
|
|
28
28
|
Please only edit your sudoers configuration with ``visudo`` or equivalent.
|
|
29
|
-
|
|
29
|
+
|
|
30
|
+
.. note::
|
|
31
|
+
Older versions of ``sudo`` do not support the ``--preserve-env=VARIABLE`` argument. If your version of ``sudo`` is too old, set ``"preserveEnv"`` to ``false`` in your controller configuration, and add ``Defaults env_keep += "CARTA_AUTH_TOKEN"`` to your sudoers configuration.
|
|
32
|
+
|
|
30
33
|
.. _config-authentication:
|
|
31
34
|
|
|
32
35
|
Authentication
|
|
@@ -22,9 +22,9 @@ Detailed :ref:`step-by-step instructions<focal_instructions>` are provided for U
|
|
|
22
22
|
ubuntu_focal_instructions
|
|
23
23
|
schema
|
|
24
24
|
|
|
25
|
-
.. |backend-github| image:: https://img.shields.io/badge/CARTA%20Version-
|
|
25
|
+
.. |backend-github| image:: https://img.shields.io/badge/CARTA%20Version-3.0.0--beta.1c-brightgreen
|
|
26
26
|
:alt: View this backend version on GitHub
|
|
27
|
-
:target: https://github.com/CARTAvis/carta-backend/releases/tag/
|
|
27
|
+
:target: https://github.com/CARTAvis/carta-backend/releases/tag/v3.0.0-beta.1c
|
|
28
28
|
|
|
29
29
|
.. |npm-package| image:: https://img.shields.io/npm/v/carta-controller/dev.svg?style=flat
|
|
30
30
|
:alt: View this project on npm
|
|
@@ -10,7 +10,7 @@ The CARTA controller provides a simple dashboard which authenticates users and a
|
|
|
10
10
|
Dependencies
|
|
11
11
|
------------
|
|
12
12
|
|
|
13
|
-
To allow the controller to serve CARTA sessions, you must give it access to an executable CARTA backend, which can be either a compiled executable or a container. If you want to use a non-standard version of the CARTA frontend, you must also build it, and adjust the controller configuration to point to it. You should use the ``
|
|
13
|
+
To allow the controller to serve CARTA sessions, you must give it access to an executable CARTA backend, which can be either a compiled executable or a container. If you want to use a non-standard version of the CARTA frontend, you must also build it, and adjust the controller configuration to point to it. You should use the ``v3.0.0-beta.1c`` tag of `the CARTA backend <https://github.com/CARTAvis/carta-backend>`_.
|
|
14
14
|
|
|
15
15
|
By default, the controller runs on port 8000. It should be run behind a proxy, so that it can be accessed via HTTP and HTTPS.
|
|
16
16
|
|
|
@@ -63,7 +63,7 @@ Install CARTA controller
|
|
|
63
63
|
|
|
64
64
|
.. note::
|
|
65
65
|
|
|
66
|
-
Currently supported versions of NodeJS are v12, v14 and v16. In the example below we install the latest LTS version of NodeJS from the NodeSource repo. Do not pass the ``--unsafe-perm`` flag to ``npm`` if using a local install.
|
|
66
|
+
Currently supported versions of NodeJS are v12, v14 and v16. In the example below we install the latest LTS version of NodeJS from the `NodeSource repo <https://github.com/nodesource/distributions>`_. Do not pass the ``--unsafe-perm`` flag to ``npm`` if using a local install.
|
|
67
67
|
|
|
68
68
|
.. code-block:: shell
|
|
69
69
|
|
|
@@ -187,7 +187,7 @@
|
|
|
187
187
|
"ldapOptions": {
|
|
188
188
|
"description": "Options to path through to the LDAP auth instance",
|
|
189
189
|
"type": "object",
|
|
190
|
-
"additionalProperties":
|
|
190
|
+
"additionalProperties": true,
|
|
191
191
|
"required": [
|
|
192
192
|
"url",
|
|
193
193
|
"searchBase"
|
|
@@ -217,6 +217,39 @@
|
|
|
217
217
|
"description": "Whether to automatically reconnect to LDAP",
|
|
218
218
|
"type": "boolean",
|
|
219
219
|
"default": true
|
|
220
|
+
},
|
|
221
|
+
"bindProperty": {
|
|
222
|
+
"description": "Property of the LDAP user object to use when binding to verify the password",
|
|
223
|
+
"type": "string",
|
|
224
|
+
"default": "dn"
|
|
225
|
+
},
|
|
226
|
+
"searchScope" : {
|
|
227
|
+
"description": "Scope of the search",
|
|
228
|
+
"type": "string",
|
|
229
|
+
"enum": ["base", "one", "sub"],
|
|
230
|
+
"default": "sub"
|
|
231
|
+
},
|
|
232
|
+
"bindDN": {
|
|
233
|
+
"description": "Admin connection DN, e.g. uid=myapp,ou=users,dc=example,dc=org. If not given at all, admin client is not bound.",
|
|
234
|
+
"type": "string"
|
|
235
|
+
},
|
|
236
|
+
"bindCredentials": {
|
|
237
|
+
"description": "Password for bindDN",
|
|
238
|
+
"type": "string"
|
|
239
|
+
},
|
|
240
|
+
"cache": {
|
|
241
|
+
"description": "If true, then up to 100 credentials at a time will be cached for 5 minutes",
|
|
242
|
+
"type": "boolean",
|
|
243
|
+
"default": false
|
|
244
|
+
},
|
|
245
|
+
"strictDN": {
|
|
246
|
+
"description": "Force strict DN parsing for client methods",
|
|
247
|
+
"type": "boolean",
|
|
248
|
+
"default": true
|
|
249
|
+
},
|
|
250
|
+
"idleTimeout": {
|
|
251
|
+
"description": "Milliseconds after last activity before client emits idle event",
|
|
252
|
+
"type": "number"
|
|
220
253
|
}
|
|
221
254
|
}
|
|
222
255
|
}
|
|
@@ -366,6 +399,11 @@
|
|
|
366
399
|
"type": "string",
|
|
367
400
|
"examples": ["localhost", "127.0.0.1"]
|
|
368
401
|
},
|
|
402
|
+
"httpOnly": {
|
|
403
|
+
"description": "Allow HTTP-only connections. For testing or internal networks only",
|
|
404
|
+
"type": "boolean",
|
|
405
|
+
"default": false
|
|
406
|
+
},
|
|
369
407
|
"serverAddress": {
|
|
370
408
|
"description": "Public-facing server address",
|
|
371
409
|
"type": "string",
|
|
@@ -422,6 +460,11 @@
|
|
|
422
460
|
],
|
|
423
461
|
"default": "/usr/bin/carta_backend"
|
|
424
462
|
},
|
|
463
|
+
"preserveEnv": {
|
|
464
|
+
"description": "Use the --preserve-env argument when calling sudo",
|
|
465
|
+
"type": "boolean",
|
|
466
|
+
"default": true
|
|
467
|
+
},
|
|
425
468
|
"killCommand": {
|
|
426
469
|
"description": "Path to CARTA kill script",
|
|
427
470
|
"type": "string",
|