Skip to content
This repository has been archived by the owner on Dec 14, 2018. It is now read-only.

Allow IgnoreAntiForgeryToken applied on Razor Page models to work #7907

Merged
merged 1 commit into from
Jun 13, 2018

Conversation

pranavkm
Copy link
Contributor

Fixes #7795

@pranavkm pranavkm requested a review from rynowak June 12, 2018 20:03
Copy link
Member

@dougbu dougbu left a 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))
Copy link
Member

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?

Copy link
Contributor Author

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);
Copy link
Member

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?

Copy link
Contributor Author

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.

Copy link
Member

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);
Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Member

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()
{
}
Copy link
Member

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()
{
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove these methods.

@pranavkm pranavkm force-pushed the prkrishn/auto-antiforgery branch from 4f6782a to 329f1c4 Compare June 13, 2018 17:20
@pranavkm
Copy link
Contributor Author

That bug was about [IgnoreAntiforgeryToken] on handler methods,

Spoke to @dougbu offline. We specifically do not support any filters on page handler methods. For 2.2.0, we added an analyzer that complains if you do: #7684

@pranavkm
Copy link
Contributor Author

🆙 📅


private static bool HasAllowAnonymous(IList<IFilterMetadata> filters)
{
for (var i = 0; i < filters.Count; i++)
Copy link
Member

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();

Copy link
Contributor Author

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.

Copy link
Member

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

Copy link
Member

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.

Copy link
Contributor Author

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;
Copy link
Member

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?

Copy link
Contributor Author

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.

Copy link
Member

@dougbu dougbu left a 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);
Copy link
Member

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);
Copy link
Member

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.

@pranavkm pranavkm merged commit 287a3c5 into dev Jun 13, 2018
@dougbu dougbu deleted the prkrishn/auto-antiforgery branch July 15, 2018 03:42
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants