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.
Files changed (35) hide show
  1. package/config/config_schema.json +39 -1
  2. package/dist/auth/ldap.js +13 -11
  3. package/dist/auth/ldap.js.map +1 -1
  4. package/dist/config.js +7 -1
  5. package/dist/controllerTests.js +59 -34
  6. package/dist/database.js +6 -6
  7. package/dist/serverHandlers.js +27 -11
  8. package/dist/util.js +14 -1
  9. package/docs/_build/doctrees/configuration.doctree +0 -0
  10. package/docs/_build/doctrees/environment.pickle +0 -0
  11. package/docs/_build/doctrees/index.doctree +0 -0
  12. package/docs/_build/doctrees/introduction.doctree +0 -0
  13. package/docs/_build/doctrees/schema.doctree +0 -0
  14. package/docs/_build/doctrees/ubuntu_focal_instructions.doctree +0 -0
  15. package/docs/_build/html/.buildinfo +1 -1
  16. package/docs/_build/html/_sources/configuration.rst.txt +4 -1
  17. package/docs/_build/html/_sources/index.rst.txt +2 -2
  18. package/docs/_build/html/_sources/introduction.rst.txt +1 -1
  19. package/docs/_build/html/_sources/ubuntu_focal_instructions.rst.txt +1 -1
  20. package/docs/_build/html/_static/config/config_schema.json +44 -1
  21. package/docs/_build/html/_static/config/layout_schema_2.json +17 -86
  22. package/docs/_build/html/_static/config/snippet_schema.json +44 -0
  23. package/docs/_build/html/_static/documentation_options.js +1 -1
  24. package/docs/_build/html/configuration.html +5 -1
  25. package/docs/_build/html/genindex.html +1 -1
  26. package/docs/_build/html/index.html +2 -2
  27. package/docs/_build/html/installation.html +1 -1
  28. package/docs/_build/html/introduction.html +2 -2
  29. package/docs/_build/html/schema.html +137 -35
  30. package/docs/_build/html/search.html +1 -1
  31. package/docs/_build/html/searchindex.js +1 -1
  32. package/docs/_build/html/ubuntu_focal_instructions.html +2 -2
  33. package/docs/src/configuration.rst +4 -1
  34. package/package.json +1 -1
  35. 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": false,
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
- else {
36
- try {
37
- const uid = userid.uid(username);
38
- console.log(`Authenticated as user ${username} with uid ${uid} using LDAP`);
39
- return local_1.addTokensToResponse(authConf, username, res);
40
- }
41
- catch (e) {
42
- return res.status(403).json({ statusCode: 403, message: "User does not exist" });
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) => {
@@ -1 +1 @@
1
- {"version":3,"file":"ldap.js","sourceRoot":"","sources":["../../src/auth/ldap.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ldap.js","sourceRoot":"","sources":["../../src/auth/ldap.ts"],"names":[],"mappings":"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"}
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 });
@@ -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
- const logLocation = config_1.ServerConfig.logFileTemplate
53
- .replace("{username}", username)
54
- .replace("{pid}", "9999")
55
- .replace("{datetime}", moment().format("YYYYMMDD.h_mm_ss"));
56
- try {
57
- const logStream = fs.createWriteStream(logLocation, { flags: "a" });
58
- logStream.write("test");
59
- logStream.close();
60
- fs.unlinkSync(logLocation);
61
- console.log(logSymbols.success, `Checked log writing for user ${username}`);
62
- }
63
- catch (err) {
64
- throw new Error(`Could not create log file at ${logLocation} for user ${username}. Please check your config file's logFileTemplate option`);
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, result) => {
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
- reject(new Error(`Could not authenticate as user ${username}`));
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 LDAP connection for user ${username}`);
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
- console.log(e);
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
- "--preserve-env=CARTA_AUTH_TOKEN",
174
- "-u", `${username}`,
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", "true",
177
- "--debug_no_auth", "true",
178
- "--no_log", config_1.ServerConfig.logFileTemplate ? "true" : "false",
179
- "--port", `${port}`,
180
- "--top_level_folder", config_1.ServerConfig.rootFolderTemplate.replace("{username}", username),
181
- config_1.ServerConfig.baseFolderTemplate.replace("{username}", username),
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
- const backendProcess = child_process_1.spawn("sudo", args);
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("Backend process terminated. Please check your sudoers config, processCommand option and additionalArgs section");
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("Backend process already killed");
236
+ throw new Error(`Backend process already killed, signal code ${existingProcess.signalCode}`);
214
237
  }
215
- const res = child_process_1.spawnSync("sudo", ["-u", `${username}`, config_1.ServerConfig.killCommand, `${existingProcess.pid}`]);
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("Cannot execute kill script. Please check your killCommand option");
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
- console.log(err);
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
- console.log(err);
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
- console.log(err.errmsg);
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
- console.log(err);
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
- console.log(err);
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
- console.log(err.errmsg);
226
+ util_1.verboseError(err);
227
227
  return next({ statusCode: 500, message: err.errmsg });
228
228
  }
229
229
  });
@@ -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
- "--preserve-env=CARTA_AUTH_TOKEN",
178
- "-u", `${username}`,
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", "true",
181
- "--no_log", config_1.ServerConfig.logFileTemplate ? "true" : "false",
182
- "--port", `${port}`,
183
- "--top_level_folder", config_1.ServerConfig.rootFolderTemplate.replace("{username}", username),
184
- config_1.ServerConfig.baseFolderTemplate.replace("{username}", username),
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.close();
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.close();
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
@@ -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: b9e9ea0b4abf5f06de7b98cc0b9165b2
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-2.0.0--beta.0-brightgreen
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/v2.0.0-beta.0
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 ``v2.0.0-beta.0`` tag of `the CARTA backend <https://github.com/CARTAvis/carta-backend>`_.
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": false,
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",