-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
PAS-462 | BEEEP Migrate
Access Denied
to Blazor. (#600)
- Loading branch information
1 parent
75b7715
commit 7b4faa4
Showing
5 changed files
with
241 additions
and
36 deletions.
There are no files selected for viewing
41 changes: 41 additions & 0 deletions
41
src/AdminConsole/Components/Pages/Account/AccessDenied.razor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |