Skip to content

Commit

Permalink
Fix two factor enforcement.
Browse files Browse the repository at this point in the history
  • Loading branch information
bitbound committed May 31, 2024
1 parent b440aba commit 9ce6e01
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 31 deletions.
42 changes: 24 additions & 18 deletions Server/Auth/TwoFactorRequiredHandler.cs
Original file line number Diff line number Diff line change
@@ -1,31 +1,21 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Remotely.Server.Models;
using Remotely.Server.Services;
using Remotely.Shared.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Security.Principal;

namespace Remotely.Server.Auth;

public class TwoFactorRequiredHandler : AuthorizationHandler<TwoFactorRequiredRequirement>
public class TwoFactorRequiredHandler(
IHttpContextAccessor _contextAccessor,
IDataService _dataService) : AuthorizationHandler<TwoFactorRequiredRequirement>
{
private readonly IDataService _dataService;

public TwoFactorRequiredHandler(IDataService dataService)
{
_dataService = dataService;
}

protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, TwoFactorRequiredRequirement requirement)
{
var settings = await _dataService.GetSettings();
if (context.User.Identity?.IsAuthenticated == true &&
context.User.Identity.Name is not null &&
settings.Require2FA)
if (context.User?.Identity is { } identity &&
IsTwoFactorRequired(identity, settings))
{
var userResult = await _dataService.GetUserByName(context.User.Identity.Name);
var userResult = await _dataService.GetUserByName(identity.Name!);

if (!userResult.IsSuccess ||
!userResult.Value.TwoFactorEnabled)
Expand All @@ -36,4 +26,20 @@ context.User.Identity.Name is not null &&
}
context.Succeed(requirement);
}

private bool IsTwoFactorRequired(IIdentity identity, SettingsModel settings)
{
// Account management pages are exempt since they're required
// to set up 2FA.
var path = _contextAccessor.HttpContext?.Request.Path ?? "";
if (path.StartsWithSegments("/Account/Manage"))
{
return false;
}

return
settings.Require2FA &&
identity.IsAuthenticated &&
identity.Name is not null;
}
}
11 changes: 0 additions & 11 deletions Server/Components/AuthorizedIndex.razor
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,6 @@
@code {
private SettingsModel? _settings;

protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (User is not null &&
_settings?.Require2FA == true &&
!User.TwoFactorEnabled)
{
NavManager.NavigateTo("/TwoFactorRequired");
}
await base.OnAfterRenderAsync(firstRender);
}

protected override async Task OnInitializedAsync()
{
_settings = await DataService.GetSettings();
Expand Down
12 changes: 10 additions & 2 deletions Server/Components/Layout/MainLayout.razor
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
@using Remotely.Server.Components
@using Remotely.Server.Auth
@inherits LayoutComponentBase
@inject NavigationManager NavMan

<AuthorizeView Policy="@PolicyNames.TwoFactorRequired">
<Authorized>
Expand All @@ -25,7 +26,7 @@
<div class="col-sm-12">
<p>Two-factor authentication is required. Click the button below to set up your authenticator app.</p>
<p>
<a href="Account/Manage/TwoFactorAuthentication" class="btn btn-primary">Enable 2FA</a>
<button class="btn btn-primary" @onclick="NavigateToTwoFactor">Enable 2FA</button>
</p>
</div>
</div>
Expand All @@ -42,4 +43,11 @@

<ToastHarness />
<LoaderHarness />
<ModalHarness />
<ModalHarness />

@code {
private void NavigateToTwoFactor()
{
NavMan.NavigateTo("/Account/Manage/TwoFactorAuthentication", true);
}
}

0 comments on commit 9ce6e01

Please sign in to comment.