diff --git a/src/Application.Interfaces/Audits.Designer.cs b/src/Application.Interfaces/Audits.Designer.cs
index f262f831..e758f46a 100644
--- a/src/Application.Interfaces/Audits.Designer.cs
+++ b/src/Application.Interfaces/Audits.Designer.cs
@@ -59,6 +59,33 @@ internal Audits() {
}
}
+ ///
+ /// Looks up a localized string similar to CSRFProtection.Failed.
+ ///
+ public static string CSRFMiddleware_CSRFProtection_Failed {
+ get {
+ return ResourceManager.GetString("CSRFMiddleware_CSRFProtection_Failed", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to EndUser.PlatformFeatureAssigned.
+ ///
+ public static string EndUserApplication_PlatformFeatureAssigned {
+ get {
+ return ResourceManager.GetString("EndUserApplication_PlatformFeatureAssigned", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to EndUser.PlatformFeatureUnassigned.
+ ///
+ public static string EndUserApplication_PlatformFeatureUnassigned {
+ get {
+ return ResourceManager.GetString("EndUserApplication_PlatformFeatureUnassigned", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to EndUser.PlatformRolesAssigned.
///
@@ -77,6 +104,24 @@ public static string EndUserApplication_PlatformRolesUnassigned {
}
}
+ ///
+ /// Looks up a localized string similar to EndUser.TenantFeatureAssigned.
+ ///
+ public static string EndUserApplication_TenantFeatureAssigned {
+ get {
+ return ResourceManager.GetString("EndUserApplication_TenantFeatureAssigned", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to EndUser.TenantFeatureUnassigned.
+ ///
+ public static string EndUserApplication_TenantFeatureUnassigned {
+ get {
+ return ResourceManager.GetString("EndUserApplication_TenantFeatureUnassigned", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to EndUser.TenantRolesAssigned.
///
diff --git a/src/Application.Interfaces/Audits.resx b/src/Application.Interfaces/Audits.resx
index 47da3f3a..eb42dd23 100644
--- a/src/Application.Interfaces/Audits.resx
+++ b/src/Application.Interfaces/Audits.resx
@@ -63,4 +63,19 @@
Authentication.Passed
+
+ CSRFProtection.Failed
+
+
+ EndUser.PlatformFeatureAssigned
+
+
+ EndUser.PlatformFeatureUnassigned
+
+
+ EndUser.TenantFeatureAssigned
+
+
+ EndUser.TenantFeatureUnassigned
+
\ No newline at end of file
diff --git a/src/Application.Interfaces/UsageConstants.cs b/src/Application.Interfaces/UsageConstants.cs
index e370ad96..504032eb 100644
--- a/src/Application.Interfaces/UsageConstants.cs
+++ b/src/Application.Interfaces/UsageConstants.cs
@@ -14,7 +14,11 @@ public static class Components
public static class Properties
{
public const string AuditCode = "Code";
+ public const string AvatarUrl = "AvatarUrl";
public const string CallId = "CallId";
+ public const string CarMake = "Make";
+ public const string CarModel = "Model";
+ public const string CarYear = "Year";
public const string Component = "Component";
public const string Duration = "Duration";
public const string EmailAddress = "EmailAddress";
@@ -26,12 +30,15 @@ public static class Properties
public const string Id = "ResourceId";
public const string IpAddress = "IpAddress";
public const string MetricEventName = "Metric";
+ public const string Name = "Name";
public const string Path = "Path";
+ public const string UserIdOverride = "UserIdOverride";
public const string ReferredBy = "ReferredBy";
public const string ResourceId = "ResourceId";
public const string Started = "Started";
public const string TenantId = "TenantId";
public const string Timestamp = "Timestamp";
+ public const string Timezone = "Timezone";
public const string UsedById = "UserId";
public const string UserAgent = "UserAgent";
}
@@ -40,19 +47,29 @@ public static class Events
{
public static class UsageScenarios
{
- public const string Audit = "Audited";
- public const string BookingCancelled = "Booking Cancelled";
- public const string BookingCreated = "Booking Created";
- public const string GuestInvited = "User Guest Invited";
- public const string MachineRegistered = "Machine Registered";
- public const string Measurement = "Measured";
- public const string PersonRegistrationConfirmed = "User Registered";
- public const string PersonRegistrationCreated = "User Registration Created";
- public const string PersonReRegistered = "User Registration ReAttempted";
- public const string UserExtendedLogin = "User Extended Login";
- public const string UserLogin = "User Login";
- public const string UserLogout = "User Logout";
- public const string UserPasswordReset = "User Password Reset";
+ public static class Core
+ {
+ public const string BookingCancelled = "Booking Cancelled";
+ public const string BookingCreated = "Booking Created";
+ public const string CarRegistered = "Car Registered";
+ }
+
+ public static class Generic
+ {
+ public const string Audit = "Audited";
+ public const string GuestInvited = "User Guest Invited";
+ public const string MachineRegistered = "Machine Registered";
+ public const string Measurement = "Measured";
+ public const string PersonRegistrationConfirmed = "User Registered";
+ public const string PersonRegistrationCreated = "User Registration Created";
+ public const string PersonReRegistered = "User Registration ReAttempted";
+ public const string UserExtendedLogin = "User Extended Login";
+ public const string UserLogin = "User Login";
+ public const string UserLogout = "User Logout";
+ public const string UserPasswordForgotten = "User Password Forgotten";
+ public const string UserPasswordReset = "User Password Reset";
+ public const string UserProfileChanged = "User Profile Updated";
+ }
}
public static class Web
diff --git a/src/BookingsApplication/BookingsApplication.cs b/src/BookingsApplication/BookingsApplication.cs
index b656e6b1..d1674311 100644
--- a/src/BookingsApplication/BookingsApplication.cs
+++ b/src/BookingsApplication/BookingsApplication.cs
@@ -57,7 +57,7 @@ public async Task> CancelBookingAsync(ICallerContext caller, strin
}
_recorder.TraceInformation(caller.ToCall(), "Booking {Id} was cancelled", booking.Id);
- _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.BookingCancelled,
+ _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.Core.BookingCancelled,
new Dictionary
{
{ UsageConstants.Properties.Id, booking.Id },
@@ -112,7 +112,7 @@ public async Task> MakeBookingAsync(ICallerContext caller
booking = saved.Value;
_recorder.TraceInformation(caller.ToCall(), "Booking {Id} was created", booking.Id);
- _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.BookingCreated,
+ _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.Core.BookingCreated,
new Dictionary
{
{ UsageConstants.Properties.Id, booking.Id },
diff --git a/src/CarsApplication/CarsApplication.cs b/src/CarsApplication/CarsApplication.cs
index 45d22d3a..7aa0eda3 100644
--- a/src/CarsApplication/CarsApplication.cs
+++ b/src/CarsApplication/CarsApplication.cs
@@ -153,6 +153,14 @@ public async Task> RegisterCarAsync(ICallerContext caller, st
return saved.Match>(c =>
{
_recorder.TraceInformation(caller.ToCall(), "Car {Id} was registered", c.Value.Id);
+ _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.Core.CarRegistered,
+ new Dictionary
+ {
+ { UsageConstants.Properties.Id, car.Id },
+ { UsageConstants.Properties.CarMake, car.Manufacturer.Value.Make.Text },
+ { UsageConstants.Properties.CarModel, car.Manufacturer.Value.Model.Text },
+ { UsageConstants.Properties.CarYear, car.Manufacturer.Value.Year.Number }
+ });
return c.Value.ToCar();
}, error => error);
}
diff --git a/src/EndUsersApplication/EndUsersApplication.cs b/src/EndUsersApplication/EndUsersApplication.cs
index 5ef0f328..521025ce 100644
--- a/src/EndUsersApplication/EndUsersApplication.cs
+++ b/src/EndUsersApplication/EndUsersApplication.cs
@@ -151,7 +151,7 @@ public async Task> RegisterMachineAsync(ICaller
machine = saved.Value;
_recorder.TraceInformation(caller.ToCall(), "Registered machine: {Id}", machine.Id);
- _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.MachineRegistered);
+ _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.Generic.MachineRegistered);
if (caller.IsAuthenticated)
{
@@ -290,7 +290,7 @@ public async Task> RegisterPersonAsync(ICallerC
_recorder.TraceInformation(caller.ToCall(),
"Attempted re-registration of user: {Id}, with email {EmailAddress}", unregisteredUser.Id, email);
- _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.PersonReRegistered,
+ _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.Generic.PersonReRegistered,
new Dictionary
{
{ UsageConstants.Properties.Id, unregisteredUser.Id },
@@ -339,7 +339,7 @@ public async Task> RegisterPersonAsync(ICallerC
_recorder.AuditAgainst(caller.ToCall(), person.Id,
Audits.EndUsersApplication_User_Registered_TermsAccepted,
"EndUser {Id} accepted their terms and conditions", person.Id);
- _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.PersonRegistrationCreated);
+ _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.Generic.PersonRegistrationCreated);
var defaultOrganizationId = person.DefaultMembership.OrganizationId;
var serviceCaller = Caller.CreateAsMaintenance(caller.CallId);
diff --git a/src/EndUsersApplication/InvitationsApplication.cs b/src/EndUsersApplication/InvitationsApplication.cs
index 0b7a3063..4f1f6ac1 100644
--- a/src/EndUsersApplication/InvitationsApplication.cs
+++ b/src/EndUsersApplication/InvitationsApplication.cs
@@ -54,7 +54,7 @@ public async Task> InviteGuestAsync(ICallerContext cal
invitee = saved.Value;
_recorder.TraceInformation(caller.ToCall(), "Guest {Id} was invited", invitee.Id);
- _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.GuestInvited,
+ _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.Generic.GuestInvited,
new Dictionary
{
{ nameof(EndUserRoot.Id), invitee.Id },
@@ -103,7 +103,7 @@ public async Task> ResendGuestInvitationAsync(ICallerContext calle
}
_recorder.TraceInformation(caller.ToCall(), "Guest {Id} was re-invited", invitee.Id);
- _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.GuestInvited,
+ _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.Generic.GuestInvited,
new Dictionary
{
{ nameof(EndUserRoot.Id), invitee.Id },
diff --git a/src/IdentityApplication/PasswordCredentialsApplication.cs b/src/IdentityApplication/PasswordCredentialsApplication.cs
index 85a358ae..6fdd9d48 100644
--- a/src/IdentityApplication/PasswordCredentialsApplication.cs
+++ b/src/IdentityApplication/PasswordCredentialsApplication.cs
@@ -233,6 +233,11 @@ await _notificationsService.NotifyPasswordResetUnknownUserCourtesyAsync(caller,
credentials = saved.Value;
_recorder.TraceInformation(caller.ToCall(), "Password reset initiated for {Id}", credentials.UserId);
+ _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.Generic.UserPasswordForgotten,
+ new Dictionary
+ {
+ { nameof(PasswordCredential.Id), credentials.UserId }
+ });
return Result.Ok;
}
@@ -350,7 +355,7 @@ public async Task> CompletePasswordResetAsync(ICallerContext calle
credentials = saved.Value;
_recorder.TraceInformation(caller.ToCall(), "Password was reset for {Id}", credentials.UserId);
- _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.UserPasswordReset,
+ _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.Generic.UserPasswordReset,
new Dictionary
{
{ nameof(credentials.Id), credentials.UserId }
@@ -414,7 +419,7 @@ public async Task> ConfirmPersonRegistrationAsync(ICallerContext c
_recorder.TraceInformation(caller.ToCall(), "Password credentials for {UserId} have been verified",
credential.UserId);
_recorder.TrackUsage(caller.ToCall(),
- UsageConstants.Events.UsageScenarios.PersonRegistrationConfirmed,
+ UsageConstants.Events.UsageScenarios.Generic.PersonRegistrationConfirmed,
new Dictionary
{
{ nameof(credential.Id), credential.UserId }
diff --git a/src/Infrastructure.Hosting.Common/Recording/HostRecorder.cs b/src/Infrastructure.Hosting.Common/Recording/HostRecorder.cs
index 7d08dbbc..2525fcd3 100644
--- a/src/Infrastructure.Hosting.Common/Recording/HostRecorder.cs
+++ b/src/Infrastructure.Hosting.Common/Recording/HostRecorder.cs
@@ -164,7 +164,7 @@ public void AuditAgainst(ICallContext? context, string againstId, string auditCo
AugmentMessageTemplateAndArguments(context, $"Audit: {auditCode}, against {againstId}, {messageTemplate}",
templateArgs);
TraceInformation(safeContext, augmentedMessageTemplate, augmentedArguments);
- TrackUsageFor(safeContext, againstId, UsageConstants.Events.UsageScenarios.Audit,
+ TrackUsageFor(safeContext, againstId, UsageConstants.Events.UsageScenarios.Generic.Audit,
new Dictionary
{
{ UsageConstants.Properties.UsedById, againstId },
@@ -202,7 +202,7 @@ public void Measure(ICallContext? context, string eventName, Dictionary();
usageContext.Add(UsageConstants.Properties.MetricEventName, eventName.ToLowerInvariant());
- TrackUsage(safeContext, UsageConstants.Events.UsageScenarios.Measurement, usageContext);
+ TrackUsage(safeContext, UsageConstants.Events.UsageScenarios.Generic.Measurement, usageContext);
_metricsReporter.Measure(safeContext, eventName, additional ?? new Dictionary());
}
diff --git a/src/Infrastructure.Web.Hosting.Common.UnitTests/Pipeline/CSRFMiddlewareSpec.cs b/src/Infrastructure.Web.Hosting.Common.UnitTests/Pipeline/CSRFMiddlewareSpec.cs
index 8ef79305..16b623db 100644
--- a/src/Infrastructure.Web.Hosting.Common.UnitTests/Pipeline/CSRFMiddlewareSpec.cs
+++ b/src/Infrastructure.Web.Hosting.Common.UnitTests/Pipeline/CSRFMiddlewareSpec.cs
@@ -1,6 +1,7 @@
using System.IdentityModel.Tokens.Jwt;
using System.Net;
using System.Security.Claims;
+using Application.Interfaces;
using Application.Interfaces.Services;
using Common;
using Common.Extensions;
@@ -24,6 +25,7 @@ public class CSRFMiddlewareSpec
private readonly CSRFMiddleware _middleware;
private readonly Mock _next;
private readonly ServiceProvider _serviceProvider;
+ private readonly Mock _callerContextFactory;
public CSRFMiddlewareSpec()
{
@@ -40,6 +42,9 @@ public CSRFMiddlewareSpec()
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton(new LoggerFactory());
_serviceProvider = serviceCollection.BuildServiceProvider();
+ _callerContextFactory = new Mock();
+ _callerContextFactory.Setup(c => c.Create())
+ .Returns(Mock.Of(cc => cc.CallerId == "auserid"));
_middleware = new CSRFMiddleware(_next.Object, recorder.Object, _hostSettings.Object, _csrfService.Object);
}
@@ -52,7 +57,7 @@ public async Task WhenInvokeAsyncAndIsIgnoredMethod_ThenContinuesPipeline()
Request = { Method = HttpMethods.Get }
};
- await _middleware.InvokeAsync(context);
+ await _middleware.InvokeAsync(context, _callerContextFactory.Object);
_next.Verify(n => n.Invoke(context));
_csrfService.Verify(
@@ -66,7 +71,7 @@ public async Task WhenInvokeAsyncAndMissingHostName_ThenRespondsWithAProblem()
var context = SetupContext();
_hostSettings.Setup(s => s.GetWebsiteHostBaseUrl()).Returns("notauri");
- await _middleware.InvokeAsync(context);
+ await _middleware.InvokeAsync(context, _callerContextFactory.Object);
context.Response.Should().BeAProblem(HttpStatusCode.InternalServerError,
Resources.CSRFMiddleware_InvalidHostName.Format("notauri"));
@@ -78,7 +83,7 @@ public async Task WhenInvokeAsyncAndMissingCookie_ThenRespondsWithAProblem()
{
var context = SetupContext();
- await _middleware.InvokeAsync(context);
+ await _middleware.InvokeAsync(context, _callerContextFactory.Object);
context.Response.Should().BeAProblem(HttpStatusCode.Forbidden,
Resources.CSRFMiddleware_MissingCSRFCookieValue);
@@ -92,7 +97,7 @@ public async Task WhenInvokeAsyncAndMissingHeader_ThenRespondsWithAProblem()
context.Request.Cookies = SetupCookies(new Dictionary
{ { CSRFConstants.Cookies.AntiCSRF, "ananticsrfcookie" } });
- await _middleware.InvokeAsync(context);
+ await _middleware.InvokeAsync(context, _callerContextFactory.Object);
context.Response.Should().BeAProblem(HttpStatusCode.Forbidden,
Resources.CSRFMiddleware_MissingCSRFHeaderValue);
@@ -110,7 +115,7 @@ public async Task WhenInvokeAsyncAndAuthTokenIsInvalid_ThenRespondsWithAProblem(
});
context.Request.Headers.Append(CSRFConstants.Headers.AntiCSRF, new StringValues("ananticsrfheader"));
- await _middleware.InvokeAsync(context);
+ await _middleware.InvokeAsync(context, _callerContextFactory.Object);
context.Response.Should().BeAProblem(HttpStatusCode.Forbidden,
Resources.CSRFMiddleware_InvalidToken);
@@ -131,7 +136,7 @@ public async Task WhenInvokeAsyncAndTokenNotContainUserIdClaim_ThenRespondsWithA
});
context.Request.Headers.Append(CSRFConstants.Headers.AntiCSRF, new StringValues("ananticsrfheader"));
- await _middleware.InvokeAsync(context);
+ await _middleware.InvokeAsync(context, _callerContextFactory.Object);
context.Response.Should().BeAProblem(HttpStatusCode.Forbidden,
Resources.CSRFMiddleware_InvalidToken);
@@ -152,7 +157,7 @@ public async Task WhenInvokeAsyncAndTokensNotVerifiedForNoUser_ThenRespondsWithA
It.IsAny>()))
.Returns(false);
- await _middleware.InvokeAsync(context);
+ await _middleware.InvokeAsync(context, _callerContextFactory.Object);
context.Response.Should().BeAProblem(HttpStatusCode.Forbidden,
Resources.CSRFMiddleware_InvalidSignature.Format(nameof(Optional.None)));
@@ -181,7 +186,7 @@ public async Task WhenInvokeAsyncAndTokensNotVerifiedForUser_ThenRespondsWithAPr
It.IsAny>()))
.Returns(false);
- await _middleware.InvokeAsync(context);
+ await _middleware.InvokeAsync(context, _callerContextFactory.Object);
context.Response.Should().BeAProblem(HttpStatusCode.Forbidden,
Resources.CSRFMiddleware_InvalidSignature.Format("auserid"));
@@ -212,7 +217,7 @@ public async Task WhenInvokeAsyncAndTokensIsVerifiedButNoOriginAndNoReferer_Then
It.IsAny>()))
.Returns(true);
- await _middleware.InvokeAsync(context);
+ await _middleware.InvokeAsync(context, _callerContextFactory.Object);
context.Response.Should().BeAProblem(HttpStatusCode.Forbidden,
Resources.CSRFMiddleware_MissingOriginAndReferer);
@@ -243,7 +248,7 @@ public async Task WhenInvokeAsyncAndTokensIsVerifiedButOriginNotHost_ThenRespond
It.IsAny>()))
.Returns(true);
- await _middleware.InvokeAsync(context);
+ await _middleware.InvokeAsync(context, _callerContextFactory.Object);
context.Response.Should().BeAProblem(HttpStatusCode.Forbidden,
Resources.CSRFMiddleware_OriginMismatched);
@@ -274,7 +279,7 @@ public async Task WhenInvokeAsyncAndTokensIsVerifiedButRefererNotHost_ThenRespon
It.IsAny>()))
.Returns(true);
- await _middleware.InvokeAsync(context);
+ await _middleware.InvokeAsync(context, _callerContextFactory.Object);
context.Response.Should().BeAProblem(HttpStatusCode.Forbidden,
Resources.CSRFMiddleware_RefererMismatched);
@@ -305,7 +310,7 @@ public async Task WhenInvokeAsyncAndTokensIsVerifiedAndOriginIsHostForUser_ThenC
It.IsAny>()))
.Returns(true);
- await _middleware.InvokeAsync(context);
+ await _middleware.InvokeAsync(context, _callerContextFactory.Object);
context.Response.Should().NotBeAProblem();
_csrfService.Setup(crs => crs.VerifyTokens("ananticsrfheader", "ananticsrfcookie", "auserid"))
@@ -335,7 +340,7 @@ public async Task WhenInvokeAsyncAndTokensIsVerifiedAndRefererIsHostForUser_Then
It.IsAny>()))
.Returns(true);
- await _middleware.InvokeAsync(context);
+ await _middleware.InvokeAsync(context, _callerContextFactory.Object);
context.Response.Should().NotBeAProblem();
_csrfService.Setup(crs => crs.VerifyTokens("ananticsrfheader", "ananticsrfcookie", "auserid"))
@@ -358,7 +363,7 @@ public async Task WhenInvokeAsyncAndTokensIsVerifiedAndOriginIsHostForNoUser_The
It.IsAny>()))
.Returns(true);
- await _middleware.InvokeAsync(context);
+ await _middleware.InvokeAsync(context, _callerContextFactory.Object);
context.Response.Should().NotBeAProblem();
_csrfService.Setup(crs => crs.VerifyTokens("ananticsrfheader", "ananticsrfcookie", Optional.None))
@@ -381,7 +386,7 @@ public async Task WhenInvokeAsyncAndTokensIsVerifiedAndRefererIsHostForNoUser_Th
It.IsAny>()))
.Returns(true);
- await _middleware.InvokeAsync(context);
+ await _middleware.InvokeAsync(context, _callerContextFactory.Object);
context.Response.Should().NotBeAProblem();
_csrfService.Setup(crs => crs.VerifyTokens("ananticsrfheader", "ananticsrfcookie", Optional.None))
diff --git a/src/Infrastructure.Web.Hosting.Common/Pipeline/CSRFMiddleware.cs b/src/Infrastructure.Web.Hosting.Common/Pipeline/CSRFMiddleware.cs
index 5f0afddd..eea9072d 100644
--- a/src/Infrastructure.Web.Hosting.Common/Pipeline/CSRFMiddleware.cs
+++ b/src/Infrastructure.Web.Hosting.Common/Pipeline/CSRFMiddleware.cs
@@ -1,6 +1,9 @@
+using Application.Common.Extensions;
+using Application.Interfaces;
using Application.Interfaces.Services;
using Common;
using Common.Extensions;
+using Infrastructure.Interfaces;
using Infrastructure.Web.Api.Common;
using Infrastructure.Web.Api.Common.Extensions;
using Infrastructure.Web.Hosting.Common.Extensions;
@@ -37,8 +40,9 @@ public CSRFMiddleware(RequestDelegate next, IRecorder recorder, IHostSettings ho
_csrfService = csrfService;
}
- public async Task InvokeAsync(HttpContext context)
+ public async Task InvokeAsync(HttpContext context, ICallerContextFactory callerContextFactory)
{
+ var caller = callerContextFactory.Create();
var request = context.Request;
if (IgnoredMethods.Contains(request.Method))
{
@@ -51,6 +55,8 @@ public async Task InvokeAsync(HttpContext context)
{
var httpError = result.Error.ToHttpError();
var details = Results.Problem(statusCode: (int)httpError.Code, detail: httpError.Message);
+ _recorder.Audit(caller.ToCall(), Audits.CSRFMiddleware_CSRFProtection_Failed,
+ "User {Id} failed CSRF protection", caller.CallerId);
await details
.ExecuteAsync(context);
return;
diff --git a/src/Infrastructure.Web.Website.UnitTests/Application/AuthenticationApplicationSpec.cs b/src/Infrastructure.Web.Website.UnitTests/Application/AuthenticationApplicationSpec.cs
index 69d3684e..97a1a39b 100644
--- a/src/Infrastructure.Web.Website.UnitTests/Application/AuthenticationApplicationSpec.cs
+++ b/src/Infrastructure.Web.Website.UnitTests/Application/AuthenticationApplicationSpec.cs
@@ -37,7 +37,7 @@ public async Task WhenLogout_ThenLogsOut()
result.Should().BeSuccess();
_recorder.Verify(rec =>
- rec.TrackUsage(It.IsAny(), UsageConstants.Events.UsageScenarios.UserLogout, null));
+ rec.TrackUsage(It.IsAny(), UsageConstants.Events.UsageScenarios.Generic.UserLogout, null));
}
[Fact]
@@ -78,7 +78,7 @@ public async Task WhenAuthenticateWithCredentials_ThenAuthenticates()
&& req.Password == "apassword"
), null, It.IsAny()));
_recorder.Verify(rec =>
- rec.TrackUsage(It.IsAny(), UsageConstants.Events.UsageScenarios.UserLogin, null));
+ rec.TrackUsage(It.IsAny(), UsageConstants.Events.UsageScenarios.Generic.UserLogin, null));
}
[Fact]
@@ -118,7 +118,7 @@ public async Task WhenAuthenticateWithSingleSignOn_ThenAuthenticates()
req.AuthCode == "anauthcode"
), null, It.IsAny()));
_recorder.Verify(rec =>
- rec.TrackUsage(It.IsAny(), UsageConstants.Events.UsageScenarios.UserLogin, null));
+ rec.TrackUsage(It.IsAny(), UsageConstants.Events.UsageScenarios.Generic.UserLogin, null));
}
[Fact]
@@ -172,6 +172,7 @@ public async Task WhenRefreshTokenCookieExists_ThenRefreshesAndSetsCookie()
req.RefreshToken == "arefreshtoken"
), null, It.IsAny()));
_recorder.Verify(rec =>
- rec.TrackUsage(It.IsAny(), UsageConstants.Events.UsageScenarios.UserExtendedLogin, null));
+ rec.TrackUsage(It.IsAny(), UsageConstants.Events.UsageScenarios.Generic.UserExtendedLogin,
+ null));
}
}
\ No newline at end of file
diff --git a/src/UserProfilesApplication/UserProfilesApplication.cs b/src/UserProfilesApplication/UserProfilesApplication.cs
index 7c014f86..b10759bc 100644
--- a/src/UserProfilesApplication/UserProfilesApplication.cs
+++ b/src/UserProfilesApplication/UserProfilesApplication.cs
@@ -63,6 +63,8 @@ public async Task> ChangeProfileAvatarAsync(ICallerCo
profile = saved.Value;
_recorder.TraceInformation(caller.ToCall(), "Profile {Id} avatar was added for user {UserId}", profile.Id,
userId);
+ _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.Generic.UserProfileChanged,
+ profile.ToUsageEvent(caller));
return profile.ToProfile();
}
@@ -103,6 +105,8 @@ public async Task> DeleteProfileAvatarAsync(ICallerCo
profile = saved.Value;
_recorder.TraceInformation(caller.ToCall(), "Profile {Id} avatar was deleted for user {UserId}", profile.Id,
userId);
+ _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.Generic.UserProfileChanged,
+ profile.ToUsageEvent(caller));
return profile.ToProfile();
}
@@ -293,6 +297,8 @@ public async Task> ChangeProfileAsync(ICallerContext
profile = saved.Value;
_recorder.TraceInformation(caller.ToCall(), "Profile {Id} was updated for user {UserId}", profile.Id,
profile.UserId);
+ _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.Generic.UserProfileChanged,
+ profile.ToUsageEvent(caller));
return profile.ToProfile();
}
@@ -348,6 +354,8 @@ public async Task> ChangeContactAddressAsync(ICallerC
profile = saved.Value;
_recorder.TraceInformation(caller.ToCall(), "Profile {Id} contact address was updated for user {UserId}",
profile.Id, userId);
+ _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.Generic.UserProfileChanged,
+ profile.ToUsageEvent(caller));
return profile.ToProfile();
}
@@ -436,6 +444,27 @@ public static UserProfile ToProfile(this UserProfileRoot profile)
};
}
+ public static Dictionary ToUsageEvent(this UserProfileRoot profile, ICallerContext caller)
+ {
+ var context = new Dictionary
+ {
+ [UsageConstants.Properties.UserIdOverride] = profile.UserId,
+ [UsageConstants.Properties.Name] = profile.Name.ToName(),
+ [UsageConstants.Properties.Timezone] = profile.Timezone.Code.ToString()
+ };
+ if (profile.EmailAddress.HasValue)
+ {
+ context[UsageConstants.Properties.EmailAddress] = profile.EmailAddress.Value.Address;
+ }
+
+ if (profile.Avatar.HasValue)
+ {
+ context[UsageConstants.Properties.AvatarUrl] = profile.Avatar.Value.Url;
+ }
+
+ return context;
+ }
+
private static ProfileAddress ToAddress(this Address address)
{
var dto = address.Convert();
diff --git a/src/WebsiteHost/Application/AuthenticationApplication.cs b/src/WebsiteHost/Application/AuthenticationApplication.cs
index 360d1f50..36fb334d 100644
--- a/src/WebsiteHost/Application/AuthenticationApplication.cs
+++ b/src/WebsiteHost/Application/AuthenticationApplication.cs
@@ -50,14 +50,14 @@ public async Task> AuthenticateAsync(ICallerCo
return authenticated.Error.ToError();
}
- _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.UserLogin);
+ _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.Generic.UserLogin);
return authenticated.Value.ToTokens();
}
public Task> LogoutAsync(ICallerContext caller, CancellationToken cancellationToken)
{
- _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.UserLogout);
+ _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.Generic.UserLogout);
return Task.FromResult(Result.Ok);
}
@@ -79,7 +79,7 @@ public async Task> RefreshTokenAsync(ICallerCo
return refreshed.Error.ToError();
}
- _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.UserExtendedLogin);
+ _recorder.TrackUsage(caller.ToCall(), UsageConstants.Events.UsageScenarios.Generic.UserExtendedLogin);
return refreshed.Value.ToTokens();
}