From bf3855ae338c89e4062e5d2a8b90c8c790036ab5 Mon Sep 17 00:00:00 2001 From: Andrey Savihin Date: Thu, 25 Apr 2024 13:48:23 +0300 Subject: [PATCH 1/4] Bug 66037 - logout notification via socket --- common/ASC.Api.Core/Model/EmployeeFullDto.cs | 4 ++++ .../ASC.Core.Common/Data/DbLoginEventsManager.cs | 4 +++- .../ASC.Core.Common/Quota/QuotaSocketManager.cs | 5 +++++ common/ASC.Socket.IO/app/controllers/files.js | 5 +++++ common/ASC.Socket.IO/app/hubs/files.js | 8 +++++++- products/ASC.People/Server/Api/UserController.cs | 4 ++++ web/ASC.Web.Api/Api/AuthenticationController.cs | 2 ++ web/ASC.Web.Api/Api/ConnectionsController.cs | 15 ++++++++++++++- 8 files changed, 44 insertions(+), 3 deletions(-) diff --git a/common/ASC.Api.Core/Model/EmployeeFullDto.cs b/common/ASC.Api.Core/Model/EmployeeFullDto.cs index dc58572653c..c91ac96926b 100644 --- a/common/ASC.Api.Core/Model/EmployeeFullDto.cs +++ b/common/ASC.Api.Core/Model/EmployeeFullDto.cs @@ -167,6 +167,10 @@ public class EmployeeFullDto : EmployeeDto /// System.Boolean, System public bool? IsCustomQuota { get; set; } + /// Current login event ID + /// System.Int32, System + public int? LoginEventId { get; set; } + public static new EmployeeFullDto GetSample() { return new EmployeeFullDto diff --git a/common/ASC.Core.Common/Data/DbLoginEventsManager.cs b/common/ASC.Core.Common/Data/DbLoginEventsManager.cs index 489422c4d08..6612ee2a327 100644 --- a/common/ASC.Core.Common/Data/DbLoginEventsManager.cs +++ b/common/ASC.Core.Common/Data/DbLoginEventsManager.cs @@ -152,13 +152,15 @@ public async Task LogOutAllActiveConnectionsForTenantAsync(int tenantId) await InnerLogOutAsync(loginEventContext, loginEvents); } - public async Task LogOutAllActiveConnectionsExceptThisAsync(int loginEventId, int tenantId, Guid userId) + public async Task> LogOutAllActiveConnectionsExceptThisAsync(int loginEventId, int tenantId, Guid userId) { await using var loginEventContext = await dbContextFactory.CreateDbContextAsync(); var loginEvents = await Queries.LoginEventsExceptThisAsync(loginEventContext, tenantId, userId, loginEventId).ToListAsync(); await InnerLogOutAsync(loginEventContext, loginEvents); + + return loginEvents; } private async Task InnerLogOutAsync(MessagesContext loginEventContext, List loginEvents) diff --git a/common/ASC.Core.Common/Quota/QuotaSocketManager.cs b/common/ASC.Core.Common/Quota/QuotaSocketManager.cs index 2343e718d28..a944d8cab6c 100644 --- a/common/ASC.Core.Common/Quota/QuotaSocketManager.cs +++ b/common/ASC.Core.Common/Quota/QuotaSocketManager.cs @@ -58,6 +58,11 @@ public async Task ChangeQuotaFeatureValue(string featureId, object value) await MakeRequest("change-quota-feature-value", new { room, featureId, value }); } + public async Task LogoutSession(Guid userId, int loginEventId = 0) + { + await MakeRequest("logout-session", new { userId, loginEventId }); + } + private async Task GetQuotaRoom() { var tenantId = await _tenantManager.GetCurrentTenantIdAsync(); diff --git a/common/ASC.Socket.IO/app/controllers/files.js b/common/ASC.Socket.IO/app/controllers/files.js index 384abc66e0a..afcb4868d23 100644 --- a/common/ASC.Socket.IO/app/controllers/files.js +++ b/common/ASC.Socket.IO/app/controllers/files.js @@ -71,5 +71,10 @@ res.end(); }); + router.post("/logout-session", (req, res) => { + files.logoutSession(req.body); + res.end(); + }); + return router; }; \ No newline at end of file diff --git a/common/ASC.Socket.IO/app/hubs/files.js b/common/ASC.Socket.IO/app/hubs/files.js index 796b5618293..29d3de7b852 100644 --- a/common/ASC.Socket.IO/app/hubs/files.js +++ b/common/ASC.Socket.IO/app/hubs/files.js @@ -294,6 +294,11 @@ } } + function logoutSession({ userId, loginEventId } = {}) { + logger.info(`logout user ${userId} session ${loginEventId}`); + filesIO.to(userId).emit("s:logout-session", loginEventId); + } + return { startEdit, stopEdit, @@ -308,6 +313,7 @@ changeQuotaFeatureValue, changeUserQuotaFeatureValue, markAsNewFiles, - markAsNewFolders + markAsNewFolders, + logoutSession }; }; diff --git a/products/ASC.People/Server/Api/UserController.cs b/products/ASC.People/Server/Api/UserController.cs index 934e0e45080..8ac3a90c2ba 100644 --- a/products/ASC.People/Server/Api/UserController.cs +++ b/products/ASC.People/Server/Api/UserController.cs @@ -25,12 +25,14 @@ // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode using ASC.Api.Core.Core; +using ASC.Core.Security.Authentication; namespace ASC.People.Api; public class UserController(ICache cache, TenantManager tenantManager, CookiesManager cookiesManager, + CookieStorage cookieStorage, CustomNamingPeople customNamingPeople, EmployeeDtoHelper employeeDtoHelper, EmployeeFullDtoHelper employeeFullDtoHelper, @@ -991,6 +993,8 @@ public async Task SelfAsync() result.Theme = (await settingsManager.LoadForCurrentUserAsync()).Theme; + result.LoginEventId = cookieStorage.GetLoginEventIdFromCookie(cookiesManager.GetCookies(CookiesType.AuthKey)); + return result; } diff --git a/web/ASC.Web.Api/Api/AuthenticationController.cs b/web/ASC.Web.Api/Api/AuthenticationController.cs index 53b8283d625..1dd55364d21 100644 --- a/web/ASC.Web.Api/Api/AuthenticationController.cs +++ b/web/ASC.Web.Api/Api/AuthenticationController.cs @@ -66,6 +66,7 @@ public class AuthenticationController( ApiContext apiContext, AuthContext authContext, CookieStorage cookieStorage, + QuotaSocketManager quotaSocketManager, DbLoginEventsManager dbLoginEventsManager, BruteForceLoginManager bruteForceLoginManager, TfaAppAuthSettingsHelper tfaAppAuthSettingsHelper, @@ -286,6 +287,7 @@ public async Task LogoutAsync() var loginEventId = cookieStorage.GetLoginEventIdFromCookie(cookie); var tenantId = await tenantManager.GetCurrentTenantIdAsync(); await dbLoginEventsManager.LogOutEventAsync(tenantId, loginEventId); + await quotaSocketManager.LogoutSession(securityContext.CurrentAccount.ID, loginEventId); var user = await userManager.GetUsersAsync(securityContext.CurrentAccount.ID); var loginName = user.DisplayUserName(false, displayUserSettingsHelper); diff --git a/web/ASC.Web.Api/Api/ConnectionsController.cs b/web/ASC.Web.Api/Api/ConnectionsController.cs index d0454fd76cf..a64e96aad51 100644 --- a/web/ASC.Web.Api/Api/ConnectionsController.cs +++ b/web/ASC.Web.Api/Api/ConnectionsController.cs @@ -46,6 +46,7 @@ public class ConnectionsController( MessageService messageService, CookiesManager cookiesManager, CookieStorage cookieStorage, + QuotaSocketManager quotaSocketManager, GeolocationHelper geolocationHelper, ApiDateTimeHelper apiDateTimeHelper) : ControllerBase @@ -205,7 +206,12 @@ public async Task LogOutAllExceptThisConnection() var userName = user.DisplayUserName(false, displayUserSettingsHelper); var loginEventFromCookie = GetLoginEventIdFromCookie(); - await dbLoginEventsManager.LogOutAllActiveConnectionsExceptThisAsync(loginEventFromCookie, user.TenantId, user.Id); + var loginEvents = await dbLoginEventsManager.LogOutAllActiveConnectionsExceptThisAsync(loginEventFromCookie, user.TenantId, user.Id); + + foreach (var loginEvent in loginEvents) + { + await quotaSocketManager.LogoutSession(user.Id, loginEvent.Id); + } await messageService.SendAsync(MessageAction.UserLogoutActiveConnections, userName); return userName; @@ -252,6 +258,11 @@ public async Task LogOutActiveConnection(int loginEventId) await dbLoginEventsManager.LogOutEventAsync(loginEvent.TenantId, loginEvent.Id); + if (loginEvent.UserId.HasValue) + { + await quotaSocketManager.LogoutSession(loginEvent.UserId.Value, loginEvent.Id); + } + await messageService.SendAsync(MessageAction.UserLogoutActiveConnection, userName); return true; } @@ -271,6 +282,8 @@ private async Task LogOutAllActiveConnections(Guid? userId = null) await messageService.SendAsync(currentUserId.Equals(user.Id) ? MessageAction.UserLogoutActiveConnections : MessageAction.UserLogoutActiveConnectionsForUser, MessageTarget.Create(user.Id), auditEventDate, userName); await cookiesManager.ResetUserCookieAsync(user.Id); + + await quotaSocketManager.LogoutSession(user.Id); } private int GetLoginEventIdFromCookie() From 8923eb34eac1865d7452a6b3d01abddccdf31a72 Mon Sep 17 00:00:00 2001 From: Andrey Savihin Date: Mon, 5 Aug 2024 16:56:39 +0300 Subject: [PATCH 2/4] ASC.Socket.IO: using tenantid in logout-session event --- common/ASC.Socket.IO/app/hubs/files.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/ASC.Socket.IO/app/hubs/files.js b/common/ASC.Socket.IO/app/hubs/files.js index b958ceb9da2..bf9fd663ef3 100644 --- a/common/ASC.Socket.IO/app/hubs/files.js +++ b/common/ASC.Socket.IO/app/hubs/files.js @@ -338,8 +338,9 @@ module.exports = (io) => { } function logoutSession({ userId, loginEventId } = {}) { + const room = getRoom(userId); logger.info(`logout user ${userId} session ${loginEventId}`); - filesIO.to(userId).emit("s:logout-session", loginEventId); + filesIO.to(room).emit("s:logout-session", loginEventId); } return { From 025a21dc8f2fb8997989c8aac9fecaed766ed6a1 Mon Sep 17 00:00:00 2001 From: Andrey Savihin Date: Tue, 6 Aug 2024 12:53:04 +0300 Subject: [PATCH 3/4] ASC.Socket.IO: using tenantid in logout-session event --- common/ASC.Core.Common/Quota/QuotaSocketManager.cs | 4 +++- common/ASC.Socket.IO/app/hubs/files.js | 7 +++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/common/ASC.Core.Common/Quota/QuotaSocketManager.cs b/common/ASC.Core.Common/Quota/QuotaSocketManager.cs index a9d03819e32..ac7c1eab788 100644 --- a/common/ASC.Core.Common/Quota/QuotaSocketManager.cs +++ b/common/ASC.Core.Common/Quota/QuotaSocketManager.cs @@ -67,7 +67,9 @@ public async Task ChangeInvitationLimitValue(int value) public async Task LogoutSession(Guid userId, int loginEventId = 0) { - await MakeRequest("logout-session", new { userId, loginEventId }); + var tenantId = await _tenantManager.GetCurrentTenantIdAsync(); + + await MakeRequest("logout-session", new { tenantId, userId, loginEventId }); } private async Task GetQuotaRoom() diff --git a/common/ASC.Socket.IO/app/hubs/files.js b/common/ASC.Socket.IO/app/hubs/files.js index bf9fd663ef3..eb9b10381da 100644 --- a/common/ASC.Socket.IO/app/hubs/files.js +++ b/common/ASC.Socket.IO/app/hubs/files.js @@ -337,10 +337,9 @@ module.exports = (io) => { filesIO.to(room).emit("s:update-history", { id, type }); } - function logoutSession({ userId, loginEventId } = {}) { - const room = getRoom(userId); - logger.info(`logout user ${userId} session ${loginEventId}`); - filesIO.to(room).emit("s:logout-session", loginEventId); + function logoutSession({ tenantId, userId, loginEventId } = {}) { + logger.info(`logout user ${userId} session ${loginEventId} tenant ${tenantId}`); + filesIO.to(`${tenantId}-${userId}`).emit("s:logout-session", loginEventId); } return { From 8b6f9b5d0cde5b02191a6edf687f844fa60668af Mon Sep 17 00:00:00 2001 From: Andrey Savihin Date: Tue, 6 Aug 2024 13:47:21 +0300 Subject: [PATCH 4/4] ASC.Socket.IO: using tenantid in logout-session event --- common/ASC.Core.Common/Quota/QuotaSocketManager.cs | 2 +- common/ASC.Socket.IO/app/hubs/files.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/common/ASC.Core.Common/Quota/QuotaSocketManager.cs b/common/ASC.Core.Common/Quota/QuotaSocketManager.cs index ac7c1eab788..c9dfae6e6a0 100644 --- a/common/ASC.Core.Common/Quota/QuotaSocketManager.cs +++ b/common/ASC.Core.Common/Quota/QuotaSocketManager.cs @@ -69,7 +69,7 @@ public async Task LogoutSession(Guid userId, int loginEventId = 0) { var tenantId = await _tenantManager.GetCurrentTenantIdAsync(); - await MakeRequest("logout-session", new { tenantId, userId, loginEventId }); + await MakeRequest("logout-session", new { room = $"{tenantId}-{userId}", loginEventId }); } private async Task GetQuotaRoom() diff --git a/common/ASC.Socket.IO/app/hubs/files.js b/common/ASC.Socket.IO/app/hubs/files.js index eb9b10381da..55fd6070add 100644 --- a/common/ASC.Socket.IO/app/hubs/files.js +++ b/common/ASC.Socket.IO/app/hubs/files.js @@ -337,9 +337,9 @@ module.exports = (io) => { filesIO.to(room).emit("s:update-history", { id, type }); } - function logoutSession({ tenantId, userId, loginEventId } = {}) { - logger.info(`logout user ${userId} session ${loginEventId} tenant ${tenantId}`); - filesIO.to(`${tenantId}-${userId}`).emit("s:logout-session", loginEventId); + function logoutSession({ room, loginEventId } = {}) { + logger.info(`logout user ${room} session ${loginEventId}`); + filesIO.to(room).emit("s:logout-session", loginEventId); } return {