Skip to content

Commit

Permalink
Updated the PageSecurityValidator with an edge case where pages with …
Browse files Browse the repository at this point in the history
…multiple attributes can be validated

(%release-note:

- Updated the PageSecurityValidator with an edge case where pages with AllowAnonymous attribute will be considered public regardless if they have Authorize attribute. This is due to how ASPNetCore globally applied page security work, it includes both Authorize and AllowAnonymouse attributes to the RouteEndpoint object of the page.

%)
  • Loading branch information
Farshad DASHTI authored and Farshad DASHTI committed Nov 4, 2024
1 parent 27472bd commit 6df5add
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public static IEnumerable<object[]> GetPageSecurityTestData(string jsonContent,
public static IEnumerable<object[]> GetPageSecurityTestDataFromFile(string configFilePath, IEnumerable<RouteEndpoint> endpoints, bool globalAuthorizationEnabled)
{
var jsonContent = File.ReadAllText(configFilePath);

return GetPageSecurityTestData(jsonContent, endpoints, globalAuthorizationEnabled);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,55 @@
using Microsoft.AspNetCore.Routing;

namespace DfE.CoreLibs.Testing.Authorization.Validators
{
{
public class PageSecurityValidator(RouteEndpoint endpoint, bool globalAuthorizationEnabled = false)
{
public ValidationResult ValidateSinglePageSecurity(string route, string expectedSecurity)
{
var hasAuthorizeMetadata = endpoint.Metadata.Any(m => m is AuthorizeAttribute);
var hasAllowAnonymousMetadata = endpoint.Metadata.Any(m => m is AllowAnonymousAttribute);
var authorizeAttributes = endpoint.Metadata.OfType<AuthorizeAttribute>().ToList();

if (globalAuthorizationEnabled)
{
if (expectedSecurity == "AllowAnonymous")
{
if (hasAuthorizeMetadata)
{
return ValidationResult.Failed($"Page {route} should be anonymous but is protected.");
}
}
else
{
if (!hasAuthorizeMetadata)
{
return ValidationResult.Failed($"Page {route} should be protected globally but has no Authorize attribute.");
}
}
if (globalAuthorizationEnabled && expectedSecurity != "AllowAnonymous" && !hasAuthorizeMetadata)
{
return ValidationResult.Failed($"Page {route} should be protected globally but has no Authorize attribute.");
}

if (expectedSecurity.StartsWith("Authorize"))
return expectedSecurity switch
{
var expectedRequirements = ValidatorHelper.ParseExpectedSecurity(expectedSecurity);
try
{
ValidatorHelper.ValidateAuthorizeAttributes(authorizeAttributes, route, expectedRequirements);
}
catch (Exception ex)
{
return ValidationResult.Failed(ex.Message);
}
}
"AllowAnonymous" => ValidateAllowAnonymousPage(route, hasAuthorizeMetadata, hasAllowAnonymousMetadata),
var security when security.StartsWith("Authorize") => ValidateAuthorizePage(route, authorizeAttributes, expectedSecurity, hasAllowAnonymousMetadata),
_ => ValidationResult.Success()
};
}

private static ValidationResult ValidateAllowAnonymousPage(string route, bool hasAuthorizeMetadata, bool hasAllowAnonymousMetadata)
{
// AllowAnonymous page checks
if (hasAllowAnonymousMetadata)
return ValidationResult.Success();

return hasAuthorizeMetadata
? ValidationResult.Failed($"Page {route} should be anonymous but is protected.")
: ValidationResult.Success();
}

return ValidationResult.Success();
private static ValidationResult ValidateAuthorizePage(string route, List<AuthorizeAttribute> authorizeAttributes, string expectedSecurity, bool hasAllowAnonymousMetadata)
{
if (hasAllowAnonymousMetadata)
return ValidationResult.Failed($"Page {route} should be protected but is anonymous.");

var expectedRequirements = ValidatorHelper.ParseExpectedSecurity(expectedSecurity);

try
{
ValidatorHelper.ValidateAuthorizeAttributes(authorizeAttributes, route, expectedRequirements);
return ValidationResult.Success();
}
catch (Exception ex)
{
return ValidationResult.Failed(ex.Message);
}
}
}
}

0 comments on commit 6df5add

Please sign in to comment.