Merge pull request #8626 from dotnet-maestro-bot/merge/release/2.2-to-master
[automated] Merge branch 'release/2.2' => 'master'
This commit is contained in:
commit
79458c16fd
|
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Mvc.Core.Infrastructure;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A <see cref="BadRequestResult"/> used for antiforgery validation
|
||||||
|
/// failures. Use <see cref="IAntiforgeryValidationFailedResult"/> to
|
||||||
|
/// match for validation failures inside MVC result filters.
|
||||||
|
/// </summary>
|
||||||
|
public class AntiforgeryValidationFailedResult : BadRequestResult, IAntiforgeryValidationFailedResult
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Core.Infrastructure
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an <see cref="IActionResult"/> that is used when the
|
||||||
|
/// antiforgery validation failed. This can be matched inside MVC result
|
||||||
|
/// filters to process the validation failure.
|
||||||
|
/// </summary>
|
||||||
|
public interface IAntiforgeryValidationFailedResult : IActionResult
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|
@ -57,11 +57,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
{
|
{
|
||||||
foreach (var item in _razorFileSystem.EnumerateItems(_pagesOptions.RootDirectory))
|
foreach (var item in _razorFileSystem.EnumerateItems(_pagesOptions.RootDirectory))
|
||||||
{
|
{
|
||||||
if (!IsRouteable(item))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var relativePath = item.CombinedPath;
|
var relativePath = item.CombinedPath;
|
||||||
if (context.RouteModels.Any(m => string.Equals(relativePath, m.RelativePath, StringComparison.OrdinalIgnoreCase)))
|
if (context.RouteModels.Any(m => string.Equals(relativePath, m.RelativePath, StringComparison.OrdinalIgnoreCase)))
|
||||||
{
|
{
|
||||||
|
|
@ -99,11 +94,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
{
|
{
|
||||||
foreach (var item in _razorFileSystem.EnumerateItems(AreaRootDirectory))
|
foreach (var item in _razorFileSystem.EnumerateItems(AreaRootDirectory))
|
||||||
{
|
{
|
||||||
if (!IsRouteable(item))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var relativePath = item.CombinedPath;
|
var relativePath = item.CombinedPath;
|
||||||
if (context.RouteModels.Any(m => string.Equals(relativePath, m.RelativePath, StringComparison.OrdinalIgnoreCase)))
|
if (context.RouteModels.Any(m => string.Equals(relativePath, m.RelativePath, StringComparison.OrdinalIgnoreCase)))
|
||||||
{
|
{
|
||||||
|
|
@ -125,11 +115,5 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsRouteable(RazorProjectItem item)
|
|
||||||
{
|
|
||||||
// Pages like _ViewImports should not be routeable.
|
|
||||||
return !item.FileName.StartsWith("_", StringComparison.OrdinalIgnoreCase);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||||
catch (AntiforgeryValidationException exception)
|
catch (AntiforgeryValidationException exception)
|
||||||
{
|
{
|
||||||
_logger.AntiforgeryTokenInvalid(exception.Message, exception);
|
_logger.AntiforgeryTokenInvalid(exception.Message, exception);
|
||||||
context.Result = new BadRequestResult();
|
context.Result = new AntiforgeryValidationFailedResult();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Antiforgery;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
|
|
@ -175,5 +174,32 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
var pragmaValue = Assert.Single(response.Headers.Pragma.ToArray());
|
var pragmaValue = Assert.Single(response.Headers.Pragma.ToArray());
|
||||||
Assert.Equal("no-cache", pragmaValue.Name);
|
Assert.Equal("no-cache", pragmaValue.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task RequestWithoutAntiforgeryToken_SendsBadRequest()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Antiforgery/Login");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await Client.SendAsync(request);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task RequestWithoutAntiforgeryToken_ExecutesResultFilter()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Antiforgery/LoginWithRedirectResultFilter");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await Client.SendAsync(request);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
|
||||||
|
Assert.Equal("http://example.com/antiforgery-redirect", response.Headers.Location.AbsoluteUri);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -6,7 +6,6 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||||
using Microsoft.AspNetCore.Mvc.Razor;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
|
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Razor.Hosting;
|
using Microsoft.AspNetCore.Razor.Hosting;
|
||||||
|
|
@ -563,6 +562,57 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void OnProvidersExecuting_AllowsRazorFilesWithUnderscorePrefix()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var descriptors = new[]
|
||||||
|
{
|
||||||
|
CreateVersion_2_1_Descriptor("/Pages/_About.cshtml"),
|
||||||
|
CreateVersion_2_1_Descriptor("/Pages/Home.cshtml"),
|
||||||
|
};
|
||||||
|
|
||||||
|
var provider = CreateProvider(descriptors: descriptors);
|
||||||
|
var context = new PageRouteModelProviderContext();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
provider.OnProvidersExecuting(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Collection(
|
||||||
|
context.RouteModels,
|
||||||
|
result =>
|
||||||
|
{
|
||||||
|
Assert.Equal("/Pages/_About.cshtml", result.RelativePath);
|
||||||
|
Assert.Equal("/_About", result.ViewEnginePath);
|
||||||
|
Assert.Collection(
|
||||||
|
result.Selectors,
|
||||||
|
selector => Assert.Equal("_About", selector.AttributeRouteModel.Template));
|
||||||
|
Assert.Collection(
|
||||||
|
result.RouteValues.OrderBy(k => k.Key),
|
||||||
|
kvp =>
|
||||||
|
{
|
||||||
|
Assert.Equal("page", kvp.Key);
|
||||||
|
Assert.Equal("/_About", kvp.Value);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
result =>
|
||||||
|
{
|
||||||
|
Assert.Equal("/Pages/Home.cshtml", result.RelativePath);
|
||||||
|
Assert.Equal("/Home", result.ViewEnginePath);
|
||||||
|
Assert.Collection(
|
||||||
|
result.Selectors,
|
||||||
|
selector => Assert.Equal("Home", selector.AttributeRouteModel.Template));
|
||||||
|
Assert.Collection(
|
||||||
|
result.RouteValues.OrderBy(k => k.Key),
|
||||||
|
kvp =>
|
||||||
|
{
|
||||||
|
Assert.Equal("page", kvp.Key);
|
||||||
|
Assert.Equal("/Home", kvp.Value);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetRouteTemplate_ReturnsPathFromRazorPageAttribute()
|
public void GetRouteTemplate_ReturnsPathFromRazorPageAttribute()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
fileSystem.Add(new TestRazorProjectItem("/Areas/Products/Pages/Manage/Categories.cshtml", "@page"));
|
fileSystem.Add(new TestRazorProjectItem("/Areas/Products/Pages/Manage/Categories.cshtml", "@page"));
|
||||||
fileSystem.Add(new TestRazorProjectItem("/Areas/Products/Pages/Index.cshtml", "@page"));
|
fileSystem.Add(new TestRazorProjectItem("/Areas/Products/Pages/Index.cshtml", "@page"));
|
||||||
fileSystem.Add(new TestRazorProjectItem("/Areas/Products/Pages/List.cshtml", "@page \"{sortOrder?}\""));
|
fileSystem.Add(new TestRazorProjectItem("/Areas/Products/Pages/List.cshtml", "@page \"{sortOrder?}\""));
|
||||||
fileSystem.Add(new TestRazorProjectItem("/Areas/Products/Pages/_ViewStart.cshtml", "@page"));
|
fileSystem.Add(new TestRazorProjectItem("/Areas/Products/Pages/_Test.cshtml", "@page"));
|
||||||
|
|
||||||
var optionsManager = Options.Create(new RazorPagesOptions { AllowAreas = true });
|
var optionsManager = Options.Create(new RazorPagesOptions { AllowAreas = true });
|
||||||
var provider = new RazorProjectPageRouteModelProvider(fileSystem, optionsManager, NullLoggerFactory.Instance);
|
var provider = new RazorProjectPageRouteModelProvider(fileSystem, optionsManager, NullLoggerFactory.Instance);
|
||||||
|
|
@ -102,6 +102,24 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
model =>
|
model =>
|
||||||
|
{
|
||||||
|
Assert.Equal("/Areas/Products/Pages/_Test.cshtml", model.RelativePath);
|
||||||
|
Assert.Equal("/_Test", model.ViewEnginePath);
|
||||||
|
Assert.Collection(model.Selectors,
|
||||||
|
selector => Assert.Equal("Products/_Test", selector.AttributeRouteModel.Template));
|
||||||
|
Assert.Collection(model.RouteValues.OrderBy(k => k.Key),
|
||||||
|
kvp =>
|
||||||
|
{
|
||||||
|
Assert.Equal("area", kvp.Key);
|
||||||
|
Assert.Equal("Products", kvp.Value);
|
||||||
|
},
|
||||||
|
kvp =>
|
||||||
|
{
|
||||||
|
Assert.Equal("page", kvp.Key);
|
||||||
|
Assert.Equal("/_Test", kvp.Value);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
model =>
|
||||||
{
|
{
|
||||||
Assert.Equal("/Areas/Products/Pages/Manage/Categories.cshtml", model.RelativePath);
|
Assert.Equal("/Areas/Products/Pages/Manage/Categories.cshtml", model.RelativePath);
|
||||||
Assert.Equal("/Manage/Categories", model.ViewEnginePath);
|
Assert.Equal("/Manage/Categories", model.ViewEnginePath);
|
||||||
|
|
@ -272,37 +290,13 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void OnProvidersExecuting_SkipsPagesStartingWithUnderscore()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var fileSystem = new VirtualRazorProjectFileSystem();
|
|
||||||
fileSystem.Add(new TestRazorProjectItem("/Pages/Home.cshtml", "@page"));
|
|
||||||
fileSystem.Add(new TestRazorProjectItem("/Pages/_Layout.cshtml", "@page"));
|
|
||||||
|
|
||||||
var optionsManager = Options.Create(new RazorPagesOptions());
|
|
||||||
optionsManager.Value.RootDirectory = "/";
|
|
||||||
var provider = new RazorProjectPageRouteModelProvider(fileSystem, optionsManager, NullLoggerFactory.Instance);
|
|
||||||
var context = new PageRouteModelProviderContext();
|
|
||||||
|
|
||||||
// Act
|
|
||||||
provider.OnProvidersExecuting(context);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Collection(context.RouteModels,
|
|
||||||
model =>
|
|
||||||
{
|
|
||||||
Assert.Equal("/Pages/Home.cshtml", model.RelativePath);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void OnProvidersExecuting_DiscoversFilesUnderBasePath()
|
public void OnProvidersExecuting_DiscoversFilesUnderBasePath()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var fileSystem = new VirtualRazorProjectFileSystem();
|
var fileSystem = new VirtualRazorProjectFileSystem();
|
||||||
fileSystem.Add(new TestRazorProjectItem("/Pages/Index.cshtml", "@page"));
|
fileSystem.Add(new TestRazorProjectItem("/Pages/Index.cshtml", "@page"));
|
||||||
fileSystem.Add(new TestRazorProjectItem("/Pages/_Layout.cshtml", "@page"));
|
fileSystem.Add(new TestRazorProjectItem("/Pages/_Layout.cshtml", ""));
|
||||||
fileSystem.Add(new TestRazorProjectItem("/NotPages/Index.cshtml", "@page"));
|
fileSystem.Add(new TestRazorProjectItem("/NotPages/Index.cshtml", "@page"));
|
||||||
fileSystem.Add(new TestRazorProjectItem("/NotPages/_Layout.cshtml", "@page"));
|
fileSystem.Add(new TestRazorProjectItem("/NotPages/_Layout.cshtml", "@page"));
|
||||||
fileSystem.Add(new TestRazorProjectItem("/Index.cshtml", "@page"));
|
fileSystem.Add(new TestRazorProjectItem("/Index.cshtml", "@page"));
|
||||||
|
|
|
||||||
|
|
@ -73,5 +73,29 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||||
// Assert
|
// Assert
|
||||||
antiforgery.Verify(a => a.ValidateRequestAsync(It.IsAny<HttpContext>()), Times.Never());
|
antiforgery.Verify(a => a.ValidateRequestAsync(It.IsAny<HttpContext>()), Times.Never());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Filter_SetsFailureResult()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var antiforgery = new Mock<IAntiforgery>(MockBehavior.Strict);
|
||||||
|
antiforgery
|
||||||
|
.Setup(a => a.ValidateRequestAsync(It.IsAny<HttpContext>()))
|
||||||
|
.Throws(new AntiforgeryValidationException("Failed"))
|
||||||
|
.Verifiable();
|
||||||
|
|
||||||
|
var filter = new ValidateAntiforgeryTokenAuthorizationFilter(antiforgery.Object, NullLoggerFactory.Instance);
|
||||||
|
|
||||||
|
var actionContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor());
|
||||||
|
actionContext.HttpContext.Request.Method = "POST";
|
||||||
|
|
||||||
|
var context = new AuthorizationFilterContext(actionContext, new[] { filter });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await filter.OnAuthorizationAsync(context);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsType<AntiforgeryValidationFailedResult>(context.Result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using BasicWebSite.Filters;
|
||||||
using BasicWebSite.Models;
|
using BasicWebSite.Models;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
@ -39,6 +40,16 @@ namespace BasicWebSite.Controllers
|
||||||
return "OK";
|
return "OK";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// POST: /Antiforgery/LoginWithRedirectResultFilter
|
||||||
|
[HttpPost]
|
||||||
|
[AllowAnonymous]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
[TypeFilter(typeof(RedirectAntiforgeryValidationFailedResultFilter))]
|
||||||
|
public string LoginWithRedirectResultFilter(LoginViewModel model)
|
||||||
|
{
|
||||||
|
return "Ok";
|
||||||
|
}
|
||||||
|
|
||||||
// GET: /Antiforgery/FlushAsyncLogin
|
// GET: /Antiforgery/FlushAsyncLogin
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
public ActionResult FlushAsyncLogin(string returnUrl = null)
|
public ActionResult FlushAsyncLogin(string returnUrl = null)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Core.Infrastructure;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
|
||||||
|
namespace BasicWebSite.Filters
|
||||||
|
{
|
||||||
|
public class RedirectAntiforgeryValidationFailedResultFilter : IAlwaysRunResultFilter
|
||||||
|
{
|
||||||
|
public void OnResultExecuting(ResultExecutingContext context)
|
||||||
|
{
|
||||||
|
if (context.Result is IAntiforgeryValidationFailedResult result)
|
||||||
|
{
|
||||||
|
context.Result = new RedirectResult("http://example.com/antiforgery-redirect");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnResultExecuted(ResultExecutedContext context)
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue