dbgate-api-premium 6.5.4 → 6.5.6
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 +263 -66
- package/src/controllers/auth.js +89 -18
- package/src/controllers/cloud.js +18 -0
- package/src/controllers/config.js +57 -18
- 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 +133 -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 +250 -2
- package/src/utility/auditlog.js +288 -0
- package/src/utility/authProxy.js +31 -2
- package/src/utility/checkLicense.js +3 -0
- package/src/utility/cloudIntf.js +46 -3
- package/src/utility/getChartExport.js +11 -3
- package/src/utility/getMapExport.js +1 -1
- package/src/utility/loginchecker.js +69 -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.6",
|
|
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.6",
|
|
34
34
|
"dbgate-query-splitter": "^4.11.5",
|
|
35
|
-
"dbgate-sqltree": "^6.5.
|
|
36
|
-
"dbgate-tools": "^6.5.
|
|
35
|
+
"dbgate-sqltree": "^6.5.6",
|
|
36
|
+
"dbgate-tools": "^6.5.6",
|
|
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.6",
|
|
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, markTokenAsLoggedIn } = require('../utility/loginchecker');
|
|
24
26
|
|
|
25
27
|
async function loadPermissionsForUserId(userId) {
|
|
26
28
|
const rolePermissions = sortPermissionsFromTheSameLevel(await storageReadUserRolePermissions(userId));
|
|
@@ -50,21 +52,39 @@ class StorageProviderBase extends AuthProviderBase {
|
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
class AnonymousProvider extends StorageProviderBase {
|
|
53
|
-
async login(login, password, options = undefined) {
|
|
55
|
+
async login(login, password, options = undefined, req = undefined) {
|
|
54
56
|
const permissions = await [
|
|
55
57
|
...getPredefinedPermissions('anonymous-user'),
|
|
56
58
|
...(await storageReadRolePermissions(-1)),
|
|
57
59
|
];
|
|
58
60
|
|
|
61
|
+
if (!(await isLoginLicensed(req, `anonymous`))) {
|
|
62
|
+
return { error: LOGIN_LIMIT_ERROR };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
sendToAuditLog(req, {
|
|
66
|
+
category: 'auth',
|
|
67
|
+
component: 'AnonymousProvider',
|
|
68
|
+
action: 'login',
|
|
69
|
+
event: 'login.anonymous',
|
|
70
|
+
severity: 'info',
|
|
71
|
+
message: 'Anonymous login',
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const licenseUid = 'anonymous';
|
|
75
|
+
const accessToken = jwt.sign(
|
|
76
|
+
{
|
|
77
|
+
amoid: this.amoid,
|
|
78
|
+
permissions,
|
|
79
|
+
licenseUid,
|
|
80
|
+
},
|
|
81
|
+
getTokenSecret(),
|
|
82
|
+
{ expiresIn: getTokenLifetime() }
|
|
83
|
+
);
|
|
84
|
+
markTokenAsLoggedIn(licenseUid, accessToken);
|
|
85
|
+
|
|
59
86
|
return {
|
|
60
|
-
accessToken
|
|
61
|
-
{
|
|
62
|
-
amoid: this.amoid,
|
|
63
|
-
permissions,
|
|
64
|
-
},
|
|
65
|
-
getTokenSecret(),
|
|
66
|
-
{ expiresIn: getTokenLifetime() }
|
|
67
|
-
),
|
|
87
|
+
accessToken,
|
|
68
88
|
};
|
|
69
89
|
}
|
|
70
90
|
}
|
|
@@ -73,7 +93,7 @@ class LocalAuthProvider extends StorageProviderBase {
|
|
|
73
93
|
constructor(config) {
|
|
74
94
|
super(config);
|
|
75
95
|
}
|
|
76
|
-
async login(login, password) {
|
|
96
|
+
async login(login, password, _options, req) {
|
|
77
97
|
const rows = await storageSelectFmt('select * from ~users where login = %v', login);
|
|
78
98
|
if (rows.length == 0) {
|
|
79
99
|
return { error: 'Login not allowed' };
|
|
@@ -83,19 +103,49 @@ class LocalAuthProvider extends StorageProviderBase {
|
|
|
83
103
|
const userId = row.id;
|
|
84
104
|
const permissions = await loadPermissionsForUserId(userId);
|
|
85
105
|
|
|
106
|
+
if (!(await isLoginLicensed(req, `local:${login}`))) {
|
|
107
|
+
return { error: LOGIN_LIMIT_ERROR };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
sendToAuditLog(req, {
|
|
111
|
+
category: 'auth',
|
|
112
|
+
component: 'LocalAuthProvider',
|
|
113
|
+
action: 'login',
|
|
114
|
+
event: 'login.local',
|
|
115
|
+
severity: 'info',
|
|
116
|
+
detail: { login },
|
|
117
|
+
message: 'Local login successful',
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const licenseUid = `local:${login}`;
|
|
121
|
+
const accessToken = jwt.sign(
|
|
122
|
+
{
|
|
123
|
+
amoid: this.amoid,
|
|
124
|
+
login,
|
|
125
|
+
permissions,
|
|
126
|
+
userId,
|
|
127
|
+
licenseUid,
|
|
128
|
+
},
|
|
129
|
+
getTokenSecret(),
|
|
130
|
+
{ expiresIn: getTokenLifetime() }
|
|
131
|
+
);
|
|
132
|
+
markTokenAsLoggedIn(licenseUid, accessToken);
|
|
133
|
+
|
|
86
134
|
return {
|
|
87
|
-
accessToken
|
|
88
|
-
{
|
|
89
|
-
amoid: this.amoid,
|
|
90
|
-
login,
|
|
91
|
-
permissions,
|
|
92
|
-
userId,
|
|
93
|
-
},
|
|
94
|
-
getTokenSecret(),
|
|
95
|
-
{ expiresIn: getTokenLifetime() }
|
|
96
|
-
),
|
|
135
|
+
accessToken,
|
|
97
136
|
};
|
|
98
137
|
}
|
|
138
|
+
|
|
139
|
+
sendToAuditLog(req, {
|
|
140
|
+
category: 'auth',
|
|
141
|
+
component: 'LocalAuthProvider',
|
|
142
|
+
action: 'loginFail',
|
|
143
|
+
event: 'login.localFailed',
|
|
144
|
+
severity: 'warn',
|
|
145
|
+
detail: { login },
|
|
146
|
+
message: 'Local login failed',
|
|
147
|
+
});
|
|
148
|
+
|
|
99
149
|
return { error: 'Invalid credentials' };
|
|
100
150
|
}
|
|
101
151
|
|
|
@@ -121,7 +171,7 @@ class OauthProvider extends StorageProviderBase {
|
|
|
121
171
|
return this.config.oauthLogout;
|
|
122
172
|
}
|
|
123
173
|
|
|
124
|
-
async oauthToken(params) {
|
|
174
|
+
async oauthToken(params, req) {
|
|
125
175
|
const { redirectUri, code } = params;
|
|
126
176
|
|
|
127
177
|
const scopeParam = this.config.oauthScope ? `&scope=${this.config.oauthScope}` : '';
|
|
@@ -151,6 +201,16 @@ class OauthProvider extends StorageProviderBase {
|
|
|
151
201
|
const permissions = await loadPermissionsForUserId(loginRows[0]?.id ?? -1);
|
|
152
202
|
|
|
153
203
|
if (this.config.oauthOnlyDefinedLogins == 1 && loginRows.length == 0) {
|
|
204
|
+
sendToAuditLog(req, {
|
|
205
|
+
category: 'auth',
|
|
206
|
+
component: 'OauthProvider',
|
|
207
|
+
action: 'loginFail',
|
|
208
|
+
event: 'login.oauthNotAllowed',
|
|
209
|
+
severity: 'warn',
|
|
210
|
+
detail: { login },
|
|
211
|
+
message: `Username ${login} not allowed to log in`,
|
|
212
|
+
});
|
|
213
|
+
|
|
154
214
|
return { error: `Username ${login} not allowed to log in` };
|
|
155
215
|
}
|
|
156
216
|
|
|
@@ -171,21 +231,50 @@ class OauthProvider extends StorageProviderBase {
|
|
|
171
231
|
if (this.config.oauthOnlyDefinedGroups == 1) {
|
|
172
232
|
const roleRows = await storageSelectFmt('select * from ~roles where ~name in (%,v)', groups);
|
|
173
233
|
if (roleRows.length == 0) {
|
|
234
|
+
sendToAuditLog(req, {
|
|
235
|
+
category: 'auth',
|
|
236
|
+
component: 'OauthProvider',
|
|
237
|
+
action: 'loginFail',
|
|
238
|
+
event: 'login.groupNotAllowed',
|
|
239
|
+
severity: 'warn',
|
|
240
|
+
detail: { login },
|
|
241
|
+
message: `Groups ${groups.join(', ')} not allowed to log in`,
|
|
242
|
+
});
|
|
243
|
+
|
|
174
244
|
return { error: `Groups ${groups.join(', ')} not allowed to log in` };
|
|
175
245
|
}
|
|
176
246
|
}
|
|
177
247
|
|
|
248
|
+
if (!(await isLoginLicensed(req, `oauth:${login}`))) {
|
|
249
|
+
return { error: LOGIN_LIMIT_ERROR };
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
sendToAuditLog(req, {
|
|
253
|
+
category: 'auth',
|
|
254
|
+
component: 'OauthProvider',
|
|
255
|
+
action: 'login',
|
|
256
|
+
event: 'login.oauth',
|
|
257
|
+
severity: 'info',
|
|
258
|
+
detail: { login, userId: loginRows[0]?.id },
|
|
259
|
+
message: `User ${login} logged in via OAUTH`,
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
const licenseUid = `oauth:${login}`;
|
|
263
|
+
const accessToken = jwt.sign(
|
|
264
|
+
{
|
|
265
|
+
amoid: this.amoid,
|
|
266
|
+
login,
|
|
267
|
+
permissions,
|
|
268
|
+
userId: loginRows[0]?.id,
|
|
269
|
+
licenseUid,
|
|
270
|
+
},
|
|
271
|
+
getTokenSecret(),
|
|
272
|
+
{ expiresIn: getTokenLifetime() }
|
|
273
|
+
);
|
|
274
|
+
markTokenAsLoggedIn(licenseUid, accessToken);
|
|
275
|
+
|
|
178
276
|
return {
|
|
179
|
-
accessToken
|
|
180
|
-
{
|
|
181
|
-
amoid: this.amoid,
|
|
182
|
-
login,
|
|
183
|
-
permissions,
|
|
184
|
-
userId: loginRows[0]?.id,
|
|
185
|
-
},
|
|
186
|
-
getTokenSecret(),
|
|
187
|
-
{ expiresIn: getTokenLifetime() }
|
|
188
|
-
),
|
|
277
|
+
accessToken,
|
|
189
278
|
};
|
|
190
279
|
}
|
|
191
280
|
|
|
@@ -214,7 +303,7 @@ class ADProvider extends StorageProviderBase {
|
|
|
214
303
|
super(config);
|
|
215
304
|
}
|
|
216
305
|
|
|
217
|
-
async login(login, password) {
|
|
306
|
+
async login(login, password, _options, req) {
|
|
218
307
|
const adConfig = {
|
|
219
308
|
url: this.config.adUrl,
|
|
220
309
|
baseDN: this.config.adBaseDN,
|
|
@@ -225,6 +314,16 @@ class ADProvider extends StorageProviderBase {
|
|
|
225
314
|
try {
|
|
226
315
|
const res = await ad.authenticate(login, password);
|
|
227
316
|
if (!res) {
|
|
317
|
+
sendToAuditLog(req, {
|
|
318
|
+
category: 'auth',
|
|
319
|
+
component: 'OauthProvider',
|
|
320
|
+
action: 'loginFail',
|
|
321
|
+
event: 'login.adRejected',
|
|
322
|
+
severity: 'warn',
|
|
323
|
+
detail: { login },
|
|
324
|
+
message: `AD rejected login for ${login}`,
|
|
325
|
+
});
|
|
326
|
+
|
|
228
327
|
return { error: `Login failed, AD rejected login ${login}` };
|
|
229
328
|
}
|
|
230
329
|
|
|
@@ -237,18 +336,47 @@ class ADProvider extends StorageProviderBase {
|
|
|
237
336
|
}
|
|
238
337
|
}
|
|
239
338
|
|
|
339
|
+
if (!(await isLoginLicensed(req, `ad:${login}`))) {
|
|
340
|
+
return { error: LOGIN_LIMIT_ERROR };
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
sendToAuditLog(req, {
|
|
344
|
+
category: 'auth',
|
|
345
|
+
component: 'ADProvider',
|
|
346
|
+
action: 'login',
|
|
347
|
+
event: 'login.ad',
|
|
348
|
+
severity: 'info',
|
|
349
|
+
detail: { login },
|
|
350
|
+
message: `User ${login} logged in via AD`,
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
const licenseUid = `ad:${login}`;
|
|
354
|
+
const accessToken = jwt.sign(
|
|
355
|
+
{
|
|
356
|
+
amoid: this.amoid,
|
|
357
|
+
login,
|
|
358
|
+
permissions,
|
|
359
|
+
licenseUid,
|
|
360
|
+
},
|
|
361
|
+
getTokenSecret(),
|
|
362
|
+
{ expiresIn: getTokenLifetime() }
|
|
363
|
+
);
|
|
364
|
+
markTokenAsLoggedIn(licenseUid, accessToken);
|
|
365
|
+
|
|
240
366
|
return {
|
|
241
|
-
accessToken
|
|
242
|
-
{
|
|
243
|
-
amoid: this.amoid,
|
|
244
|
-
login,
|
|
245
|
-
permissions,
|
|
246
|
-
},
|
|
247
|
-
getTokenSecret(),
|
|
248
|
-
{ expiresIn: getTokenLifetime() }
|
|
249
|
-
),
|
|
367
|
+
accessToken,
|
|
250
368
|
};
|
|
251
369
|
} catch (e) {
|
|
370
|
+
sendToAuditLog(req, {
|
|
371
|
+
category: 'auth',
|
|
372
|
+
component: 'OauthProvider',
|
|
373
|
+
action: 'loginFail',
|
|
374
|
+
event: 'login.adError',
|
|
375
|
+
severity: 'warn',
|
|
376
|
+
detail: { login, error: e.message },
|
|
377
|
+
message: `AD login error for ${login}`,
|
|
378
|
+
});
|
|
379
|
+
|
|
252
380
|
return { error: `Login failed: ${e.message}` };
|
|
253
381
|
}
|
|
254
382
|
}
|
|
@@ -276,26 +404,56 @@ class DatabaseProvider extends StorageProviderBase {
|
|
|
276
404
|
}));
|
|
277
405
|
}
|
|
278
406
|
|
|
279
|
-
async login(login, password, options) {
|
|
407
|
+
async login(login, password, options, req) {
|
|
280
408
|
const { conid } = options;
|
|
281
409
|
const rows = login ? await storageSelectFmt('select * from ~users where ~login = %v', login) : [];
|
|
282
410
|
if (this.config.dbloginOnlyDefinedLogins == 1 && rows.length == 0) {
|
|
283
|
-
|
|
411
|
+
sendToAuditLog(req, {
|
|
412
|
+
category: 'auth',
|
|
413
|
+
component: 'DatabaseProvider',
|
|
414
|
+
action: 'loginFail',
|
|
415
|
+
event: 'login.dbLoginNotAllowed',
|
|
416
|
+
severity: 'warn',
|
|
417
|
+
detail: { login },
|
|
418
|
+
message: `Login ${login} not allowed to log in`,
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
return { error: 'Login not allowed', login };
|
|
284
422
|
}
|
|
285
423
|
const userId = rows[0]?.id;
|
|
286
424
|
const permissions = await loadPermissionsForUserId(userId ?? -1);
|
|
425
|
+
|
|
426
|
+
if (!(await isLoginLicensed(req, `db:${login}`))) {
|
|
427
|
+
return { error: LOGIN_LIMIT_ERROR };
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
sendToAuditLog(req, {
|
|
431
|
+
category: 'auth',
|
|
432
|
+
component: 'DatabaseProvider',
|
|
433
|
+
action: 'login',
|
|
434
|
+
event: 'login.dbLogin',
|
|
435
|
+
severity: 'info',
|
|
436
|
+
detail: { login },
|
|
437
|
+
message: `User ${login} logged in via database`,
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
const licenseUid = `db:${login}`;
|
|
441
|
+
const accessToken = jwt.sign(
|
|
442
|
+
{
|
|
443
|
+
amoid: this.amoid,
|
|
444
|
+
login,
|
|
445
|
+
permissions,
|
|
446
|
+
userId,
|
|
447
|
+
conid,
|
|
448
|
+
licenseUid,
|
|
449
|
+
},
|
|
450
|
+
getTokenSecret(),
|
|
451
|
+
{ expiresIn: getTokenLifetime() }
|
|
452
|
+
);
|
|
453
|
+
markTokenAsLoggedIn(licenseUid, accessToken);
|
|
454
|
+
|
|
287
455
|
return {
|
|
288
|
-
accessToken
|
|
289
|
-
{
|
|
290
|
-
amoid: this.amoid,
|
|
291
|
-
login,
|
|
292
|
-
permissions,
|
|
293
|
-
userId,
|
|
294
|
-
conid,
|
|
295
|
-
},
|
|
296
|
-
getTokenSecret(),
|
|
297
|
-
{ expiresIn: getTokenLifetime() }
|
|
298
|
-
),
|
|
456
|
+
accessToken,
|
|
299
457
|
};
|
|
300
458
|
}
|
|
301
459
|
|
|
@@ -320,7 +478,7 @@ class MsEntraProvider extends StorageProviderBase {
|
|
|
320
478
|
return null;
|
|
321
479
|
}
|
|
322
480
|
|
|
323
|
-
async oauthToken(params) {
|
|
481
|
+
async oauthToken(params, req) {
|
|
324
482
|
const { sid, code } = params;
|
|
325
483
|
|
|
326
484
|
const token = await authProxyGetTokenFromCode({ sid, code });
|
|
@@ -336,26 +494,65 @@ class MsEntraProvider extends StorageProviderBase {
|
|
|
336
494
|
|
|
337
495
|
if (this.config.msentraOnlyDefinedLogins == 1) {
|
|
338
496
|
if (loginRows.length == 0) {
|
|
497
|
+
sendToAuditLog(req, {
|
|
498
|
+
category: 'auth',
|
|
499
|
+
component: 'MsEntraProvider',
|
|
500
|
+
action: 'loginFail',
|
|
501
|
+
event: 'login.msentraNotAllowed',
|
|
502
|
+
severity: 'warn',
|
|
503
|
+
detail: { email },
|
|
504
|
+
message: `Email ${email} not allowed to log in`,
|
|
505
|
+
});
|
|
506
|
+
|
|
339
507
|
return { error: `Email ${email} not allowed to log in` };
|
|
340
508
|
}
|
|
341
509
|
}
|
|
342
510
|
|
|
343
511
|
if (token) {
|
|
512
|
+
if (!(await isLoginLicensed(req, `msentra:${payload.unique_name}`))) {
|
|
513
|
+
return { error: LOGIN_LIMIT_ERROR };
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
sendToAuditLog(req, {
|
|
517
|
+
category: 'auth',
|
|
518
|
+
component: 'MsEntraProvider',
|
|
519
|
+
action: 'login',
|
|
520
|
+
event: 'login.msentra',
|
|
521
|
+
severity: 'info',
|
|
522
|
+
detail: { login: payload.unique_name, userId: loginRows[0]?.id },
|
|
523
|
+
message: `User ${payload.unique_name} logged in via MS Entra`,
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
const licenseUid = `msentra:${payload.unique_name}`;
|
|
527
|
+
const accessToken = jwt.sign(
|
|
528
|
+
{
|
|
529
|
+
amoid: this.amoid,
|
|
530
|
+
permissions,
|
|
531
|
+
msentraToken: token,
|
|
532
|
+
userId: loginRows[0]?.id,
|
|
533
|
+
login: payload.unique_name,
|
|
534
|
+
licenseUid,
|
|
535
|
+
},
|
|
536
|
+
getTokenSecret(),
|
|
537
|
+
{ expiresIn: getTokenLifetime() }
|
|
538
|
+
);
|
|
539
|
+
markTokenAsLoggedIn(licenseUid, accessToken);
|
|
540
|
+
|
|
344
541
|
return {
|
|
345
|
-
accessToken
|
|
346
|
-
{
|
|
347
|
-
amoid: this.amoid,
|
|
348
|
-
permissions,
|
|
349
|
-
msentraToken: token,
|
|
350
|
-
userId: loginRows[0]?.id,
|
|
351
|
-
login: payload.unique_name,
|
|
352
|
-
},
|
|
353
|
-
getTokenSecret(),
|
|
354
|
-
{ expiresIn: getTokenLifetime() }
|
|
355
|
-
),
|
|
542
|
+
accessToken,
|
|
356
543
|
};
|
|
357
544
|
}
|
|
358
545
|
|
|
546
|
+
sendToAuditLog(req, {
|
|
547
|
+
category: 'auth',
|
|
548
|
+
component: 'MsEntraProvider',
|
|
549
|
+
action: 'loginFail',
|
|
550
|
+
event: 'login.msentraNotFound',
|
|
551
|
+
severity: 'warn',
|
|
552
|
+
detail: { email },
|
|
553
|
+
message: `Token not found for email ${email}`,
|
|
554
|
+
});
|
|
555
|
+
|
|
359
556
|
return { error: 'Token not found' };
|
|
360
557
|
}
|
|
361
558
|
|
package/src/controllers/auth.js
CHANGED
|
@@ -13,8 +13,21 @@ 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 {
|
|
25
|
+
isLoginLicensed,
|
|
26
|
+
LOGIN_LIMIT_ERROR,
|
|
27
|
+
markTokenAsLoggedIn,
|
|
28
|
+
markUserAsActive,
|
|
29
|
+
markLoginAsLoggedOut,
|
|
30
|
+
} = require('../utility/loginchecker');
|
|
18
31
|
|
|
19
32
|
const logger = getLogger('auth');
|
|
20
33
|
|
|
@@ -54,6 +67,11 @@ function authMiddleware(req, res, next) {
|
|
|
54
67
|
|
|
55
68
|
// const isAdminPage = req.headers['x-is-admin-page'] == 'true';
|
|
56
69
|
|
|
70
|
+
if (process.env.SKIP_ALL_AUTH) {
|
|
71
|
+
// API is not authorized for basic auth
|
|
72
|
+
return next();
|
|
73
|
+
}
|
|
74
|
+
|
|
57
75
|
if (process.env.BASIC_AUTH) {
|
|
58
76
|
// API is not authorized for basic auth
|
|
59
77
|
return next();
|
|
@@ -72,6 +90,8 @@ function authMiddleware(req, res, next) {
|
|
|
72
90
|
try {
|
|
73
91
|
const decoded = jwt.verify(token, getTokenSecret());
|
|
74
92
|
req.user = decoded;
|
|
93
|
+
markUserAsActive(decoded.licenseUid, token);
|
|
94
|
+
|
|
75
95
|
return next();
|
|
76
96
|
} catch (err) {
|
|
77
97
|
if (skipAuth) {
|
|
@@ -87,12 +107,12 @@ function authMiddleware(req, res, next) {
|
|
|
87
107
|
|
|
88
108
|
module.exports = {
|
|
89
109
|
oauthToken_meta: true,
|
|
90
|
-
async oauthToken(params) {
|
|
110
|
+
async oauthToken(params, req) {
|
|
91
111
|
const { amoid } = params;
|
|
92
|
-
return getAuthProviderById(amoid).oauthToken(params);
|
|
112
|
+
return getAuthProviderById(amoid).oauthToken(params, req);
|
|
93
113
|
},
|
|
94
114
|
login_meta: true,
|
|
95
|
-
async login(params) {
|
|
115
|
+
async login(params, req) {
|
|
96
116
|
const { amoid, login, password, isAdminPage } = params;
|
|
97
117
|
|
|
98
118
|
if (isAdminPage) {
|
|
@@ -102,25 +122,52 @@ module.exports = {
|
|
|
102
122
|
adminPassword = decryptPasswordString(adminConfig?.adminPassword);
|
|
103
123
|
}
|
|
104
124
|
if (adminPassword && adminPassword == password) {
|
|
125
|
+
if (!(await isLoginLicensed(req, `superadmin`))) {
|
|
126
|
+
return { error: LOGIN_LIMIT_ERROR };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
sendToAuditLog(req, {
|
|
130
|
+
category: 'auth',
|
|
131
|
+
component: 'AuthController',
|
|
132
|
+
action: 'login',
|
|
133
|
+
event: 'login.admin',
|
|
134
|
+
severity: 'info',
|
|
135
|
+
message: 'Administration login successful',
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const licenseUid = `superadmin`;
|
|
139
|
+
const accessToken = jwt.sign(
|
|
140
|
+
{
|
|
141
|
+
login: 'superadmin',
|
|
142
|
+
permissions: await storage.loadSuperadminPermissions(),
|
|
143
|
+
roleId: -3,
|
|
144
|
+
licenseUid,
|
|
145
|
+
},
|
|
146
|
+
getTokenSecret(),
|
|
147
|
+
{
|
|
148
|
+
expiresIn: getTokenLifetime(),
|
|
149
|
+
}
|
|
150
|
+
);
|
|
151
|
+
markTokenAsLoggedIn(licenseUid, accessToken);
|
|
152
|
+
|
|
105
153
|
return {
|
|
106
|
-
accessToken
|
|
107
|
-
{
|
|
108
|
-
login: 'superadmin',
|
|
109
|
-
permissions: await storage.loadSuperadminPermissions(),
|
|
110
|
-
roleId: -3,
|
|
111
|
-
},
|
|
112
|
-
getTokenSecret(),
|
|
113
|
-
{
|
|
114
|
-
expiresIn: getTokenLifetime(),
|
|
115
|
-
}
|
|
116
|
-
),
|
|
154
|
+
accessToken,
|
|
117
155
|
};
|
|
118
156
|
}
|
|
119
157
|
|
|
158
|
+
sendToAuditLog(req, {
|
|
159
|
+
category: 'auth',
|
|
160
|
+
component: 'AuthController',
|
|
161
|
+
action: 'loginFail',
|
|
162
|
+
event: 'login.adminFailed',
|
|
163
|
+
severity: 'warn',
|
|
164
|
+
message: 'Administraton login failed',
|
|
165
|
+
});
|
|
166
|
+
|
|
120
167
|
return { error: 'Login failed' };
|
|
121
168
|
}
|
|
122
169
|
|
|
123
|
-
return getAuthProviderById(amoid).login(login, password);
|
|
170
|
+
return getAuthProviderById(amoid).login(login, password, undefined, req);
|
|
124
171
|
},
|
|
125
172
|
|
|
126
173
|
getProviders_meta: true,
|
|
@@ -138,8 +185,8 @@ module.exports = {
|
|
|
138
185
|
},
|
|
139
186
|
|
|
140
187
|
createCloudLoginSession_meta: true,
|
|
141
|
-
async createCloudLoginSession({ client }) {
|
|
142
|
-
const res = await createDbGateIdentitySession(client);
|
|
188
|
+
async createCloudLoginSession({ client, redirectUri }) {
|
|
189
|
+
const res = await createDbGateIdentitySession(client, redirectUri);
|
|
143
190
|
startCloudTokenChecking(res.sid, tokenHolder => {
|
|
144
191
|
socket.emit('got-cloud-token', tokenHolder);
|
|
145
192
|
socket.emitChanged('cloud-content-changed');
|
|
@@ -148,5 +195,29 @@ module.exports = {
|
|
|
148
195
|
return res;
|
|
149
196
|
},
|
|
150
197
|
|
|
198
|
+
cloudLoginRedirected_meta: true,
|
|
199
|
+
async cloudLoginRedirected({ sid }) {
|
|
200
|
+
const tokenHolder = await readCloudTokenHolder(sid);
|
|
201
|
+
return tokenHolder;
|
|
202
|
+
},
|
|
203
|
+
|
|
204
|
+
cloudTestLogin_meta: true,
|
|
205
|
+
async cloudTestLogin({ email }) {
|
|
206
|
+
const tokenHolder = await readCloudTestTokenHolder(email);
|
|
207
|
+
return tokenHolder;
|
|
208
|
+
},
|
|
209
|
+
|
|
210
|
+
logoutAdmin_meta: true,
|
|
211
|
+
async logoutAdmin() {
|
|
212
|
+
await markLoginAsLoggedOut('superadmin');
|
|
213
|
+
return true;
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
logoutUser_meta: true,
|
|
217
|
+
async logoutUser({}, req) {
|
|
218
|
+
await markLoginAsLoggedOut(req?.user?.licenseUid);
|
|
219
|
+
return true;
|
|
220
|
+
},
|
|
221
|
+
|
|
151
222
|
authMiddleware,
|
|
152
223
|
};
|
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
|
};
|