From a36fda11e3914e13f472938d57865ff104ba6aa9 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Wed, 24 Jun 2020 17:28:02 +0800 Subject: [PATCH 1/9] Init UserSecurityLog. --- .../Volo.Abp.Security.csproj | 1 + .../SecurityLog/IUserSecurityLogStore.cs | 9 ++++ .../Users/SecurityLog/UserSecurityLogInfo.cs | 53 +++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/IUserSecurityLogStore.cs create mode 100644 framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/UserSecurityLogInfo.cs diff --git a/framework/src/Volo.Abp.Security/Volo.Abp.Security.csproj b/framework/src/Volo.Abp.Security/Volo.Abp.Security.csproj index 65aca85c88..6ffaac1232 100644 --- a/framework/src/Volo.Abp.Security/Volo.Abp.Security.csproj +++ b/framework/src/Volo.Abp.Security/Volo.Abp.Security.csproj @@ -16,6 +16,7 @@ + diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/IUserSecurityLogStore.cs b/framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/IUserSecurityLogStore.cs new file mode 100644 index 0000000000..18d5b1c23e --- /dev/null +++ b/framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/IUserSecurityLogStore.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.Users.SecurityLog +{ + public interface IUserSecurityLogStore + { + Task SaveAsync(UserSecurityLogInfo userSecurityLogInfo); + } +} diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/UserSecurityLogInfo.cs b/framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/UserSecurityLogInfo.cs new file mode 100644 index 0000000000..5ecb8d9314 --- /dev/null +++ b/framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/UserSecurityLogInfo.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using Volo.Abp.Data; + +namespace Volo.Abp.Users.SecurityLog +{ + [Serializable] + public class UserSecurityLogInfo : IHasExtraProperties + { + /// + /// The name of the application or service writing user security logs. + /// Default: null. + /// + public string ApplicationName { get; set; } + + /// + /// Web, JWT, Identity, Identity_Server + /// + public string Identity { get; set; } + + /// + /// login_successful, login_failed, logout, change_pwd, refresh_token... + /// + public string Action { get; set; } + + public Dictionary ExtraProperties { get; } + + public Guid? UserId { get; set; } + + public string UserName { get; set; } + + public Guid? TenantId { get; set; } + + public string TenantName { get; set; } + + public string ClientId { get; set; } + + public string ClientName { get; set; } + + public string CorrelationId { get; set; } + + public string ClientIpAddress { get; set; } + + public string BrowserInfo { get; set; } + + public DateTime CreationTime { get; set; } + + public UserSecurityLogInfo() + { + ExtraProperties = new Dictionary(); + } + } +} From 65957cbb6e2fa3c1d5b5a2c5d14cb527289a23be Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Wed, 8 Jul 2020 17:34:33 +0800 Subject: [PATCH 2/9] Add some infrastructure for security logs. --- .../Auditing/AspNetCoreAuditLogContributor.cs | 24 +----- .../AspNetCoreSecurityLogManager.cs | 74 +++++++++++++++++++ .../HttpContextWebClientInfoProvider.cs | 43 +++++++++++ .../WebClientInfo/IWebClientInfoProvider.cs | 9 +++ .../Abp/SecurityLog/AbpSecurityLogOptions.cs | 21 ++++++ .../SecurityLog/DefaultSecurityLogManager.cs | 34 +++++++++ .../Abp/SecurityLog/ISecurityLogManager.cs | 11 +++ .../Volo/Abp/SecurityLog/ISecurityLogStore.cs | 9 +++ .../SecurityLogInfo.cs} | 11 ++- .../Abp/SecurityLog/SimpleSecurityLogStore.cs | 22 ++++++ .../SecurityLog/IUserSecurityLogStore.cs | 9 --- .../IdentityServerSupportedLoginModel.cs | 3 + .../Account/Controllers/AccountController.cs | 25 ++++++- .../Pages/Account/AccountPageModel.cs | 11 +++ .../Pages/Account/Login.cshtml.cs | 8 +- 15 files changed, 277 insertions(+), 37 deletions(-) create mode 100644 framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/SecurityLog/AspNetCoreSecurityLogManager.cs create mode 100644 framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/WebClientInfo/HttpContextWebClientInfoProvider.cs create mode 100644 framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/WebClientInfo/IWebClientInfoProvider.cs create mode 100644 framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/AbpSecurityLogOptions.cs create mode 100644 framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs create mode 100644 framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs create mode 100644 framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogStore.cs rename framework/src/Volo.Abp.Security/Volo/Abp/{Users/SecurityLog/UserSecurityLogInfo.cs => SecurityLog/SecurityLogInfo.cs} (82%) create mode 100644 framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SimpleSecurityLogStore.cs delete mode 100644 framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/IUserSecurityLogStore.cs diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AspNetCoreAuditLogContributor.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AspNetCoreAuditLogContributor.cs index 378b92a14a..04238a9a45 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AspNetCoreAuditLogContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AspNetCoreAuditLogContributor.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Volo.Abp.AspNetCore.WebClientInfo; using Volo.Abp.Auditing; using Volo.Abp.DependencyInjection; @@ -35,14 +36,15 @@ namespace Volo.Abp.AspNetCore.Auditing context.AuditInfo.Url = BuildUrl(httpContext); } + var clientInfoProvider = context.ServiceProvider.GetRequiredService(); if (context.AuditInfo.ClientIpAddress == null) { - context.AuditInfo.ClientIpAddress = GetClientIpAddress(httpContext); + context.AuditInfo.ClientIpAddress = clientInfoProvider.ClientIpAddress; } if (context.AuditInfo.BrowserInfo == null) { - context.AuditInfo.BrowserInfo = GetBrowserInfo(httpContext); + context.AuditInfo.BrowserInfo = clientInfoProvider.BrowserInfo; } //TODO: context.AuditInfo.ClientName @@ -62,24 +64,6 @@ namespace Volo.Abp.AspNetCore.Auditing } } - protected virtual string GetBrowserInfo(HttpContext httpContext) - { - return httpContext.Request?.Headers?["User-Agent"]; - } - - protected virtual string GetClientIpAddress(HttpContext httpContext) - { - try - { - return httpContext.Connection?.RemoteIpAddress?.ToString(); - } - catch (Exception ex) - { - Logger.LogException(ex, LogLevel.Warning); - return null; - } - } - protected virtual string BuildUrl(HttpContext httpContext) { //TODO: Add options to include/exclude query, schema and host diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/SecurityLog/AspNetCoreSecurityLogManager.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/SecurityLog/AspNetCoreSecurityLogManager.cs new file mode 100644 index 0000000000..4c60a6ce37 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/SecurityLog/AspNetCoreSecurityLogManager.cs @@ -0,0 +1,74 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Volo.Abp.AspNetCore.WebClientInfo; +using Volo.Abp.Clients; +using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy; +using Volo.Abp.SecurityLog; +using Volo.Abp.Timing; +using Volo.Abp.Tracing; +using Volo.Abp.Users; + +namespace Volo.Abp.AspNetCore.SecurityLog +{ + [Dependency(ReplaceServices = true)] + public class AspNetCoreSecurityLogManager : DefaultSecurityLogManager + { + protected ILogger Logger { get; } + protected IClock Clock { get; } + protected ICurrentUser CurrentUser { get; } + protected ICurrentTenant CurrentTenant { get; } + protected ICurrentClient CurrentClient { get; } + protected IHttpContextAccessor HttpContextAccessor { get; } + protected ICorrelationIdProvider CorrelationIdProvider { get; } + + protected IWebClientInfoProvider WebClientInfoProvider { get; } + + public AspNetCoreSecurityLogManager( + IOptions securityLogOptions, + ISecurityLogStore securityLogStore, + ILogger logger, + IClock clock, + ICurrentUser currentUser, + ICurrentTenant currentTenant, + ICurrentClient currentClient, + IHttpContextAccessor httpContextAccessor, + ICorrelationIdProvider correlationIdProvider, + IWebClientInfoProvider webClientInfoProvider) + : base(securityLogOptions, securityLogStore) + { + Logger = logger; + Clock = clock; + CurrentUser = currentUser; + CurrentTenant = currentTenant; + CurrentClient = currentClient; + HttpContextAccessor = httpContextAccessor; + CorrelationIdProvider = correlationIdProvider; + WebClientInfoProvider = webClientInfoProvider; + } + + public override async Task CreateAsync() + { + var securityLogInfo = await base.CreateAsync(); + + securityLogInfo.CreationTime = Clock.Now; + + securityLogInfo.TenantId = CurrentTenant.Id; + securityLogInfo.TenantName = CurrentTenant.Name; + + securityLogInfo.UserId = CurrentUser.Id; + securityLogInfo.UserName = CurrentUser.UserName; + + securityLogInfo.ClientId = CurrentClient.Id; + + securityLogInfo.CorrelationId = CorrelationIdProvider.Get(); + + securityLogInfo.ClientIpAddress = WebClientInfoProvider.ClientIpAddress; + securityLogInfo.BrowserInfo = WebClientInfoProvider.BrowserInfo; + + return securityLogInfo; + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/WebClientInfo/HttpContextWebClientInfoProvider.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/WebClientInfo/HttpContextWebClientInfoProvider.cs new file mode 100644 index 0000000000..503771c938 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/WebClientInfo/HttpContextWebClientInfoProvider.cs @@ -0,0 +1,43 @@ +using System; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.AspNetCore.WebClientInfo +{ + public class HttpContextWebClientInfoProvider : IWebClientInfoProvider, ITransientDependency + { + protected ILogger Logger { get; } + protected IHttpContextAccessor HttpContextAccessor { get; } + + public HttpContextWebClientInfoProvider( + ILogger logger, + IHttpContextAccessor httpContextAccessor) + { + Logger = logger; + HttpContextAccessor = httpContextAccessor; + } + + public string BrowserInfo => GetBrowserInfo(); + + public string ClientIpAddress => GetClientIpAddress(); + + protected virtual string GetBrowserInfo() + { + return HttpContextAccessor.HttpContext?.Request?.Headers?["User-Agent"]; + } + + protected virtual string GetClientIpAddress() + { + try + { + return HttpContextAccessor.HttpContext?.Connection?.RemoteIpAddress?.ToString(); + } + catch (Exception ex) + { + Logger.LogException(ex, LogLevel.Warning); + return null; + } + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/WebClientInfo/IWebClientInfoProvider.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/WebClientInfo/IWebClientInfoProvider.cs new file mode 100644 index 0000000000..3a15ac2f93 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/WebClientInfo/IWebClientInfoProvider.cs @@ -0,0 +1,9 @@ +namespace Volo.Abp.AspNetCore.WebClientInfo +{ + public interface IWebClientInfoProvider + { + string BrowserInfo { get; } + + string ClientIpAddress { get; } + } +} diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/AbpSecurityLogOptions.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/AbpSecurityLogOptions.cs new file mode 100644 index 0000000000..a1cc6406f4 --- /dev/null +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/AbpSecurityLogOptions.cs @@ -0,0 +1,21 @@ +namespace Volo.Abp.SecurityLog +{ + public class AbpSecurityLogOptions + { + /// + /// Default: true. + /// + public bool IsEnabled { get; set; } + + /// + /// The name of the application or service writing security log. + /// Default: null. + /// + public string ApplicationName { get; set; } + + public AbpSecurityLogOptions() + { + IsEnabled = true; + } + } +} diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs new file mode 100644 index 0000000000..0f5d40567c --- /dev/null +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs @@ -0,0 +1,34 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.SecurityLog +{ + public class DefaultSecurityLogManager : ISecurityLogManager, ITransientDependency + { + protected AbpSecurityLogOptions SecurityLogOptions { get; } + + protected ISecurityLogStore SecurityLogStore { get; } + + public DefaultSecurityLogManager( + IOptions securityLogOptions, + ISecurityLogStore securityLogStore) + { + SecurityLogStore = securityLogStore; + SecurityLogOptions = securityLogOptions.Value; + } + + public virtual Task CreateAsync() + { + return Task.FromResult(new SecurityLogInfo + { + ApplicationName = SecurityLogOptions.ApplicationName + }); + } + + public async Task SaveAsync(SecurityLogInfo securityLogInfo) + { + await SecurityLogStore.SaveAsync(securityLogInfo); + } + } +} diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs new file mode 100644 index 0000000000..f762522509 --- /dev/null +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs @@ -0,0 +1,11 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.SecurityLog +{ + public interface ISecurityLogManager + { + Task CreateAsync(); + + Task SaveAsync(SecurityLogInfo securityLogInfo); + } +} diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogStore.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogStore.cs new file mode 100644 index 0000000000..df2496f307 --- /dev/null +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogStore.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.SecurityLog +{ + public interface ISecurityLogStore + { + Task SaveAsync(SecurityLogInfo securityLogInfo); + } +} diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/UserSecurityLogInfo.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs similarity index 82% rename from framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/UserSecurityLogInfo.cs rename to framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs index 5ecb8d9314..11f46c7527 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/UserSecurityLogInfo.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs @@ -2,10 +2,10 @@ using System.Collections.Generic; using Volo.Abp.Data; -namespace Volo.Abp.Users.SecurityLog +namespace Volo.Abp.SecurityLog { [Serializable] - public class UserSecurityLogInfo : IHasExtraProperties + public class SecurityLogInfo : IHasExtraProperties { /// /// The name of the application or service writing user security logs. @@ -45,9 +45,14 @@ namespace Volo.Abp.Users.SecurityLog public DateTime CreationTime { get; set; } - public UserSecurityLogInfo() + public SecurityLogInfo() { ExtraProperties = new Dictionary(); } + + public override string ToString() + { + return $"SECURITY LOG: [{ApplicationName} - {Identity} - {Action}]"; + } } } diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SimpleSecurityLogStore.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SimpleSecurityLogStore.cs new file mode 100644 index 0000000000..bc9c22c4df --- /dev/null +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SimpleSecurityLogStore.cs @@ -0,0 +1,22 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.SecurityLog +{ + public class SimpleSecurityLogStore : ISecurityLogStore, ITransientDependency + { + public ILogger Logger { get; set; } + + public SimpleSecurityLogStore(ILogger logger) + { + Logger = logger; + } + + public Task SaveAsync(SecurityLogInfo securityLogInfo) + { + Logger.LogInformation(securityLogInfo.ToString()); + return Task.FromResult(0); + } + } +} diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/IUserSecurityLogStore.cs b/framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/IUserSecurityLogStore.cs deleted file mode 100644 index 18d5b1c23e..0000000000 --- a/framework/src/Volo.Abp.Security/Volo/Abp/Users/SecurityLog/IUserSecurityLogStore.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Threading.Tasks; - -namespace Volo.Abp.Users.SecurityLog -{ - public interface IUserSecurityLogStore - { - Task SaveAsync(UserSecurityLogInfo userSecurityLogInfo); - } -} diff --git a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs index 60f55497da..af157ed629 100644 --- a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs +++ b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs @@ -15,6 +15,7 @@ using System.Threading.Tasks; using Volo.Abp.Account.Settings; using Volo.Abp.DependencyInjection; using Volo.Abp.MultiTenancy; +using Volo.Abp.SecurityLog; using Volo.Abp.Settings; using Volo.Abp.Uow; @@ -127,6 +128,8 @@ namespace Volo.Abp.Account.Web.Pages.Account true ); + await CreateSecurityLog("Login_" + result); + if (result.RequiresTwoFactor) { return RedirectToPage("./SendSecurityCode", new diff --git a/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs b/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs index 64fbdd40d1..38e8e7e7c2 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs @@ -7,6 +7,7 @@ using Volo.Abp.Account.Settings; using Volo.Abp.Account.Web.Areas.Account.Controllers.Models; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.Identity; +using Volo.Abp.SecurityLog; using Volo.Abp.Settings; using Volo.Abp.Validation; using SignInResult = Microsoft.AspNetCore.Identity.SignInResult; @@ -25,14 +26,20 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers protected SignInManager SignInManager { get; } protected IdentityUserManager UserManager { get; } protected ISettingProvider SettingProvider { get; } + protected ISecurityLogManager SecurityLogManager { get; } - public AccountController(SignInManager signInManager, IdentityUserManager userManager, ISettingProvider settingProvider) + public AccountController( + SignInManager signInManager, + IdentityUserManager userManager, + ISettingProvider settingProvider, + ISecurityLogManager securityLogManager) { LocalizationResource = typeof(AccountResource); SignInManager = signInManager; UserManager = userManager; SettingProvider = settingProvider; + SecurityLogManager = securityLogManager; } [HttpPost] @@ -44,19 +51,23 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers ValidateLoginInfo(login); await ReplaceEmailToUsernameOfInputIfNeeds(login); - - return GetAbpLoginResult(await SignInManager.PasswordSignInAsync( + var loginResult = GetAbpLoginResult(await SignInManager.PasswordSignInAsync( login.UserNameOrEmailAddress, login.Password, login.RememberMe, true )); + + await CreateSecurityLog("Login_" + loginResult.Result); + + return loginResult; } [HttpGet] [Route("logout")] public virtual async Task Logout() { + await CreateSecurityLog("Logout"); await SignInManager.SignOutAsync(); } @@ -150,5 +161,13 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers throw new UserFriendlyException(L["LocalLoginDisabledMessage"]); } } + + protected virtual async Task CreateSecurityLog(string action) + { + var securityLog = await SecurityLogManager.CreateAsync(); + securityLog.Identity = "Web"; + securityLog.Action = action; + await SecurityLogManager.SaveAsync(securityLog); + } } } diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/AccountPageModel.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/AccountPageModel.cs index 41bdd93647..d7fd0f8239 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/AccountPageModel.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/AccountPageModel.cs @@ -1,12 +1,14 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Volo.Abp.Account.Localization; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; using Volo.Abp.Identity; +using Volo.Abp.SecurityLog; using IdentityUser = Volo.Abp.Identity.IdentityUser; namespace Volo.Abp.Account.Web.Pages.Account @@ -15,6 +17,7 @@ namespace Volo.Abp.Account.Web.Pages.Account { public SignInManager SignInManager { get; set; } public IdentityUserManager UserManager { get; set; } + public ISecurityLogManager SecurityLogManager { get; } protected AccountPageModel() { @@ -76,5 +79,13 @@ namespace Volo.Abp.Account.Web.Pages.Account { return "~/"; //TODO: ??? } + + protected virtual async Task CreateSecurityLog(string action) + { + var securityLog = await SecurityLogManager.CreateAsync(); + securityLog.Identity = "Web"; + securityLog.Action = action; + await SecurityLogManager.SaveAsync(securityLog); + } } } diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs index 5251cb12f1..2916e60b4f 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs @@ -14,8 +14,8 @@ using Volo.Abp.Account.Settings; using Volo.Abp.Auditing; using Volo.Abp.Identity; using Volo.Abp.Security.Claims; +using Volo.Abp.SecurityLog; using Volo.Abp.Settings; -using Volo.Abp.Uow; using Volo.Abp.Validation; using IdentityUser = Volo.Abp.Identity.IdentityUser; @@ -83,7 +83,7 @@ namespace Volo.Abp.Account.Web.Pages.Account ValidateModel(); ExternalProviders = await GetExternalProviders(); - + EnableLocalLogin = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin); await ReplaceEmailToUsernameOfInputIfNeeds(); @@ -95,6 +95,8 @@ namespace Volo.Abp.Account.Web.Pages.Account true ); + await CreateSecurityLog(result.ToString()); + if (result.RequiresTwoFactor) { return RedirectToPage("./SendSecurityCode", new @@ -182,6 +184,8 @@ namespace Volo.Abp.Account.Web.Pages.Account bypassTwoFactor: true ); + await CreateSecurityLog(result.ToString()); + if (result.IsLockedOut) { throw new UserFriendlyException("Cannot proceed because user is locked out!"); From 73de02689f78726665326cb3da2c69c534bb799e Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Thu, 9 Jul 2020 10:34:50 +0800 Subject: [PATCH 3/9] Refactoring ISecurityLogManager. --- .../AspNetCoreSecurityLogManager.cs | 2 +- .../SecurityLog/DefaultSecurityLogManager.cs | 17 ++-- .../Abp/SecurityLog/ISecurityLogManager.cs | 7 +- .../Volo/Abp/SecurityLog/SecurityLogInfo.cs | 2 - .../IdentityServerSupportedLoginModel.cs | 9 +- .../Account/Controllers/AccountController.cs | 40 +++++---- .../Pages/Account/AccountPageModel.cs | 14 +-- .../Pages/Account/Login.cshtml.cs | 28 +++++- .../Pages/Account/Logout.cshtml.cs | 7 ++ .../AspNetCore/SignInResultExtensions.cs | 37 ++++++++ .../IdentitySecurityLogActionConsts.cs | 33 +++++++ .../IdentitySecurityLogIdentityConsts.cs | 11 +++ .../Identity/AbpIdentityResultExtensions.cs | 12 ++- .../Volo/Abp/Identity/SecurityLogEvent.cs | 18 ++++ .../Volo/Abp/Identity/SecurityLogHandler.cs | 85 +++++++++++++++++++ 15 files changed, 271 insertions(+), 51 deletions(-) create mode 100644 modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/SignInResultExtensions.cs create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogActionConsts.cs create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogIdentityConsts.cs create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogEvent.cs create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogHandler.cs diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/SecurityLog/AspNetCoreSecurityLogManager.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/SecurityLog/AspNetCoreSecurityLogManager.cs index 4c60a6ce37..55ece86be2 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/SecurityLog/AspNetCoreSecurityLogManager.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/SecurityLog/AspNetCoreSecurityLogManager.cs @@ -49,7 +49,7 @@ namespace Volo.Abp.AspNetCore.SecurityLog WebClientInfoProvider = webClientInfoProvider; } - public override async Task CreateAsync() + protected override async Task CreateAsync() { var securityLogInfo = await base.CreateAsync(); diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs index 0f5d40567c..fcc03965f2 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; @@ -18,17 +19,19 @@ namespace Volo.Abp.SecurityLog SecurityLogOptions = securityLogOptions.Value; } - public virtual Task CreateAsync() + public async Task SaveAsync(Action saveAction) + { + var securityLogInfo = await CreateAsync(); + saveAction?.Invoke(securityLogInfo); + await SecurityLogStore.SaveAsync(securityLogInfo); + } + + protected virtual Task CreateAsync() { return Task.FromResult(new SecurityLogInfo { ApplicationName = SecurityLogOptions.ApplicationName }); } - - public async Task SaveAsync(SecurityLogInfo securityLogInfo) - { - await SecurityLogStore.SaveAsync(securityLogInfo); - } } } diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs index f762522509..0bedfd0411 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs @@ -1,11 +1,10 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; namespace Volo.Abp.SecurityLog { public interface ISecurityLogManager { - Task CreateAsync(); - - Task SaveAsync(SecurityLogInfo securityLogInfo); + Task SaveAsync(Action saveAction); } } diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs index 11f46c7527..6185777b97 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs @@ -35,8 +35,6 @@ namespace Volo.Abp.SecurityLog public string ClientId { get; set; } - public string ClientName { get; set; } - public string CorrelationId { get; set; } public string ClientIpAddress { get; set; } diff --git a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs index af157ed629..0d90972792 100644 --- a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs +++ b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs @@ -14,6 +14,8 @@ using System.Security.Principal; using System.Threading.Tasks; using Volo.Abp.Account.Settings; using Volo.Abp.DependencyInjection; +using Volo.Abp.Identity; +using Volo.Abp.Identity.AspNetCore; using Volo.Abp.MultiTenancy; using Volo.Abp.SecurityLog; using Volo.Abp.Settings; @@ -128,7 +130,12 @@ namespace Volo.Abp.Account.Web.Pages.Account true ); - await CreateSecurityLog("Login_" + result); + await LocalEventBus.PublishAsync(new SecurityLogEvent + { + Identity = IdentitySecurityLogIdentityConsts.Identity, + Action = result.ToIdentitySecurityLogAction(), + UserName = LoginInput.UserNameOrEmailAddress + }); if (result.RequiresTwoFactor) { diff --git a/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs b/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs index 38e8e7e7c2..69b57a42f4 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs @@ -6,7 +6,9 @@ using Volo.Abp.Account.Localization; using Volo.Abp.Account.Settings; using Volo.Abp.Account.Web.Areas.Account.Controllers.Models; using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.EventBus.Local; using Volo.Abp.Identity; +using Volo.Abp.Identity.AspNetCore; using Volo.Abp.SecurityLog; using Volo.Abp.Settings; using Volo.Abp.Validation; @@ -26,20 +28,22 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers protected SignInManager SignInManager { get; } protected IdentityUserManager UserManager { get; } protected ISettingProvider SettingProvider { get; } - protected ISecurityLogManager SecurityLogManager { get; } + + protected ILocalEventBus LocalEventBus { get; } public AccountController( SignInManager signInManager, IdentityUserManager userManager, ISettingProvider settingProvider, - ISecurityLogManager securityLogManager) + ISecurityLogManager securityLogManager, + ILocalEventBus localEventBus) { LocalizationResource = typeof(AccountResource); SignInManager = signInManager; UserManager = userManager; SettingProvider = settingProvider; - SecurityLogManager = securityLogManager; + LocalEventBus = localEventBus; } [HttpPost] @@ -51,23 +55,33 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers ValidateLoginInfo(login); await ReplaceEmailToUsernameOfInputIfNeeds(login); - var loginResult = GetAbpLoginResult(await SignInManager.PasswordSignInAsync( + var signInResult = await SignInManager.PasswordSignInAsync( login.UserNameOrEmailAddress, login.Password, login.RememberMe, true - )); + ); - await CreateSecurityLog("Login_" + loginResult.Result); + await LocalEventBus.PublishAsync(new SecurityLogEvent + { + Identity = IdentitySecurityLogIdentityConsts.Identity, + Action = signInResult.ToIdentitySecurityLogAction(), + UserName = login.UserNameOrEmailAddress + }); - return loginResult; + return GetAbpLoginResult(signInResult); } [HttpGet] [Route("logout")] public virtual async Task Logout() { - await CreateSecurityLog("Logout"); + await LocalEventBus.PublishAsync(new SecurityLogEvent + { + Identity = IdentitySecurityLogIdentityConsts.Identity, + Action = IdentitySecurityLogActionConsts.Logout + }); + await SignInManager.SignOutAsync(); } @@ -133,7 +147,7 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers return new AbpLoginResult(LoginResultType.InvalidUserNameOrPassword); } - return new AbpLoginResult(LoginResultType.Success); + return new AbpLoginResult(LoginResultType.Succeeded); } protected virtual void ValidateLoginInfo(UserLoginInfo login) @@ -161,13 +175,5 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers throw new UserFriendlyException(L["LocalLoginDisabledMessage"]); } } - - protected virtual async Task CreateSecurityLog(string action) - { - var securityLog = await SecurityLogManager.CreateAsync(); - securityLog.Identity = "Web"; - securityLog.Action = action; - await SecurityLogManager.SaveAsync(securityLog); - } } } diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/AccountPageModel.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/AccountPageModel.cs index d7fd0f8239..e645c9c9cf 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/AccountPageModel.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/AccountPageModel.cs @@ -1,14 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Volo.Abp.Account.Localization; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; +using Volo.Abp.EventBus.Local; using Volo.Abp.Identity; -using Volo.Abp.SecurityLog; using IdentityUser = Volo.Abp.Identity.IdentityUser; namespace Volo.Abp.Account.Web.Pages.Account @@ -17,7 +15,7 @@ namespace Volo.Abp.Account.Web.Pages.Account { public SignInManager SignInManager { get; set; } public IdentityUserManager UserManager { get; set; } - public ISecurityLogManager SecurityLogManager { get; } + public ILocalEventBus LocalEventBus { get; set; } protected AccountPageModel() { @@ -79,13 +77,5 @@ namespace Volo.Abp.Account.Web.Pages.Account { return "~/"; //TODO: ??? } - - protected virtual async Task CreateSecurityLog(string action) - { - var securityLog = await SecurityLogManager.CreateAsync(); - securityLog.Identity = "Web"; - securityLog.Action = action; - await SecurityLogManager.SaveAsync(securityLog); - } } } diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs index 2916e60b4f..06903ad44f 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs @@ -13,11 +13,12 @@ using System.Threading.Tasks; using Volo.Abp.Account.Settings; using Volo.Abp.Auditing; using Volo.Abp.Identity; +using Volo.Abp.Identity.AspNetCore; using Volo.Abp.Security.Claims; -using Volo.Abp.SecurityLog; using Volo.Abp.Settings; using Volo.Abp.Validation; using IdentityUser = Volo.Abp.Identity.IdentityUser; +using SignInResult = Microsoft.AspNetCore.Identity.SignInResult; namespace Volo.Abp.Account.Web.Pages.Account { @@ -95,7 +96,12 @@ namespace Volo.Abp.Account.Web.Pages.Account true ); - await CreateSecurityLog(result.ToString()); + await LocalEventBus.PublishAsync(new SecurityLogEvent + { + Identity = IdentitySecurityLogIdentityConsts.Identity, + Action = result.ToIdentitySecurityLogAction(), + UserName = LoginInput.UserNameOrEmailAddress + }); if (result.RequiresTwoFactor) { @@ -184,7 +190,14 @@ namespace Volo.Abp.Account.Web.Pages.Account bypassTwoFactor: true ); - await CreateSecurityLog(result.ToString()); + if (!result.Succeeded) + { + await LocalEventBus.PublishAsync(new SecurityLogEvent + { + Identity = IdentitySecurityLogIdentityConsts.IdentityExternal, + Action = "Login" + result + }); + } if (result.IsLockedOut) { @@ -208,6 +221,15 @@ namespace Volo.Abp.Account.Web.Pages.Account var user = await CreateExternalUserAsync(info); await SignInManager.SignInAsync(user, false); + + await LocalEventBus.PublishAsync(new SecurityLogEvent + { + Identity = IdentitySecurityLogIdentityConsts.IdentityExternal, + Action = result.ToIdentitySecurityLogAction(), + UserName = user.Name, + TenantId = user.TenantId + }); + return RedirectSafely(returnUrl, returnUrlHash); } diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs index 8cb2c2bc1e..a9d4ed9a53 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; +using Volo.Abp.Identity; namespace Volo.Abp.Account.Web.Pages.Account { @@ -15,6 +16,12 @@ namespace Volo.Abp.Account.Web.Pages.Account public virtual async Task OnGetAsync() { + await LocalEventBus.PublishAsync(new SecurityLogEvent + { + Identity = IdentitySecurityLogIdentityConsts.Identity, + Action = IdentitySecurityLogActionConsts.Logout + }); + await SignInManager.SignOutAsync(); if (ReturnUrl != null) { diff --git a/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/SignInResultExtensions.cs b/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/SignInResultExtensions.cs new file mode 100644 index 0000000000..39e3ae92fc --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/SignInResultExtensions.cs @@ -0,0 +1,37 @@ +using Microsoft.AspNetCore.Identity; + +namespace Volo.Abp.Identity.AspNetCore +{ + public static class SignInResultExtensions + { + public static string ToIdentitySecurityLogAction(this SignInResult result) + { + if (result.Succeeded) + { + return IdentitySecurityLogActionConsts.LoginSucceeded; + } + + if (result.IsLockedOut) + { + return IdentitySecurityLogActionConsts.LoginLockedout; + } + + if (result.RequiresTwoFactor) + { + return IdentitySecurityLogActionConsts.LoginRequiresTwoFactor; + } + + if (result.IsNotAllowed) + { + return IdentitySecurityLogActionConsts.LoginNotAllowed; + } + + if (!result.Succeeded) + { + return IdentitySecurityLogActionConsts.LoginFailed; + } + + return IdentitySecurityLogActionConsts.LoginFailed; + } + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogActionConsts.cs b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogActionConsts.cs new file mode 100644 index 0000000000..ea5276e673 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogActionConsts.cs @@ -0,0 +1,33 @@ +namespace Volo.Abp.Identity +{ + public class IdentitySecurityLogActionConsts + { + public static string LoginSucceeded { get; set; } = "LoginSucceeded"; + + public static string LoginLockedout { get; set; } = "LoginLockedout"; + + public static string LoginNotAllowed { get; set; } = "LoginNotAllowed"; + + public static string LoginRequiresTwoFactor { get; set; } = "LoginRequiresTwoFactor"; + + public static string LoginFailed { get; set; } = "LoginFailed"; + + public static string LoginInvalidUserName { get; set; } = "LoginInvalidUserName"; + + public static string LoginInvalidUserNameOrPassword { get; set; } = "LoginInvalidUserNameOrPassword"; + + public static string Logout { get; set; } = "Logout"; + + public static string ChangeUserName { get; set; } = "ChangeUserName"; + + public static string ChangeEmail { get; set; } = "ChangeEmail"; + + public static string ChangePhoneNumber { get; set; } = "ChangePhoneNumber"; + + public static string ChangePassword { get; set; } = "ChangePassword"; + + public static string TwoFactorEnabled { get; set; } = "TwoFactorEnabled"; + + public static string TwoFactorDisabled { get; set; } = "TwoFactorDisabled"; + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogIdentityConsts.cs b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogIdentityConsts.cs new file mode 100644 index 0000000000..5616dfb4e6 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogIdentityConsts.cs @@ -0,0 +1,11 @@ +namespace Volo.Abp.Identity +{ + public static class IdentitySecurityLogIdentityConsts + { + public static string Identity { get; set; } = "Identity"; + + public static string IdentityExternal { get; set; } = "IdentityExternal"; + + public static string IdentityTwoFactor { get; set; } = "IdentityTwoFactor"; + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/AbpIdentityResultExtensions.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/AbpIdentityResultExtensions.cs index 58349e8b69..0ef3582af1 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/AbpIdentityResultExtensions.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/AbpIdentityResultExtensions.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Globalization; using Microsoft.Extensions.Localization; using Volo.Abp.Identity; +using Volo.Abp.Localization; using Volo.Abp.Text.Formatting; namespace Microsoft.AspNetCore.Identity @@ -48,12 +49,15 @@ namespace Microsoft.AspNetCore.Identity if (!localizedString.ResourceNotFound) { - var englishLocalizedString = localizer.WithCulture(CultureInfo.GetCultureInfo("en"))[key]; - if (!englishLocalizedString.ResourceNotFound) + using (CultureHelper.Use(CultureInfo.GetCultureInfo("en"))) { - if (FormattedStringValueExtracter.IsMatch(error.Description, englishLocalizedString.Value, out var values)) + var englishLocalizedString = localizer[key]; + if (!englishLocalizedString.ResourceNotFound) { - return string.Format(localizedString.Value, values.Cast().ToArray()); + if (FormattedStringValueExtracter.IsMatch(error.Description, englishLocalizedString.Value, out var values)) + { + return string.Format(localizedString.Value, values.Cast().ToArray()); + } } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogEvent.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogEvent.cs new file mode 100644 index 0000000000..d8857d02d9 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogEvent.cs @@ -0,0 +1,18 @@ +using System; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.Identity +{ + public class SecurityLogEvent : IMultiTenant + { + public Guid? TenantId { get; set; } + + public string Identity { get; set; } + + public string Action { get; set; } + + public string UserName { get; set; } + + public string ClientId { get; set; } + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogHandler.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogHandler.cs new file mode 100644 index 0000000000..43321668b1 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogHandler.cs @@ -0,0 +1,85 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Volo.Abp.DependencyInjection; +using Volo.Abp.EventBus; +using Volo.Abp.Security.Claims; +using Volo.Abp.SecurityLog; +using Volo.Abp.Uow; +using Volo.Abp.Users; + +namespace Volo.Abp.Identity +{ + public class SecurityLogHandler : ILocalEventHandler, ITransientDependency + { + protected ISecurityLogManager SecurityLogManager { get; } + protected IdentityUserManager UserManager { get; } + protected ICurrentPrincipalAccessor CurrentPrincipalAccessor { get; } + protected IUserClaimsPrincipalFactory UserClaimsPrincipalFactory { get; } + protected ICurrentUser CurrentUser { get; } + protected IUnitOfWorkManager UnitOfWorkManager { get; } + + public SecurityLogHandler( + ISecurityLogManager securityLogManager, + IdentityUserManager userManager, + ICurrentPrincipalAccessor currentPrincipalAccessor, + IUserClaimsPrincipalFactory userClaimsPrincipalFactory, + ICurrentUser currentUser, + IUnitOfWorkManager unitOfWorkManager) + { + SecurityLogManager = securityLogManager; + UserManager = userManager; + CurrentPrincipalAccessor = currentPrincipalAccessor; + UserClaimsPrincipalFactory = userClaimsPrincipalFactory; + CurrentUser = currentUser; + UnitOfWorkManager = unitOfWorkManager; + } + + public async Task HandleEventAsync(SecurityLogEvent eventData) + { + Action securityLogAction = securityLog => + { + securityLog.Identity = eventData.Identity; + securityLog.Action = eventData.Action; + + if (securityLog.UserName.IsNullOrWhiteSpace()) + { + securityLog.UserName = eventData.UserName; + } + + if (securityLog.ClientId.IsNullOrWhiteSpace()) + { + securityLog.ClientId = eventData.ClientId; + } + }; + + using (var uow = UnitOfWorkManager.Begin(requiresNew: true)) + { + if (CurrentUser.IsAuthenticated) + { + await SecurityLogManager.SaveAsync(securityLogAction); + } + else + { + if (eventData.UserName.IsNullOrWhiteSpace()) + { + await SecurityLogManager.SaveAsync(securityLogAction); + } + else + { + var user = await UserManager.FindByNameAsync(eventData.UserName); + if (user != null) + { + using (CurrentPrincipalAccessor.Change(await UserClaimsPrincipalFactory.CreateAsync(user))) + { + await SecurityLogManager.SaveAsync(securityLogAction); + } + } + } + } + + await uow.CompleteAsync(); + } + } + } +} From 0466207a6d6545a51953a7b47d8270546c51c8f9 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Thu, 9 Jul 2020 14:08:53 +0800 Subject: [PATCH 4/9] Implement security log in Identity module. --- .../SecurityLog/DefaultSecurityLogManager.cs | 2 +- .../Abp/SecurityLog/ISecurityLogManager.cs | 2 +- .../Volo/Abp/SecurityLog/SecurityLogInfo.cs | 2 +- .../Abp/Security/AbpSecurityTestModule.cs | 9 +- .../SecurityLog/SecurityLogManager_Tests.cs | 45 +++++++++ .../IdentityServerSupportedLoginModel.cs | 2 +- .../IdentityServerSupportedLogoutModel.cs | 7 ++ .../Account/Controllers/AccountController.cs | 6 +- .../Pages/Account/Login.cshtml.cs | 6 +- .../Pages/Account/Logout.cshtml.cs | 2 +- .../Abp/Identity/IdentitySecurityLogConsts.cs | 52 ++++++++++ .../IIdentitySecurityLogRepository.cs | 37 +++++++ .../Volo/Abp/Identity/IdentitySecurityLog.cs | 64 ++++++++++++ ...ogEvent.cs => IdentitySecurityLogEvent.cs} | 2 +- ...ndler.cs => IdentitySecurityLogHandler.cs} | 38 ++++--- .../Abp/Identity/IdentitySecurityLogStore.cs | 44 +++++++++ .../EFCoreIdentitySecurityLogRepository.cs | 98 ++++++++++++++++++ .../EntityFrameworkCore/IIdentityDbContext.cs | 3 + .../EntityFrameworkCore/IdentityDbContext.cs | 4 +- ...IdentityDbContextModelBuilderExtensions.cs | 28 +++++- .../MongoDB/AbpIdentityMongoDbContext.cs | 4 +- .../AbpIdentityMongoDbContextExtensions.cs | 7 +- .../MongoDB/AbpIdentityMongoDbModule.cs | 1 + .../MongoDB/IAbpIdentityMongoDbContext.cs | 4 +- .../MongoIdentitySecurityLogRepository.cs | 99 +++++++++++++++++++ .../IdentitySecurityLogRepository_Tests.cs | 7 ++ .../IdentitySecurityLogRepository_Tests.cs | 10 ++ .../Identity/AbpIdentityTestDataBuilder.cs | 36 ++++++- .../IdentitySecurityLogRepository_Tests.cs | 36 +++++++ 29 files changed, 615 insertions(+), 42 deletions(-) create mode 100644 framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/SecurityLog/SecurityLogManager_Tests.cs create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogConsts.cs create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentitySecurityLogRepository.cs create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLog.cs rename modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/{SecurityLogEvent.cs => IdentitySecurityLogEvent.cs} (84%) rename modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/{SecurityLogHandler.cs => IdentitySecurityLogHandler.cs} (67%) create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogStore.cs create mode 100644 modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EFCoreIdentitySecurityLogRepository.cs create mode 100644 modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySecurityLogRepository.cs create mode 100644 modules/identity/test/Volo.Abp.Identity.EntityFrameworkCore.Tests/Volo/Abp/Identity/EntityFrameworkCore/IdentitySecurityLogRepository_Tests.cs create mode 100644 modules/identity/test/Volo.Abp.Identity.MongoDB.Tests/Volo/Abp/Identity/MongoDB/IdentitySecurityLogRepository_Tests.cs create mode 100644 modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentitySecurityLogRepository_Tests.cs diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs index fcc03965f2..ab260ff708 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs @@ -19,7 +19,7 @@ namespace Volo.Abp.SecurityLog SecurityLogOptions = securityLogOptions.Value; } - public async Task SaveAsync(Action saveAction) + public async Task SaveAsync(Action saveAction = null) { var securityLogInfo = await CreateAsync(); saveAction?.Invoke(securityLogInfo); diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs index 0bedfd0411..f368489fb0 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/ISecurityLogManager.cs @@ -5,6 +5,6 @@ namespace Volo.Abp.SecurityLog { public interface ISecurityLogManager { - Task SaveAsync(Action saveAction); + Task SaveAsync(Action saveAction = null); } } diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs index 6185777b97..e40b877fcf 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs @@ -5,7 +5,7 @@ using Volo.Abp.Data; namespace Volo.Abp.SecurityLog { [Serializable] - public class SecurityLogInfo : IHasExtraProperties + public class SecurityLogInfo { /// /// The name of the application or service writing user security logs. diff --git a/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/AbpSecurityTestModule.cs b/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/AbpSecurityTestModule.cs index b71a0a214a..a1ce5c56aa 100644 --- a/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/AbpSecurityTestModule.cs +++ b/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/AbpSecurityTestModule.cs @@ -1,4 +1,5 @@ using Volo.Abp.Modularity; +using Volo.Abp.SecurityLog; namespace Volo.Abp.Security { @@ -8,6 +9,12 @@ namespace Volo.Abp.Security )] public class AbpSecurityTestModule : AbpModule { - + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(x => + { + x.ApplicationName = "AbpSecurityTest"; + }); + } } } diff --git a/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/SecurityLog/SecurityLogManager_Tests.cs b/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/SecurityLog/SecurityLogManager_Tests.cs new file mode 100644 index 0000000000..94fb6bccda --- /dev/null +++ b/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/SecurityLog/SecurityLogManager_Tests.cs @@ -0,0 +1,45 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using NSubstitute; +using Volo.Abp.SecurityLog; +using Volo.Abp.Testing; +using Xunit; + +namespace Volo.Abp.Security.SecurityLog +{ + + public class SecurityLogManager_Tests : AbpIntegratedTest + { + private readonly ISecurityLogManager _securityLogManager; + + private ISecurityLogStore _auditingStore; + + public SecurityLogManager_Tests() + { + _securityLogManager = GetRequiredService(); + } + + protected override void AfterAddApplication(IServiceCollection services) + { + _auditingStore = Substitute.For(); + services.AddSingleton(_auditingStore); + } + + [Fact] + public async Task SaveAsync() + { + await _securityLogManager.SaveAsync(securityLog => + { + securityLog.Identity = "Test"; + securityLog.Action = "Test-Action"; + securityLog.UserName = "Test-User"; + }); + + await _auditingStore.Received().SaveAsync(Arg.Is(log => + log.ApplicationName == "AbpSecurityTest" && + log.Identity == "Test" && + log.Action == "Test-Action" && + log.UserName == "Test-User")); + } + } +} diff --git a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs index 0d90972792..d26e64181d 100644 --- a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs +++ b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs @@ -130,7 +130,7 @@ namespace Volo.Abp.Account.Web.Pages.Account true ); - await LocalEventBus.PublishAsync(new SecurityLogEvent + await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent { Identity = IdentitySecurityLogIdentityConsts.Identity, Action = result.ToIdentitySecurityLogAction(), diff --git a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLogoutModel.cs b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLogoutModel.cs index 43857cc111..b25b34799d 100644 --- a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLogoutModel.cs +++ b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLogoutModel.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Mvc; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Volo.Abp.DependencyInjection; +using Volo.Abp.Identity; namespace Volo.Abp.Account.Web.Pages.Account { @@ -19,6 +20,12 @@ namespace Volo.Abp.Account.Web.Pages.Account public override async Task OnGetAsync() { + await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent + { + Identity = IdentitySecurityLogIdentityConsts.Identity, + Action = IdentitySecurityLogActionConsts.Logout + }); + await SignInManager.SignOutAsync(); var logoutId = Request.Query["logoutId"].ToString(); diff --git a/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs b/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs index 69b57a42f4..aa22882701 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs @@ -62,7 +62,7 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers true ); - await LocalEventBus.PublishAsync(new SecurityLogEvent + await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent { Identity = IdentitySecurityLogIdentityConsts.Identity, Action = signInResult.ToIdentitySecurityLogAction(), @@ -76,7 +76,7 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers [Route("logout")] public virtual async Task Logout() { - await LocalEventBus.PublishAsync(new SecurityLogEvent + await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent { Identity = IdentitySecurityLogIdentityConsts.Identity, Action = IdentitySecurityLogActionConsts.Logout @@ -147,7 +147,7 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers return new AbpLoginResult(LoginResultType.InvalidUserNameOrPassword); } - return new AbpLoginResult(LoginResultType.Succeeded); + return new AbpLoginResult(LoginResultType.Success); } protected virtual void ValidateLoginInfo(UserLoginInfo login) diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs index 06903ad44f..8dc2ef3273 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs @@ -96,7 +96,7 @@ namespace Volo.Abp.Account.Web.Pages.Account true ); - await LocalEventBus.PublishAsync(new SecurityLogEvent + await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent { Identity = IdentitySecurityLogIdentityConsts.Identity, Action = result.ToIdentitySecurityLogAction(), @@ -192,7 +192,7 @@ namespace Volo.Abp.Account.Web.Pages.Account if (!result.Succeeded) { - await LocalEventBus.PublishAsync(new SecurityLogEvent + await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent { Identity = IdentitySecurityLogIdentityConsts.IdentityExternal, Action = "Login" + result @@ -222,7 +222,7 @@ namespace Volo.Abp.Account.Web.Pages.Account await SignInManager.SignInAsync(user, false); - await LocalEventBus.PublishAsync(new SecurityLogEvent + await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent { Identity = IdentitySecurityLogIdentityConsts.IdentityExternal, Action = result.ToIdentitySecurityLogAction(), diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs index a9d4ed9a53..fe7361e4ce 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs @@ -16,7 +16,7 @@ namespace Volo.Abp.Account.Web.Pages.Account public virtual async Task OnGetAsync() { - await LocalEventBus.PublishAsync(new SecurityLogEvent + await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent { Identity = IdentitySecurityLogIdentityConsts.Identity, Action = IdentitySecurityLogActionConsts.Logout diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogConsts.cs b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogConsts.cs new file mode 100644 index 0000000000..43b2dd25fb --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentitySecurityLogConsts.cs @@ -0,0 +1,52 @@ +namespace Volo.Abp.Identity +{ + public class IdentitySecurityLogConsts + { + /// + /// Default value: 96 + /// + public static int MaxApplicationNameLength { get; set; } = 96; + + /// + /// Default value: 96 + /// + public static int MaxIdentityLength { get; set; } = 96; + + /// + /// Default value: 96 + /// + public static int MaxActionLength { get; set; } = 96; + + + /// + /// Default value: 256 + /// + public static int MaxUserNameLength { get; set; } = 256; + + /// + /// Default value: 64 + /// + public static int MaxTenantNameLength { get; set; } = 64; + + /// + /// Default value: 64 + /// + public static int MaxClientIpAddressLength { get; set; } = 64; + + /// + /// Default value: 64 + /// + public static int MaxClientIdLength { get; set; } = 64; + + /// + /// Default value: 64 + /// + public static int MaxCorrelationIdLength { get; set; } = 64; + + /// + /// Default value: 512 + /// + public static int MaxBrowserInfoLength { get; set; } = 512; + + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentitySecurityLogRepository.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentitySecurityLogRepository.cs new file mode 100644 index 0000000000..8732355c14 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentitySecurityLogRepository.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; + +namespace Volo.Abp.Identity +{ + public interface IIdentitySecurityLogRepository : IBasicRepository + { + Task> GetListAsync( + string sorting = null, + int maxResultCount = 50, + int skipCount = 0, + DateTime? startTime = null, + DateTime? endTime = null, + string applicationName = null, + string identity = null, + string action = null, + string userName = null, + string clientId = null, + string correlationId = null, + bool includeDetails = false, + CancellationToken cancellationToken = default); + + Task GetCountAsync( + DateTime? startTime = null, + DateTime? endTime = null, + string applicationName = null, + string identity = null, + string action = null, + string userName = null, + string clientId = null, + string correlationId = null, + CancellationToken cancellationToken = default); + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLog.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLog.cs new file mode 100644 index 0000000000..b720f667f0 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLog.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Guids; +using Volo.Abp.MultiTenancy; +using Volo.Abp.SecurityLog; + +namespace Volo.Abp.Identity +{ + public class IdentitySecurityLog : AggregateRoot, IMultiTenant + { + public Guid? TenantId { get; protected set; } + + public string ApplicationName { get; protected set; } + + public string Identity { get; protected set; } + + public string Action { get; protected set; } + + public Guid? UserId { get; protected set; } + + public string UserName { get; protected set; } + + public string TenantName { get; protected set; } + + public string ClientId { get; protected set; } + + public string CorrelationId { get; protected set; } + + public string ClientIpAddress { get; protected set; } + + public string BrowserInfo { get; protected set; } + + public DateTime CreationTime { get; protected set; } + + protected IdentitySecurityLog() + { + ExtraProperties = new Dictionary(); + } + + public IdentitySecurityLog(IGuidGenerator guidGenerator, SecurityLogInfo securityLogInfo) + { + Id = guidGenerator.Create(); + TenantId = securityLogInfo.TenantId; + TenantName = securityLogInfo.TenantName.Truncate(IdentitySecurityLogConsts.MaxTenantNameLength); + + ApplicationName = securityLogInfo.ApplicationName.Truncate(IdentitySecurityLogConsts.MaxApplicationNameLength); + Identity = securityLogInfo.Identity.Truncate(IdentitySecurityLogConsts.MaxIdentityLength); + Action = securityLogInfo.Action.Truncate(IdentitySecurityLogConsts.MaxActionLength); + + UserId = securityLogInfo.UserId; + UserName = securityLogInfo.UserName.Truncate(IdentitySecurityLogConsts.MaxUserNameLength); + + CreationTime = securityLogInfo.CreationTime; + + ClientIpAddress = securityLogInfo.ClientIpAddress.Truncate(IdentitySecurityLogConsts.MaxClientIpAddressLength); + ClientId = securityLogInfo.ClientId.Truncate(IdentitySecurityLogConsts.MaxClientIdLength); + CorrelationId = securityLogInfo.CorrelationId.Truncate(IdentitySecurityLogConsts.MaxCorrelationIdLength); + BrowserInfo = securityLogInfo.BrowserInfo.Truncate(IdentitySecurityLogConsts.MaxBrowserInfoLength); + + ExtraProperties = securityLogInfo.ExtraProperties; + } + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogEvent.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogEvent.cs similarity index 84% rename from modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogEvent.cs rename to modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogEvent.cs index d8857d02d9..93296619f6 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogEvent.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogEvent.cs @@ -3,7 +3,7 @@ using Volo.Abp.MultiTenancy; namespace Volo.Abp.Identity { - public class SecurityLogEvent : IMultiTenant + public class IdentitySecurityLogEvent : IMultiTenant { public Guid? TenantId { get; set; } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogHandler.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogHandler.cs similarity index 67% rename from modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogHandler.cs rename to modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogHandler.cs index 43321668b1..4e0c46b2f7 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/SecurityLogHandler.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogHandler.cs @@ -10,32 +10,29 @@ using Volo.Abp.Users; namespace Volo.Abp.Identity { - public class SecurityLogHandler : ILocalEventHandler, ITransientDependency + public class IdentitySecurityLogHandler : ILocalEventHandler, ITransientDependency { protected ISecurityLogManager SecurityLogManager { get; } protected IdentityUserManager UserManager { get; } protected ICurrentPrincipalAccessor CurrentPrincipalAccessor { get; } protected IUserClaimsPrincipalFactory UserClaimsPrincipalFactory { get; } protected ICurrentUser CurrentUser { get; } - protected IUnitOfWorkManager UnitOfWorkManager { get; } - public SecurityLogHandler( + public IdentitySecurityLogHandler( ISecurityLogManager securityLogManager, IdentityUserManager userManager, ICurrentPrincipalAccessor currentPrincipalAccessor, IUserClaimsPrincipalFactory userClaimsPrincipalFactory, - ICurrentUser currentUser, - IUnitOfWorkManager unitOfWorkManager) + ICurrentUser currentUser) { SecurityLogManager = securityLogManager; UserManager = userManager; CurrentPrincipalAccessor = currentPrincipalAccessor; UserClaimsPrincipalFactory = userClaimsPrincipalFactory; CurrentUser = currentUser; - UnitOfWorkManager = unitOfWorkManager; } - public async Task HandleEventAsync(SecurityLogEvent eventData) + public async Task HandleEventAsync(IdentitySecurityLogEvent eventData) { Action securityLogAction = securityLog => { @@ -53,32 +50,31 @@ namespace Volo.Abp.Identity } }; - using (var uow = UnitOfWorkManager.Begin(requiresNew: true)) + if (CurrentUser.IsAuthenticated) { - if (CurrentUser.IsAuthenticated) + await SecurityLogManager.SaveAsync(securityLogAction); + } + else + { + if (eventData.UserName.IsNullOrWhiteSpace()) { await SecurityLogManager.SaveAsync(securityLogAction); } else { - if (eventData.UserName.IsNullOrWhiteSpace()) + var user = await UserManager.FindByNameAsync(eventData.UserName); + if (user != null) { - await SecurityLogManager.SaveAsync(securityLogAction); + using (CurrentPrincipalAccessor.Change(await UserClaimsPrincipalFactory.CreateAsync(user))) + { + await SecurityLogManager.SaveAsync(securityLogAction); + } } else { - var user = await UserManager.FindByNameAsync(eventData.UserName); - if (user != null) - { - using (CurrentPrincipalAccessor.Change(await UserClaimsPrincipalFactory.CreateAsync(user))) - { - await SecurityLogManager.SaveAsync(securityLogAction); - } - } + await SecurityLogManager.SaveAsync(securityLogAction); } } - - await uow.CompleteAsync(); } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogStore.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogStore.cs new file mode 100644 index 0000000000..696fc3ad6a --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogStore.cs @@ -0,0 +1,44 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Guids; +using Volo.Abp.SecurityLog; +using Volo.Abp.Uow; + +namespace Volo.Abp.Identity +{ + [Dependency(ReplaceServices = true)] + public class IdentitySecurityLogStore : ISecurityLogStore, ITransientDependency + { + public ILogger Logger { get; set; } + + protected AbpSecurityLogOptions SecurityLogOptions { get; } + protected IIdentitySecurityLogRepository IdentitySecurityLogRepository { get; } + protected IGuidGenerator GuidGenerator { get; } + protected IUnitOfWorkManager UnitOfWorkManager { get; } + + public IdentitySecurityLogStore( + ILogger logger, + IOptions securityLogOptions, + IIdentitySecurityLogRepository identitySecurityLogRepository, + IGuidGenerator guidGenerator, + IUnitOfWorkManager unitOfWorkManager) + { + Logger = logger; + SecurityLogOptions = securityLogOptions.Value; + IdentitySecurityLogRepository = identitySecurityLogRepository; + GuidGenerator = guidGenerator; + UnitOfWorkManager = unitOfWorkManager; + } + + public async Task SaveAsync(SecurityLogInfo securityLogInfo) + { + using (var uow = UnitOfWorkManager.Begin(requiresNew: true)) + { + await IdentitySecurityLogRepository.InsertAsync(new IdentitySecurityLog(GuidGenerator, securityLogInfo)); + await uow.CompleteAsync(); + } + } + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EFCoreIdentitySecurityLogRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EFCoreIdentitySecurityLogRepository.cs new file mode 100644 index 0000000000..1801a49136 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EFCoreIdentitySecurityLogRepository.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +namespace Volo.Abp.Identity.EntityFrameworkCore +{ + public class EFCoreIdentitySecurityLogRepository : EfCoreRepository, IIdentitySecurityLogRepository + { + public EFCoreIdentitySecurityLogRepository(IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + + } + + public async Task> GetListAsync( + string sorting = null, + int maxResultCount = 50, + int skipCount = 0, + DateTime? startTime = null, + DateTime? endTime = null, + string applicationName = null, + string identity = null, + string action = null, + string userName = null, + string clientId = null, + string correlationId = null, + bool includeDetails = false, + CancellationToken cancellationToken = default) + { + var query = GetListQuery( + startTime, + endTime, + applicationName, + identity, + action, + userName, + clientId, + correlationId + ); + + return await query.OrderBy(sorting ?? nameof(IdentitySecurityLog.CreationTime) + " desc") + .PageBy(skipCount, maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + + public async Task GetCountAsync( + DateTime? startTime = null, + DateTime? endTime = null, + string applicationName = null, + string identity = null, + string action = null, + string userName = null, + string clientId = null, + string correlationId = null, + CancellationToken cancellationToken = default) + { + var query = GetListQuery( + startTime, + endTime, + applicationName, + identity, + action, + userName, + clientId, + correlationId + ); + + return await query.LongCountAsync(GetCancellationToken(cancellationToken)); + } + + protected virtual IQueryable GetListQuery( + DateTime? startTime = null, + DateTime? endTime = null, + string applicationName = null, + string identity = null, + string action = null, + string userName = null, + string clientId = null, + string correlationId = null) + { + return DbSet.AsNoTracking() + .WhereIf(startTime.HasValue, securityLog => securityLog.CreationTime >= startTime) + .WhereIf(endTime.HasValue, securityLog => securityLog.CreationTime >= endTime) + .WhereIf(!applicationName.IsNullOrWhiteSpace(), securityLog => securityLog.ApplicationName == applicationName) + .WhereIf(!identity.IsNullOrWhiteSpace(), securityLog => securityLog.Identity == identity) + .WhereIf(!action.IsNullOrWhiteSpace(), securityLog => securityLog.Action == action) + .WhereIf(!userName.IsNullOrWhiteSpace(), securityLog => securityLog.UserName == userName) + .WhereIf(!clientId.IsNullOrWhiteSpace(), securityLog => securityLog.ClientId == clientId) + .WhereIf(!correlationId.IsNullOrWhiteSpace(), securityLog => securityLog.CorrelationId == correlationId); + } + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IIdentityDbContext.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IIdentityDbContext.cs index f27c9b534a..48da4daf87 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IIdentityDbContext.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IIdentityDbContext.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.SecurityLog; namespace Volo.Abp.Identity.EntityFrameworkCore { @@ -14,5 +15,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore DbSet ClaimTypes { get; set; } DbSet OrganizationUnits { get; set; } + + DbSet IdentitySecurityLogs { get; set; } } } diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContext.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContext.cs index 811280de7b..16679429b8 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContext.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContext.cs @@ -18,6 +18,8 @@ namespace Volo.Abp.Identity.EntityFrameworkCore public DbSet OrganizationUnits { get; set; } + public DbSet IdentitySecurityLogs { get; set; } + public IdentityDbContext(DbContextOptions options) : base(options) { @@ -31,4 +33,4 @@ namespace Volo.Abp.Identity.EntityFrameworkCore builder.ConfigureIdentity(); } } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs index 000a2a8f00..373abbe804 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs @@ -204,6 +204,32 @@ namespace Volo.Abp.Identity.EntityFrameworkCore b.HasIndex(ou => new {ou.UserId, ou.OrganizationUnitId}); }); + + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "SecurityLogs", options.Schema); + + b.ConfigureByConvention(); + + b.Property(x => x.TenantName).HasMaxLength(IdentitySecurityLogConsts.MaxTenantNameLength); + + b.Property(x => x.ApplicationName).HasMaxLength(IdentitySecurityLogConsts.MaxApplicationNameLength); + b.Property(x => x.Identity).HasMaxLength(IdentitySecurityLogConsts.MaxIdentityLength); + b.Property(x => x.Action).HasMaxLength(IdentitySecurityLogConsts.MaxActionLength); + + b.Property(x => x.UserName).HasMaxLength(IdentitySecurityLogConsts.MaxUserNameLength); + + b.Property(x => x.ClientIpAddress).HasMaxLength(IdentitySecurityLogConsts.MaxClientIpAddressLength); + b.Property(x => x.ClientId).HasMaxLength(IdentitySecurityLogConsts.MaxClientIdLength); + b.Property(x => x.CorrelationId).HasMaxLength(IdentitySecurityLogConsts.MaxCorrelationIdLength); + b.Property(x => x.BrowserInfo).HasMaxLength(IdentitySecurityLogConsts.MaxBrowserInfoLength); + + b.HasIndex(x => new { x.TenantId, x.ApplicationName }); + b.HasIndex(x => new { x.TenantId, x.Identity }); + b.HasIndex(x => new { x.TenantId, x.Action }); + b.HasIndex(x => new { x.TenantId, x.UserId }); + }); + } } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContext.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContext.cs index 3240ce1454..19c3316b88 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContext.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContext.cs @@ -15,6 +15,8 @@ namespace Volo.Abp.Identity.MongoDB public IMongoCollection OrganizationUnits => Collection(); + public IMongoCollection IdentitySecurityLogs => Collection(); + protected override void CreateModel(IMongoModelBuilder modelBuilder) { base.CreateModel(modelBuilder); @@ -22,4 +24,4 @@ namespace Volo.Abp.Identity.MongoDB modelBuilder.ConfigureIdentity(); } } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContextExtensions.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContextExtensions.cs index bc303e0eb5..89aeddeb92 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContextExtensions.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbContextExtensions.cs @@ -36,6 +36,11 @@ namespace Volo.Abp.Identity.MongoDB { b.CollectionName = options.CollectionPrefix + "OrganizationUnits"; }); + + builder.Entity(b => + { + b.CollectionName = options.CollectionPrefix + "SecurityLogs"; + }); } } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbModule.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbModule.cs index 268c718b12..3ceab94e23 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbModule.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/AbpIdentityMongoDbModule.cs @@ -18,6 +18,7 @@ namespace Volo.Abp.Identity.MongoDB options.AddRepository(); options.AddRepository(); options.AddRepository(); + options.AddRepository(); }); } } diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/IAbpIdentityMongoDbContext.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/IAbpIdentityMongoDbContext.cs index c903c5d96d..54819ffa19 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/IAbpIdentityMongoDbContext.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/IAbpIdentityMongoDbContext.cs @@ -14,5 +14,7 @@ namespace Volo.Abp.Identity.MongoDB IMongoCollection ClaimTypes { get; } IMongoCollection OrganizationUnits { get; } + + IMongoCollection IdentitySecurityLogs { get; } } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySecurityLogRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySecurityLogRepository.cs new file mode 100644 index 0000000000..5fccb0d2ab --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySecurityLogRepository.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Threading; +using System.Threading.Tasks; +using MongoDB.Driver; +using MongoDB.Driver.Linq; +using Volo.Abp.Domain.Repositories.MongoDB; +using Volo.Abp.MongoDB; + +namespace Volo.Abp.Identity.MongoDB +{ + public class MongoIdentitySecurityLogRepository : MongoDbRepository, IIdentitySecurityLogRepository + { + public MongoIdentitySecurityLogRepository(IMongoDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public async Task> GetListAsync( + string sorting = null, + int maxResultCount = 50, + int skipCount = 0, + DateTime? startTime = null, + DateTime? endTime = null, + string applicationName = null, + string identity = null, + string action = null, + string userName = null, + string clientId = null, + string correlationId = null, + bool includeDetails = false, + CancellationToken cancellationToken = default) + { + var query = GetListQuery( + startTime, + endTime, + applicationName, + identity, + action, + userName, + clientId, + correlationId + ); + + return await query.OrderBy(sorting ?? nameof(IdentitySecurityLog.CreationTime) + " desc") + .As>() + .PageBy>(skipCount, maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + + public async Task GetCountAsync( + DateTime? startTime = null, + DateTime? endTime = null, + string applicationName = null, + string identity = null, + string action = null, + string userName = null, + string clientId = null, + string correlationId = null, + CancellationToken cancellationToken = default) + { + var query = GetListQuery( + startTime, + endTime, + applicationName, + identity, + action, + userName, + clientId, + correlationId + ); + + return await query.As>().LongCountAsync(GetCancellationToken(cancellationToken)); + } + + protected virtual IQueryable GetListQuery( + DateTime? startTime = null, + DateTime? endTime = null, + string applicationName = null, + string identity = null, + string action = null, + string userName = null, + string clientId = null, + string correlationId = null) + { + return GetMongoQueryable() + .WhereIf(startTime.HasValue, securityLog => securityLog.CreationTime >= startTime) + .WhereIf(endTime.HasValue, securityLog => securityLog.CreationTime >= endTime) + .WhereIf(!applicationName.IsNullOrWhiteSpace(), securityLog => securityLog.ApplicationName == applicationName) + .WhereIf(!identity.IsNullOrWhiteSpace(), securityLog => securityLog.Identity == identity) + .WhereIf(!action.IsNullOrWhiteSpace(), securityLog => securityLog.Action == action) + .WhereIf(!userName.IsNullOrWhiteSpace(), securityLog => securityLog.UserName == userName) + .WhereIf(!clientId.IsNullOrWhiteSpace(), securityLog => securityLog.ClientId == clientId) + .WhereIf(!correlationId.IsNullOrWhiteSpace(), securityLog => securityLog.CorrelationId == correlationId); + } + } +} diff --git a/modules/identity/test/Volo.Abp.Identity.EntityFrameworkCore.Tests/Volo/Abp/Identity/EntityFrameworkCore/IdentitySecurityLogRepository_Tests.cs b/modules/identity/test/Volo.Abp.Identity.EntityFrameworkCore.Tests/Volo/Abp/Identity/EntityFrameworkCore/IdentitySecurityLogRepository_Tests.cs new file mode 100644 index 0000000000..434f74706d --- /dev/null +++ b/modules/identity/test/Volo.Abp.Identity.EntityFrameworkCore.Tests/Volo/Abp/Identity/EntityFrameworkCore/IdentitySecurityLogRepository_Tests.cs @@ -0,0 +1,7 @@ +namespace Volo.Abp.Identity.EntityFrameworkCore +{ + public class IdentitySecurityLogRepository_Tests : IdentitySecurityLogRepository_Tests + { + + } +} diff --git a/modules/identity/test/Volo.Abp.Identity.MongoDB.Tests/Volo/Abp/Identity/MongoDB/IdentitySecurityLogRepository_Tests.cs b/modules/identity/test/Volo.Abp.Identity.MongoDB.Tests/Volo/Abp/Identity/MongoDB/IdentitySecurityLogRepository_Tests.cs new file mode 100644 index 0000000000..85d496fdb2 --- /dev/null +++ b/modules/identity/test/Volo.Abp.Identity.MongoDB.Tests/Volo/Abp/Identity/MongoDB/IdentitySecurityLogRepository_Tests.cs @@ -0,0 +1,10 @@ +using Xunit; + +namespace Volo.Abp.Identity.MongoDB +{ + [Collection(MongoTestCollection.Name)] + public class IdentitySecurityLogRepository_Tests : IdentitySecurityLogRepository_Tests + { + + } +} diff --git a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestDataBuilder.cs b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestDataBuilder.cs index 9258be16af..79dd858c20 100644 --- a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestDataBuilder.cs +++ b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/AbpIdentityTestDataBuilder.cs @@ -1,9 +1,10 @@ -using System; +using System; using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; using Volo.Abp.DependencyInjection; using Volo.Abp.Guids; +using Volo.Abp.SecurityLog; namespace Volo.Abp.Identity { @@ -14,6 +15,7 @@ namespace Volo.Abp.Identity private readonly IIdentityClaimTypeRepository _identityClaimTypeRepository; private readonly IIdentityRoleRepository _roleRepository; private readonly IOrganizationUnitRepository _organizationUnitRepository; + private readonly IIdentitySecurityLogRepository _identitySecurityLogRepository; private readonly ILookupNormalizer _lookupNormalizer; private readonly IdentityTestData _testData; private readonly OrganizationUnitManager _organizationUnitManager; @@ -31,6 +33,7 @@ namespace Volo.Abp.Identity IIdentityClaimTypeRepository identityClaimTypeRepository, IIdentityRoleRepository roleRepository, IOrganizationUnitRepository organizationUnitRepository, + IIdentitySecurityLogRepository identitySecurityLogRepository, ILookupNormalizer lookupNormalizer, IdentityTestData testData, OrganizationUnitManager organizationUnitManager) @@ -43,6 +46,7 @@ namespace Volo.Abp.Identity _testData = testData; _organizationUnitRepository = organizationUnitRepository; _organizationUnitManager = organizationUnitManager; + _identitySecurityLogRepository = identitySecurityLogRepository; } public async Task Build() @@ -51,6 +55,7 @@ namespace Volo.Abp.Identity await AddOrganizationUnits(); await AddUsers(); await AddClaimTypes(); + await AddSecurityLogs(); } private async Task AddRoles() @@ -69,7 +74,7 @@ namespace Volo.Abp.Identity } /* Creates OU tree as shown below: - * + * * - OU1 * - OU11 * - OU111 @@ -138,5 +143,30 @@ namespace Volo.Abp.Identity var ou = await _organizationUnitRepository.InsertAsync(new OrganizationUnit(_guidGenerator.Create(), displayName, parentId) { Code = code }); return ou; } + + private async Task AddSecurityLogs() + { + await _identitySecurityLogRepository.InsertAsync(new IdentitySecurityLog(_guidGenerator, new SecurityLogInfo + { + ApplicationName = "Test-ApplicationName", + Identity = "Test-Identity", + Action = "Test-Action", + UserId = _testData.UserJohnId, + UserName = "john.nash", + + CreationTime = new DateTime(2020, 01, 01, 10, 0, 0) + })); + + await _identitySecurityLogRepository.InsertAsync(new IdentitySecurityLog(_guidGenerator, new SecurityLogInfo + { + ApplicationName = "Test-ApplicationName", + Identity = "Test-Identity", + Action = "Test-Action", + UserId = _testData.UserDavidId, + UserName = "david", + + CreationTime = new DateTime(2020, 01, 02, 10, 0, 0) + })); + } } -} \ No newline at end of file +} diff --git a/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentitySecurityLogRepository_Tests.cs b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentitySecurityLogRepository_Tests.cs new file mode 100644 index 0000000000..13ff8a06a3 --- /dev/null +++ b/modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentitySecurityLogRepository_Tests.cs @@ -0,0 +1,36 @@ +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.Modularity; +using Xunit; + +namespace Volo.Abp.Identity +{ + public abstract class IdentitySecurityLogRepository_Tests : AbpIdentityTestBase + where TStartupModule : IAbpModule + { + protected IIdentitySecurityLogRepository RoleRepository { get; } + protected IdentityTestData TestData { get; } + + protected IdentitySecurityLogRepository_Tests() + { + RoleRepository = GetRequiredService(); + TestData = GetRequiredService(); + } + + [Fact] + public async Task GetListAsync() + { + var logs = await RoleRepository.GetListAsync(); + logs.ShouldNotBeEmpty(); + logs.ShouldContain(x => x.ApplicationName == "Test-ApplicationName" && x.UserId == TestData.UserJohnId); + logs.ShouldContain(x => x.ApplicationName == "Test-ApplicationName" && x.UserId == TestData.UserDavidId); + } + + [Fact] + public async Task GetCountAsync() + { + var count = await RoleRepository.GetCountAsync(); + count.ShouldBe(2); + } + } +} From 0c97d90c7d6eb49a3bb73332e5e69da123463eed Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Thu, 9 Jul 2020 14:11:56 +0800 Subject: [PATCH 5/9] Update Volo.Abp.Security.csproj. --- framework/src/Volo.Abp.Security/Volo.Abp.Security.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/framework/src/Volo.Abp.Security/Volo.Abp.Security.csproj b/framework/src/Volo.Abp.Security/Volo.Abp.Security.csproj index 6ffaac1232..65aca85c88 100644 --- a/framework/src/Volo.Abp.Security/Volo.Abp.Security.csproj +++ b/framework/src/Volo.Abp.Security/Volo.Abp.Security.csproj @@ -16,7 +16,6 @@ - From a03ef9964151c6d455a8cf32a178dbf73fbc99c4 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Thu, 9 Jul 2020 14:20:04 +0800 Subject: [PATCH 6/9] Update SecurityLogInfo. --- .../Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs index e40b877fcf..c6e562f6c8 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using Volo.Abp.Data; namespace Volo.Abp.SecurityLog { From 787a09546ff7cd9f32225d6f20ebe98449fe1bd4 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Fri, 10 Jul 2020 13:50:53 +0800 Subject: [PATCH 7/9] Add filter for IIdentitySecurityLogRepository. --- .../Pages/Account/Login.cshtml.cs | 3 +- .../IIdentitySecurityLogRepository.cs | 8 +++ .../Abp/Identity/IdentitySecurityLogEvent.cs | 15 +++++ .../Identity/IdentitySecurityLogHandler.cs | 5 ++ .../EFCoreIdentitySecurityLogRepository.cs | 13 +++- .../MongoIdentitySecurityLogRepository.cs | 62 ++++++++++++------- 6 files changed, 81 insertions(+), 25 deletions(-) diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs index 8dc2ef3273..ca2125396c 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs @@ -226,8 +226,7 @@ namespace Volo.Abp.Account.Web.Pages.Account { Identity = IdentitySecurityLogIdentityConsts.IdentityExternal, Action = result.ToIdentitySecurityLogAction(), - UserName = user.Name, - TenantId = user.TenantId + UserName = user.Name }); return RedirectSafely(returnUrl, returnUrlHash); diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentitySecurityLogRepository.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentitySecurityLogRepository.cs index 8732355c14..f68f289b4f 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentitySecurityLogRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentitySecurityLogRepository.cs @@ -17,6 +17,7 @@ namespace Volo.Abp.Identity string applicationName = null, string identity = null, string action = null, + Guid? userId = null, string userName = null, string clientId = null, string correlationId = null, @@ -29,9 +30,16 @@ namespace Volo.Abp.Identity string applicationName = null, string identity = null, string action = null, + Guid? userId = null, string userName = null, string clientId = null, string correlationId = null, CancellationToken cancellationToken = default); + + Task GetByUserIdAsync( + Guid id, + Guid userId, + bool includeDetails = false, + CancellationToken cancellationToken = default); } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogEvent.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogEvent.cs index 93296619f6..faac2d5033 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogEvent.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogEvent.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Volo.Abp.MultiTenancy; namespace Volo.Abp.Identity @@ -14,5 +15,19 @@ namespace Volo.Abp.Identity public string UserName { get; set; } public string ClientId { get; set; } + + public Dictionary ExtraProperties { get; } + + public IdentitySecurityLogEvent() + { + ExtraProperties = new Dictionary(); + } + + public virtual IdentitySecurityLogEvent WithProperty(string key, object value) + { + ExtraProperties[key] = value; + return this; + } + } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogHandler.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogHandler.cs index 4e0c46b2f7..5000d4d288 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogHandler.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogHandler.cs @@ -48,6 +48,11 @@ namespace Volo.Abp.Identity { securityLog.ClientId = eventData.ClientId; } + + foreach (var property in eventData.ExtraProperties) + { + securityLog.ExtraProperties[property.Key] = property.Value; + } }; if (CurrentUser.IsAuthenticated) diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EFCoreIdentitySecurityLogRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EFCoreIdentitySecurityLogRepository.cs index 1801a49136..137341a25e 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EFCoreIdentitySecurityLogRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EFCoreIdentitySecurityLogRepository.cs @@ -27,6 +27,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore string applicationName = null, string identity = null, string action = null, + Guid? userId = null, string userName = null, string clientId = null, string correlationId = null, @@ -39,6 +40,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore applicationName, identity, action, + userId, userName, clientId, correlationId @@ -55,6 +57,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore string applicationName = null, string identity = null, string action = null, + Guid? userId = null, string userName = null, string clientId = null, string correlationId = null, @@ -66,6 +69,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore applicationName, identity, action, + userId, userName, clientId, correlationId @@ -74,12 +78,18 @@ namespace Volo.Abp.Identity.EntityFrameworkCore return await query.LongCountAsync(GetCancellationToken(cancellationToken)); } - protected virtual IQueryable GetListQuery( + public async Task GetByUserIdAsync(Guid id, Guid userId, bool includeDetails = false, CancellationToken cancellationToken = default) + { + return await DbSet.FirstOrDefaultAsync(x => x.Id == id && x.UserId == userId, GetCancellationToken(cancellationToken)); + } + + protected virtual IQueryable GetListQuery( DateTime? startTime = null, DateTime? endTime = null, string applicationName = null, string identity = null, string action = null, + Guid? userId = null, string userName = null, string clientId = null, string correlationId = null) @@ -90,6 +100,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore .WhereIf(!applicationName.IsNullOrWhiteSpace(), securityLog => securityLog.ApplicationName == applicationName) .WhereIf(!identity.IsNullOrWhiteSpace(), securityLog => securityLog.Identity == identity) .WhereIf(!action.IsNullOrWhiteSpace(), securityLog => securityLog.Action == action) + .WhereIf(userId.HasValue, securityLog => securityLog.UserId == userId) .WhereIf(!userName.IsNullOrWhiteSpace(), securityLog => securityLog.UserName == userName) .WhereIf(!clientId.IsNullOrWhiteSpace(), securityLog => securityLog.ClientId == clientId) .WhereIf(!correlationId.IsNullOrWhiteSpace(), securityLog => securityLog.CorrelationId == correlationId); diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySecurityLogRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySecurityLogRepository.cs index 5fccb0d2ab..4336abaaae 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySecurityLogRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySecurityLogRepository.cs @@ -11,7 +11,8 @@ using Volo.Abp.MongoDB; namespace Volo.Abp.Identity.MongoDB { - public class MongoIdentitySecurityLogRepository : MongoDbRepository, IIdentitySecurityLogRepository + public class MongoIdentitySecurityLogRepository : + MongoDbRepository, IIdentitySecurityLogRepository { public MongoIdentitySecurityLogRepository(IMongoDbContextProvider dbContextProvider) : base(dbContextProvider) @@ -27,6 +28,7 @@ namespace Volo.Abp.Identity.MongoDB string applicationName = null, string identity = null, string action = null, + Guid? userId = null, string userName = null, string clientId = null, string correlationId = null, @@ -39,6 +41,7 @@ namespace Volo.Abp.Identity.MongoDB applicationName, identity, action, + userId, userName, clientId, correlationId @@ -56,6 +59,7 @@ namespace Volo.Abp.Identity.MongoDB string applicationName = null, string identity = null, string action = null, + Guid? userId = null, string userName = null, string clientId = null, string correlationId = null, @@ -67,33 +71,47 @@ namespace Volo.Abp.Identity.MongoDB applicationName, identity, action, + userId, userName, clientId, correlationId ); - return await query.As>().LongCountAsync(GetCancellationToken(cancellationToken)); + return await query.As>() + .LongCountAsync(GetCancellationToken(cancellationToken)); } - protected virtual IQueryable GetListQuery( - DateTime? startTime = null, - DateTime? endTime = null, - string applicationName = null, - string identity = null, - string action = null, - string userName = null, - string clientId = null, - string correlationId = null) - { - return GetMongoQueryable() - .WhereIf(startTime.HasValue, securityLog => securityLog.CreationTime >= startTime) - .WhereIf(endTime.HasValue, securityLog => securityLog.CreationTime >= endTime) - .WhereIf(!applicationName.IsNullOrWhiteSpace(), securityLog => securityLog.ApplicationName == applicationName) - .WhereIf(!identity.IsNullOrWhiteSpace(), securityLog => securityLog.Identity == identity) - .WhereIf(!action.IsNullOrWhiteSpace(), securityLog => securityLog.Action == action) - .WhereIf(!userName.IsNullOrWhiteSpace(), securityLog => securityLog.UserName == userName) - .WhereIf(!clientId.IsNullOrWhiteSpace(), securityLog => securityLog.ClientId == clientId) - .WhereIf(!correlationId.IsNullOrWhiteSpace(), securityLog => securityLog.CorrelationId == correlationId); - } + + public async Task GetByUserIdAsync(Guid id, Guid userId, bool includeDetails = false, + CancellationToken cancellationToken = default) + { + return await GetMongoQueryable().FirstOrDefaultAsync(x => x.Id == id && x.UserId == userId, + GetCancellationToken(cancellationToken)); + } + + protected virtual IQueryable GetListQuery( + DateTime? startTime = null, + DateTime? endTime = null, + string applicationName = null, + string identity = null, + string action = null, + Guid? userId = null, + string userName = null, + string clientId = null, + string correlationId = null) + { + return GetMongoQueryable() + .WhereIf(startTime.HasValue, securityLog => securityLog.CreationTime >= startTime) + .WhereIf(endTime.HasValue, securityLog => securityLog.CreationTime >= endTime) + .WhereIf(!applicationName.IsNullOrWhiteSpace(), + securityLog => securityLog.ApplicationName == applicationName) + .WhereIf(!identity.IsNullOrWhiteSpace(), securityLog => securityLog.Identity == identity) + .WhereIf(!action.IsNullOrWhiteSpace(), securityLog => securityLog.Action == action) + .WhereIf(userId.HasValue, securityLog => securityLog.UserId == userId) + .WhereIf(!userName.IsNullOrWhiteSpace(), securityLog => securityLog.UserName == userName) + .WhereIf(!clientId.IsNullOrWhiteSpace(), securityLog => securityLog.ClientId == clientId) + .WhereIf(!correlationId.IsNullOrWhiteSpace(), + securityLog => securityLog.CorrelationId == correlationId); + } } } From 37508abfa22c17ce661edf8feb40a3fa0103c7cf Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Fri, 10 Jul 2020 14:51:34 +0800 Subject: [PATCH 8/9] Update template projects migrations. --- .../20200710064926_Initial.Designer.cs} | 168 +++++++++++++++++- .../Migrations/20200710064926_Initial.cs} | 100 +++++++++++ ...ectNameMigrationsDbContextModelSnapshot.cs | 75 ++++++++ .../20200710065039_Initial.Designer.cs} | 168 ++++++++---------- .../Migrations/20200710065039_Initial.cs} | 100 +++++------ ...verHostMigrationsDbContextModelSnapshot.cs | 75 ++++++++ ....cs => 20200710065052_Initial.Designer.cs} | 77 +++++++- ...0_Initial.cs => 20200710065052_Initial.cs} | 48 +++++ .../UnifiedDbContextModelSnapshot.cs | 75 ++++++++ 9 files changed, 740 insertions(+), 146 deletions(-) rename templates/{module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200624023331_Initial.Designer.cs => app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200710064926_Initial.Designer.cs} (92%) rename templates/{module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200624023331_Initial.cs => app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200710064926_Initial.cs} (91%) rename templates/{app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200624023152_Initial.Designer.cs => module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200710065039_Initial.Designer.cs} (96%) rename templates/{app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200624023152_Initial.cs => module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200710065039_Initial.cs} (96%) rename templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/{20200624023340_Initial.Designer.cs => 20200710065052_Initial.Designer.cs} (93%) rename templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/{20200624023340_Initial.cs => 20200710065052_Initial.cs} (92%) diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200624023331_Initial.Designer.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200710064926_Initial.Designer.cs similarity index 92% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200624023331_Initial.Designer.cs rename to templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200710064926_Initial.Designer.cs index 23c25b58cd..e2ca97db45 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200624023331_Initial.Designer.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200710064926_Initial.Designer.cs @@ -10,8 +10,8 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Migrations { - [DbContext(typeof(IdentityServerHostMigrationsDbContext))] - [Migration("20200624023331_Initial")] + [DbContext(typeof(MyProjectNameMigrationsDbContext))] + [Migration("20200710064926_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -275,6 +275,95 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpEntityPropertyChanges"); }); + modelBuilder.Entity("Volo.Abp.BackgroundJobs.BackgroundJobRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("IsAbandoned") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("JobArgs") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasMaxLength(1048576); + + b.Property("JobName") + .IsRequired() + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("LastTryTime") + .HasColumnType("datetime2"); + + b.Property("NextTryTime") + .HasColumnType("datetime2"); + + b.Property("Priority") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint") + .HasDefaultValue((byte)15); + + b.Property("TryCount") + .ValueGeneratedOnAdd() + .HasColumnType("smallint") + .HasDefaultValue((short)0); + + b.HasKey("Id"); + + b.HasIndex("IsAbandoned", "NextTryTime"); + + b.ToTable("AbpBackgroundJobs"); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ProviderName") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpFeatureValues"); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => { b.Property("Id") @@ -399,6 +488,81 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpRoleClaims"); }); + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("ApplicationName") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("BrowserInfo") + .HasColumnType("nvarchar(512)") + .HasMaxLength(512); + + b.Property("ClientId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ClientIpAddress") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("CorrelationId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("Identity") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantName") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs"); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => { b.Property("Id") diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200624023331_Initial.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200710064926_Initial.cs similarity index 91% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200624023331_Initial.cs rename to templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200710064926_Initial.cs index 9287186f86..2c82babc5b 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200624023331_Initial.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200710064926_Initial.cs @@ -39,6 +39,27 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpAuditLogs", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpBackgroundJobs", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(maxLength: 40, nullable: true), + JobName = table.Column(maxLength: 128, nullable: false), + JobArgs = table.Column(maxLength: 1048576, nullable: false), + TryCount = table.Column(nullable: false, defaultValue: (short)0), + CreationTime = table.Column(nullable: false), + NextTryTime = table.Column(nullable: false), + LastTryTime = table.Column(nullable: true), + IsAbandoned = table.Column(nullable: false, defaultValue: false), + Priority = table.Column(nullable: false, defaultValue: (byte)15) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpBackgroundJobs", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpClaimTypes", columns: table => new @@ -59,6 +80,21 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpClaimTypes", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpFeatureValues", + columns: table => new + { + Id = table.Column(nullable: false), + Name = table.Column(maxLength: 128, nullable: false), + Value = table.Column(maxLength: 128, nullable: false), + ProviderName = table.Column(maxLength: 64, nullable: true), + ProviderKey = table.Column(maxLength: 64, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpFeatureValues", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpOrganizationUnits", columns: table => new @@ -123,6 +159,31 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpRoles", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpSecurityLogs", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(maxLength: 40, nullable: true), + TenantId = table.Column(nullable: true), + ApplicationName = table.Column(maxLength: 96, nullable: true), + Identity = table.Column(maxLength: 96, nullable: true), + Action = table.Column(maxLength: 96, nullable: true), + UserId = table.Column(nullable: true), + UserName = table.Column(maxLength: 256, nullable: true), + TenantName = table.Column(maxLength: 64, nullable: true), + ClientId = table.Column(maxLength: 64, nullable: true), + CorrelationId = table.Column(maxLength: 64, nullable: true), + ClientIpAddress = table.Column(maxLength: 64, nullable: true), + BrowserInfo = table.Column(maxLength: 512, nullable: true), + CreationTime = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpSecurityLogs", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpSettings", columns: table => new @@ -887,6 +948,11 @@ namespace MyCompanyName.MyProjectName.Migrations table: "AbpAuditLogs", columns: new[] { "TenantId", "UserId", "ExecutionTime" }); + migrationBuilder.CreateIndex( + name: "IX_AbpBackgroundJobs_IsAbandoned_NextTryTime", + table: "AbpBackgroundJobs", + columns: new[] { "IsAbandoned", "NextTryTime" }); + migrationBuilder.CreateIndex( name: "IX_AbpEntityChanges_AuditLogId", table: "AbpEntityChanges", @@ -902,6 +968,11 @@ namespace MyCompanyName.MyProjectName.Migrations table: "AbpEntityPropertyChanges", column: "EntityChangeId"); + migrationBuilder.CreateIndex( + name: "IX_AbpFeatureValues_Name_ProviderName_ProviderKey", + table: "AbpFeatureValues", + columns: new[] { "Name", "ProviderName", "ProviderKey" }); + migrationBuilder.CreateIndex( name: "IX_AbpOrganizationUnitRoles_RoleId_OrganizationUnitId", table: "AbpOrganizationUnitRoles", @@ -932,6 +1003,26 @@ namespace MyCompanyName.MyProjectName.Migrations table: "AbpRoles", column: "NormalizedName"); + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_Action", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "Action" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_ApplicationName", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "ApplicationName" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_Identity", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "Identity" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_UserId", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "UserId" }); + migrationBuilder.CreateIndex( name: "IX_AbpSettings_Name_ProviderName_ProviderKey", table: "AbpSettings", @@ -1020,12 +1111,18 @@ namespace MyCompanyName.MyProjectName.Migrations migrationBuilder.DropTable( name: "AbpAuditLogActions"); + migrationBuilder.DropTable( + name: "AbpBackgroundJobs"); + migrationBuilder.DropTable( name: "AbpClaimTypes"); migrationBuilder.DropTable( name: "AbpEntityPropertyChanges"); + migrationBuilder.DropTable( + name: "AbpFeatureValues"); + migrationBuilder.DropTable( name: "AbpOrganizationUnitRoles"); @@ -1035,6 +1132,9 @@ namespace MyCompanyName.MyProjectName.Migrations migrationBuilder.DropTable( name: "AbpRoleClaims"); + migrationBuilder.DropTable( + name: "AbpSecurityLogs"); + migrationBuilder.DropTable( name: "AbpSettings"); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/MyProjectNameMigrationsDbContextModelSnapshot.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/MyProjectNameMigrationsDbContextModelSnapshot.cs index 77d771b803..f06dda1edc 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/MyProjectNameMigrationsDbContextModelSnapshot.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/MyProjectNameMigrationsDbContextModelSnapshot.cs @@ -486,6 +486,81 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpRoleClaims"); }); + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("ApplicationName") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("BrowserInfo") + .HasColumnType("nvarchar(512)") + .HasMaxLength(512); + + b.Property("ClientId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ClientIpAddress") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("CorrelationId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("Identity") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantName") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs"); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => { b.Property("Id") diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200624023152_Initial.Designer.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200710065039_Initial.Designer.cs similarity index 96% rename from templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200624023152_Initial.Designer.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200710065039_Initial.Designer.cs index 174de5bc94..00033c31b9 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200624023152_Initial.Designer.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200710065039_Initial.Designer.cs @@ -10,8 +10,8 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Migrations { - [DbContext(typeof(MyProjectNameMigrationsDbContext))] - [Migration("20200624023152_Initial")] + [DbContext(typeof(IdentityServerHostMigrationsDbContext))] + [Migration("20200710065039_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -275,95 +275,6 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpEntityPropertyChanges"); }); - modelBuilder.Entity("Volo.Abp.BackgroundJobs.BackgroundJobRecord", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnName("ConcurrencyStamp") - .HasColumnType("nvarchar(40)") - .HasMaxLength(40); - - b.Property("CreationTime") - .HasColumnName("CreationTime") - .HasColumnType("datetime2"); - - b.Property("ExtraProperties") - .HasColumnName("ExtraProperties") - .HasColumnType("nvarchar(max)"); - - b.Property("IsAbandoned") - .ValueGeneratedOnAdd() - .HasColumnType("bit") - .HasDefaultValue(false); - - b.Property("JobArgs") - .IsRequired() - .HasColumnType("nvarchar(max)") - .HasMaxLength(1048576); - - b.Property("JobName") - .IsRequired() - .HasColumnType("nvarchar(128)") - .HasMaxLength(128); - - b.Property("LastTryTime") - .HasColumnType("datetime2"); - - b.Property("NextTryTime") - .HasColumnType("datetime2"); - - b.Property("Priority") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint") - .HasDefaultValue((byte)15); - - b.Property("TryCount") - .ValueGeneratedOnAdd() - .HasColumnType("smallint") - .HasDefaultValue((short)0); - - b.HasKey("Id"); - - b.HasIndex("IsAbandoned", "NextTryTime"); - - b.ToTable("AbpBackgroundJobs"); - }); - - modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureValue", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("Name") - .IsRequired() - .HasColumnType("nvarchar(128)") - .HasMaxLength(128); - - b.Property("ProviderKey") - .HasColumnType("nvarchar(64)") - .HasMaxLength(64); - - b.Property("ProviderName") - .HasColumnType("nvarchar(64)") - .HasMaxLength(64); - - b.Property("Value") - .IsRequired() - .HasColumnType("nvarchar(128)") - .HasMaxLength(128); - - b.HasKey("Id"); - - b.HasIndex("Name", "ProviderName", "ProviderKey"); - - b.ToTable("AbpFeatureValues"); - }); - modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => { b.Property("Id") @@ -488,6 +399,81 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpRoleClaims"); }); + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("ApplicationName") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("BrowserInfo") + .HasColumnType("nvarchar(512)") + .HasMaxLength(512); + + b.Property("ClientId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ClientIpAddress") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("CorrelationId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("Identity") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantName") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs"); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => { b.Property("Id") diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200624023152_Initial.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200710065039_Initial.cs similarity index 96% rename from templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200624023152_Initial.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200710065039_Initial.cs index b98f3342be..f80a5d9936 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200624023152_Initial.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200710065039_Initial.cs @@ -39,27 +39,6 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpAuditLogs", x => x.Id); }); - migrationBuilder.CreateTable( - name: "AbpBackgroundJobs", - columns: table => new - { - Id = table.Column(nullable: false), - ExtraProperties = table.Column(nullable: true), - ConcurrencyStamp = table.Column(maxLength: 40, nullable: true), - JobName = table.Column(maxLength: 128, nullable: false), - JobArgs = table.Column(maxLength: 1048576, nullable: false), - TryCount = table.Column(nullable: false, defaultValue: (short)0), - CreationTime = table.Column(nullable: false), - NextTryTime = table.Column(nullable: false), - LastTryTime = table.Column(nullable: true), - IsAbandoned = table.Column(nullable: false, defaultValue: false), - Priority = table.Column(nullable: false, defaultValue: (byte)15) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpBackgroundJobs", x => x.Id); - }); - migrationBuilder.CreateTable( name: "AbpClaimTypes", columns: table => new @@ -80,21 +59,6 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpClaimTypes", x => x.Id); }); - migrationBuilder.CreateTable( - name: "AbpFeatureValues", - columns: table => new - { - Id = table.Column(nullable: false), - Name = table.Column(maxLength: 128, nullable: false), - Value = table.Column(maxLength: 128, nullable: false), - ProviderName = table.Column(maxLength: 64, nullable: true), - ProviderKey = table.Column(maxLength: 64, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpFeatureValues", x => x.Id); - }); - migrationBuilder.CreateTable( name: "AbpOrganizationUnits", columns: table => new @@ -159,6 +123,31 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpRoles", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpSecurityLogs", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(maxLength: 40, nullable: true), + TenantId = table.Column(nullable: true), + ApplicationName = table.Column(maxLength: 96, nullable: true), + Identity = table.Column(maxLength: 96, nullable: true), + Action = table.Column(maxLength: 96, nullable: true), + UserId = table.Column(nullable: true), + UserName = table.Column(maxLength: 256, nullable: true), + TenantName = table.Column(maxLength: 64, nullable: true), + ClientId = table.Column(maxLength: 64, nullable: true), + CorrelationId = table.Column(maxLength: 64, nullable: true), + ClientIpAddress = table.Column(maxLength: 64, nullable: true), + BrowserInfo = table.Column(maxLength: 512, nullable: true), + CreationTime = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpSecurityLogs", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpSettings", columns: table => new @@ -923,11 +912,6 @@ namespace MyCompanyName.MyProjectName.Migrations table: "AbpAuditLogs", columns: new[] { "TenantId", "UserId", "ExecutionTime" }); - migrationBuilder.CreateIndex( - name: "IX_AbpBackgroundJobs_IsAbandoned_NextTryTime", - table: "AbpBackgroundJobs", - columns: new[] { "IsAbandoned", "NextTryTime" }); - migrationBuilder.CreateIndex( name: "IX_AbpEntityChanges_AuditLogId", table: "AbpEntityChanges", @@ -943,11 +927,6 @@ namespace MyCompanyName.MyProjectName.Migrations table: "AbpEntityPropertyChanges", column: "EntityChangeId"); - migrationBuilder.CreateIndex( - name: "IX_AbpFeatureValues_Name_ProviderName_ProviderKey", - table: "AbpFeatureValues", - columns: new[] { "Name", "ProviderName", "ProviderKey" }); - migrationBuilder.CreateIndex( name: "IX_AbpOrganizationUnitRoles_RoleId_OrganizationUnitId", table: "AbpOrganizationUnitRoles", @@ -978,6 +957,26 @@ namespace MyCompanyName.MyProjectName.Migrations table: "AbpRoles", column: "NormalizedName"); + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_Action", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "Action" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_ApplicationName", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "ApplicationName" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_Identity", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "Identity" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_UserId", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "UserId" }); + migrationBuilder.CreateIndex( name: "IX_AbpSettings_Name_ProviderName_ProviderKey", table: "AbpSettings", @@ -1066,18 +1065,12 @@ namespace MyCompanyName.MyProjectName.Migrations migrationBuilder.DropTable( name: "AbpAuditLogActions"); - migrationBuilder.DropTable( - name: "AbpBackgroundJobs"); - migrationBuilder.DropTable( name: "AbpClaimTypes"); migrationBuilder.DropTable( name: "AbpEntityPropertyChanges"); - migrationBuilder.DropTable( - name: "AbpFeatureValues"); - migrationBuilder.DropTable( name: "AbpOrganizationUnitRoles"); @@ -1087,6 +1080,9 @@ namespace MyCompanyName.MyProjectName.Migrations migrationBuilder.DropTable( name: "AbpRoleClaims"); + migrationBuilder.DropTable( + name: "AbpSecurityLogs"); + migrationBuilder.DropTable( name: "AbpSettings"); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/IdentityServerHostMigrationsDbContextModelSnapshot.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/IdentityServerHostMigrationsDbContextModelSnapshot.cs index 44c00e04d4..3129fab657 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/IdentityServerHostMigrationsDbContextModelSnapshot.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/IdentityServerHostMigrationsDbContextModelSnapshot.cs @@ -397,6 +397,81 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpRoleClaims"); }); + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("ApplicationName") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("BrowserInfo") + .HasColumnType("nvarchar(512)") + .HasMaxLength(512); + + b.Property("ClientId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ClientIpAddress") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("CorrelationId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("Identity") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantName") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs"); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => { b.Property("Id") diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200624023340_Initial.Designer.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200710065052_Initial.Designer.cs similarity index 93% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200624023340_Initial.Designer.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200710065052_Initial.Designer.cs index d93e2804a6..4afc02af46 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200624023340_Initial.Designer.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200710065052_Initial.Designer.cs @@ -11,7 +11,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Migrations { [DbContext(typeof(UnifiedDbContext))] - [Migration("20200624023340_Initial")] + [Migration("20200710065052_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -399,6 +399,81 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpRoleClaims"); }); + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("ApplicationName") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("BrowserInfo") + .HasColumnType("nvarchar(512)") + .HasMaxLength(512); + + b.Property("ClientId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ClientIpAddress") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("CorrelationId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("Identity") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantName") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs"); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => { b.Property("Id") diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200624023340_Initial.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200710065052_Initial.cs similarity index 92% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200624023340_Initial.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200710065052_Initial.cs index ad7940fa81..a0d5e132a9 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200624023340_Initial.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200710065052_Initial.cs @@ -123,6 +123,31 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpRoles", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpSecurityLogs", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(maxLength: 40, nullable: true), + TenantId = table.Column(nullable: true), + ApplicationName = table.Column(maxLength: 96, nullable: true), + Identity = table.Column(maxLength: 96, nullable: true), + Action = table.Column(maxLength: 96, nullable: true), + UserId = table.Column(nullable: true), + UserName = table.Column(maxLength: 256, nullable: true), + TenantName = table.Column(maxLength: 64, nullable: true), + ClientId = table.Column(maxLength: 64, nullable: true), + CorrelationId = table.Column(maxLength: 64, nullable: true), + ClientIpAddress = table.Column(maxLength: 64, nullable: true), + BrowserInfo = table.Column(maxLength: 512, nullable: true), + CreationTime = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpSecurityLogs", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpSettings", columns: table => new @@ -515,6 +540,26 @@ namespace MyCompanyName.MyProjectName.Migrations table: "AbpRoles", column: "NormalizedName"); + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_Action", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "Action" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_ApplicationName", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "ApplicationName" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_Identity", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "Identity" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpSecurityLogs_TenantId_UserId", + table: "AbpSecurityLogs", + columns: new[] { "TenantId", "UserId" }); + migrationBuilder.CreateIndex( name: "IX_AbpSettings_Name_ProviderName_ProviderKey", table: "AbpSettings", @@ -586,6 +631,9 @@ namespace MyCompanyName.MyProjectName.Migrations migrationBuilder.DropTable( name: "AbpRoleClaims"); + migrationBuilder.DropTable( + name: "AbpSecurityLogs"); + migrationBuilder.DropTable( name: "AbpSettings"); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs index 157b210fc4..47b094f3c5 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs @@ -397,6 +397,81 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpRoleClaims"); }); + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("ApplicationName") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("BrowserInfo") + .HasColumnType("nvarchar(512)") + .HasMaxLength(512); + + b.Property("ClientId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ClientIpAddress") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("CorrelationId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("Identity") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantName") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs"); + }); + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => { b.Property("Id") From 40dc60cb6cb41bb80d33b54c6d21fcadde837e85 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Fri, 10 Jul 2020 15:31:14 +0800 Subject: [PATCH 9/9] Disable Security Log feature. --- .../SecurityLog/AspNetCoreSecurityLogManager.cs | 1 - .../Abp/SecurityLog/DefaultSecurityLogManager.cs | 5 +++++ .../Volo/Abp/SecurityLog/SecurityLogInfo.cs | 10 ---------- .../Volo/Abp/SecurityLog/SimpleSecurityLogStore.cs | 12 ++++++++++-- .../Volo/Abp/Identity/IdentitySecurityLogStore.cs | 5 +++++ 5 files changed, 20 insertions(+), 13 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/SecurityLog/AspNetCoreSecurityLogManager.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/SecurityLog/AspNetCoreSecurityLogManager.cs index 55ece86be2..f0fc0aa347 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/SecurityLog/AspNetCoreSecurityLogManager.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/SecurityLog/AspNetCoreSecurityLogManager.cs @@ -23,7 +23,6 @@ namespace Volo.Abp.AspNetCore.SecurityLog protected ICurrentClient CurrentClient { get; } protected IHttpContextAccessor HttpContextAccessor { get; } protected ICorrelationIdProvider CorrelationIdProvider { get; } - protected IWebClientInfoProvider WebClientInfoProvider { get; } public AspNetCoreSecurityLogManager( diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs index ab260ff708..f628958bc4 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/DefaultSecurityLogManager.cs @@ -21,6 +21,11 @@ namespace Volo.Abp.SecurityLog public async Task SaveAsync(Action saveAction = null) { + if (!SecurityLogOptions.IsEnabled) + { + return; + } + var securityLogInfo = await CreateAsync(); saveAction?.Invoke(securityLogInfo); await SecurityLogStore.SaveAsync(securityLogInfo); diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs index c6e562f6c8..b187b5bfa2 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SecurityLogInfo.cs @@ -6,20 +6,10 @@ namespace Volo.Abp.SecurityLog [Serializable] public class SecurityLogInfo { - /// - /// The name of the application or service writing user security logs. - /// Default: null. - /// public string ApplicationName { get; set; } - /// - /// Web, JWT, Identity, Identity_Server - /// public string Identity { get; set; } - /// - /// login_successful, login_failed, logout, change_pwd, refresh_token... - /// public string Action { get; set; } public Dictionary ExtraProperties { get; } diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SimpleSecurityLogStore.cs b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SimpleSecurityLogStore.cs index bc9c22c4df..fe6496ef40 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SimpleSecurityLogStore.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/SecurityLog/SimpleSecurityLogStore.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; namespace Volo.Abp.SecurityLog @@ -7,16 +8,23 @@ namespace Volo.Abp.SecurityLog public class SimpleSecurityLogStore : ISecurityLogStore, ITransientDependency { public ILogger Logger { get; set; } + protected AbpSecurityLogOptions SecurityLogOptions { get; } - public SimpleSecurityLogStore(ILogger logger) + public SimpleSecurityLogStore(ILogger logger, IOptions securityLogOptions) { Logger = logger; + SecurityLogOptions = securityLogOptions.Value; } public Task SaveAsync(SecurityLogInfo securityLogInfo) { + if (!SecurityLogOptions.IsEnabled) + { + return Task.CompletedTask; + } + Logger.LogInformation(securityLogInfo.ToString()); - return Task.FromResult(0); + return Task.CompletedTask; } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogStore.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogStore.cs index 696fc3ad6a..17e3c20794 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogStore.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentitySecurityLogStore.cs @@ -34,6 +34,11 @@ namespace Volo.Abp.Identity public async Task SaveAsync(SecurityLogInfo securityLogInfo) { + if (!SecurityLogOptions.IsEnabled) + { + return; + } + using (var uow = UnitOfWorkManager.Begin(requiresNew: true)) { await IdentitySecurityLogRepository.InsertAsync(new IdentitySecurityLog(GuidGenerator, securityLogInfo));