mirror of https://github.com/abpframework/abp.git
29 changed files with 615 additions and 42 deletions
@ -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")); |
|||
} |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
@ -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> |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -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…
Reference in new issue