Implement security log in Identity module.

pull/4675/head
maliming 5 years ago
parent 73de02689f
commit 0466207a6d

@ -19,7 +19,7 @@ namespace Volo.Abp.SecurityLog
SecurityLogOptions = securityLogOptions.Value;
}
public async Task SaveAsync(Action<SecurityLogInfo> saveAction)
public async Task SaveAsync(Action<SecurityLogInfo> saveAction = null)
{
var securityLogInfo = await CreateAsync();
saveAction?.Invoke(securityLogInfo);

@ -5,6 +5,6 @@ namespace Volo.Abp.SecurityLog
{
public interface ISecurityLogManager
{
Task SaveAsync(Action<SecurityLogInfo> saveAction);
Task SaveAsync(Action<SecurityLogInfo> saveAction = null);
}
}

@ -5,7 +5,7 @@ using Volo.Abp.Data;
namespace Volo.Abp.SecurityLog
{
[Serializable]
public class SecurityLogInfo : IHasExtraProperties
public class SecurityLogInfo
{
/// <summary>
/// The name of the application or service writing user security logs.

@ -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<AbpSecurityLogOptions>(x =>
{
x.ApplicationName = "AbpSecurityTest";
});
}
}
}

@ -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<AbpSecurityTestModule>
{
private readonly ISecurityLogManager _securityLogManager;
private ISecurityLogStore _auditingStore;
public SecurityLogManager_Tests()
{
_securityLogManager = GetRequiredService<ISecurityLogManager>();
}
protected override void AfterAddApplication(IServiceCollection services)
{
_auditingStore = Substitute.For<ISecurityLogStore>();
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<SecurityLogInfo>(log =>
log.ApplicationName == "AbpSecurityTest" &&
log.Identity == "Test" &&
log.Action == "Test-Action" &&
log.UserName == "Test-User"));
}
}
}

@ -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(),

@ -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<IActionResult> OnGetAsync()
{
await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent
{
Identity = IdentitySecurityLogIdentityConsts.Identity,
Action = IdentitySecurityLogActionConsts.Logout
});
await SignInManager.SignOutAsync();
var logoutId = Request.Query["logoutId"].ToString();

@ -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)

@ -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(),

@ -16,7 +16,7 @@ namespace Volo.Abp.Account.Web.Pages.Account
public virtual async Task<IActionResult> OnGetAsync()
{
await LocalEventBus.PublishAsync(new SecurityLogEvent
await LocalEventBus.PublishAsync(new IdentitySecurityLogEvent
{
Identity = IdentitySecurityLogIdentityConsts.Identity,
Action = IdentitySecurityLogActionConsts.Logout

@ -0,0 +1,52 @@
namespace Volo.Abp.Identity
{
public class IdentitySecurityLogConsts
{
/// <summary>
/// Default value: 96
/// </summary>
public static int MaxApplicationNameLength { get; set; } = 96;
/// <summary>
/// Default value: 96
/// </summary>
public static int MaxIdentityLength { get; set; } = 96;
/// <summary>
/// Default value: 96
/// </summary>
public static int MaxActionLength { get; set; } = 96;
/// <summary>
/// Default value: 256
/// </summary>
public static int MaxUserNameLength { get; set; } = 256;
/// <summary>
/// Default value: 64
/// </summary>
public static int MaxTenantNameLength { get; set; } = 64;
/// <summary>
/// Default value: 64
/// </summary>
public static int MaxClientIpAddressLength { get; set; } = 64;
/// <summary>
/// Default value: 64
/// </summary>
public static int MaxClientIdLength { get; set; } = 64;
/// <summary>
/// Default value: 64
/// </summary>
public static int MaxCorrelationIdLength { get; set; } = 64;
/// <summary>
/// Default value: 512
/// </summary>
public static int MaxBrowserInfoLength { get; set; } = 512;
}
}

@ -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<IdentitySecurityLog, Guid>
{
Task<List<IdentitySecurityLog>> 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<long> 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);
}
}

@ -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<Guid>, 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<string, object>();
}
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;
}
}
}

@ -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; }

@ -10,32 +10,29 @@ using Volo.Abp.Users;
namespace Volo.Abp.Identity
{
public class SecurityLogHandler : ILocalEventHandler<SecurityLogEvent>, ITransientDependency
public class IdentitySecurityLogHandler : ILocalEventHandler<IdentitySecurityLogEvent>, ITransientDependency
{
protected ISecurityLogManager SecurityLogManager { get; }
protected IdentityUserManager UserManager { get; }
protected ICurrentPrincipalAccessor CurrentPrincipalAccessor { get; }
protected IUserClaimsPrincipalFactory<IdentityUser> UserClaimsPrincipalFactory { get; }
protected ICurrentUser CurrentUser { get; }
protected IUnitOfWorkManager UnitOfWorkManager { get; }
public SecurityLogHandler(
public IdentitySecurityLogHandler(
ISecurityLogManager securityLogManager,
IdentityUserManager userManager,
ICurrentPrincipalAccessor currentPrincipalAccessor,
IUserClaimsPrincipalFactory<IdentityUser> 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<SecurityLogInfo> 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();
}
}
}

@ -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<IdentitySecurityLogStore> Logger { get; set; }
protected AbpSecurityLogOptions SecurityLogOptions { get; }
protected IIdentitySecurityLogRepository IdentitySecurityLogRepository { get; }
protected IGuidGenerator GuidGenerator { get; }
protected IUnitOfWorkManager UnitOfWorkManager { get; }
public IdentitySecurityLogStore(
ILogger<IdentitySecurityLogStore> logger,
IOptions<AbpSecurityLogOptions> 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();
}
}
}
}

@ -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<IIdentityDbContext, IdentitySecurityLog, Guid>, IIdentitySecurityLogRepository
{
public EFCoreIdentitySecurityLogRepository(IDbContextProvider<IIdentityDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
public async Task<List<IdentitySecurityLog>> 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<long> 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<IdentitySecurityLog> 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);
}
}
}

@ -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<IdentityClaimType> ClaimTypes { get; set; }
DbSet<OrganizationUnit> OrganizationUnits { get; set; }
DbSet<IdentitySecurityLog> IdentitySecurityLogs { get; set; }
}
}

@ -18,6 +18,8 @@ namespace Volo.Abp.Identity.EntityFrameworkCore
public DbSet<OrganizationUnit> OrganizationUnits { get; set; }
public DbSet<IdentitySecurityLog> IdentitySecurityLogs { get; set; }
public IdentityDbContext(DbContextOptions<IdentityDbContext> options)
: base(options)
{
@ -31,4 +33,4 @@ namespace Volo.Abp.Identity.EntityFrameworkCore
builder.ConfigureIdentity();
}
}
}
}

@ -204,6 +204,32 @@ namespace Volo.Abp.Identity.EntityFrameworkCore
b.HasIndex(ou => new {ou.UserId, ou.OrganizationUnitId});
});
builder.Entity<IdentitySecurityLog>(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 });
});
}
}
}
}

@ -15,6 +15,8 @@ namespace Volo.Abp.Identity.MongoDB
public IMongoCollection<OrganizationUnit> OrganizationUnits => Collection<OrganizationUnit>();
public IMongoCollection<IdentitySecurityLog> IdentitySecurityLogs => Collection<IdentitySecurityLog>();
protected override void CreateModel(IMongoModelBuilder modelBuilder)
{
base.CreateModel(modelBuilder);
@ -22,4 +24,4 @@ namespace Volo.Abp.Identity.MongoDB
modelBuilder.ConfigureIdentity();
}
}
}
}

@ -36,6 +36,11 @@ namespace Volo.Abp.Identity.MongoDB
{
b.CollectionName = options.CollectionPrefix + "OrganizationUnits";
});
builder.Entity<IdentitySecurityLog>(b =>
{
b.CollectionName = options.CollectionPrefix + "SecurityLogs";
});
}
}
}
}

@ -18,6 +18,7 @@ namespace Volo.Abp.Identity.MongoDB
options.AddRepository<IdentityRole, MongoIdentityRoleRepository>();
options.AddRepository<IdentityClaimType, MongoIdentityRoleRepository>();
options.AddRepository<OrganizationUnit, MongoIdentityRoleRepository>();
options.AddRepository<IdentitySecurityLog, MongoIdentitySecurityLogRepository>();
});
}
}

@ -14,5 +14,7 @@ namespace Volo.Abp.Identity.MongoDB
IMongoCollection<IdentityClaimType> ClaimTypes { get; }
IMongoCollection<OrganizationUnit> OrganizationUnits { get; }
IMongoCollection<IdentitySecurityLog> IdentitySecurityLogs { get; }
}
}
}

@ -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<IAbpIdentityMongoDbContext, IdentitySecurityLog, Guid>, IIdentitySecurityLogRepository
{
public MongoIdentitySecurityLogRepository(IMongoDbContextProvider<IAbpIdentityMongoDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
public async Task<List<IdentitySecurityLog>> 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<IMongoQueryable<IdentitySecurityLog>>()
.PageBy<IdentitySecurityLog, IMongoQueryable<IdentitySecurityLog>>(skipCount, maxResultCount)
.ToListAsync(GetCancellationToken(cancellationToken));
}
public async Task<long> 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<IMongoQueryable<IdentitySecurityLog>>().LongCountAsync(GetCancellationToken(cancellationToken));
}
protected virtual IQueryable<IdentitySecurityLog> 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);
}
}
}

@ -0,0 +1,7 @@
namespace Volo.Abp.Identity.EntityFrameworkCore
{
public class IdentitySecurityLogRepository_Tests : IdentitySecurityLogRepository_Tests<AbpIdentityEntityFrameworkCoreTestModule>
{
}
}

@ -0,0 +1,10 @@
using Xunit;
namespace Volo.Abp.Identity.MongoDB
{
[Collection(MongoTestCollection.Name)]
public class IdentitySecurityLogRepository_Tests : IdentitySecurityLogRepository_Tests<AbpIdentityMongoDbTestModule>
{
}
}

@ -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)
}));
}
}
}
}

@ -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<TStartupModule> : AbpIdentityTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
protected IIdentitySecurityLogRepository RoleRepository { get; }
protected IdentityTestData TestData { get; }
protected IdentitySecurityLogRepository_Tests()
{
RoleRepository = GetRequiredService<IIdentitySecurityLogRepository>();
TestData = GetRequiredService<IdentityTestData>();
}
[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);
}
}
}
Loading…
Cancel
Save