Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 35 additions & 9 deletions src/Areas/Identity/Pages/Account/LogOut.cshtml
Original file line number Diff line number Diff line change
@@ -1,27 +1,53 @@
@page
@using NodeGuard.Data.Models
@using Microsoft.AspNetCore.Identity
@using NodeGuard.Services
@using NodeGuard.Helpers
@using System.Security.Claims
@attribute [IgnoreAntiforgeryToken]
@inject SignInManager<ApplicationUser> SignInManager
@inject IAuditService AuditService
@inject IHttpContextAccessor HttpContextAccessor
@functions {
public async Task<IActionResult> OnPost()
{
if (SignInManager.IsSignedIn(User))
{
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
var username = User.Identity?.Name;
await SignInManager.SignOutAsync();
await AuditService.LogAsync(
AuditActionType.Logout,
AuditEventType.Success,
AuditObjectType.User,
userId,
userId,
username,
HttpContextAccessor.HttpContext.GetClientIpAddress(),
new { Username = username });
}

return Redirect("~/");
}

public async Task<IActionResult> OnGet()
{
if (SignInManager.IsSignedIn(User))
{
await SignInManager.SignOutAsync();
}

return Redirect("~/");
}
public async Task<IActionResult> OnGet()
{
if (SignInManager.IsSignedIn(User))
{
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
var username = User.Identity?.Name;
await SignInManager.SignOutAsync();
await AuditService.LogAsync(
AuditActionType.Logout,
AuditEventType.Success,
AuditObjectType.User,
userId,
userId,
username,
HttpContextAccessor.HttpContext.GetClientIpAddress(),
new { Username = username });
}

return Redirect("~/");
}
}
36 changes: 35 additions & 1 deletion src/Areas/Identity/Pages/Account/Login.cshtml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,24 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using NodeGuard.Services;
using NodeGuard.Helpers;

namespace NodeGuard.Areas.Identity.Pages.Account
{
public class LoginModel : PageModel
{
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly ILogger<LoginModel> _logger;
private readonly IAuditService _auditService;
private readonly UserManager<ApplicationUser> _userManager;

public LoginModel(SignInManager<ApplicationUser> signInManager, ILogger<LoginModel> logger)
public LoginModel(SignInManager<ApplicationUser> signInManager, ILogger<LoginModel> logger, IAuditService auditService, UserManager<ApplicationUser> userManager)
{
_signInManager = signInManager;
_logger = logger;
_auditService = auditService;
_userManager = userManager;
}

/// <summary>
Expand Down Expand Up @@ -128,6 +134,16 @@ public async Task<IActionResult> OnPostAsync(string returnUrl = null)
if (result.Succeeded)
{
_logger.LogInformation("User logged in.");
var user = await _userManager.FindByNameAsync(Input.Username);
await _auditService.LogAsync(
AuditActionType.Login,
AuditEventType.Success,
AuditObjectType.User,
user?.Id,
user?.Id,
Input.Username,
HttpContext.GetClientIpAddress(),
new { Username = Input.Username });
return LocalRedirect(returnUrl);
}
if (result.RequiresTwoFactor)
Expand All @@ -137,10 +153,28 @@ public async Task<IActionResult> OnPostAsync(string returnUrl = null)
if (result.IsLockedOut)
{
_logger.LogWarning("User account locked out.");
await _auditService.LogAsync(
AuditActionType.Login,
AuditEventType.Failure,
AuditObjectType.User,
null,
null,
Input.Username,
HttpContext.GetClientIpAddress(),
new { Username = Input.Username, Reason = "Account locked out" });
return RedirectToPage("./Lockout");
}
else
{
await _auditService.LogAsync(
AuditActionType.Login,
AuditEventType.Failure,
AuditObjectType.User,
null,
null,
Input.Username,
HttpContext.GetClientIpAddress(),
new { Username = Input.Username, Reason = "Invalid credentials" });
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return Page();
}
Expand Down
34 changes: 33 additions & 1 deletion src/Areas/Identity/Pages/Account/LoginWith2fa.cshtml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Identity;
using NodeGuard.Services;
using NodeGuard.Helpers;

namespace NodeGuard.Areas.Identity.Pages.Account
{
Expand All @@ -15,15 +17,18 @@ public class LoginWith2faModel : PageModel
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly UserManager<ApplicationUser> _userManager;
private readonly ILogger<LoginWith2faModel> _logger;
private readonly IAuditService _auditService;

public LoginWith2faModel(
SignInManager<ApplicationUser> signInManager,
UserManager<ApplicationUser> userManager,
ILogger<LoginWith2faModel> logger)
ILogger<LoginWith2faModel> logger,
IAuditService auditService)
{
_signInManager = signInManager;
_userManager = userManager;
_logger = logger;
_auditService = auditService;
}

/// <summary>
Expand Down Expand Up @@ -109,16 +114,43 @@ public async Task<IActionResult> OnPostAsync(bool rememberMe, string returnUrl =
if (result.Succeeded)
{
_logger.LogInformation("User with ID '{UserId}' logged in with 2fa.", user.Id);
await _auditService.LogAsync(
AuditActionType.TwoFactorLogin,
AuditEventType.Success,
AuditObjectType.User,
userId,
userId,
user.UserName,
HttpContext.GetClientIpAddress(),
new { Username = user.UserName });
return LocalRedirect(returnUrl);
}
else if (result.IsLockedOut)
{
_logger.LogWarning("User with ID '{UserId}' account locked out.", user.Id);
await _auditService.LogAsync(
AuditActionType.TwoFactorLogin,
AuditEventType.Failure,
AuditObjectType.User,
userId,
userId,
user.UserName,
HttpContext.GetClientIpAddress(),
new { Username = user.UserName, Reason = "Account locked out" });
return RedirectToPage("./Lockout");
}
else
{
_logger.LogWarning("Invalid authenticator code entered for user with ID '{UserId}'.", user.Id);
await _auditService.LogAsync(
AuditActionType.TwoFactorLogin,
AuditEventType.Failure,
AuditObjectType.User,
userId,
userId,
user.UserName,
HttpContext.GetClientIpAddress(),
new { Username = user.UserName, Reason = "Invalid authenticator code" });
ModelState.AddModelError(string.Empty, "Invalid authenticator code.");
return Page();
}
Expand Down
14 changes: 13 additions & 1 deletion src/Areas/Identity/Pages/Account/Manage/Disable2fa.cshtml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,24 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using NodeGuard.Services;

namespace NodeGuard.Areas.Identity.Pages.Account.Manage
{
public class Disable2faModel : PageModel
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly ILogger<Disable2faModel> _logger;
private readonly IAuditService _auditService;

public Disable2faModel(
UserManager<ApplicationUser> userManager,
ILogger<Disable2faModel> logger)
ILogger<Disable2faModel> logger,
IAuditService auditService)
{
_userManager = userManager;
_logger = logger;
_auditService = auditService;
}

/// <summary>
Expand Down Expand Up @@ -63,6 +67,14 @@ public async Task<IActionResult> OnPostAsync()
}

_logger.LogInformation("User with ID '{UserId}' has disabled 2fa.", _userManager.GetUserId(User));

await _auditService.LogAsync(
AuditActionType.TwoFactorDisabled,
AuditEventType.Success,
AuditObjectType.User,
user.Id,
new { Username = user.UserName });

StatusMessage = "2fa has been disabled. You can reenable 2fa when you setup an authenticator app";
return RedirectToPage("./TwoFactorAuthentication");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using NodeGuard.Services;

namespace NodeGuard.Areas.Identity.Pages.Account.Manage
{
Expand All @@ -22,17 +23,20 @@ public class EnableAuthenticatorModel : PageModel
private readonly UserManager<ApplicationUser> _userManager;
private readonly ILogger<EnableAuthenticatorModel> _logger;
private readonly UrlEncoder _urlEncoder;
private readonly IAuditService _auditService;

private const string AuthenticatorUriFormat = "otpauth://totp/{0}:{1}?secret={2}&issuer={0}&digits=6";

public EnableAuthenticatorModel(
UserManager<ApplicationUser> userManager,
ILogger<EnableAuthenticatorModel> logger,
UrlEncoder urlEncoder)
UrlEncoder urlEncoder,
IAuditService auditService)
{
_userManager = userManager;
_logger = logger;
_urlEncoder = urlEncoder;
_auditService = auditService;
}

/// <summary>
Expand Down Expand Up @@ -129,6 +133,13 @@ public async Task<IActionResult> OnPostAsync()
var userId = await _userManager.GetUserIdAsync(user);
_logger.LogInformation("User with ID '{UserId}' has enabled 2FA with an authenticator app.", userId);

await _auditService.LogAsync(
AuditActionType.TwoFactorEnabled,
AuditEventType.Success,
AuditObjectType.User,
userId,
new { Username = user.UserName });

StatusMessage = "Your authenticator app has been verified.";

if (await _userManager.CountRecoveryCodesAsync(user) == 0)
Expand Down
2 changes: 2 additions & 0 deletions src/Data/ApplicationDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,5 +121,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
public DbSet<APIToken> ApiTokens { get; set; }

public DbSet<SwapOut> SwapOuts { get; set; }

public DbSet<AuditLog> AuditLogs { get; set; }
}
}
Loading
Loading