-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Allow IgnoreAntiForgeryToken applied on Razor Page models to work #7907
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good but does this actually fix the original #7795? That bug was about [IgnoreAntiforgeryToken]
on handler methods, not the overall page model. (Discussion of how to apply the attribute at the page model level diverted the discussion.)
At least need a test involving the attribute on page handlers.
@@ -189,7 +189,7 @@ public AuthorizeFilter(string policy) | |||
var authenticateResult = await policyEvaluator.AuthenticateAsync(effectivePolicy, context.HttpContext); | |||
|
|||
// Allow Anonymous skips all authorization | |||
if (context.Filters.Any(item => item is IAllowAnonymousFilter)) | |||
if (HasAllowAnonymous(context.Filters)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To confirm:
- The later
ToArray()
calls are the only thing preventing removal of the Linq dependency? - This change is just for perf and consistency and no behaviours change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is just for perf and consistency and no behaviours change?
Yup. I noticed this unnecessary Linq use when I was making a similar change to the Antiforgery filter.
var reader = new StringReader(htmlContent); | ||
var htmlDocument = XDocument.Load(reader); | ||
var parser = new HtmlParser(); | ||
var htmlDocument = parser.Parse(htmlContent); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This parser should handle implied CDATA elements e.g. <script>
and DTD declarations better than XDocument
. But, I'm curious if anything elsewhere in this PR broke the previous approach?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I backed out a couple of tests that passed the IHtmlDocument
in, but in general seems like the correct thing to use a Html parser to parse html.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. Just confirming.
|
||
var responseBody = await response.Content.ReadAsStringAsync(); | ||
var formToken = AntiforgeryTestHelper.RetrieveAntiforgeryToken(responseBody); | ||
var cookie = AntiforgeryTestHelper.RetrieveAntiforgeryCookie(response); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggest using fixture.CreateClient(...)
in this class to avoid need to manually copy the cookie over. CreateDefaultClient(...)
should be avoided unless specifically testing redirects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CreateDefaultClient(...) should be avoided unless specifically testing redirects.
We use it in all our functional tests. Leaving this code as is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We use it in all our functional tests
Not completely true -- we use both methods on a seemingly-random basis. Should move toward CreateClient()
in a similar fashion to moving to realz internal
classes.
|
||
public void OnPost() | ||
{ | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove these boilerplate methods.
|
||
public void OnPost() | ||
{ | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove these methods.
4f6782a
to
329f1c4
Compare
🆙 📅 |
|
||
private static bool HasAllowAnonymous(IList<IFilterMetadata> filters) | ||
{ | ||
for (var i = 0; i < filters.Count; i++) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is speed the main concern here to not use the following instead:
return filters.OfType<IAllowAnonymousFilter>().Any();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
filters.OfType<IAllowAnonymousFilter>().Any()
results in needless allocations, writing a bespoke code avoids this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with that, but then you have to do the same in the other place, where you used exactly that:) (the linq expression): https://github.com/aspnet/Mvc/pull/7907/files#diff-50e1233b5c1f8070fd737eac5239cea1R34
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mkArtakMSFT filters execute in every request. No need to optimize application model providers because they run just once.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh right. This one's part of the auth filter so it's on a hot path (runs per request for all actions with auth). The other one's an app model provider, which in production runs once for the lifetime of the application.
internal class AutoValidateAntiforgeryPageApplicationModelProvider : IPageApplicationModelProvider | ||
{ | ||
// The order is set to execute after the DefaultPageApplicationModelProvider. | ||
public int Order => -1000 + 10; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Relying on the hardcoded values for orders isn't good in terms of maintaining relative orders. Why won't we define constants (or static readonly
fields) to reference instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For one, this code was moved as is (I changed the namespace from .Internal
-> internal class
) which git really doesn't seem to track as a rename. That said, we only ever have one constant for all our providers - viz the default is -1000
. We really don't have any significant numbers outside of it. There really isn't a lot of value in turning that one digit in to a constant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please do not squash commits before the review is done. Good to see the updates as we go.
var reader = new StringReader(htmlContent); | ||
var htmlDocument = XDocument.Load(reader); | ||
var parser = new HtmlParser(); | ||
var htmlDocument = parser.Parse(htmlContent); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. Just confirming.
|
||
var responseBody = await response.Content.ReadAsStringAsync(); | ||
var formToken = AntiforgeryTestHelper.RetrieveAntiforgeryToken(responseBody); | ||
var cookie = AntiforgeryTestHelper.RetrieveAntiforgeryCookie(response); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We use it in all our functional tests
Not completely true -- we use both methods on a seemingly-random basis. Should move toward CreateClient()
in a similar fashion to moving to realz internal
classes.
Fixes #7795