Skip to content

Commit

Permalink
Merge pull request #10570 from abpframework/maliming/AbpAuditHubFilter
Browse files Browse the repository at this point in the history
Fix audit issues in Blazor Server.
  • Loading branch information
hikalkan committed Nov 11, 2021
2 parents 49e821a + c0206ba commit d408fa0
Show file tree
Hide file tree
Showing 9 changed files with 249 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Auditing;
using Volo.Abp.AspNetCore.SignalR.Auditing;
using Volo.Abp.AspNetCore.SignalR.Authentication;
using Volo.Abp.Auditing;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Modularity;

Expand All @@ -34,7 +37,9 @@ public override void ConfigureServices(ServiceConfigurationContext context)
var routePatterns = new List<string> {"/signalr-hubs"};
var signalRServerBuilder = context.Services.AddSignalR(options =>
{
options.AddFilter<AbpSignalRHubFilter>();
options.AddFilter<AbpHubContextAccessorHubFilter>();
options.AddFilter<AbpAuthenticationHubFilter>();
options.AddFilter<AbpAuditHubFilter>();
});

context.Services.ExecutePreConfiguredActions(signalRServerBuilder);
Expand Down Expand Up @@ -75,6 +80,11 @@ public override void ConfigureServices(ServiceConfigurationContext context)
options.IgnoredUrls.AddIfNotContains(x => routePattern.StartsWith(x), () => routePattern);
}
});

Configure<AbpAuditingOptions>(options =>
{
options.Contributors.Add(new AspNetCoreSignalRAuditLogContributor());
});
}

private void AutoAddHubTypes(IServiceCollection services)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.AspNetCore.SignalR;

namespace Volo.Abp.AspNetCore.SignalR
{
public class AbpHubContext
{
public IServiceProvider ServiceProvider { get; }

public Hub Hub { get; }

public MethodInfo HubMethod { get; }

public IReadOnlyList<object> HubMethodArguments { get; }

public AbpHubContext(IServiceProvider serviceProvider, Hub hub, MethodInfo hubMethod, IReadOnlyList<object> hubMethodArguments)
{
ServiceProvider = serviceProvider;
Hub = hub;
HubMethod = hubMethod;
HubMethodArguments = hubMethodArguments;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.DependencyInjection;

namespace Volo.Abp.AspNetCore.SignalR
{
public class AbpHubContextAccessorHubFilter : IHubFilter
{
public virtual async ValueTask<object> InvokeMethodAsync(HubInvocationContext invocationContext, Func<HubInvocationContext, ValueTask<object>> next)
{
var hubContextAccessor = invocationContext.ServiceProvider.GetRequiredService<IAbpHubContextAccessor>();
using (hubContextAccessor.Change(new AbpHubContext(
invocationContext.ServiceProvider,
invocationContext.Hub,
invocationContext.HubMethod,
invocationContext.HubMethodArguments)))
{
return await next(invocationContext);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.Auditing;
using Volo.Abp.Uow;
using Volo.Abp.Users;

namespace Volo.Abp.AspNetCore.SignalR.Auditing
{
public class AbpAuditHubFilter : IHubFilter
{
public virtual async ValueTask<object> InvokeMethodAsync(HubInvocationContext invocationContext, Func<HubInvocationContext, ValueTask<object>> next)
{
var options = invocationContext.ServiceProvider.GetRequiredService<IOptions<AbpAuditingOptions>>().Value;
if (!options.IsEnabled)
{
return await next(invocationContext);
}

var hasError = false;
var auditingManager = invocationContext.ServiceProvider.GetRequiredService<IAuditingManager>();
using (var saveHandle = auditingManager.BeginScope())
{
Debug.Assert(auditingManager.Current != null);
object result;
try
{
result = await next(invocationContext);

if (auditingManager.Current.Log.Exceptions.Any())
{
hasError = true;
}
}
catch (Exception ex)
{
hasError = true;

if (!auditingManager.Current.Log.Exceptions.Contains(ex))
{
auditingManager.Current.Log.Exceptions.Add(ex);
}

throw;
}
finally
{
if (ShouldWriteAuditLog(invocationContext.ServiceProvider, hasError))
{
var unitOfWorkManager = invocationContext.ServiceProvider.GetRequiredService<IUnitOfWorkManager>();
if (unitOfWorkManager.Current != null)
{
await unitOfWorkManager.Current.SaveChangesAsync();
}

await saveHandle.SaveAsync();
}
}

return result;
}
}

private bool ShouldWriteAuditLog(IServiceProvider serviceProvider, bool hasError)
{
var options = serviceProvider.GetRequiredService<IOptions<AbpAuditingOptions>>().Value;
if (options.AlwaysLogOnException && hasError)
{
return true;
}

if (!options.IsEnabledForAnonymousUsers && !serviceProvider.GetRequiredService<ICurrentUser>().IsAuthenticated)
{
return false;
}

var auditingManager = serviceProvider.GetRequiredService<IAuditingManager>();
if (auditingManager.Current == null ||
auditingManager.Current.Log.Actions.IsNullOrEmpty())
{
return false;
}

return true;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System.Linq;
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;

namespace Volo.Abp.AspNetCore.SignalR.Auditing
{
public class AspNetCoreSignalRAuditLogContributor : AuditLogContributor, ITransientDependency
{
public ILogger<AspNetCoreSignalRAuditLogContributor> Logger { get; set; }

public AspNetCoreSignalRAuditLogContributor()
{
Logger = NullLogger<AspNetCoreSignalRAuditLogContributor>.Instance;
}

public override void PreContribute(AuditLogContributionContext context)
{
var hubContext = context.ServiceProvider.GetRequiredService<IAbpHubContextAccessor>().Context;
if (hubContext == null)
{
return;
}

var clientInfoProvider = context.ServiceProvider.GetRequiredService<IWebClientInfoProvider>();
if (context.AuditInfo.ClientIpAddress == null)
{
context.AuditInfo.ClientIpAddress = clientInfoProvider.ClientIpAddress;
}

if (context.AuditInfo.BrowserInfo == null)
{
context.AuditInfo.BrowserInfo = clientInfoProvider.BrowserInfo;
}

//TODO: context.AuditInfo.ClientName
}

public override void PostContribute(AuditLogContributionContext context)
{
var hubContext = context.ServiceProvider.GetRequiredService<IAbpHubContextAccessor>().Context;
if (hubContext == null)
{
return;
}

var firstAction = context.AuditInfo.Actions.FirstOrDefault();
context.AuditInfo.Url = firstAction?.ServiceName + "." + firstAction?.MethodName;
context.AuditInfo.HttpStatusCode = null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Security.Claims;

namespace Volo.Abp.AspNetCore.SignalR
namespace Volo.Abp.AspNetCore.SignalR.Authentication
{
public class AbpSignalRHubFilter : IHubFilter
public class AbpAuthenticationHubFilter : IHubFilter
{
public virtual async ValueTask<object> InvokeMethodAsync(HubInvocationContext invocationContext, Func<HubInvocationContext, ValueTask<object>> next)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Threading;
using Volo.Abp.DependencyInjection;

namespace Volo.Abp.AspNetCore.SignalR
{
public class DefaultAbpHubContextAccessor : IAbpHubContextAccessor, ISingletonDependency
{
public AbpHubContext Context => _currentHubContext.Value;

private readonly AsyncLocal<AbpHubContext> _currentHubContext = new AsyncLocal<AbpHubContext>();

public virtual IDisposable Change(AbpHubContext context)
{
var parent = Context;
_currentHubContext.Value = context;
return new DisposeAction(() =>
{
_currentHubContext.Value = parent;
});
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;

namespace Volo.Abp.AspNetCore.SignalR
{
public interface IAbpHubContextAccessor
{
AbpHubContext Context { get; }

IDisposable Change(AbpHubContext context);
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ public override void PreContribute(AuditLogContributionContext context)
return;
}

if (httpContext.WebSockets.IsWebSocketRequest)
{
return;
}

if (context.AuditInfo.HttpMethod == null)
{
context.AuditInfo.HttpMethod = httpContext.Request.Method;
Expand Down

0 comments on commit d408fa0

Please sign in to comment.