Skip to content

Commit

Permalink
PAS-462 | BEEEP Migrate Access Denied to Blazor. (#600)
Browse files Browse the repository at this point in the history
  • Loading branch information
jonashendrickx authored Jun 5, 2024
1 parent 75b7715 commit 7b4faa4
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 36 deletions.
41 changes: 41 additions & 0 deletions src/AdminConsole/Components/Pages/Account/AccessDenied.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
@page "/Account/AccessDenied"

@using Microsoft.AspNetCore.Identity
@using Passwordless.AdminConsole.Identity
@using Passwordless.Common.Extensions

@inject IHttpContextAccessor HttpContextAccessor
@inject SignInManager<ConsoleAdmin> SignInManager

<Page Title="Access Denied">
<p>Oh, this shouldn't happen.</p>
<p>Sometimes it happens by mistake and you can <a class="link-blue" href="@ReturnUrl">try again</a>.</p>
</Page>

@code {
private string? _returnUrl;

[SupplyParameterFromQuery(Name = "ReturnUrl")]
public string? ReturnUrl
{
get => _returnUrl;
set
{
if (value != null && !value.IsLocalUrl())
{
_returnUrl = null;
}
else
{
_returnUrl = value;
}
}
}

protected override async Task OnInitializedAsync()
{
var claimsPrincipal = HttpContextAccessor.HttpContext!.User;
var user = await SignInManager.UserManager.GetUserAsync(claimsPrincipal);
await SignInManager.RefreshSignInAsync(user);
}
}
9 changes: 0 additions & 9 deletions src/AdminConsole/Pages/Account/AccessDenied.cshtml

This file was deleted.

27 changes: 0 additions & 27 deletions src/AdminConsole/Pages/Account/AccessDenied.cshtml.cs

This file was deleted.

64 changes: 64 additions & 0 deletions src/Common/Extensions/UrlExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
namespace Passwordless.Common.Extensions;

public static class UrlExtensions
{
public static bool IsLocalUrl(this string url)
{
if (url.Length == 0)
{
return false;
}
// Allows "/" or "/foo" but not "//" or "/\".
if (url[0] == '/')
{
// url is exactly "/"
if (url.Length == 1)
{
return true;
}

// url doesn't start with "//" or "/\"
if (url[1] != '/' && url[1] != '\\')
{
return !HasControlCharacter(url.AsSpan(1));
}

return false;
}

// Allows "~/" or "~/foo" but not "~//" or "~/\".
if (url[0] == '~' && url.Length > 1 && url[1] == '/')
{
// url is exactly "~/"
if (url.Length == 2)
{
return true;
}

// url doesn't start with "~//" or "~/\"
if (url[2] != '/' && url[2] != '\\')
{
return !HasControlCharacter(url.AsSpan(2));
}

return false;
}

return false;

static bool HasControlCharacter(ReadOnlySpan<char> readOnlySpan)
{
// URLs may not contain ASCII control characters.
for (var i = 0; i < readOnlySpan.Length; i++)
{
if (char.IsControl(readOnlySpan[i]))
{
return true;
}
}

return false;
}
}

}
136 changes: 136 additions & 0 deletions tests/Common.Tests/Extensions/UrlExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
using Passwordless.Common.Extensions;

namespace Passwordless.Common.Tests.Extensions;

public class UrlExtensionsTests
{
[Fact]
public void IsLocalUrl_GivenUrl_WhenUrlIsEmpty_ThenShouldReturnFalse()
{
// Arrange
var sut = string.Empty;

// Act
var actual = sut.IsLocalUrl();

// Assert
Assert.False(actual);
}

[Fact]
public void IsLocalUrl_GivenUrl_WhenUrlIsSlash_ThenShouldReturnTrue()
{
// Arrange
var sut = "/";

// Act
var actual = sut.IsLocalUrl();

// Assert
Assert.True(actual);
}

[Fact]
public void IsLocalUrl_GivenUrl_WhenUrlIsSlashFoo_ThenShouldReturnTrue()
{
// Arrange
var sut = "/foo";

// Act
var actual = sut.IsLocalUrl();

// Assert
Assert.True(actual);
}

[Fact]
public void IsLocalUrl_GivenUrl_WhenUrlIsDoubleSlash_ThenShouldReturnFalse()
{
// Arrange
var sut = "//";

// Act
var actual = sut.IsLocalUrl();

// Assert
Assert.False(actual);
}

[Fact]
public void IsLocalUrl_GivenUrl_WhenUrlIsSlashBackslash_ThenShouldReturnFalse()
{
// Arrange
var sut = "/\\";

// Act
var actual = sut.IsLocalUrl();

// Assert
Assert.False(actual);
}

[Fact]
public void IsLocalUrl_GivenUrl_WhenUrlIsTildeSlash_ThenShouldReturnTrue()
{
// Arrange
var sut = "~/";

// Act
var actual = sut.IsLocalUrl();

// Assert
Assert.True(actual);
}

[Fact]
public void IsLocalUrl_GivenUrl_WhenUrlIsTildeSlashFoo_ThenShouldReturnTrue()
{
// Arrange
var sut = "~/foo";

// Act
var actual = sut.IsLocalUrl();

// Assert
Assert.True(actual);
}

[Fact]
public void IsLocalUrl_GivenUrl_WhenUrlIsTildeDoubleSlash_ThenShouldReturnFalse()
{
// Arrange
var sut = "~//";

// Act
var actual = sut.IsLocalUrl();

// Assert
Assert.False(actual);
}

[Fact]
public void IsLocalUrl_GivenUrl_WhenUrlIsTildeBackslash_ThenShouldReturnFalse()
{
// Arrange
var sut = "~/\\";

// Act
var actual = sut.IsLocalUrl();

// Assert
Assert.False(actual);
}

[Fact]
public void IsLocalUrl_GivenUrl_WhenUrlContainsControlCharacter_ThenShouldReturnFalse()
{
// Arrange
var sut = "/\u0001";

// Act
var actual = sut.IsLocalUrl();

// Assert
Assert.False(actual);
}
}

0 comments on commit 7b4faa4

Please sign in to comment.