dbgate-api-premium 6.5.3 → 6.5.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/package.json +5 -5
- package/src/auth/authProvider.js +2 -2
- package/src/auth/storageAuthProvider.js +181 -7
- package/src/controllers/auth.js +51 -7
- package/src/controllers/cloud.js +18 -0
- package/src/controllers/config.js +16 -2
- package/src/controllers/connections.js +5 -5
- package/src/controllers/databaseConnections.js +102 -8
- package/src/controllers/files.js +2 -2
- package/src/controllers/runners.js +24 -1
- package/src/controllers/serverConnections.js +12 -0
- package/src/controllers/sessions.js +14 -1
- package/src/controllers/storage.js +138 -4
- package/src/controllers/storageDb.js +3 -1
- package/src/currentVersion.js +2 -2
- package/src/shell/deployDb.js +1 -1
- package/src/shell/generateDeploySql.js +1 -1
- package/src/shell/importDbFromFolder.js +2 -5
- package/src/storageModel.js +304 -62
- package/src/utility/auditlog.js +288 -0
- package/src/utility/authProxy.js +9 -2
- package/src/utility/checkLicense.js +2 -0
- package/src/utility/cloudIntf.js +33 -2
- package/src/utility/connectUtility.js +2 -1
- package/src/utility/getChartExport.js +11 -3
- package/src/utility/getMapExport.js +1 -1
- package/src/utility/loginchecker.js +44 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dbgate-api-premium",
|
|
3
3
|
"main": "src/index.js",
|
|
4
|
-
"version": "6.5.
|
|
4
|
+
"version": "6.5.5",
|
|
5
5
|
"homepage": "https://dbgate.org/",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
"compare-versions": "^3.6.0",
|
|
31
31
|
"cors": "^2.8.5",
|
|
32
32
|
"cross-env": "^6.0.3",
|
|
33
|
-
"dbgate-datalib": "^6.5.
|
|
33
|
+
"dbgate-datalib": "^6.5.5",
|
|
34
34
|
"dbgate-query-splitter": "^4.11.5",
|
|
35
|
-
"dbgate-sqltree": "^6.5.
|
|
36
|
-
"dbgate-tools": "^6.5.
|
|
35
|
+
"dbgate-sqltree": "^6.5.5",
|
|
36
|
+
"dbgate-tools": "^6.5.5",
|
|
37
37
|
"debug": "^4.3.4",
|
|
38
38
|
"diff": "^5.0.0",
|
|
39
39
|
"diff2html": "^3.4.13",
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"devDependencies": {
|
|
86
86
|
"@types/fs-extra": "^9.0.11",
|
|
87
87
|
"@types/lodash": "^4.14.149",
|
|
88
|
-
"dbgate-types": "^6.5.
|
|
88
|
+
"dbgate-types": "^6.5.5",
|
|
89
89
|
"env-cmd": "^10.1.0",
|
|
90
90
|
"jsdoc-to-markdown": "^9.0.5",
|
|
91
91
|
"node-loader": "^1.0.2",
|
package/src/auth/authProvider.js
CHANGED
|
@@ -11,7 +11,7 @@ const logger = getLogger('authProvider');
|
|
|
11
11
|
class AuthProviderBase {
|
|
12
12
|
amoid = 'none';
|
|
13
13
|
|
|
14
|
-
async login(login, password, options = undefined) {
|
|
14
|
+
async login(login, password, options = undefined, req = undefined) {
|
|
15
15
|
return {
|
|
16
16
|
accessToken: jwt.sign(
|
|
17
17
|
{
|
|
@@ -23,7 +23,7 @@ class AuthProviderBase {
|
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
oauthToken(params) {
|
|
26
|
+
oauthToken(params, req) {
|
|
27
27
|
return {};
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -21,6 +21,8 @@ const axios = require('axios');
|
|
|
21
21
|
const _ = require('lodash');
|
|
22
22
|
const { authProxyGetTokenFromCode, authProxyGetRedirectUrl } = require('../utility/authProxy');
|
|
23
23
|
const { decryptUser } = require('../utility/crypting');
|
|
24
|
+
const { sendToAuditLog } = require('../utility/auditlog');
|
|
25
|
+
const { isLoginLicensed, LOGIN_LIMIT_ERROR } = require('../utility/loginchecker');
|
|
24
26
|
|
|
25
27
|
async function loadPermissionsForUserId(userId) {
|
|
26
28
|
const rolePermissions = sortPermissionsFromTheSameLevel(await storageReadUserRolePermissions(userId));
|
|
@@ -29,6 +31,7 @@ async function loadPermissionsForUserId(userId) {
|
|
|
29
31
|
return [...getPredefinedPermissions('logged-user'), ...loggedUserPermissions, ...rolePermissions, ...userPermissions];
|
|
30
32
|
}
|
|
31
33
|
|
|
34
|
+
|
|
32
35
|
class StorageProviderBase extends AuthProviderBase {
|
|
33
36
|
constructor(config) {
|
|
34
37
|
super();
|
|
@@ -50,17 +53,31 @@ class StorageProviderBase extends AuthProviderBase {
|
|
|
50
53
|
}
|
|
51
54
|
|
|
52
55
|
class AnonymousProvider extends StorageProviderBase {
|
|
53
|
-
async login(login, password, options = undefined) {
|
|
56
|
+
async login(login, password, options = undefined, req = undefined) {
|
|
54
57
|
const permissions = await [
|
|
55
58
|
...getPredefinedPermissions('anonymous-user'),
|
|
56
59
|
...(await storageReadRolePermissions(-1)),
|
|
57
60
|
];
|
|
58
61
|
|
|
62
|
+
if (!(await isLoginLicensed(req, `anonymous`))) {
|
|
63
|
+
return { error: LOGIN_LIMIT_ERROR };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
sendToAuditLog(req, {
|
|
67
|
+
category: 'auth',
|
|
68
|
+
component: 'AnonymousProvider',
|
|
69
|
+
action: 'login',
|
|
70
|
+
event: 'login.anonymous',
|
|
71
|
+
severity: 'info',
|
|
72
|
+
message: 'Anonymous login',
|
|
73
|
+
});
|
|
74
|
+
|
|
59
75
|
return {
|
|
60
76
|
accessToken: jwt.sign(
|
|
61
77
|
{
|
|
62
78
|
amoid: this.amoid,
|
|
63
79
|
permissions,
|
|
80
|
+
licenseUid: 'anonymous',
|
|
64
81
|
},
|
|
65
82
|
getTokenSecret(),
|
|
66
83
|
{ expiresIn: getTokenLifetime() }
|
|
@@ -73,7 +90,7 @@ class LocalAuthProvider extends StorageProviderBase {
|
|
|
73
90
|
constructor(config) {
|
|
74
91
|
super(config);
|
|
75
92
|
}
|
|
76
|
-
async login(login, password) {
|
|
93
|
+
async login(login, password, _options, req) {
|
|
77
94
|
const rows = await storageSelectFmt('select * from ~users where login = %v', login);
|
|
78
95
|
if (rows.length == 0) {
|
|
79
96
|
return { error: 'Login not allowed' };
|
|
@@ -83,6 +100,20 @@ class LocalAuthProvider extends StorageProviderBase {
|
|
|
83
100
|
const userId = row.id;
|
|
84
101
|
const permissions = await loadPermissionsForUserId(userId);
|
|
85
102
|
|
|
103
|
+
if (!(await isLoginLicensed(req, `local:${login}`))) {
|
|
104
|
+
return { error: LOGIN_LIMIT_ERROR };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
sendToAuditLog(req, {
|
|
108
|
+
category: 'auth',
|
|
109
|
+
component: 'LocalAuthProvider',
|
|
110
|
+
action: 'login',
|
|
111
|
+
event: 'login.local',
|
|
112
|
+
severity: 'info',
|
|
113
|
+
detail: { login },
|
|
114
|
+
message: 'Local login successful',
|
|
115
|
+
});
|
|
116
|
+
|
|
86
117
|
return {
|
|
87
118
|
accessToken: jwt.sign(
|
|
88
119
|
{
|
|
@@ -90,12 +121,24 @@ class LocalAuthProvider extends StorageProviderBase {
|
|
|
90
121
|
login,
|
|
91
122
|
permissions,
|
|
92
123
|
userId,
|
|
124
|
+
licenseUid: `local:${login}`,
|
|
93
125
|
},
|
|
94
126
|
getTokenSecret(),
|
|
95
127
|
{ expiresIn: getTokenLifetime() }
|
|
96
128
|
),
|
|
97
129
|
};
|
|
98
130
|
}
|
|
131
|
+
|
|
132
|
+
sendToAuditLog(req, {
|
|
133
|
+
category: 'auth',
|
|
134
|
+
component: 'LocalAuthProvider',
|
|
135
|
+
action: 'loginFail',
|
|
136
|
+
event: 'login.localFailed',
|
|
137
|
+
severity: 'warn',
|
|
138
|
+
detail: { login },
|
|
139
|
+
message: 'Local login failed',
|
|
140
|
+
});
|
|
141
|
+
|
|
99
142
|
return { error: 'Invalid credentials' };
|
|
100
143
|
}
|
|
101
144
|
|
|
@@ -121,7 +164,7 @@ class OauthProvider extends StorageProviderBase {
|
|
|
121
164
|
return this.config.oauthLogout;
|
|
122
165
|
}
|
|
123
166
|
|
|
124
|
-
async oauthToken(params) {
|
|
167
|
+
async oauthToken(params, req) {
|
|
125
168
|
const { redirectUri, code } = params;
|
|
126
169
|
|
|
127
170
|
const scopeParam = this.config.oauthScope ? `&scope=${this.config.oauthScope}` : '';
|
|
@@ -151,6 +194,16 @@ class OauthProvider extends StorageProviderBase {
|
|
|
151
194
|
const permissions = await loadPermissionsForUserId(loginRows[0]?.id ?? -1);
|
|
152
195
|
|
|
153
196
|
if (this.config.oauthOnlyDefinedLogins == 1 && loginRows.length == 0) {
|
|
197
|
+
sendToAuditLog(req, {
|
|
198
|
+
category: 'auth',
|
|
199
|
+
component: 'OauthProvider',
|
|
200
|
+
action: 'loginFail',
|
|
201
|
+
event: 'login.oauthNotAllowed',
|
|
202
|
+
severity: 'warn',
|
|
203
|
+
detail: { login },
|
|
204
|
+
message: `Username ${login} not allowed to log in`,
|
|
205
|
+
});
|
|
206
|
+
|
|
154
207
|
return { error: `Username ${login} not allowed to log in` };
|
|
155
208
|
}
|
|
156
209
|
|
|
@@ -171,10 +224,34 @@ class OauthProvider extends StorageProviderBase {
|
|
|
171
224
|
if (this.config.oauthOnlyDefinedGroups == 1) {
|
|
172
225
|
const roleRows = await storageSelectFmt('select * from ~roles where ~name in (%,v)', groups);
|
|
173
226
|
if (roleRows.length == 0) {
|
|
227
|
+
sendToAuditLog(req, {
|
|
228
|
+
category: 'auth',
|
|
229
|
+
component: 'OauthProvider',
|
|
230
|
+
action: 'loginFail',
|
|
231
|
+
event: 'login.groupNotAllowed',
|
|
232
|
+
severity: 'warn',
|
|
233
|
+
detail: { login },
|
|
234
|
+
message: `Groups ${groups.join(', ')} not allowed to log in`,
|
|
235
|
+
});
|
|
236
|
+
|
|
174
237
|
return { error: `Groups ${groups.join(', ')} not allowed to log in` };
|
|
175
238
|
}
|
|
176
239
|
}
|
|
177
240
|
|
|
241
|
+
if (!(await isLoginLicensed(req, `oauth:${login}`))) {
|
|
242
|
+
return { error: LOGIN_LIMIT_ERROR };
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
sendToAuditLog(req, {
|
|
246
|
+
category: 'auth',
|
|
247
|
+
component: 'OauthProvider',
|
|
248
|
+
action: 'login',
|
|
249
|
+
event: 'login.oauth',
|
|
250
|
+
severity: 'info',
|
|
251
|
+
detail: { login, userId: loginRows[0]?.id },
|
|
252
|
+
message: `User ${login} logged in via OAUTH`,
|
|
253
|
+
});
|
|
254
|
+
|
|
178
255
|
return {
|
|
179
256
|
accessToken: jwt.sign(
|
|
180
257
|
{
|
|
@@ -182,6 +259,7 @@ class OauthProvider extends StorageProviderBase {
|
|
|
182
259
|
login,
|
|
183
260
|
permissions,
|
|
184
261
|
userId: loginRows[0]?.id,
|
|
262
|
+
licenseUid: `oauth:${login}`,
|
|
185
263
|
},
|
|
186
264
|
getTokenSecret(),
|
|
187
265
|
{ expiresIn: getTokenLifetime() }
|
|
@@ -214,7 +292,7 @@ class ADProvider extends StorageProviderBase {
|
|
|
214
292
|
super(config);
|
|
215
293
|
}
|
|
216
294
|
|
|
217
|
-
async login(login, password) {
|
|
295
|
+
async login(login, password, _options, req) {
|
|
218
296
|
const adConfig = {
|
|
219
297
|
url: this.config.adUrl,
|
|
220
298
|
baseDN: this.config.adBaseDN,
|
|
@@ -225,6 +303,16 @@ class ADProvider extends StorageProviderBase {
|
|
|
225
303
|
try {
|
|
226
304
|
const res = await ad.authenticate(login, password);
|
|
227
305
|
if (!res) {
|
|
306
|
+
sendToAuditLog(req, {
|
|
307
|
+
category: 'auth',
|
|
308
|
+
component: 'OauthProvider',
|
|
309
|
+
action: 'loginFail',
|
|
310
|
+
event: 'login.adRejected',
|
|
311
|
+
severity: 'warn',
|
|
312
|
+
detail: { login },
|
|
313
|
+
message: `AD rejected login for ${login}`,
|
|
314
|
+
});
|
|
315
|
+
|
|
228
316
|
return { error: `Login failed, AD rejected login ${login}` };
|
|
229
317
|
}
|
|
230
318
|
|
|
@@ -237,18 +325,43 @@ class ADProvider extends StorageProviderBase {
|
|
|
237
325
|
}
|
|
238
326
|
}
|
|
239
327
|
|
|
328
|
+
if (!(await isLoginLicensed(req, `ad:${login}`))) {
|
|
329
|
+
return { error: LOGIN_LIMIT_ERROR };
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
sendToAuditLog(req, {
|
|
333
|
+
category: 'auth',
|
|
334
|
+
component: 'ADProvider',
|
|
335
|
+
action: 'login',
|
|
336
|
+
event: 'login.ad',
|
|
337
|
+
severity: 'info',
|
|
338
|
+
detail: { login },
|
|
339
|
+
message: `User ${login} logged in via AD`,
|
|
340
|
+
});
|
|
341
|
+
|
|
240
342
|
return {
|
|
241
343
|
accessToken: jwt.sign(
|
|
242
344
|
{
|
|
243
345
|
amoid: this.amoid,
|
|
244
346
|
login,
|
|
245
347
|
permissions,
|
|
348
|
+
licenseUid: `ad:${login}`,
|
|
246
349
|
},
|
|
247
350
|
getTokenSecret(),
|
|
248
351
|
{ expiresIn: getTokenLifetime() }
|
|
249
352
|
),
|
|
250
353
|
};
|
|
251
354
|
} catch (e) {
|
|
355
|
+
sendToAuditLog(req, {
|
|
356
|
+
category: 'auth',
|
|
357
|
+
component: 'OauthProvider',
|
|
358
|
+
action: 'loginFail',
|
|
359
|
+
event: 'login.adError',
|
|
360
|
+
severity: 'warn',
|
|
361
|
+
detail: { login, error: e.message },
|
|
362
|
+
message: `AD login error for ${login}`,
|
|
363
|
+
});
|
|
364
|
+
|
|
252
365
|
return { error: `Login failed: ${e.message}` };
|
|
253
366
|
}
|
|
254
367
|
}
|
|
@@ -276,14 +389,39 @@ class DatabaseProvider extends StorageProviderBase {
|
|
|
276
389
|
}));
|
|
277
390
|
}
|
|
278
391
|
|
|
279
|
-
async login(login, password, options) {
|
|
392
|
+
async login(login, password, options, req) {
|
|
280
393
|
const { conid } = options;
|
|
281
394
|
const rows = login ? await storageSelectFmt('select * from ~users where ~login = %v', login) : [];
|
|
282
395
|
if (this.config.dbloginOnlyDefinedLogins == 1 && rows.length == 0) {
|
|
283
|
-
|
|
396
|
+
sendToAuditLog(req, {
|
|
397
|
+
category: 'auth',
|
|
398
|
+
component: 'DatabaseProvider',
|
|
399
|
+
action: 'loginFail',
|
|
400
|
+
event: 'login.dbLoginNotAllowed',
|
|
401
|
+
severity: 'warn',
|
|
402
|
+
detail: { login },
|
|
403
|
+
message: `Login ${login} not allowed to log in`,
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
return { error: 'Login not allowed', login };
|
|
284
407
|
}
|
|
285
408
|
const userId = rows[0]?.id;
|
|
286
409
|
const permissions = await loadPermissionsForUserId(userId ?? -1);
|
|
410
|
+
|
|
411
|
+
if (!(await isLoginLicensed(req, `db:${login}`))) {
|
|
412
|
+
return { error: LOGIN_LIMIT_ERROR };
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
sendToAuditLog(req, {
|
|
416
|
+
category: 'auth',
|
|
417
|
+
component: 'DatabaseProvider',
|
|
418
|
+
action: 'login',
|
|
419
|
+
event: 'login.dbLogin',
|
|
420
|
+
severity: 'info',
|
|
421
|
+
detail: { login },
|
|
422
|
+
message: `User ${login} logged in via database`,
|
|
423
|
+
});
|
|
424
|
+
|
|
287
425
|
return {
|
|
288
426
|
accessToken: jwt.sign(
|
|
289
427
|
{
|
|
@@ -292,6 +430,7 @@ class DatabaseProvider extends StorageProviderBase {
|
|
|
292
430
|
permissions,
|
|
293
431
|
userId,
|
|
294
432
|
conid,
|
|
433
|
+
licenseUid: `db:${login}`,
|
|
295
434
|
},
|
|
296
435
|
getTokenSecret(),
|
|
297
436
|
{ expiresIn: getTokenLifetime() }
|
|
@@ -320,7 +459,7 @@ class MsEntraProvider extends StorageProviderBase {
|
|
|
320
459
|
return null;
|
|
321
460
|
}
|
|
322
461
|
|
|
323
|
-
async oauthToken(params) {
|
|
462
|
+
async oauthToken(params, req) {
|
|
324
463
|
const { sid, code } = params;
|
|
325
464
|
|
|
326
465
|
const token = await authProxyGetTokenFromCode({ sid, code });
|
|
@@ -336,11 +475,35 @@ class MsEntraProvider extends StorageProviderBase {
|
|
|
336
475
|
|
|
337
476
|
if (this.config.msentraOnlyDefinedLogins == 1) {
|
|
338
477
|
if (loginRows.length == 0) {
|
|
478
|
+
sendToAuditLog(req, {
|
|
479
|
+
category: 'auth',
|
|
480
|
+
component: 'MsEntraProvider',
|
|
481
|
+
action: 'loginFail',
|
|
482
|
+
event: 'login.msentraNotAllowed',
|
|
483
|
+
severity: 'warn',
|
|
484
|
+
detail: { email },
|
|
485
|
+
message: `Email ${email} not allowed to log in`,
|
|
486
|
+
});
|
|
487
|
+
|
|
339
488
|
return { error: `Email ${email} not allowed to log in` };
|
|
340
489
|
}
|
|
341
490
|
}
|
|
342
491
|
|
|
343
492
|
if (token) {
|
|
493
|
+
if (!(await isLoginLicensed(req, `msentra:${payload.unique_name}`))) {
|
|
494
|
+
return { error: LOGIN_LIMIT_ERROR };
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
sendToAuditLog(req, {
|
|
498
|
+
category: 'auth',
|
|
499
|
+
component: 'MsEntraProvider',
|
|
500
|
+
action: 'login',
|
|
501
|
+
event: 'login.msentra',
|
|
502
|
+
severity: 'info',
|
|
503
|
+
detail: { login: payload.unique_name, userId: loginRows[0]?.id },
|
|
504
|
+
message: `User ${payload.unique_name} logged in via MS Entra`,
|
|
505
|
+
});
|
|
506
|
+
|
|
344
507
|
return {
|
|
345
508
|
accessToken: jwt.sign(
|
|
346
509
|
{
|
|
@@ -349,6 +512,7 @@ class MsEntraProvider extends StorageProviderBase {
|
|
|
349
512
|
msentraToken: token,
|
|
350
513
|
userId: loginRows[0]?.id,
|
|
351
514
|
login: payload.unique_name,
|
|
515
|
+
licenseUid: `msentra:${payload.unique_name}`,
|
|
352
516
|
},
|
|
353
517
|
getTokenSecret(),
|
|
354
518
|
{ expiresIn: getTokenLifetime() }
|
|
@@ -356,6 +520,16 @@ class MsEntraProvider extends StorageProviderBase {
|
|
|
356
520
|
};
|
|
357
521
|
}
|
|
358
522
|
|
|
523
|
+
sendToAuditLog(req, {
|
|
524
|
+
category: 'auth',
|
|
525
|
+
component: 'MsEntraProvider',
|
|
526
|
+
action: 'loginFail',
|
|
527
|
+
event: 'login.msentraNotFound',
|
|
528
|
+
severity: 'warn',
|
|
529
|
+
detail: { email },
|
|
530
|
+
message: `Token not found for email ${email}`,
|
|
531
|
+
});
|
|
532
|
+
|
|
359
533
|
return { error: 'Token not found' };
|
|
360
534
|
}
|
|
361
535
|
|
package/src/controllers/auth.js
CHANGED
|
@@ -13,8 +13,15 @@ const {
|
|
|
13
13
|
} = require('../auth/authProvider');
|
|
14
14
|
const storage = require('./storage');
|
|
15
15
|
const { decryptPasswordString } = require('../utility/crypting');
|
|
16
|
-
const {
|
|
16
|
+
const {
|
|
17
|
+
createDbGateIdentitySession,
|
|
18
|
+
startCloudTokenChecking,
|
|
19
|
+
readCloudTokenHolder,
|
|
20
|
+
readCloudTestTokenHolder,
|
|
21
|
+
} = require('../utility/cloudIntf');
|
|
17
22
|
const socket = require('../utility/socket');
|
|
23
|
+
const { sendToAuditLog } = require('../utility/auditlog');
|
|
24
|
+
const { isLoginLicensed, LOGIN_LIMIT_ERROR } = require('../utility/loginchecker');
|
|
18
25
|
|
|
19
26
|
const logger = getLogger('auth');
|
|
20
27
|
|
|
@@ -72,6 +79,8 @@ function authMiddleware(req, res, next) {
|
|
|
72
79
|
try {
|
|
73
80
|
const decoded = jwt.verify(token, getTokenSecret());
|
|
74
81
|
req.user = decoded;
|
|
82
|
+
storage.markUserAsActive(decoded.licenseUid);
|
|
83
|
+
|
|
75
84
|
return next();
|
|
76
85
|
} catch (err) {
|
|
77
86
|
if (skipAuth) {
|
|
@@ -87,12 +96,12 @@ function authMiddleware(req, res, next) {
|
|
|
87
96
|
|
|
88
97
|
module.exports = {
|
|
89
98
|
oauthToken_meta: true,
|
|
90
|
-
async oauthToken(params) {
|
|
99
|
+
async oauthToken(params, req) {
|
|
91
100
|
const { amoid } = params;
|
|
92
|
-
return getAuthProviderById(amoid).oauthToken(params);
|
|
101
|
+
return getAuthProviderById(amoid).oauthToken(params, req);
|
|
93
102
|
},
|
|
94
103
|
login_meta: true,
|
|
95
|
-
async login(params) {
|
|
104
|
+
async login(params, req) {
|
|
96
105
|
const { amoid, login, password, isAdminPage } = params;
|
|
97
106
|
|
|
98
107
|
if (isAdminPage) {
|
|
@@ -102,12 +111,26 @@ module.exports = {
|
|
|
102
111
|
adminPassword = decryptPasswordString(adminConfig?.adminPassword);
|
|
103
112
|
}
|
|
104
113
|
if (adminPassword && adminPassword == password) {
|
|
114
|
+
if (!(await isLoginLicensed(req, `superadmin`))) {
|
|
115
|
+
return { error: LOGIN_LIMIT_ERROR };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
sendToAuditLog(req, {
|
|
119
|
+
category: 'auth',
|
|
120
|
+
component: 'AuthController',
|
|
121
|
+
action: 'login',
|
|
122
|
+
event: 'login.admin',
|
|
123
|
+
severity: 'info',
|
|
124
|
+
message: 'Administration login successful',
|
|
125
|
+
});
|
|
126
|
+
|
|
105
127
|
return {
|
|
106
128
|
accessToken: jwt.sign(
|
|
107
129
|
{
|
|
108
130
|
login: 'superadmin',
|
|
109
131
|
permissions: await storage.loadSuperadminPermissions(),
|
|
110
132
|
roleId: -3,
|
|
133
|
+
licenseUid: `superadmin`,
|
|
111
134
|
},
|
|
112
135
|
getTokenSecret(),
|
|
113
136
|
{
|
|
@@ -117,10 +140,19 @@ module.exports = {
|
|
|
117
140
|
};
|
|
118
141
|
}
|
|
119
142
|
|
|
143
|
+
sendToAuditLog(req, {
|
|
144
|
+
category: 'auth',
|
|
145
|
+
component: 'AuthController',
|
|
146
|
+
action: 'loginFail',
|
|
147
|
+
event: 'login.adminFailed',
|
|
148
|
+
severity: 'warn',
|
|
149
|
+
message: 'Administraton login failed',
|
|
150
|
+
});
|
|
151
|
+
|
|
120
152
|
return { error: 'Login failed' };
|
|
121
153
|
}
|
|
122
154
|
|
|
123
|
-
return getAuthProviderById(amoid).login(login, password);
|
|
155
|
+
return getAuthProviderById(amoid).login(login, password, undefined, req);
|
|
124
156
|
},
|
|
125
157
|
|
|
126
158
|
getProviders_meta: true,
|
|
@@ -138,8 +170,8 @@ module.exports = {
|
|
|
138
170
|
},
|
|
139
171
|
|
|
140
172
|
createCloudLoginSession_meta: true,
|
|
141
|
-
async createCloudLoginSession({ client }) {
|
|
142
|
-
const res = await createDbGateIdentitySession(client);
|
|
173
|
+
async createCloudLoginSession({ client, redirectUri }) {
|
|
174
|
+
const res = await createDbGateIdentitySession(client, redirectUri);
|
|
143
175
|
startCloudTokenChecking(res.sid, tokenHolder => {
|
|
144
176
|
socket.emit('got-cloud-token', tokenHolder);
|
|
145
177
|
socket.emitChanged('cloud-content-changed');
|
|
@@ -148,5 +180,17 @@ module.exports = {
|
|
|
148
180
|
return res;
|
|
149
181
|
},
|
|
150
182
|
|
|
183
|
+
cloudLoginRedirected_meta: true,
|
|
184
|
+
async cloudLoginRedirected({ sid }) {
|
|
185
|
+
const tokenHolder = await readCloudTokenHolder(sid);
|
|
186
|
+
return tokenHolder;
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
cloudTestLogin_meta: true,
|
|
190
|
+
async cloudTestLogin({ email }) {
|
|
191
|
+
const tokenHolder = await readCloudTestTokenHolder(email);
|
|
192
|
+
return tokenHolder;
|
|
193
|
+
},
|
|
194
|
+
|
|
151
195
|
authMiddleware,
|
|
152
196
|
};
|
package/src/controllers/cloud.js
CHANGED
|
@@ -258,4 +258,22 @@ module.exports = {
|
|
|
258
258
|
await fs.writeFile(filePath, content);
|
|
259
259
|
return true;
|
|
260
260
|
},
|
|
261
|
+
|
|
262
|
+
folderUsers_meta: true,
|
|
263
|
+
async folderUsers({ folid }) {
|
|
264
|
+
const resp = await callCloudApiGet(`content-folders/users/${folid}`);
|
|
265
|
+
return resp;
|
|
266
|
+
},
|
|
267
|
+
|
|
268
|
+
setFolderUserRole_meta: true,
|
|
269
|
+
async setFolderUserRole({ folid, email, role }) {
|
|
270
|
+
const resp = await callCloudApiPost(`content-folders/set-user-role/${folid}`, { email, role });
|
|
271
|
+
return resp;
|
|
272
|
+
},
|
|
273
|
+
|
|
274
|
+
removeFolderUser_meta: true,
|
|
275
|
+
async removeFolderUser({ folid, email }) {
|
|
276
|
+
const resp = await callCloudApiPost(`content-folders/remove-user/${folid}`, { email });
|
|
277
|
+
return resp;
|
|
278
|
+
},
|
|
261
279
|
};
|
|
@@ -29,6 +29,7 @@ const {
|
|
|
29
29
|
} = require('../utility/crypting');
|
|
30
30
|
|
|
31
31
|
const lock = new AsyncLock();
|
|
32
|
+
let cachedSettingsValue = null;
|
|
32
33
|
|
|
33
34
|
module.exports = {
|
|
34
35
|
// settingsValue: {},
|
|
@@ -118,6 +119,7 @@ module.exports = {
|
|
|
118
119
|
supportCloudAutoUpgrade: !!process.env.CLOUD_UPGRADE_FILE,
|
|
119
120
|
allowPrivateCloud: platformInfo.isElectron || !!process.env.ALLOW_DBGATE_PRIVATE_CLOUD,
|
|
120
121
|
...currentVersion,
|
|
122
|
+
redirectToDbGateCloudLogin: !!process.env.REDIRECT_TO_DBGATE_CLOUD_LOGIN,
|
|
121
123
|
};
|
|
122
124
|
|
|
123
125
|
return configResult;
|
|
@@ -144,6 +146,13 @@ module.exports = {
|
|
|
144
146
|
return res;
|
|
145
147
|
},
|
|
146
148
|
|
|
149
|
+
async getCachedSettings() {
|
|
150
|
+
if (!cachedSettingsValue) {
|
|
151
|
+
cachedSettingsValue = await this.loadSettings();
|
|
152
|
+
}
|
|
153
|
+
return cachedSettingsValue;
|
|
154
|
+
},
|
|
155
|
+
|
|
147
156
|
deleteSettings_meta: true,
|
|
148
157
|
async deleteSettings() {
|
|
149
158
|
await fs.unlink(path.join(datadir(), processArgs.runE2eTests ? 'settings-e2etests.json' : 'settings.json'));
|
|
@@ -257,6 +266,7 @@ module.exports = {
|
|
|
257
266
|
updateSettings_meta: true,
|
|
258
267
|
async updateSettings(values, req) {
|
|
259
268
|
if (!hasPermission(`settings/change`, req)) return false;
|
|
269
|
+
cachedSettingsValue = null;
|
|
260
270
|
|
|
261
271
|
const res = await lock.acquire('settings', async () => {
|
|
262
272
|
const currentValue = await this.loadSettings();
|
|
@@ -265,7 +275,11 @@ module.exports = {
|
|
|
265
275
|
if (process.env.STORAGE_DATABASE) {
|
|
266
276
|
updated = {
|
|
267
277
|
...currentValue,
|
|
268
|
-
...values,
|
|
278
|
+
..._.mapValues(values, v => {
|
|
279
|
+
if (v === true) return 'true';
|
|
280
|
+
if (v === false) return 'false';
|
|
281
|
+
return v;
|
|
282
|
+
}),
|
|
269
283
|
};
|
|
270
284
|
await storage.writeConfig({
|
|
271
285
|
group: 'settings',
|
|
@@ -303,7 +317,7 @@ module.exports = {
|
|
|
303
317
|
const resp = await axios.default.get('https://raw.githubusercontent.com/dbgate/dbgate/master/CHANGELOG.md');
|
|
304
318
|
return resp.data;
|
|
305
319
|
} catch (err) {
|
|
306
|
-
return ''
|
|
320
|
+
return '';
|
|
307
321
|
}
|
|
308
322
|
},
|
|
309
323
|
|
|
@@ -536,14 +536,14 @@ module.exports = {
|
|
|
536
536
|
},
|
|
537
537
|
|
|
538
538
|
dbloginAuthToken_meta: true,
|
|
539
|
-
async dbloginAuthToken({ amoid, code, conid, redirectUri, sid }) {
|
|
539
|
+
async dbloginAuthToken({ amoid, code, conid, redirectUri, sid }, req) {
|
|
540
540
|
try {
|
|
541
541
|
const connection = await this.getCore({ conid });
|
|
542
542
|
const driver = requireEngineDriver(connection);
|
|
543
543
|
const accessToken = await driver.getAuthTokenFromCode(connection, { code, redirectUri, sid });
|
|
544
544
|
const volatile = await this.saveVolatile({ conid, accessToken });
|
|
545
545
|
const authProvider = getAuthProviderById(amoid);
|
|
546
|
-
const resp = await authProvider.login(null, null, { conid: volatile._id });
|
|
546
|
+
const resp = await authProvider.login(null, null, { conid: volatile._id }, req);
|
|
547
547
|
return resp;
|
|
548
548
|
} catch (err) {
|
|
549
549
|
logger.error(extractErrorLogData(err), 'Error getting DB token');
|
|
@@ -552,18 +552,18 @@ module.exports = {
|
|
|
552
552
|
},
|
|
553
553
|
|
|
554
554
|
dbloginAuth_meta: true,
|
|
555
|
-
async dbloginAuth({ amoid, conid, user, password }) {
|
|
555
|
+
async dbloginAuth({ amoid, conid, user, password }, req) {
|
|
556
556
|
if (user || password) {
|
|
557
557
|
const saveResp = await this.saveVolatile({ conid, user, password, test: true });
|
|
558
558
|
if (saveResp.msgtype == 'connected') {
|
|
559
|
-
const loginResp = await getAuthProviderById(amoid).login(user, password, { conid: saveResp._id });
|
|
559
|
+
const loginResp = await getAuthProviderById(amoid).login(user, password, { conid: saveResp._id }, req);
|
|
560
560
|
return loginResp;
|
|
561
561
|
}
|
|
562
562
|
return saveResp;
|
|
563
563
|
}
|
|
564
564
|
|
|
565
565
|
// user and password is stored in connection, volatile connection is not needed
|
|
566
|
-
const loginResp = await getAuthProviderById(amoid).login(null, null, { conid });
|
|
566
|
+
const loginResp = await getAuthProviderById(amoid).login(null, null, { conid }, req);
|
|
567
567
|
return loginResp;
|
|
568
568
|
},
|
|
569
569
|
|