Change FormTagHelper
to apply to all form tags.
#6156
Conversation
TagBuilder tagBuilder; | ||
if (Route == null) | ||
TagBuilder tagBuilder = null; | ||
if (Action == null && Controller == null && Route == null && _routeValues == null && Fragment == null && Area == null) |
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.
Will there ever be a case where _routeValues
is non-null but empty? What gets generated in that case?
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.
Yes, that could happen if a user did <form asp-all-route-data="new Dictionary<string, string>()">
. In that case the user is being explicit and providing attributes; we'd want to follow the normal FormTagHelper rendering path.
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.
Will look at a few more things later...
@@ -1,4 +1,4 @@ | |||
<html> | |||
<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.
Huh?
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.
No clue. :thuglife:
// null which is interpreted as true unless element includes an action attribute. | ||
services.AddMvc().InitializeTagHelper<FormTagHelper>((helper, _) => helper.Antiforgery = false); | ||
// Add MVC services to the services container. | ||
services.AddMvc(); |
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.
Undo this. The site is intentionally testing e2e behaviour with the Antiforgery
property set to false
.
<form></form> | ||
<form action="/HtmlGeneration_Home/Form" method="post"></form> | ||
<form><input name="__RequestVerificationToken" type="hidden" value="{0}" /></form> | ||
<form action="/HtmlGeneration_Home/Form" method="post"><input name="__RequestVerificationToken" type="hidden" value="{0}" /></form> |
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.
Amazed we only have two <form>
elements without attributes we recognized. That's sad.
metadataProvider: metadataProvider); | ||
var expectedPostContent = HtmlContentUtilities.HtmlContentToString( | ||
htmlGenerator.GenerateAntiforgery(viewContext), | ||
HtmlEncoder.Default); |
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.
de-indent
// Assert | ||
Assert.Empty(output.Attributes); | ||
Assert.Empty(output.PreContent.GetContent()); | ||
Assert.True(output.Content.GetContent().Length == 0); |
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.
Assert.Empty(output.Content.GetContent())
Assert.Empty(output.Attributes); | ||
Assert.Empty(output.PreContent.GetContent()); | ||
Assert.True(output.Content.GetContent().Length == 0); | ||
Assert.Equal(expectedPostContent, output.PostContent.GetContent()); |
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.
Why no confirmation that PreElement
and PostElement
remain empty?
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.
Just staying consistent with the other tests. I'll add though.
6c3ef52
to
b4b3151
Compare
🆙 📅 |
{ | ||
if (string.Equals(attribute.Name.LocalName, "action", StringComparison.OrdinalIgnoreCase)) |
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.
Agree confirming the action
attribute exists was useless. Nice your new tests found that 👍
#endif | ||
} | ||
|
||
|
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.
Blankety Blank Blank?
@@ -0,0 +1,5 @@ | |||
<form><input name="__RequestVerificationToken" type="hidden" value="{0}" /></form> |
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.
There's a bug here. The default method
is get
and so no antiforgery token should be added by default. Line 248 in the tag helper needs to handle null
or empty too.
<form method="get"></form> | ||
<form method="post"><input name="__RequestVerificationToken" type="hidden" value="{0}" /></form> | ||
<form action="/Foo/Bar/Baz.html" method="get"></form> | ||
<form action="/Foo/Bar/Baz.html" method="post"></form> |
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.
Tag helper should have added an antiforgery token, changing the behaviour when user includes action
attribute. Need to make a change around line 168 in the tag helper to match the updated line 248.
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.
Talked with Damian about this. Since the user specified action
, they're opting out of our TagHelper ways. Therefore, don't generate a token.
[HtmlTargetElement("form", Attributes = ControllerAttributeName)] | ||
[HtmlTargetElement("form", Attributes = RouteAttributeName)] | ||
[HtmlTargetElement("form", Attributes = RouteValuesDictionaryName)] | ||
[HtmlTargetElement("form", Attributes = RouteValuesPrefix + "*")] |
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.
Let's be explicit rather than use the naming convention to target <form>
elements: Stick with [HtmlTargetElement("form")]
.
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.
thx
b4b3151
to
c10ce6c
Compare
🆙 📅 |
<form method="get"></form> | ||
<form method="post"><input name="__RequestVerificationToken" type="hidden" value="{0}" /></form> | ||
<form action="/Foo/Bar/Baz.html" method="get"></form> | ||
<form action="/Foo/Bar/Baz.html" method="post"></form> |
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.
Tag helper should have added an antiforgery token, changing the behaviour when user includes
action
attribute. Need to make a change around line 168 in the tag helper to match the updated line 248.
Talked with Damian about this. Since the user specified
action
, they're opting out of our TagHelper ways. Therefore, don't generate a token.
Let's chat quickly tomorrow. I agree the user has opted out of the tag helper generating an action
in this case. But, I'm not sure why <form action="" method="post">
is any more an opt out of antiforgery than <form method="post">
is -- both submit the same data to the same URL.
c10ce6c
to
8ea8521
Compare
🆙 📅 |
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.
A few small comments. But, let's wait for Monday to get this in.
{ | ||
// User is using the FormTagHelper like a normal <form> tag that has an empty action attribute. | ||
// i.e. <form action="" method="post"> | ||
antiforgeryDefault = true; |
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.
- Don't set
antiforgeryDefault
to its default again. - Mention the
action="@Url.Action(action: "Index", controller: "Home")
possibility in the comments. - nit: "e.g." not "i.e." -- don't know anything more than
action
isn't"/A/Non-empty/String"
.
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.
What's special about the @Url.Action
case? It's also an HtmlString
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.
Shoot. It actually returns a plain string
. I thought (hoped) it avoided concatenation and returned a more-segmented IHtmlContent
.
Just mention the non-string
/ non-HtmlString
possibility. It's not necessarily an empty string
or HtmlString.Empty
.
{ | ||
// User is using the FormTagHelper like a normal <form> tag. Antiforgery default should be false to | ||
// not force the antiforgery token on the user. | ||
antiforgeryDefault = false; |
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.
If we leave this alone (pending Monday's discussion), update the comments to better distinguish things from the if
case e.g. User is likely using the <form> element to submit to another site. Do not send an antiforgery token to unknown sites.
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.
Getting this in. If the decision is changed we can account for that afterwards.
@@ -4,6 +4,8 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.ComponentModel; | |||
using System.IO; |
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.
What needs System.IO?
- Added functional test to validate that non-attributed form tags have an antiforgery input generated. Re-generated baseline to reflect changes. - Added a unit test to validate that parameterless `FormTagHelper`s behave as expected. #6006
8ea8521
to
3d895a9
Compare
FormTagHelper
s behave as expected.#6006