Skip to content

Commit

Permalink
Require email and password change checkboxes.
Browse files Browse the repository at this point in the history
Instead of locking accounts with temp mails we request them to change it!

Added password change too cause why not.
  • Loading branch information
VasilisThePikachu committed Jun 25, 2024
1 parent 7056467 commit 6ac37e5
Show file tree
Hide file tree
Showing 16 changed files with 1,890 additions and 15 deletions.
1,698 changes: 1,698 additions & 0 deletions SS14.Auth.Shared/Data/Migrations/20240625192927_email-pass-required.Designer.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace SS14.Auth.Shared.Data.Migrations
{
public partial class emailpassrequired : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "RequireEmailChange",
table: "AspNetUsers",
type: "boolean",
nullable: false,
defaultValue: false);

migrationBuilder.AddColumn<bool>(
name: "RequirePasswordChange",
table: "AspNetUsers",
type: "boolean",
nullable: false,
defaultValue: false);
}

protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "RequireEmailChange",
table: "AspNetUsers");

migrationBuilder.DropColumn(
name: "RequirePasswordChange",
table: "AspNetUsers");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1249,6 +1249,12 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<bool>("RequireEmailChange")
.HasColumnType("boolean");
b.Property<bool>("RequirePasswordChange")
.HasColumnType("boolean");
b.Property<string>("SecurityStamp")
.HasColumnType("text");
Expand Down
8 changes: 7 additions & 1 deletion SS14.Auth.Shared/Data/SpaceSignInManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ protected override async Task<SignInResult> PreSignInCheck(SpaceUser user)
if (user.AdminLocked)
return SpaceSignInResult.AdminLocked;

if (user.RequireEmailChange)
return SpaceSignInResult.RequireEmailChange;

if (user.RequirePasswordChange)
return SpaceSignInResult.RequirePasswordChange;

return await base.PreSignInCheck(user);
}
}
}
6 changes: 5 additions & 1 deletion SS14.Auth.Shared/Data/SpaceSignInResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ namespace SS14.Auth.Shared.Data;
public sealed class SpaceSignInResult : SignInResult
{
public bool IsAdminLocked { get; private set; }
public bool EmailChangeRequired { get; private set; }
public bool PasswordChangeRequired { get; private set; }

public static readonly SpaceSignInResult AdminLocked = new() { IsAdminLocked = true };
}
public static readonly SpaceSignInResult RequireEmailChange = new() { EmailChangeRequired = true };
public static readonly SpaceSignInResult RequirePasswordChange = new() { PasswordChangeRequired = true };
}
10 changes: 10 additions & 0 deletions SS14.Auth.Shared/Data/SpaceUser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ public class SpaceUser : IdentityUser<Guid>
/// </summary>
public bool AdminLocked { get; set; }

/// <summary>
/// Account requires an email change before being accessible again.
/// </summary>
public bool RequireEmailChange { get; set; }

/// <summary>
/// Account requires a password change before being accessible again.
/// </summary>
public bool RequirePasswordChange { get; set; }

/// <summary>
/// Note set by hub administrator.
/// </summary>
Expand Down
28 changes: 22 additions & 6 deletions SS14.Auth/Controllers/AuthApiController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,20 @@ public async Task<IActionResult> Authenticate(AuthenticateRequest request)
AuthenticateDenyResponseCode.AccountLocked));
}

if (signInResult is SpaceSignInResult { EmailChangeRequired: true })
{
return Unauthorized(new AuthenticateDenyResponse(
new[] { "Account requires a new email." },
AuthenticateDenyResponseCode.EmailChangeNeeded));
}

if (signInResult is SpaceSignInResult { PasswordChangeRequired: true })
{
return Unauthorized(new AuthenticateDenyResponse(
new[] { "Account requires a new password." },
AuthenticateDenyResponseCode.PasswdChangeNeeded));
}

if (!signInResult.Succeeded)
{
return Unauthorized(new AuthenticateDenyResponse(
Expand All @@ -113,22 +127,22 @@ public async Task<IActionResult> Authenticate(AuthenticateRequest request)
new[] { "" },
AuthenticateDenyResponseCode.TfaRequired));
}

var verify = await _userManager.VerifyTwoFactorTokenAsync(
user,
user,
_userManager.Options.Tokens.AuthenticatorTokenProvider,
request.TfaCode);

if (!verify)
{
return Unauthorized(new AuthenticateDenyResponse(
new[] { "" },
AuthenticateDenyResponseCode.TfaInvalid));
}

// 2FA passed, we're good.
}

var (token, expireTime) =
await _sessionManager.RegisterNewSession(user, SessionManager.DefaultExpireTime);

Expand Down Expand Up @@ -278,6 +292,8 @@ public enum AuthenticateDenyResponseCode
TfaRequired = 3,
TfaInvalid = 4,
AccountLocked = 5,
EmailChangeNeeded = 6,
PasswdChangeNeeded = 7,
// @formatter:on
}

Expand Down Expand Up @@ -317,4 +333,4 @@ public enum RegisterResponseStatus
{
Registered,
RegisteredNeedConfirmation
}
}
18 changes: 18 additions & 0 deletions SS14.Web/Areas/Admin/Pages/Users/ViewUser.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,24 @@
</div>
</div>

<div class="form-group row">
<div class="col-sm-10 offset-sm-2">
<div class="form-check">
<input asp-for="Input.RequireEmailChange" class="form-check-input"/>
<label asp-for="Input.RequireEmailChange" class="form-check-label"></label>
</div>
</div>
</div>

<div class="form-group row">
<div class="col-sm-10 offset-sm-2">
<div class="form-check">
<input asp-for="Input.RequirePasswordChange" class="form-check-input"/>
<label asp-for="Input.RequirePasswordChange" class="form-check-label"></label>
</div>
</div>
</div>

<div class="form-group row">
<label asp-for="Input.AdminNotes" class="col-sm-2 col-form-label"></label>
<textarea asp-for="Input.AdminNotes" class="form-control col-sm-10"></textarea>
Expand Down
20 changes: 20 additions & 0 deletions SS14.Web/Areas/Admin/Pages/Users/ViewUser.cshtml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ public class InputModel
[Display(Name = "Locked?")]
public bool AdminLocked { get; set; }

[Display(Name = "Require Email change on next login?")]
public bool RequireEmailChange { get; set; }

[Display(Name = "Require Password change on next login?")]
public bool RequirePasswordChange { get; set; }

[Display(Name = "Administrative notes")]
public string AdminNotes { get; set; }
}
Expand Down Expand Up @@ -141,6 +147,18 @@ public async Task<IActionResult> OnPostSaveAsync(Guid id)
SpaceUser.AdminLocked = Input.AdminLocked;
}

if (SpaceUser.RequireEmailChange != Input.RequireEmailChange)
{
await _accountLogManager.Log(SpaceUser, new AccountLogAdminLockedChanged(Input.RequireEmailChange));
SpaceUser.RequireEmailChange = Input.RequireEmailChange;
}

if (SpaceUser.RequirePasswordChange != Input.RequirePasswordChange)
{
await _accountLogManager.Log(SpaceUser, new AccountLogAdminLockedChanged(Input.RequirePasswordChange));
SpaceUser.RequirePasswordChange = Input.RequirePasswordChange;
}

await CheckRole(Input.HubAdmin, AuthConstants.RoleSysAdmin);
await CheckRole(Input.ServerHubAdmin, AuthConstants.RoleServerHubAdmin);

Expand Down Expand Up @@ -237,6 +255,8 @@ private async Task LoadAsync()
ServerHubAdmin = await _userManager.IsInRoleAsync(SpaceUser, AuthConstants.RoleServerHubAdmin),
TfaEnabled = SpaceUser.TwoFactorEnabled,
AdminLocked = SpaceUser.AdminLocked,
RequireEmailChange = SpaceUser.RequireEmailChange,
RequirePasswordChange = SpaceUser.RequirePasswordChange,
AdminNotes = SpaceUser.AdminNotes
};

Expand Down
11 changes: 11 additions & 0 deletions SS14.Web/Areas/Identity/Pages/Account/EmailChangeRequired.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@page
@using SS14.Web.Areas.Identity.Pages.Account
@model LockoutModel
@{
ViewData["Title"] = "Email change required";
}

<header>
<h1 class="text-danger">@ViewData["Title"]</h1>
<p class="text-danger">This account needs a new email to be set before you can use it again. Please change it below.</p>
</header>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace SS14.Web.Areas.Identity.Pages.Account;

[AllowAnonymous]
public class ForcedEmailChangeModel : PageModel
{
public void OnGet()
{

}
}
6 changes: 1 addition & 5 deletions SS14.Web/Areas/Identity/Pages/Account/Lockout.cshtml.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;

Expand All @@ -14,4 +10,4 @@ public void OnGet()
{

}
}
}
16 changes: 14 additions & 2 deletions SS14.Web/Areas/Identity/Pages/Account/Login.cshtml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public async Task OnGetAsync(string returnUrl = null)

ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();

ReturnUrl = returnUrl;
ReturnUrl = returnUrl;
}

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
Expand Down Expand Up @@ -106,6 +106,18 @@ public async Task<IActionResult> OnPostAsync(string returnUrl = null)
return RedirectToPage("./AdminLocked");
}

if (result is SpaceSignInResult { EmailChangeRequired: true })
{
_logger.LogWarning("User account needs an email change.");
return RedirectToPage("./EmailChangeRequired");
}

if (result is SpaceSignInResult { PasswordChangeRequired: true })
{
_logger.LogWarning("User account needs a password change.");
return RedirectToPage("./PasswordChangeRequired");
}

if (result.RequiresTwoFactor)
{
return RedirectToPage("./LoginWith2fa", new {ReturnUrl = returnUrl, RememberMe = Input.RememberMe});
Expand All @@ -123,4 +135,4 @@ public async Task<IActionResult> OnPostAsync(string returnUrl = null)

// If we got this far, something failed, redisplay form
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@page
@using SS14.Web.Areas.Identity.Pages.Account
@model LockoutModel
@{
ViewData["Title"] = "Password change required";
}

<header>
<h1 class="text-danger">@ViewData["Title"]</h1>
<p class="text-danger">This account needs a new password to be set before you can use it again. Please change it below.</p>
</header>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace SS14.Web.Areas.Identity.Pages.Account;

[AllowAnonymous]
public class ForcedPassChangeModel : PageModel
{
public void OnGet()
{

}
}
4 changes: 4 additions & 0 deletions SS14.Web/PersonalDataCollector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ private static void CollectAspNetUsers(ZipArchive archive, SpaceUser user)
user.TwoFactorEnabled,
user.NormalizedUserName,
user.AdminLocked,
user.RequirePasswordChange,
user.RequireEmailChange,
user.AdminNotes,
user.LastUsernameChange
),
Expand Down Expand Up @@ -199,6 +201,8 @@ private sealed record SpaceUserData(
bool TwoFactorEnabled,
string NormalizedUserName,
bool AdminLocked,
bool RequirePasswordChange,
bool RequireEmailChange,
string AdminNotes,
DateTimeOffset? LastUsernameChange);
}

0 comments on commit 6ac37e5

Please sign in to comment.