Use new antiforgery package

This commit is contained in:
Ryan Nowak 2015-06-24 16:13:13 -07:00
parent e2787b3b84
commit 2f554c4b29
76 changed files with 224 additions and 4232 deletions

30
Mvc.sln
View File

@ -1,7 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14 # Visual Studio 14
VisualStudioVersion = 14.0.22823.1 VisualStudioVersion = 14.0.23017.0
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}"
EndProject EndProject
@ -58,8 +58,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ContentNegotiationWebSite", "test\WebSites\ContentNegotiationWebSite\ContentNegotiationWebSite.xproj", "{C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7}" Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ContentNegotiationWebSite", "test\WebSites\ContentNegotiationWebSite\ContentNegotiationWebSite.xproj", "{C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7}"
EndProject EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "AntiForgeryWebSite", "test\WebSites\AntiForgeryWebSite\AntiForgeryWebSite.xproj", "{A353B17E-A940-4CE8-8BF9-179E24A9041F}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "AddServicesWebSite", "test\WebSites\AddServicesWebSite\AddServicesWebSite.xproj", "{6A0B65CE-6B01-40D0-840D-EFF3680D1547}" Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "AddServicesWebSite", "test\WebSites\AddServicesWebSite\AddServicesWebSite.xproj", "{6A0B65CE-6B01-40D0-840D-EFF3680D1547}"
EndProject EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "FiltersWebSite", "test\WebSites\FiltersWebSite\FiltersWebSite.xproj", "{1976AC4A-FEA4-4587-A158-D9F79736D2B6}" Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "FiltersWebSite", "test\WebSites\FiltersWebSite\FiltersWebSite.xproj", "{1976AC4A-FEA4-4587-A158-D9F79736D2B6}"
@ -174,6 +172,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Extens
EndProject EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Extensions.Test", "test\Microsoft.AspNet.Mvc.Extensions.Test\Microsoft.AspNet.Mvc.Extensions.Test.xproj", "{5DF6EFA5-865E-450B-BF83-DE9CE88EB77C}" Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Extensions.Test", "test\Microsoft.AspNet.Mvc.Extensions.Test\Microsoft.AspNet.Mvc.Extensions.Test.xproj", "{5DF6EFA5-865E-450B-BF83-DE9CE88EB77C}"
EndProject EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "AntiforgeryTokenWebSite", "test\WebSites\AntiforgeryTokenWebSite\AntiforgeryTokenWebSite.xproj", "{A353B17E-A940-4CE8-8BF9-179E24A9041F}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -394,16 +394,6 @@ Global
{C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7}.Release|Mixed Platforms.Build.0 = Release|Any CPU {C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7}.Release|x86.ActiveCfg = Release|Any CPU {C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7}.Release|x86.ActiveCfg = Release|Any CPU
{A353B17E-A940-4CE8-8BF9-179E24A9041F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A353B17E-A940-4CE8-8BF9-179E24A9041F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A353B17E-A940-4CE8-8BF9-179E24A9041F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{A353B17E-A940-4CE8-8BF9-179E24A9041F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{A353B17E-A940-4CE8-8BF9-179E24A9041F}.Debug|x86.ActiveCfg = Debug|Any CPU
{A353B17E-A940-4CE8-8BF9-179E24A9041F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A353B17E-A940-4CE8-8BF9-179E24A9041F}.Release|Any CPU.Build.0 = Release|Any CPU
{A353B17E-A940-4CE8-8BF9-179E24A9041F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{A353B17E-A940-4CE8-8BF9-179E24A9041F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{A353B17E-A940-4CE8-8BF9-179E24A9041F}.Release|x86.ActiveCfg = Release|Any CPU
{6A0B65CE-6B01-40D0-840D-EFF3680D1547}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6A0B65CE-6B01-40D0-840D-EFF3680D1547}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6A0B65CE-6B01-40D0-840D-EFF3680D1547}.Debug|Any CPU.Build.0 = Debug|Any CPU {6A0B65CE-6B01-40D0-840D-EFF3680D1547}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6A0B65CE-6B01-40D0-840D-EFF3680D1547}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {6A0B65CE-6B01-40D0-840D-EFF3680D1547}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@ -1052,6 +1042,18 @@ Global
{5DF6EFA5-865E-450B-BF83-DE9CE88EB77C}.Release|Mixed Platforms.Build.0 = Release|Any CPU {5DF6EFA5-865E-450B-BF83-DE9CE88EB77C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{5DF6EFA5-865E-450B-BF83-DE9CE88EB77C}.Release|x86.ActiveCfg = Release|Any CPU {5DF6EFA5-865E-450B-BF83-DE9CE88EB77C}.Release|x86.ActiveCfg = Release|Any CPU
{5DF6EFA5-865E-450B-BF83-DE9CE88EB77C}.Release|x86.Build.0 = Release|Any CPU {5DF6EFA5-865E-450B-BF83-DE9CE88EB77C}.Release|x86.Build.0 = Release|Any CPU
{A353B17E-A940-4CE8-8BF9-179E24A9041F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A353B17E-A940-4CE8-8BF9-179E24A9041F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A353B17E-A940-4CE8-8BF9-179E24A9041F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{A353B17E-A940-4CE8-8BF9-179E24A9041F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{A353B17E-A940-4CE8-8BF9-179E24A9041F}.Debug|x86.ActiveCfg = Debug|Any CPU
{A353B17E-A940-4CE8-8BF9-179E24A9041F}.Debug|x86.Build.0 = Debug|Any CPU
{A353B17E-A940-4CE8-8BF9-179E24A9041F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A353B17E-A940-4CE8-8BF9-179E24A9041F}.Release|Any CPU.Build.0 = Release|Any CPU
{A353B17E-A940-4CE8-8BF9-179E24A9041F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{A353B17E-A940-4CE8-8BF9-179E24A9041F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{A353B17E-A940-4CE8-8BF9-179E24A9041F}.Release|x86.ActiveCfg = Release|Any CPU
{A353B17E-A940-4CE8-8BF9-179E24A9041F}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -1079,7 +1081,6 @@ Global
{62735776-46FF-4170-9392-02E128A69B89} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} {62735776-46FF-4170-9392-02E128A69B89} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{EE1AB716-F102-4CA3-AD2C-214A44B459A0} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} {EE1AB716-F102-4CA3-AD2C-214A44B459A0} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} {C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{A353B17E-A940-4CE8-8BF9-179E24A9041F} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{6A0B65CE-6B01-40D0-840D-EFF3680D1547} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} {6A0B65CE-6B01-40D0-840D-EFF3680D1547} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{1976AC4A-FEA4-4587-A158-D9F79736D2B6} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} {1976AC4A-FEA4-4587-A158-D9F79736D2B6} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{A192E504-2881-41DC-90D1-B7F1DD1134E8} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} {A192E504-2881-41DC-90D1-B7F1DD1134E8} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
@ -1137,5 +1138,6 @@ Global
{FCFE6024-2720-49B4-8257-9DBC6114F0F1} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} {FCFE6024-2720-49B4-8257-9DBC6114F0F1} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{B2CA101A-87E6-4DD2-9BB2-28DA68EF1A94} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} {B2CA101A-87E6-4DD2-9BB2-28DA68EF1A94} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
{5DF6EFA5-865E-450B-BF83-DE9CE88EB77C} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1} {5DF6EFA5-865E-450B-BF83-DE9CE88EB77C} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{A353B17E-A940-4CE8-8BF9-179E24A9041F} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View File

@ -8,9 +8,9 @@
<h2>Create</h2> <h2>Create</h2>
@* anti-forgery is on by default *@ @* antiforgery is on by default *@
@* <form/> tag helper will special-case only elements with an "asp-action" or "asp-anti-forgery" attribute. *@ @* <form/> tag helper will special-case only elements with an "asp-action" or "asp-antiforgery" attribute. *@
<form asp-anti-forgery="false" asp-action="Create"> <form asp-antiforgery="false" asp-action="Create">
<div class="form-horizontal"> <div class="form-horizontal">
@* validation summary tag helper will target just <div/> elements and append the list of errors *@ @* validation summary tag helper will target just <div/> elements and append the list of errors *@
@* - i.e. this helper, like <select/> helper appends content. *@ @* - i.e. this helper, like <select/> helper appends content. *@

View File

@ -23,12 +23,12 @@
<h3>Watch the greatest movies right here!</h3> <h3>Watch the greatest movies right here!</h3>
Submit your movie rankings: Submit your movie rankings:
<form asp-anti-forgery="false" asp-action="UpdateMovieRatings"> <form asp-antiforgery="false" asp-action="UpdateMovieRatings">
Movies + ratings go here Movies + ratings go here
<button type="submit">Update ratings</button> <button type="submit">Update ratings</button>
</form> </form>
<form asp-anti-forgery="false" asp-action="UpdateCriticsQuotes"> <form asp-antiforgery="false" asp-action="UpdateCriticsQuotes">
Movies + ratings go here Movies + ratings go here
<button type="submit">Update quotes</button> <button type="submit">Update quotes</button>
</form> </form>

View File

@ -42,150 +42,6 @@ namespace Microsoft.AspNet.Mvc.Core
return string.Format(CultureInfo.CurrentCulture, GetString("ObjectResult_MatchAllContentType"), p0, p1); return string.Format(CultureInfo.CurrentCulture, GetString("ObjectResult_MatchAllContentType"), p0, p1);
} }
/// <summary>
/// The provided anti-forgery token failed a custom data check.
/// </summary>
internal static string AntiForgeryToken_AdditionalDataCheckFailed
{
get { return GetString("AntiForgeryToken_AdditionalDataCheckFailed"); }
}
/// <summary>
/// The provided anti-forgery token failed a custom data check.
/// </summary>
internal static string FormatAntiForgeryToken_AdditionalDataCheckFailed()
{
return GetString("AntiForgeryToken_AdditionalDataCheckFailed");
}
/// <summary>
/// The provided anti-forgery token was meant for a different claims-based user than the current user.
/// </summary>
internal static string AntiForgeryToken_ClaimUidMismatch
{
get { return GetString("AntiForgeryToken_ClaimUidMismatch"); }
}
/// <summary>
/// The provided anti-forgery token was meant for a different claims-based user than the current user.
/// </summary>
internal static string FormatAntiForgeryToken_ClaimUidMismatch()
{
return GetString("AntiForgeryToken_ClaimUidMismatch");
}
/// <summary>
/// The required anti-forgery cookie "{0}" is not present.
/// </summary>
internal static string AntiForgeryToken_CookieMissing
{
get { return GetString("AntiForgeryToken_CookieMissing"); }
}
/// <summary>
/// The required anti-forgery cookie "{0}" is not present.
/// </summary>
internal static string FormatAntiForgeryToken_CookieMissing(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("AntiForgeryToken_CookieMissing"), p0);
}
/// <summary>
/// The anti-forgery token could not be decrypted.
/// </summary>
internal static string AntiForgeryToken_DeserializationFailed
{
get { return GetString("AntiForgeryToken_DeserializationFailed"); }
}
/// <summary>
/// The anti-forgery token could not be decrypted.
/// </summary>
internal static string FormatAntiForgeryToken_DeserializationFailed()
{
return GetString("AntiForgeryToken_DeserializationFailed");
}
/// <summary>
/// The required anti-forgery form field "{0}" is not present.
/// </summary>
internal static string AntiForgeryToken_FormFieldMissing
{
get { return GetString("AntiForgeryToken_FormFieldMissing"); }
}
/// <summary>
/// The required anti-forgery form field "{0}" is not present.
/// </summary>
internal static string FormatAntiForgeryToken_FormFieldMissing(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("AntiForgeryToken_FormFieldMissing"), p0);
}
/// <summary>
/// The anti-forgery cookie token and form field token do not match.
/// </summary>
internal static string AntiForgeryToken_SecurityTokenMismatch
{
get { return GetString("AntiForgeryToken_SecurityTokenMismatch"); }
}
/// <summary>
/// The anti-forgery cookie token and form field token do not match.
/// </summary>
internal static string FormatAntiForgeryToken_SecurityTokenMismatch()
{
return GetString("AntiForgeryToken_SecurityTokenMismatch");
}
/// <summary>
/// Validation of the provided anti-forgery token failed. The cookie "{0}" and the form field "{1}" were swapped.
/// </summary>
internal static string AntiForgeryToken_TokensSwapped
{
get { return GetString("AntiForgeryToken_TokensSwapped"); }
}
/// <summary>
/// Validation of the provided anti-forgery token failed. The cookie "{0}" and the form field "{1}" were swapped.
/// </summary>
internal static string FormatAntiForgeryToken_TokensSwapped(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("AntiForgeryToken_TokensSwapped"), p0, p1);
}
/// <summary>
/// The provided anti-forgery token was meant for user "{0}", but the current user is "{1}".
/// </summary>
internal static string AntiForgeryToken_UsernameMismatch
{
get { return GetString("AntiForgeryToken_UsernameMismatch"); }
}
/// <summary>
/// The provided anti-forgery token was meant for user "{0}", but the current user is "{1}".
/// </summary>
internal static string FormatAntiForgeryToken_UsernameMismatch(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("AntiForgeryToken_UsernameMismatch"), p0, p1);
}
/// <summary>
/// The anti-forgery system has the configuration value AntiForgeryOptions.RequireSsl = true, but the current request is not an SSL request.
/// </summary>
internal static string AntiForgeryWorker_RequireSSL
{
get { return GetString("AntiForgeryWorker_RequireSSL"); }
}
/// <summary>
/// The anti-forgery system has the configuration value AntiForgeryOptions.RequireSsl = true, but the current request is not an SSL request.
/// </summary>
internal static string FormatAntiForgeryWorker_RequireSSL()
{
return GetString("AntiForgeryWorker_RequireSSL");
}
/// <summary> /// <summary>
/// The method '{0}' on type '{1}' returned an instance of '{2}'. Make sure to call Unwrap on the returned value to avoid unobserved faulted Task. /// The method '{0}' on type '{1}' returned an instance of '{2}'. Make sure to call Unwrap on the returned value to avoid unobserved faulted Task.
/// </summary> /// </summary>
@ -234,22 +90,6 @@ namespace Microsoft.AspNet.Mvc.Core
return string.Format(CultureInfo.CurrentCulture, GetString("ClaimUidExtractor_ClaimNotPresent"), p0); return string.Format(CultureInfo.CurrentCulture, GetString("ClaimUidExtractor_ClaimNotPresent"), p0);
} }
/// <summary>
/// The provided identity of type '{0}' is marked IsAuthenticated = true but does not have a value for Name. By default, the anti-forgery system requires that all authenticated identities have a unique Name. If it is not possible to provide a unique Name for this identity, consider extending IAdditionalDataProvider by overriding the DefaultAdditionalDataProvider or a custom type that can provide some form of unique identifier for the current user.
/// </summary>
internal static string TokenValidator_AuthenticatedUserWithoutUsername
{
get { return GetString("TokenValidator_AuthenticatedUserWithoutUsername"); }
}
/// <summary>
/// The provided identity of type '{0}' is marked IsAuthenticated = true but does not have a value for Name. By default, the anti-forgery system requires that all authenticated identities have a unique Name. If it is not possible to provide a unique Name for this identity, consider extending IAdditionalDataProvider by overriding the DefaultAdditionalDataProvider or a custom type that can provide some form of unique identifier for the current user.
/// </summary>
internal static string FormatTokenValidator_AuthenticatedUserWithoutUsername(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("TokenValidator_AuthenticatedUserWithoutUsername"), p0);
}
/// <summary> /// <summary>
/// The class ReflectedActionFilterEndPoint only supports ReflectedActionDescriptors. /// The class ReflectedActionFilterEndPoint only supports ReflectedActionDescriptors.
/// </summary> /// </summary>

View File

@ -123,33 +123,6 @@
<data name="ObjectResult_MatchAllContentType" xml:space="preserve"> <data name="ObjectResult_MatchAllContentType" xml:space="preserve">
<value>The content-type '{0}' added in the '{1}' property is invalid. Media types which match all types or match all subtypes are not supported.</value> <value>The content-type '{0}' added in the '{1}' property is invalid. Media types which match all types or match all subtypes are not supported.</value>
</data> </data>
<data name="AntiForgeryToken_AdditionalDataCheckFailed" xml:space="preserve">
<value>The provided anti-forgery token failed a custom data check.</value>
</data>
<data name="AntiForgeryToken_ClaimUidMismatch" xml:space="preserve">
<value>The provided anti-forgery token was meant for a different claims-based user than the current user.</value>
</data>
<data name="AntiForgeryToken_CookieMissing" xml:space="preserve">
<value>The required anti-forgery cookie "{0}" is not present.</value>
</data>
<data name="AntiForgeryToken_DeserializationFailed" xml:space="preserve">
<value>The anti-forgery token could not be decrypted.</value>
</data>
<data name="AntiForgeryToken_FormFieldMissing" xml:space="preserve">
<value>The required anti-forgery form field "{0}" is not present.</value>
</data>
<data name="AntiForgeryToken_SecurityTokenMismatch" xml:space="preserve">
<value>The anti-forgery cookie token and form field token do not match.</value>
</data>
<data name="AntiForgeryToken_TokensSwapped" xml:space="preserve">
<value>Validation of the provided anti-forgery token failed. The cookie "{0}" and the form field "{1}" were swapped.</value>
</data>
<data name="AntiForgeryToken_UsernameMismatch" xml:space="preserve">
<value>The provided anti-forgery token was meant for user "{0}", but the current user is "{1}".</value>
</data>
<data name="AntiForgeryWorker_RequireSSL" xml:space="preserve">
<value>The anti-forgery system has the configuration value AntiForgeryOptions.RequireSsl = true, but the current request is not an SSL request.</value>
</data>
<data name="ActionExecutor_WrappedTaskInstance" xml:space="preserve"> <data name="ActionExecutor_WrappedTaskInstance" xml:space="preserve">
<value>The method '{0}' on type '{1}' returned an instance of '{2}'. Make sure to call Unwrap on the returned value to avoid unobserved faulted Task.</value> <value>The method '{0}' on type '{1}' returned an instance of '{2}'. Make sure to call Unwrap on the returned value to avoid unobserved faulted Task.</value>
</data> </data>
@ -159,9 +132,6 @@
<data name="ClaimUidExtractor_ClaimNotPresent" xml:space="preserve"> <data name="ClaimUidExtractor_ClaimNotPresent" xml:space="preserve">
<value>A claim of type '{0}' was not present on the provided ClaimsIdentity.</value> <value>A claim of type '{0}' was not present on the provided ClaimsIdentity.</value>
</data> </data>
<data name="TokenValidator_AuthenticatedUserWithoutUsername" xml:space="preserve">
<value>The provided identity of type '{0}' is marked IsAuthenticated = true but does not have a value for Name. By default, the anti-forgery system requires that all authenticated identities have a unique Name. If it is not possible to provide a unique Name for this identity, consider extending IAdditionalDataProvider by overriding the DefaultAdditionalDataProvider or a custom type that can provide some form of unique identifier for the current user.</value>
</data>
<data name="ReflectedActionFilterEndPoint_UnexpectedActionDescriptor" xml:space="preserve"> <data name="ReflectedActionFilterEndPoint_UnexpectedActionDescriptor" xml:space="preserve">
<value>The class ReflectedActionFilterEndPoint only supports ReflectedActionDescriptors.</value> <value>The class ReflectedActionFilterEndPoint only supports ReflectedActionDescriptors.</value>
</data> </data>

View File

@ -1,138 +0,0 @@
// 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 System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.DataProtection;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.WebUtilities;
using Microsoft.Framework.Internal;
using Microsoft.Framework.OptionsModel;
using Microsoft.Framework.WebEncoders;
namespace Microsoft.AspNet.Mvc
{
/// <summary>
/// Provides access to the anti-forgery system, which provides protection against
/// Cross-site Request Forgery (XSRF, also called CSRF) attacks.
/// </summary>
public sealed class AntiForgery
{
private static readonly string _purpose = "Microsoft.AspNet.Mvc.AntiXsrf.AntiForgeryToken.v1";
private readonly AntiForgeryWorker _worker;
public AntiForgery([NotNull] IClaimUidExtractor claimUidExtractor,
[NotNull] IDataProtectionProvider dataProtectionProvider,
[NotNull] IAntiForgeryAdditionalDataProvider additionalDataProvider,
[NotNull] IOptions<AntiForgeryOptions> antiforgeryOptions,
[NotNull] IHtmlEncoder htmlEncoder,
[NotNull] IOptions<DataProtectionOptions> dataProtectionOptions)
{
var config = antiforgeryOptions.Options;
var applicationId = dataProtectionOptions.Options.ApplicationDiscriminator ?? string.Empty;
config.CookieName = config.CookieName ?? ComputeCookieName(applicationId);
var serializer = new AntiForgeryTokenSerializer(dataProtectionProvider.CreateProtector(_purpose));
var tokenStore = new AntiForgeryTokenStore(config, serializer);
var tokenProvider = new AntiForgeryTokenProvider(config, claimUidExtractor, additionalDataProvider);
_worker = new AntiForgeryWorker(serializer, config, tokenStore, tokenProvider, tokenProvider, htmlEncoder);
}
/// <summary>
/// Generates an anti-forgery token for this request. This token can
/// be validated by calling the Validate() method.
/// </summary>
/// <param name="context">The HTTP context associated with the current call.</param>
/// <returns>An HTML string corresponding to an &lt;input type="hidden"&gt;
/// element. This element should be put inside a &lt;form&gt;.</returns>
/// <remarks>
/// This method has a side effect:
/// A response cookie is set if there is no valid cookie associated with the request.
/// </remarks>
public TagBuilder GetHtml([NotNull] HttpContext context)
{
var builder = _worker.GetFormInputElement(context);
return builder;
}
/// <summary>
/// Generates an anti-forgery token pair (cookie and form token) for this request.
/// This method is similar to GetHtml(HttpContext context), but this method gives the caller control
/// over how to persist the returned values. To validate these tokens, call the
/// appropriate overload of Validate.
/// </summary>
/// <param name="context">The HTTP context associated with the current call.</param>
/// <param name="oldCookieToken">The anti-forgery token - if any - that already existed
/// for this request. May be null. The anti-forgery system will try to reuse this cookie
/// value when generating a matching form token.</param>
/// <remarks>
/// Unlike the GetHtml(HttpContext context) method, this method has no side effect. The caller
/// is responsible for setting the response cookie and injecting the returned
/// form token as appropriate.
/// </remarks>
public AntiForgeryTokenSet GetTokens([NotNull] HttpContext context, string oldCookieToken)
{
// Will contain a new cookie value if the old cookie token
// was null or invalid. If this value is non-null when the method completes, the caller
// must persist this value in the form of a response cookie, and the existing cookie value
// should be discarded. If this value is null when the method completes, the existing
// cookie value was valid and needn't be modified.
return _worker.GetTokens(context, oldCookieToken);
}
/// <summary>
/// Validates an anti-forgery token that was supplied for this request.
/// The anti-forgery token may be generated by calling GetHtml(HttpContext context).
/// </summary>
/// <param name="context">The HTTP context associated with the current call.</param>
public async Task ValidateAsync([NotNull] HttpContext context)
{
await _worker.ValidateAsync(context);
}
/// <summary>
/// Validates an anti-forgery token pair that was generated by the GetTokens method.
/// </summary>
/// <param name="context">The HTTP context associated with the current call.</param>
/// <param name="cookieToken">The token that was supplied in the request cookie.</param>
/// <param name="formToken">The token that was supplied in the request form body.</param>
public void Validate([NotNull] HttpContext context, string cookieToken, string formToken)
{
_worker.Validate(context, cookieToken, formToken);
}
/// <summary>
/// Validates an anti-forgery token pair that was generated by the GetTokens method.
/// </summary>
/// <param name="context">The HTTP context associated with the current call.</param>
/// <param name="antiForgeryTokenSet">The anti-forgery token pair (cookie and form token) for this request.
/// </param>
public void Validate([NotNull] HttpContext context, AntiForgeryTokenSet antiForgeryTokenSet)
{
Validate(context, antiForgeryTokenSet.CookieToken, antiForgeryTokenSet.FormToken);
}
/// <summary>
/// Generates and sets an anti-forgery cookie if one is not available or not valid. Also sets response headers.
/// </summary>
/// <param name="context">The HTTP context associated with the current call.</param>
public void SetCookieTokenAndHeader([NotNull] HttpContext context)
{
_worker.SetCookieTokenAndHeader(context);
}
private string ComputeCookieName(string applicationId)
{
using (var sha256 = SHA256.Create())
{
var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(applicationId));
var subHash = hash.Take(8).ToArray();
return WebEncoders.Base64UrlEncode(subHash);
}
}
}
}

View File

@ -1,13 +0,0 @@
// 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.AspNet.Mvc
{
/// <summary>
/// Used as a per request state.
/// </summary>
internal class AntiForgeryContext
{
public AntiForgeryToken CookieToken { get; set; }
}
}

View File

@ -1,96 +0,0 @@
// 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 System;
using Microsoft.AspNet.Mvc.Extensions;
namespace Microsoft.AspNet.Mvc
{
/// <summary>
/// Provides programmatic configuration for the anti-forgery token system.
/// </summary>
public class AntiForgeryOptions
{
private const string AntiForgeryTokenFieldName = "__RequestVerificationToken";
private string _cookieName;
private string _formFieldName = AntiForgeryTokenFieldName;
public AntiForgeryOptions()
{
}
/// <summary>
/// Specifies the name of the cookie that is used by the anti-forgery
/// system.
/// </summary>
/// <remarks>
/// If an explicit name is not provided, the system will automatically
/// generate a name.
/// </remarks>
public string CookieName
{
get
{
return _cookieName;
}
set
{
if (value == null)
{
throw new ArgumentNullException(nameof(value),
Resources.FormatPropertyOfTypeCannotBeNull(
nameof(CookieName), typeof(AntiForgeryOptions)));
}
_cookieName = value;
}
}
/// <summary>
/// Specifies the name of the anti-forgery token field that is used by the anti-forgery system.
/// </summary>
public string FormFieldName
{
get
{
return _formFieldName;
}
set
{
if (value == null)
{
throw new ArgumentNullException(nameof(value),
Resources.FormatPropertyOfTypeCannotBeNull(
nameof(FormFieldName), typeof(AntiForgeryOptions)));
}
_formFieldName = value;
}
}
/// <summary>
/// Specifies whether SSL is required for the anti-forgery system
/// to operate. If this setting is 'true' and a non-SSL request
/// comes into the system, all anti-forgery APIs will fail.
/// </summary>
public bool RequireSSL
{
get;
set;
}
/// <summary>
/// Specifies whether to suppress the generation of X-Frame-Options header
/// which is used to prevent ClickJacking. By default, the X-Frame-Options
/// header is generated with the value SAMEORIGIN. If this setting is 'true',
/// the X-Frame-Options header will not be generated for the response.
/// </summary>
public bool SuppressXFrameOptionsHeader
{
get;
set;
}
}
}

View File

@ -1,53 +0,0 @@
// 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.AspNet.Mvc
{
internal sealed class AntiForgeryToken
{
internal const int SecurityTokenBitLength = 128;
internal const int ClaimUidBitLength = 256;
private string _additionalData = string.Empty;
private string _username = string.Empty;
private BinaryBlob _securityToken;
public string AdditionalData
{
get { return _additionalData; }
set
{
_additionalData = value ?? string.Empty;
}
}
public BinaryBlob ClaimUid { get; set; }
public bool IsSessionToken { get; set; }
public BinaryBlob SecurityToken
{
get
{
if (_securityToken == null)
{
_securityToken = new BinaryBlob(SecurityTokenBitLength);
}
return _securityToken;
}
set
{
_securityToken = value;
}
}
public string Username
{
get { return _username; }
set
{
_username = value ?? string.Empty;
}
}
}
}

View File

@ -1,168 +0,0 @@
// 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 System;
using System.Diagnostics;
using System.Security.Claims;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.Extensions;
namespace Microsoft.AspNet.Mvc
{
internal sealed class AntiForgeryTokenProvider : IAntiForgeryTokenValidator, IAntiForgeryTokenGenerator
{
private readonly IClaimUidExtractor _claimUidExtractor;
private readonly AntiForgeryOptions _config;
private readonly IAntiForgeryAdditionalDataProvider _additionalDataProvider;
internal AntiForgeryTokenProvider(AntiForgeryOptions config,
IClaimUidExtractor claimUidExtractor,
IAntiForgeryAdditionalDataProvider additionalDataProvider)
{
_config = config;
_claimUidExtractor = claimUidExtractor;
_additionalDataProvider = additionalDataProvider;
}
public AntiForgeryToken GenerateCookieToken()
{
return new AntiForgeryToken()
{
// SecurityToken will be populated automatically.
IsSessionToken = true
};
}
public AntiForgeryToken GenerateFormToken(HttpContext httpContext,
ClaimsIdentity identity,
AntiForgeryToken cookieToken)
{
Debug.Assert(IsCookieTokenValid(cookieToken));
var formToken = new AntiForgeryToken()
{
SecurityToken = cookieToken.SecurityToken,
IsSessionToken = false
};
var isIdentityAuthenticated = false;
// populate Username and ClaimUid
if (identity != null && identity.IsAuthenticated)
{
isIdentityAuthenticated = true;
formToken.ClaimUid = GetClaimUidBlob(_claimUidExtractor.ExtractClaimUid(identity));
if (formToken.ClaimUid == null)
{
formToken.Username = identity.Name;
}
}
// populate AdditionalData
if (_additionalDataProvider != null)
{
formToken.AdditionalData = _additionalDataProvider.GetAdditionalData(httpContext);
}
if (isIdentityAuthenticated
&& string.IsNullOrEmpty(formToken.Username)
&& formToken.ClaimUid == null
&& string.IsNullOrEmpty(formToken.AdditionalData))
{
// Application says user is authenticated, but we have no identifier for the user.
throw new InvalidOperationException(
Resources.FormatTokenValidator_AuthenticatedUserWithoutUsername(identity.GetType()));
}
return formToken;
}
public bool IsCookieTokenValid(AntiForgeryToken cookieToken)
{
return (cookieToken != null && cookieToken.IsSessionToken);
}
public void ValidateTokens(
HttpContext httpContext,
ClaimsIdentity identity,
AntiForgeryToken sessionToken,
AntiForgeryToken fieldToken)
{
// Were the tokens even present at all?
if (sessionToken == null)
{
throw new InvalidOperationException(
Resources.FormatAntiForgeryToken_CookieMissing(_config.CookieName));
}
if (fieldToken == null)
{
throw new InvalidOperationException(
Resources.FormatAntiForgeryToken_FormFieldMissing(_config.FormFieldName));
}
// Do the tokens have the correct format?
if (!sessionToken.IsSessionToken || fieldToken.IsSessionToken)
{
throw new InvalidOperationException(
Resources.FormatAntiForgeryToken_TokensSwapped(_config.CookieName, _config.FormFieldName));
}
// Are the security tokens embedded in each incoming token identical?
if (!Equals(sessionToken.SecurityToken, fieldToken.SecurityToken))
{
throw new InvalidOperationException(Resources.AntiForgeryToken_SecurityTokenMismatch);
}
// Is the incoming token meant for the current user?
var currentUsername = string.Empty;
BinaryBlob currentClaimUid = null;
if (identity != null && identity.IsAuthenticated)
{
currentClaimUid = GetClaimUidBlob(_claimUidExtractor.ExtractClaimUid(identity));
if (currentClaimUid == null)
{
currentUsername = identity.Name ?? string.Empty;
}
}
// OpenID and other similar authentication schemes use URIs for the username.
// These should be treated as case-sensitive.
var useCaseSensitiveUsernameComparison =
currentUsername.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ||
currentUsername.StartsWith("https://", StringComparison.OrdinalIgnoreCase);
if (!string.Equals(fieldToken.Username,
currentUsername,
(useCaseSensitiveUsernameComparison) ?
StringComparison.Ordinal :
StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException(
Resources.FormatAntiForgeryToken_UsernameMismatch(fieldToken.Username, currentUsername));
}
if (!Equals(fieldToken.ClaimUid, currentClaimUid))
{
throw new InvalidOperationException(Resources.AntiForgeryToken_ClaimUidMismatch);
}
// Is the AdditionalData valid?
if (_additionalDataProvider != null &&
!_additionalDataProvider.ValidateAdditionalData(httpContext, fieldToken.AdditionalData))
{
throw new InvalidOperationException(Resources.AntiForgeryToken_AdditionalDataCheckFailed);
}
}
private static BinaryBlob GetClaimUidBlob(string base64ClaimUid)
{
if (base64ClaimUid == null)
{
return null;
}
return new BinaryBlob(256, Convert.FromBase64String(base64ClaimUid));
}
}
}

View File

@ -1,136 +0,0 @@
// 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 System;
using System.IO;
using Microsoft.AspNet.DataProtection;
using Microsoft.AspNet.Mvc.Extensions;
using Microsoft.AspNet.WebUtilities;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc
{
internal sealed class AntiForgeryTokenSerializer : IAntiForgeryTokenSerializer
{
private readonly IDataProtector _cryptoSystem;
private const byte TokenVersion = 0x01;
internal AntiForgeryTokenSerializer([NotNull] IDataProtector cryptoSystem)
{
_cryptoSystem = cryptoSystem;
}
public AntiForgeryToken Deserialize(string serializedToken)
{
Exception innerException = null;
try
{
var tokenBytes = WebEncoders.Base64UrlDecode(serializedToken);
using (var stream = new MemoryStream(_cryptoSystem.Unprotect(tokenBytes)))
{
using (var reader = new BinaryReader(stream))
{
var token = DeserializeImpl(reader);
if (token != null)
{
return token;
}
}
}
}
catch (Exception ex)
{
// swallow all exceptions - homogenize error if something went wrong
innerException = ex;
}
// if we reached this point, something went wrong deserializing
throw new InvalidOperationException(Resources.AntiForgeryToken_DeserializationFailed, innerException);
}
/* The serialized format of the anti-XSRF token is as follows:
* Version: 1 byte integer
* SecurityToken: 16 byte binary blob
* IsSessionToken: 1 byte Boolean
* [if IsSessionToken != true]
* +- IsClaimsBased: 1 byte Boolean
* | [if IsClaimsBased = true]
* | `- ClaimUid: 32 byte binary blob
* | [if IsClaimsBased = false]
* | `- Username: UTF-8 string with 7-bit integer length prefix
* `- AdditionalData: UTF-8 string with 7-bit integer length prefix
*/
private static AntiForgeryToken DeserializeImpl(BinaryReader reader)
{
// we can only consume tokens of the same serialized version that we generate
var embeddedVersion = reader.ReadByte();
if (embeddedVersion != TokenVersion)
{
return null;
}
var deserializedToken = new AntiForgeryToken();
var securityTokenBytes = reader.ReadBytes(AntiForgeryToken.SecurityTokenBitLength / 8);
deserializedToken.SecurityToken =
new BinaryBlob(AntiForgeryToken.SecurityTokenBitLength, securityTokenBytes);
deserializedToken.IsSessionToken = reader.ReadBoolean();
if (!deserializedToken.IsSessionToken)
{
var isClaimsBased = reader.ReadBoolean();
if (isClaimsBased)
{
var claimUidBytes = reader.ReadBytes(AntiForgeryToken.ClaimUidBitLength / 8);
deserializedToken.ClaimUid = new BinaryBlob(AntiForgeryToken.ClaimUidBitLength, claimUidBytes);
}
else
{
deserializedToken.Username = reader.ReadString();
}
deserializedToken.AdditionalData = reader.ReadString();
}
// if there's still unconsumed data in the stream, fail
if (reader.BaseStream.ReadByte() != -1)
{
return null;
}
// success
return deserializedToken;
}
public string Serialize([NotNull] AntiForgeryToken token)
{
using (var stream = new MemoryStream())
{
using (var writer = new BinaryWriter(stream))
{
writer.Write(TokenVersion);
writer.Write(token.SecurityToken.GetData());
writer.Write(token.IsSessionToken);
if (!token.IsSessionToken)
{
if (token.ClaimUid != null)
{
writer.Write(true /* isClaimsBased */);
writer.Write(token.ClaimUid.GetData());
}
else
{
writer.Write(false /* isClaimsBased */);
writer.Write(token.Username);
}
writer.Write(token.AdditionalData);
}
writer.Flush();
return WebEncoders.Base64UrlEncode(_cryptoSystem.Protect(stream.ToArray()));
}
}
}
}
}

View File

@ -1,43 +0,0 @@
// 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 System;
using Microsoft.AspNet.Mvc.Extensions;
namespace Microsoft.AspNet.Mvc
{
/// <summary>
/// The anti-forgery token pair (cookie and form token) for a request.
/// </summary>
public class AntiForgeryTokenSet
{
/// <summary>
/// Creates the anti-forgery token pair (cookie and form token) for a request.
/// </summary>
/// <param name="formToken">The token that is supplied in the request form body.</param>
/// <param name="cookieToken">The token that is supplied in the request cookie.</param>
public AntiForgeryTokenSet(string formToken, string cookieToken)
{
if (string.IsNullOrEmpty(formToken))
{
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(formToken));
}
FormToken = formToken;
// Cookie Token is allowed to be null in the case when the old cookie is valid
// and there is no new cookieToken generated.
CookieToken = cookieToken;
}
/// <summary>
/// The token that is supplied in the request form body.
/// </summary>
public string FormToken { get; private set; }
/// The cookie token is allowed to be null.
/// This would be the case when the old cookie token is still valid.
/// In such cases a call to GetTokens would return a token set with null cookie token.
public string CookieToken { get; private set; }
}
}

View File

@ -1,79 +0,0 @@
// 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 System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc
{
// Saves anti-XSRF tokens split between HttpRequest.Cookies and HttpRequest.Form
internal sealed class AntiForgeryTokenStore : IAntiForgeryTokenStore
{
private readonly AntiForgeryOptions _config;
private readonly IAntiForgeryTokenSerializer _serializer;
internal AntiForgeryTokenStore([NotNull] AntiForgeryOptions config,
[NotNull] IAntiForgeryTokenSerializer serializer)
{
_config = config;
_serializer = serializer;
}
public AntiForgeryToken GetCookieToken(HttpContext httpContext)
{
var contextAccessor =
httpContext.RequestServices.GetRequiredService<IScopedInstance<AntiForgeryContext>>();
if (contextAccessor.Value != null)
{
return contextAccessor.Value.CookieToken;
}
var requestCookie = httpContext.Request.Cookies[_config.CookieName];
if (string.IsNullOrEmpty(requestCookie))
{
// unable to find the cookie.
return null;
}
return _serializer.Deserialize(requestCookie);
}
public async Task<AntiForgeryToken> GetFormTokenAsync(HttpContext httpContext)
{
var form = await httpContext.Request.ReadFormAsync();
var value = form[_config.FormFieldName];
if (string.IsNullOrEmpty(value))
{
// did not exist
return null;
}
return _serializer.Deserialize(value);
}
public void SaveCookieToken(HttpContext httpContext, AntiForgeryToken token)
{
// Add the cookie to the request based context.
// This is useful if the cookie needs to be reloaded in the context of the same request.
var contextAccessor =
httpContext.RequestServices.GetRequiredService<IScopedInstance<AntiForgeryContext>>();
Debug.Assert(contextAccessor.Value == null, "AntiForgeryContext should be set only once per request.");
contextAccessor.Value = new AntiForgeryContext() { CookieToken = token };
var serializedToken = _serializer.Serialize(token);
var options = new CookieOptions() { HttpOnly = true };
// Note: don't use "newCookie.Secure = _config.RequireSSL;" since the default
// value of newCookie.Secure is poulated out of band.
if (_config.RequireSSL)
{
options.Secure = true;
}
httpContext.Response.Cookies.Append(_config.CookieName, serializedToken, options);
}
}
}

View File

@ -1,257 +0,0 @@
// 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 System;
using System.Diagnostics;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.Extensions;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.Framework.Internal;
using Microsoft.Framework.WebEncoders;
namespace Microsoft.AspNet.Mvc
{
internal sealed class AntiForgeryWorker
{
private readonly AntiForgeryOptions _config;
private readonly IAntiForgeryTokenSerializer _serializer;
private readonly IAntiForgeryTokenStore _tokenStore;
private readonly IAntiForgeryTokenValidator _validator;
private readonly IAntiForgeryTokenGenerator _generator;
private readonly IHtmlEncoder _htmlEncoder;
internal AntiForgeryWorker([NotNull] IAntiForgeryTokenSerializer serializer,
[NotNull] AntiForgeryOptions config,
[NotNull] IAntiForgeryTokenStore tokenStore,
[NotNull] IAntiForgeryTokenGenerator generator,
[NotNull] IAntiForgeryTokenValidator validator,
[NotNull] IHtmlEncoder htmlEncoder)
{
_serializer = serializer;
_config = config;
_tokenStore = tokenStore;
_generator = generator;
_validator = validator;
_htmlEncoder = htmlEncoder;
}
private void CheckSSLConfig(HttpContext httpContext)
{
if (_config.RequireSSL && !httpContext.Request.IsHttps)
{
throw new InvalidOperationException(Resources.AntiForgeryWorker_RequireSSL);
}
}
private AntiForgeryToken DeserializeToken(string serializedToken)
{
return (!string.IsNullOrEmpty(serializedToken))
? _serializer.Deserialize(serializedToken)
: null;
}
private AntiForgeryToken DeserializeTokenDoesNotThrow(string serializedToken)
{
try
{
return DeserializeToken(serializedToken);
}
catch
{
// ignore failures since we'll just generate a new token
return null;
}
}
private static ClaimsIdentity ExtractIdentity(HttpContext httpContext)
{
if (httpContext != null)
{
var user = httpContext.User;
if (user != null)
{
// We only support ClaimsIdentity.
return user.Identity as ClaimsIdentity;
}
}
return null;
}
private AntiForgeryToken GetCookieTokenDoesNotThrow(HttpContext httpContext)
{
try
{
return _tokenStore.GetCookieToken(httpContext);
}
catch
{
// ignore failures since we'll just generate a new token
return null;
}
}
// [ ENTRY POINT ]
// Generates an anti-XSRF token pair for the current user. The return
// value is the hidden input form element that should be rendered in
// the <form>. This method has a side effect: it may set a response
// cookie.
public TagBuilder GetFormInputElement([NotNull] HttpContext httpContext)
{
CheckSSLConfig(httpContext);
var cookieToken = GetCookieTokenDoesNotThrow(httpContext);
var tokenSet = GetTokens(httpContext, cookieToken);
cookieToken = tokenSet.CookieToken;
var formToken = tokenSet.FormToken;
SaveCookieTokenAndHeader(httpContext, cookieToken);
// <input type="hidden" name="__AntiForgeryToken" value="..." />
var inputTag = new TagBuilder("input", _htmlEncoder)
{
Attributes =
{
{ "type", "hidden" },
{ "name", _config.FormFieldName },
{ "value", _serializer.Serialize(formToken) }
}
};
return inputTag;
}
// [ ENTRY POINT ]
// Generates a (cookie, form) serialized token pair for the current user.
// The caller may specify an existing cookie value if one exists. If the
// 'new cookie value' out param is non-null, the caller *must* persist
// the new value to cookie storage since the original value was null or
// invalid. This method is side-effect free.
public AntiForgeryTokenSet GetTokens([NotNull] HttpContext httpContext, string cookieToken)
{
CheckSSLConfig(httpContext);
var deSerializedcookieToken = DeserializeTokenDoesNotThrow(cookieToken);
var tokenSet = GetTokens(httpContext, deSerializedcookieToken);
var serializedCookieToken = Serialize(tokenSet.CookieToken);
var serializedFormToken = Serialize(tokenSet.FormToken);
return new AntiForgeryTokenSet(serializedFormToken, serializedCookieToken);
}
private AntiForgeryTokenSetInternal GetTokens(HttpContext httpContext, AntiForgeryToken cookieToken)
{
var newCookieToken = ValidateAndGenerateNewCookieToken(cookieToken);
if (newCookieToken != null)
{
cookieToken = newCookieToken;
}
var formToken = _generator.GenerateFormToken(
httpContext,
ExtractIdentity(httpContext),
cookieToken);
return new AntiForgeryTokenSetInternal()
{
// Note : The new cookie would be null if the old cookie is valid.
CookieToken = newCookieToken,
FormToken = formToken
};
}
private string Serialize(AntiForgeryToken token)
{
return (token != null) ? _serializer.Serialize(token) : null;
}
// [ ENTRY POINT ]
// Given an HttpContext, validates that the anti-XSRF tokens contained
// in the cookies & form are OK for this request.
public async Task ValidateAsync([NotNull] HttpContext httpContext)
{
CheckSSLConfig(httpContext);
// Extract cookie & form tokens
var cookieToken = _tokenStore.GetCookieToken(httpContext);
var formToken = await _tokenStore.GetFormTokenAsync(httpContext);
// Validate
_validator.ValidateTokens(httpContext, ExtractIdentity(httpContext), cookieToken, formToken);
}
// [ ENTRY POINT ]
// Given the serialized string representations of a cookie & form token,
// validates that the pair is OK for this request.
public void Validate([NotNull] HttpContext httpContext, string cookieToken, string formToken)
{
CheckSSLConfig(httpContext);
// Extract cookie & form tokens
var deserializedCookieToken = DeserializeToken(cookieToken);
var deserializedFormToken = DeserializeToken(formToken);
// Validate
_validator.ValidateTokens(
httpContext,
ExtractIdentity(httpContext),
deserializedCookieToken,
deserializedFormToken);
}
/// <summary>
/// Generates and sets an anti-forgery cookie if one is not available or not valid. Also sets response headers.
/// </summary>
/// <param name="context">The HTTP context associated with the current call.</param>
public void SetCookieTokenAndHeader([NotNull] HttpContext httpContext)
{
CheckSSLConfig(httpContext);
var cookieToken = GetCookieTokenDoesNotThrow(httpContext);
cookieToken = ValidateAndGenerateNewCookieToken(cookieToken);
SaveCookieTokenAndHeader(httpContext, cookieToken);
}
// This method returns null if oldCookieToken is valid.
private AntiForgeryToken ValidateAndGenerateNewCookieToken(AntiForgeryToken cookieToken)
{
if (!_validator.IsCookieTokenValid(cookieToken))
{
// Need to make sure we're always operating with a good cookie token.
var newCookieToken = _generator.GenerateCookieToken();
Debug.Assert(_validator.IsCookieTokenValid(newCookieToken));
return newCookieToken;
}
return null;
}
private void SaveCookieTokenAndHeader(
[NotNull] HttpContext httpContext,
AntiForgeryToken cookieToken)
{
if (cookieToken != null)
{
// Persist the new cookie if it is not null.
_tokenStore.SaveCookieToken(httpContext, cookieToken);
}
if (!_config.SuppressXFrameOptionsHeader)
{
// Adding X-Frame-Options header to prevent ClickJacking. See
// http://tools.ietf.org/html/draft-ietf-websec-x-frame-options-10
// for more information.
httpContext.Response.Headers.Set("X-Frame-Options", "SAMEORIGIN");
}
}
private class AntiForgeryTokenSetInternal
{
public AntiForgeryToken FormToken { get; set; }
public AntiForgeryToken CookieToken { get; set; }
}
}
}

View File

@ -1,117 +0,0 @@
// 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 System;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;
namespace Microsoft.AspNet.Mvc
{
// Represents a binary blob (token) that contains random data.
// Useful for binary data inside a serialized stream.
[DebuggerDisplay("{DebuggerString}")]
internal sealed class BinaryBlob : IEquatable<BinaryBlob>
{
private static readonly RandomNumberGenerator _randomNumberGenerator = RandomNumberGenerator.Create();
private readonly byte[] _data;
// Generates a new token using a specified bit length.
public BinaryBlob(int bitLength)
: this(bitLength, GenerateNewToken(bitLength))
{
}
// Generates a token using an existing binary value.
public BinaryBlob(int bitLength, byte[] data)
{
if (bitLength < 32 || bitLength % 8 != 0)
{
throw new ArgumentOutOfRangeException(nameof(bitLength));
}
if (data == null || data.Length != bitLength / 8)
{
throw new ArgumentOutOfRangeException(nameof(data));
}
_data = data;
}
public int BitLength
{
get
{
return checked(_data.Length * 8);
}
}
private string DebuggerString
{
get
{
var sb = new StringBuilder("0x", 2 + (_data.Length * 2));
for (var i = 0; i < _data.Length; i++)
{
sb.AppendFormat(CultureInfo.InvariantCulture, "{0:x2}", _data[i]);
}
return sb.ToString();
}
}
public override bool Equals(object obj)
{
return Equals(obj as BinaryBlob);
}
public bool Equals(BinaryBlob other)
{
if (other == null)
{
return false;
}
Debug.Assert(this._data.Length == other._data.Length);
return AreByteArraysEqual(this._data, other._data);
}
public byte[] GetData()
{
return _data;
}
public override int GetHashCode()
{
// Since data should contain uniformly-distributed entropy, the
// first 32 bits can serve as the hash code.
Debug.Assert(_data != null && _data.Length >= (32 / 8));
return BitConverter.ToInt32(_data, 0);
}
private static byte[] GenerateNewToken(int bitLength)
{
var data = new byte[bitLength / 8];
_randomNumberGenerator.GetBytes(data);
return data;
}
// Need to mark it with NoInlining and NoOptimization attributes to ensure that the
// operation runs in constant time.
[MethodImplAttribute(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
private static bool AreByteArraysEqual(byte[] a, byte[] b)
{
if (a == null || b == null || a.Length != b.Length)
{
return false;
}
var areEqual = true;
for (var i = 0; i < a.Length; i++)
{
areEqual &= (a[i] == b[i]);
}
return areEqual;
}
}
}

View File

@ -1,26 +0,0 @@
// 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.AspNet.Http;
namespace Microsoft.AspNet.Mvc
{
/// <summary>
/// A default <see cref="IAntiForgeryAdditionalDataProvider"/> implementation.
/// </summary>
public class DefaultAntiForgeryAdditionalDataProvider : IAntiForgeryAdditionalDataProvider
{
/// <inheritdoc />
public virtual string GetAdditionalData(HttpContext context)
{
return string.Empty;
}
/// <inheritdoc />
public virtual bool ValidateAdditionalData(HttpContext context, string additionalData)
{
// Default implementation does not understand anything but empty data.
return string.IsNullOrEmpty(additionalData);
}
}
}

View File

@ -1,80 +0,0 @@
// 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 System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Claims;
using System.Security.Cryptography;
namespace Microsoft.AspNet.Mvc
{
/// <summary>
/// Default implementation of <see cref="IClaimUidExtractor"/>.
/// </summary>
public class DefaultClaimUidExtractor : IClaimUidExtractor
{
/// <inheritdoc />
public string ExtractClaimUid(ClaimsIdentity claimsIdentity)
{
if (claimsIdentity == null || !claimsIdentity.IsAuthenticated)
{
// Skip anonymous users
return null;
}
var uniqueIdentifierParameters = GetUniqueIdentifierParameters(claimsIdentity);
var claimUidBytes = ComputeSHA256(uniqueIdentifierParameters);
return Convert.ToBase64String(claimUidBytes);
}
internal static IEnumerable<string> GetUniqueIdentifierParameters(ClaimsIdentity claimsIdentity)
{
var nameIdentifierClaim = claimsIdentity.FindFirst(
claim => string.Equals(ClaimTypes.NameIdentifier, claim.Type, StringComparison.Ordinal));
if (nameIdentifierClaim != null && !string.IsNullOrEmpty(nameIdentifierClaim.Value))
{
return new string[]
{
ClaimTypes.NameIdentifier,
nameIdentifierClaim.Value
};
}
// We Do not understand this claimsIdentity, fallback on serializing the entire claims Identity.
var claims = claimsIdentity.Claims.ToList();
claims.Sort((a, b) => string.Compare(a.Type, b.Type, StringComparison.Ordinal));
var identifierParameters = new List<string>();
foreach (var claim in claims)
{
identifierParameters.Add(claim.Type);
identifierParameters.Add(claim.Value);
}
return identifierParameters;
}
private static byte[] ComputeSHA256(IEnumerable<string> parameters)
{
using (var ms = new MemoryStream())
{
using (var bw = new BinaryWriter(ms))
{
foreach (string parameter in parameters)
{
bw.Write(parameter); // also writes the length as a prefix; unambiguous
}
bw.Flush();
using (var sha256 = SHA256.Create())
{
var retVal = sha256.ComputeHash(ms.ToArray(), 0, checked((int)ms.Length));
return retVal;
}
}
}
}
}
}

View File

@ -1,39 +0,0 @@
// 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.AspNet.Http;
namespace Microsoft.AspNet.Mvc
{
/// <summary>
/// Allows providing or validating additional custom data for anti-forgery tokens.
/// For example, the developer could use this to supply a nonce when the token is
/// generated, then he could validate the nonce when the token is validated.
/// </summary>
/// <remarks>
/// The anti-forgery system already embeds the client's username within the
/// generated tokens. This interface provides and consumes <em>supplemental</em>
/// data. If an incoming anti-forgery token contains supplemental data but no
/// additional data provider is configured, the supplemental data will not be
/// validated.
/// </remarks>
public interface IAntiForgeryAdditionalDataProvider
{
/// <summary>
/// Provides additional data to be stored for the anti-forgery tokens generated
/// during this request.
/// </summary>
/// <param name="context">Information about the current request.</param>
/// <returns>Supplemental data to embed within the anti-forgery token.</returns>
string GetAdditionalData(HttpContext context);
/// <summary>
/// Validates additional data that was embedded inside an incoming anti-forgery
/// token.
/// </summary>
/// <param name="context">Information about the current request.</param>
/// <param name="additionalData">Supplemental data that was embedded within the token.</param>
/// <returns>True if the data is valid; false if the data is invalid.</returns>
bool ValidateAdditionalData(HttpContext context, string additionalData);
}
}

View File

@ -1,22 +0,0 @@
// 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 System.Security.Claims;
using Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Mvc
{
// Provides configuration information about the anti-forgery system.
internal interface IAntiForgeryTokenGenerator
{
// Generates a new random cookie token.
AntiForgeryToken GenerateCookieToken();
// Given a cookie token, generates a corresponding form token.
// The incoming cookie token must be valid.
AntiForgeryToken GenerateFormToken(
HttpContext httpContext,
ClaimsIdentity identity,
AntiForgeryToken cookieToken);
}
}

View File

@ -1,12 +0,0 @@
// 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.AspNet.Mvc
{
// Abstracts out the serialization process for an anti-forgery token
internal interface IAntiForgeryTokenSerializer
{
AntiForgeryToken Deserialize(string serializedToken);
string Serialize(AntiForgeryToken token);
}
}

View File

@ -1,16 +0,0 @@
// 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 System.Threading.Tasks;
using Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Mvc
{
// Provides an abstraction around how tokens are persisted and retrieved for a request
internal interface IAntiForgeryTokenStore
{
AntiForgeryToken GetCookieToken(HttpContext httpContext);
Task<AntiForgeryToken> GetFormTokenAsync(HttpContext httpContext);
void SaveCookieToken(HttpContext httpContext, AntiForgeryToken token);
}
}

View File

@ -1,23 +0,0 @@
// 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 System.Security.Claims;
using Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Mvc
{
// Provides an abstraction around something that can validate anti-XSRF tokens
internal interface IAntiForgeryTokenValidator
{
// Determines whether an existing cookie token is valid (well-formed).
// If it is not, the caller must call GenerateCookieToken() before calling GenerateFormToken().
bool IsCookieTokenValid(AntiForgeryToken cookieToken);
// Validates a (cookie, form) token pair.
void ValidateTokens(
HttpContext httpContext,
ClaimsIdentity identity,
AntiForgeryToken cookieToken,
AntiForgeryToken formToken);
}
}

View File

@ -1,20 +0,0 @@
// 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 System.Security.Claims;
namespace Microsoft.AspNet.Mvc
{
/// <summary>
/// This interface can extract unique identifers for a claims-based identity.
/// </summary>
public interface IClaimUidExtractor
{
/// <summary>
/// Extracts claims identifier.
/// </summary>
/// <param name="identity">The <see cref="ClaimsIdentity"/>.</param>
/// <returns>The claims identifier.</returns>
string ExtractClaimUid(ClaimsIdentity identity);
}
}

View File

@ -2,6 +2,7 @@
// 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 System; using System;
using Microsoft.AspNet.Antiforgery;
using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.DependencyInjection;
namespace Microsoft.AspNet.Mvc namespace Microsoft.AspNet.Mvc
@ -13,8 +14,8 @@ namespace Microsoft.AspNet.Mvc
public IFilter CreateInstance(IServiceProvider serviceProvider) public IFilter CreateInstance(IServiceProvider serviceProvider)
{ {
var antiForgery = serviceProvider.GetRequiredService<AntiForgery>(); var antiforgery = serviceProvider.GetRequiredService<IAntiforgery>();
return new ValidateAntiForgeryTokenAuthorizationFilter(antiForgery); return new ValidateAntiforgeryTokenAuthorizationFilter(antiforgery);
} }
} }
} }

View File

@ -2,22 +2,23 @@
// 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 System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Antiforgery;
using Microsoft.Framework.Internal; using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc namespace Microsoft.AspNet.Mvc
{ {
public class ValidateAntiForgeryTokenAuthorizationFilter : IAsyncAuthorizationFilter public class ValidateAntiforgeryTokenAuthorizationFilter : IAsyncAuthorizationFilter
{ {
private readonly AntiForgery _antiForgery; private readonly IAntiforgery _antiforgery;
public ValidateAntiForgeryTokenAuthorizationFilter([NotNull] AntiForgery antiForgery) public ValidateAntiforgeryTokenAuthorizationFilter([NotNull] IAntiforgery antiforgery)
{ {
_antiForgery = antiForgery; _antiforgery = antiforgery;
} }
public async Task OnAuthorizationAsync([NotNull] AuthorizationContext context) public async Task OnAuthorizationAsync([NotNull] AuthorizationContext context)
{ {
await _antiForgery.ValidateAsync(context.HttpContext); await _antiforgery.ValidateRequestAsync(context.HttpContext);
} }
} }
} }

View File

@ -42,150 +42,6 @@ namespace Microsoft.AspNet.Mvc.Extensions
return string.Format(CultureInfo.CurrentCulture, GetString("ObjectResult_MatchAllContentType"), p0, p1); return string.Format(CultureInfo.CurrentCulture, GetString("ObjectResult_MatchAllContentType"), p0, p1);
} }
/// <summary>
/// The provided anti-forgery token failed a custom data check.
/// </summary>
internal static string AntiForgeryToken_AdditionalDataCheckFailed
{
get { return GetString("AntiForgeryToken_AdditionalDataCheckFailed"); }
}
/// <summary>
/// The provided anti-forgery token failed a custom data check.
/// </summary>
internal static string FormatAntiForgeryToken_AdditionalDataCheckFailed()
{
return GetString("AntiForgeryToken_AdditionalDataCheckFailed");
}
/// <summary>
/// The provided anti-forgery token was meant for a different claims-based user than the current user.
/// </summary>
internal static string AntiForgeryToken_ClaimUidMismatch
{
get { return GetString("AntiForgeryToken_ClaimUidMismatch"); }
}
/// <summary>
/// The provided anti-forgery token was meant for a different claims-based user than the current user.
/// </summary>
internal static string FormatAntiForgeryToken_ClaimUidMismatch()
{
return GetString("AntiForgeryToken_ClaimUidMismatch");
}
/// <summary>
/// The required anti-forgery cookie "{0}" is not present.
/// </summary>
internal static string AntiForgeryToken_CookieMissing
{
get { return GetString("AntiForgeryToken_CookieMissing"); }
}
/// <summary>
/// The required anti-forgery cookie "{0}" is not present.
/// </summary>
internal static string FormatAntiForgeryToken_CookieMissing(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("AntiForgeryToken_CookieMissing"), p0);
}
/// <summary>
/// The anti-forgery token could not be decrypted.
/// </summary>
internal static string AntiForgeryToken_DeserializationFailed
{
get { return GetString("AntiForgeryToken_DeserializationFailed"); }
}
/// <summary>
/// The anti-forgery token could not be decrypted.
/// </summary>
internal static string FormatAntiForgeryToken_DeserializationFailed()
{
return GetString("AntiForgeryToken_DeserializationFailed");
}
/// <summary>
/// The required anti-forgery form field "{0}" is not present.
/// </summary>
internal static string AntiForgeryToken_FormFieldMissing
{
get { return GetString("AntiForgeryToken_FormFieldMissing"); }
}
/// <summary>
/// The required anti-forgery form field "{0}" is not present.
/// </summary>
internal static string FormatAntiForgeryToken_FormFieldMissing(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("AntiForgeryToken_FormFieldMissing"), p0);
}
/// <summary>
/// The anti-forgery cookie token and form field token do not match.
/// </summary>
internal static string AntiForgeryToken_SecurityTokenMismatch
{
get { return GetString("AntiForgeryToken_SecurityTokenMismatch"); }
}
/// <summary>
/// The anti-forgery cookie token and form field token do not match.
/// </summary>
internal static string FormatAntiForgeryToken_SecurityTokenMismatch()
{
return GetString("AntiForgeryToken_SecurityTokenMismatch");
}
/// <summary>
/// Validation of the provided anti-forgery token failed. The cookie "{0}" and the form field "{1}" were swapped.
/// </summary>
internal static string AntiForgeryToken_TokensSwapped
{
get { return GetString("AntiForgeryToken_TokensSwapped"); }
}
/// <summary>
/// Validation of the provided anti-forgery token failed. The cookie "{0}" and the form field "{1}" were swapped.
/// </summary>
internal static string FormatAntiForgeryToken_TokensSwapped(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("AntiForgeryToken_TokensSwapped"), p0, p1);
}
/// <summary>
/// The provided anti-forgery token was meant for user "{0}", but the current user is "{1}".
/// </summary>
internal static string AntiForgeryToken_UsernameMismatch
{
get { return GetString("AntiForgeryToken_UsernameMismatch"); }
}
/// <summary>
/// The provided anti-forgery token was meant for user "{0}", but the current user is "{1}".
/// </summary>
internal static string FormatAntiForgeryToken_UsernameMismatch(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("AntiForgeryToken_UsernameMismatch"), p0, p1);
}
/// <summary>
/// The anti-forgery system has the configuration value AntiForgeryOptions.RequireSsl = true, but the current request is not an SSL request.
/// </summary>
internal static string AntiForgeryWorker_RequireSSL
{
get { return GetString("AntiForgeryWorker_RequireSSL"); }
}
/// <summary>
/// The anti-forgery system has the configuration value AntiForgeryOptions.RequireSsl = true, but the current request is not an SSL request.
/// </summary>
internal static string FormatAntiForgeryWorker_RequireSSL()
{
return GetString("AntiForgeryWorker_RequireSSL");
}
/// <summary> /// <summary>
/// The method '{0}' on type '{1}' returned an instance of '{2}'. Make sure to call Unwrap on the returned value to avoid unobserved faulted Task. /// The method '{0}' on type '{1}' returned an instance of '{2}'. Make sure to call Unwrap on the returned value to avoid unobserved faulted Task.
/// </summary> /// </summary>
@ -234,22 +90,6 @@ namespace Microsoft.AspNet.Mvc.Extensions
return string.Format(CultureInfo.CurrentCulture, GetString("ClaimUidExtractor_ClaimNotPresent"), p0); return string.Format(CultureInfo.CurrentCulture, GetString("ClaimUidExtractor_ClaimNotPresent"), p0);
} }
/// <summary>
/// The provided identity of type '{0}' is marked IsAuthenticated = true but does not have a value for Name. By default, the anti-forgery system requires that all authenticated identities have a unique Name. If it is not possible to provide a unique Name for this identity, consider extending IAdditionalDataProvider by overriding the DefaultAdditionalDataProvider or a custom type that can provide some form of unique identifier for the current user.
/// </summary>
internal static string TokenValidator_AuthenticatedUserWithoutUsername
{
get { return GetString("TokenValidator_AuthenticatedUserWithoutUsername"); }
}
/// <summary>
/// The provided identity of type '{0}' is marked IsAuthenticated = true but does not have a value for Name. By default, the anti-forgery system requires that all authenticated identities have a unique Name. If it is not possible to provide a unique Name for this identity, consider extending IAdditionalDataProvider by overriding the DefaultAdditionalDataProvider or a custom type that can provide some form of unique identifier for the current user.
/// </summary>
internal static string FormatTokenValidator_AuthenticatedUserWithoutUsername(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("TokenValidator_AuthenticatedUserWithoutUsername"), p0);
}
/// <summary> /// <summary>
/// The class ReflectedActionFilterEndPoint only supports ReflectedActionDescriptors. /// The class ReflectedActionFilterEndPoint only supports ReflectedActionDescriptors.
/// </summary> /// </summary>

View File

@ -9,6 +9,7 @@ using System.Globalization;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using Microsoft.AspNet.Antiforgery;
using Microsoft.AspNet.Mvc.Extensions; using Microsoft.AspNet.Mvc.Extensions;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.ModelBinding.Validation; using Microsoft.AspNet.Mvc.ModelBinding.Validation;
@ -25,7 +26,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
private static readonly MethodInfo ConvertEnumFromStringMethod = private static readonly MethodInfo ConvertEnumFromStringMethod =
typeof(DefaultHtmlGenerator).GetTypeInfo().GetDeclaredMethod(nameof(ConvertEnumFromString)); typeof(DefaultHtmlGenerator).GetTypeInfo().GetDeclaredMethod(nameof(ConvertEnumFromString));
private readonly AntiForgery _antiForgery; private readonly IAntiforgery _antiforgery;
private readonly IClientModelValidatorProvider _clientModelValidatorProvider; private readonly IClientModelValidatorProvider _clientModelValidatorProvider;
private readonly IModelMetadataProvider _metadataProvider; private readonly IModelMetadataProvider _metadataProvider;
private readonly IUrlHelper _urlHelper; private readonly IUrlHelper _urlHelper;
@ -34,20 +35,20 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DefaultHtmlGenerator"/> class. /// Initializes a new instance of the <see cref="DefaultHtmlGenerator"/> class.
/// </summary> /// </summary>
/// <param name="antiForgery">The <see cref="AntiForgery"/> instance which is used to generate anti-forgery /// <param name="antiforgery">The <see cref="IAntiforgery"/> instance which is used to generate antiforgery
/// tokens.</param> /// tokens.</param>
/// <param name="optionsAccessor">The accessor for <see cref="MvcOptions"/>.</param> /// <param name="optionsAccessor">The accessor for <see cref="MvcOptions"/>.</param>
/// <param name="metadataProvider">The <see cref="IModelMetadataProvider"/>.</param> /// <param name="metadataProvider">The <see cref="IModelMetadataProvider"/>.</param>
/// <param name="urlHelper">The <see cref="IUrlHelper"/>.</param> /// <param name="urlHelper">The <see cref="IUrlHelper"/>.</param>
/// <param name="htmlEncoder">The <see cref="IHtmlEncoder"/>.</param> /// <param name="htmlEncoder">The <see cref="IHtmlEncoder"/>.</param>
public DefaultHtmlGenerator( public DefaultHtmlGenerator(
[NotNull] AntiForgery antiForgery, [NotNull] IAntiforgery antiforgery,
[NotNull] IOptions<MvcViewOptions> optionsAccessor, [NotNull] IOptions<MvcViewOptions> optionsAccessor,
[NotNull] IModelMetadataProvider metadataProvider, [NotNull] IModelMetadataProvider metadataProvider,
[NotNull] IUrlHelper urlHelper, [NotNull] IUrlHelper urlHelper,
[NotNull] IHtmlEncoder htmlEncoder) [NotNull] IHtmlEncoder htmlEncoder)
{ {
_antiForgery = antiForgery; _antiforgery = antiforgery;
var clientValidatorProviders = optionsAccessor.Options.ClientModelValidatorProviders; var clientValidatorProviders = optionsAccessor.Options.ClientModelValidatorProviders;
_clientModelValidatorProvider = new CompositeClientModelValidatorProvider(clientValidatorProviders); _clientModelValidatorProvider = new CompositeClientModelValidatorProvider(clientValidatorProviders);
_metadataProvider = metadataProvider; _metadataProvider = metadataProvider;
@ -95,10 +96,10 @@ namespace Microsoft.AspNet.Mvc.Rendering
} }
/// <inheritdoc /> /// <inheritdoc />
public virtual TagBuilder GenerateAntiForgery([NotNull] ViewContext viewContext) public virtual HtmlString GenerateAntiforgery([NotNull] ViewContext viewContext)
{ {
var tagBuilder = _antiForgery.GetHtml(viewContext.HttpContext); var tag = _antiforgery.GetHtml(viewContext.HttpContext);
return tagBuilder; return new HtmlString(tag);
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -221,13 +221,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// <inheritdoc /> /// <inheritdoc />
public HtmlString AntiForgeryToken() public HtmlString AntiForgeryToken()
{ {
var tagBuilder = _htmlGenerator.GenerateAntiForgery(ViewContext); var html = _htmlGenerator.GenerateAntiforgery(ViewContext);
if (tagBuilder == null) return html ?? HtmlString.Empty;
{
return HtmlString.Empty;
}
return tagBuilder.ToHtmlString(TagRenderMode.SelfClosing);
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -31,7 +31,12 @@ namespace Microsoft.AspNet.Mvc.Rendering
object routeValues, object routeValues,
object htmlAttributes); object htmlAttributes);
TagBuilder GenerateAntiForgery([NotNull] ViewContext viewContext); /// <summary>
/// Genrate an &lt;input type="hidden".../&gt; element containing an antiforgery token.
/// </summary>
/// <param name="viewContext">The <see cref="ViewContext"/> instance for the current scope.</param>
/// <returns>An <see cref="HtmlString"/> instance for the &lt;input type="hidden".../&gt; element.</returns>
HtmlString GenerateAntiforgery([NotNull] ViewContext viewContext);
/// <summary> /// <summary>
/// Generate a &lt;input type="checkbox".../&gt; element. /// Generate a &lt;input type="checkbox".../&gt; element.

View File

@ -99,7 +99,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
object htmlAttributes); object htmlAttributes);
/// <summary> /// <summary>
/// Returns a &lt;hidden&gt; element (anti-forgery token) that will be validated when the containing /// Returns a &lt;hidden&gt; element (antiforgery token) that will be validated when the containing
/// &lt;form&gt; is submitted. /// &lt;form&gt; is submitted.
/// </summary> /// </summary>
/// <returns>A new <see cref="HtmlString"/> containing the &lt;hidden&gt; element.</returns> /// <returns>A new <see cref="HtmlString"/> containing the &lt;hidden&gt; element.</returns>

View File

@ -123,33 +123,6 @@
<data name="ObjectResult_MatchAllContentType" xml:space="preserve"> <data name="ObjectResult_MatchAllContentType" xml:space="preserve">
<value>The content-type '{0}' added in the '{1}' property is invalid. Media types which match all types or match all subtypes are not supported.</value> <value>The content-type '{0}' added in the '{1}' property is invalid. Media types which match all types or match all subtypes are not supported.</value>
</data> </data>
<data name="AntiForgeryToken_AdditionalDataCheckFailed" xml:space="preserve">
<value>The provided anti-forgery token failed a custom data check.</value>
</data>
<data name="AntiForgeryToken_ClaimUidMismatch" xml:space="preserve">
<value>The provided anti-forgery token was meant for a different claims-based user than the current user.</value>
</data>
<data name="AntiForgeryToken_CookieMissing" xml:space="preserve">
<value>The required anti-forgery cookie "{0}" is not present.</value>
</data>
<data name="AntiForgeryToken_DeserializationFailed" xml:space="preserve">
<value>The anti-forgery token could not be decrypted.</value>
</data>
<data name="AntiForgeryToken_FormFieldMissing" xml:space="preserve">
<value>The required anti-forgery form field "{0}" is not present.</value>
</data>
<data name="AntiForgeryToken_SecurityTokenMismatch" xml:space="preserve">
<value>The anti-forgery cookie token and form field token do not match.</value>
</data>
<data name="AntiForgeryToken_TokensSwapped" xml:space="preserve">
<value>Validation of the provided anti-forgery token failed. The cookie "{0}" and the form field "{1}" were swapped.</value>
</data>
<data name="AntiForgeryToken_UsernameMismatch" xml:space="preserve">
<value>The provided anti-forgery token was meant for user "{0}", but the current user is "{1}".</value>
</data>
<data name="AntiForgeryWorker_RequireSSL" xml:space="preserve">
<value>The anti-forgery system has the configuration value AntiForgeryOptions.RequireSsl = true, but the current request is not an SSL request.</value>
</data>
<data name="ActionExecutor_WrappedTaskInstance" xml:space="preserve"> <data name="ActionExecutor_WrappedTaskInstance" xml:space="preserve">
<value>The method '{0}' on type '{1}' returned an instance of '{2}'. Make sure to call Unwrap on the returned value to avoid unobserved faulted Task.</value> <value>The method '{0}' on type '{1}' returned an instance of '{2}'. Make sure to call Unwrap on the returned value to avoid unobserved faulted Task.</value>
</data> </data>
@ -159,9 +132,6 @@
<data name="ClaimUidExtractor_ClaimNotPresent" xml:space="preserve"> <data name="ClaimUidExtractor_ClaimNotPresent" xml:space="preserve">
<value>A claim of type '{0}' was not present on the provided ClaimsIdentity.</value> <value>A claim of type '{0}' was not present on the provided ClaimsIdentity.</value>
</data> </data>
<data name="TokenValidator_AuthenticatedUserWithoutUsername" xml:space="preserve">
<value>The provided identity of type '{0}' is marked IsAuthenticated = true but does not have a value for Name. By default, the anti-forgery system requires that all authenticated identities have a unique Name. If it is not possible to provide a unique Name for this identity, consider extending IAdditionalDataProvider by overriding the DefaultAdditionalDataProvider or a custom type that can provide some form of unique identifier for the current user.</value>
</data>
<data name="ReflectedActionFilterEndPoint_UnexpectedActionDescriptor" xml:space="preserve"> <data name="ReflectedActionFilterEndPoint_UnexpectedActionDescriptor" xml:space="preserve">
<value>The class ReflectedActionFilterEndPoint only supports ReflectedActionDescriptors.</value> <value>The class ReflectedActionFilterEndPoint only supports ReflectedActionDescriptors.</value>
</data> </data>

View File

@ -5,6 +5,7 @@
"warningsAsErrors": true "warningsAsErrors": true
}, },
"dependencies": { "dependencies": {
"Microsoft.AspNet.Antiforgery": "1.0.0-*",
"Microsoft.AspNet.Authentication": "1.0.0-*", "Microsoft.AspNet.Authentication": "1.0.0-*",
"Microsoft.AspNet.Authorization": "1.0.0-*", "Microsoft.AspNet.Authorization": "1.0.0-*",
"Microsoft.AspNet.Cors.Core": "1.0.0-*", "Microsoft.AspNet.Cors.Core": "1.0.0-*",

View File

@ -8,6 +8,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Security.Claims; using System.Security.Claims;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Antiforgery;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.Razor.Internal; using Microsoft.AspNet.Mvc.Razor.Internal;
using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.Mvc.Rendering;
@ -781,8 +782,8 @@ namespace Microsoft.AspNet.Mvc.Razor
/// <remarks>The value returned is a token value that allows FlushAsync to work directly in an HTML /// <remarks>The value returned is a token value that allows FlushAsync to work directly in an HTML
/// section. However the value does not represent the rendered content. /// section. However the value does not represent the rendered content.
/// This method also writes out headers, so any modifications to headers must be done before /// This method also writes out headers, so any modifications to headers must be done before
/// <see cref="FlushAsync"/> is called. For example, call <see cref="SetAntiForgeryCookieAndHeader"/> to send /// <see cref="FlushAsync"/> is called. For example, call <see cref="SetAntiforgeryCookieAndHeader"/> to send
/// anti-forgery cookie token and X-Frame-Options header to client before this method flushes headers out. /// antiforgery cookie token and X-Frame-Options header to client before this method flushes headers out.
/// </remarks> /// </remarks>
public async Task<HtmlString> FlushAsync() public async Task<HtmlString> FlushAsync()
{ {
@ -843,15 +844,15 @@ namespace Microsoft.AspNet.Mvc.Razor
} }
/// <summary> /// <summary>
/// Sets anti-forgery cookie and X-Frame-Options header on the response. /// Sets antiforgery cookie and X-Frame-Options header on the response.
/// </summary> /// </summary>
/// <returns>A <see cref="HtmlString"/> that returns a <see cref="HtmlString.Empty"/>.</returns> /// <returns>A <see cref="HtmlString"/> that returns a <see cref="HtmlString.Empty"/>.</returns>
/// <remarks> Call this method to send anti-forgery cookie token and X-Frame-Options header to client /// <remarks> Call this method to send antiforgery cookie token and X-Frame-Options header to client
/// before <see cref="FlushAsync"/> flushes the headers. </remarks> /// before <see cref="FlushAsync"/> flushes the headers. </remarks>
public virtual HtmlString SetAntiForgeryCookieAndHeader() public virtual HtmlString SetAntiforgeryCookieAndHeader()
{ {
var antiForgery = Context.RequestServices.GetRequiredService<AntiForgery>(); var antiforgery = Context.RequestServices.GetRequiredService<IAntiforgery>();
antiForgery.SetCookieTokenAndHeader(Context); antiforgery.SetCookieTokenAndHeader(Context);
return HtmlString.Empty; return HtmlString.Empty;
} }

View File

@ -13,7 +13,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
/// <see cref="ITagHelper"/> implementation targeting &lt;form&gt; elements. /// <see cref="ITagHelper"/> implementation targeting &lt;form&gt; elements.
/// </summary> /// </summary>
[TargetElement("form", Attributes = ActionAttributeName)] [TargetElement("form", Attributes = ActionAttributeName)]
[TargetElement("form", Attributes = AntiForgeryAttributeName)] [TargetElement("form", Attributes = AntiforgeryAttributeName)]
[TargetElement("form", Attributes = ControllerAttributeName)] [TargetElement("form", Attributes = ControllerAttributeName)]
[TargetElement("form", Attributes = RouteAttributeName)] [TargetElement("form", Attributes = RouteAttributeName)]
[TargetElement("form", Attributes = RouteValuesDictionaryName)] [TargetElement("form", Attributes = RouteValuesDictionaryName)]
@ -21,7 +21,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
public class FormTagHelper : TagHelper public class FormTagHelper : TagHelper
{ {
private const string ActionAttributeName = "asp-action"; private const string ActionAttributeName = "asp-action";
private const string AntiForgeryAttributeName = "asp-anti-forgery"; private const string AntiforgeryAttributeName = "asp-antiforgery";
private const string ControllerAttributeName = "asp-controller"; private const string ControllerAttributeName = "asp-controller";
private const string RouteAttributeName = "asp-route"; private const string RouteAttributeName = "asp-route";
private const string RouteValuesDictionaryName = "asp-all-route-data"; private const string RouteValuesDictionaryName = "asp-all-route-data";
@ -56,11 +56,11 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
public string Controller { get; set; } public string Controller { get; set; }
/// <summary> /// <summary>
/// Whether the anti-forgery token should be generated. /// Whether the antiforgery token should be generated.
/// </summary> /// </summary>
/// <value>Defaults to <c>false</c> if user provides an <c>action</c> attribute; <c>true</c> otherwise.</value> /// <value>Defaults to <c>false</c> if user provides an <c>action</c> attribute; <c>true</c> otherwise.</value>
[HtmlAttributeName(AntiForgeryAttributeName)] [HtmlAttributeName(AntiforgeryAttributeName)]
public bool? AntiForgery { get; set; } public bool? Antiforgery { get; set; }
/// <summary> /// <summary>
/// Name of the route. /// Name of the route.
@ -80,7 +80,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
/// <inheritdoc /> /// <inheritdoc />
/// <remarks> /// <remarks>
/// Does nothing if user provides an <c>action</c> attribute and <see cref="AntiForgery"/> is <c>null</c> or /// Does nothing if user provides an <c>action</c> attribute and <see cref="Antiforgery"/> is <c>null</c> or
/// <c>false</c>. /// <c>false</c>.
/// </remarks> /// </remarks>
/// <exception cref="InvalidOperationException"> /// <exception cref="InvalidOperationException">
@ -89,7 +89,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
/// </exception> /// </exception>
public override void Process(TagHelperContext context, TagHelperOutput output) public override void Process(TagHelperContext context, TagHelperOutput output)
{ {
var antiForgeryDefault = true; var antiforgeryDefault = true;
// If "action" is already set, it means the user is attempting to use a normal <form>. // If "action" is already set, it means the user is attempting to use a normal <form>.
if (output.Attributes.ContainsName(HtmlActionAttributeName)) if (output.Attributes.ContainsName(HtmlActionAttributeName))
@ -107,9 +107,9 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
RouteValuesPrefix)); RouteValuesPrefix));
} }
// User is using the FormTagHelper like a normal <form> tag. Anti-forgery default should be false to // User is using the FormTagHelper like a normal <form> tag. Antiforgery default should be false to
// not force the anti-forgery token on the user. // not force the antiforgery token on the user.
antiForgeryDefault = false; antiforgeryDefault = false;
} }
else else
{ {
@ -158,12 +158,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
} }
} }
if (AntiForgery ?? antiForgeryDefault) if (Antiforgery ?? antiforgeryDefault)
{ {
var antiForgeryTagBuilder = Generator.GenerateAntiForgery(ViewContext); var antiforgeryTag = Generator.GenerateAntiforgery(ViewContext);
if (antiForgeryTagBuilder != null) if (antiforgeryTag != null)
{ {
output.PostContent.Append(antiForgeryTagBuilder.ToString(TagRenderMode.SelfClosing)); output.PostContent.Append(antiforgeryTag.ToString());
} }
} }
} }

View File

@ -33,18 +33,6 @@ namespace Microsoft.Framework.DependencyInjection
return services; return services;
} }
/// <summary>
/// Configures a set of <see cref="AntiForgeryOptions"/> for the application.
/// </summary>
/// <param name="services">The services available in the application.</param>
/// <param name="setupAction">The <see cref="AntiForgeryOptions"/> which need to be configured.</param>
public static void ConfigureAntiforgery(
[NotNull] this IServiceCollection services,
[NotNull] Action<AntiForgeryOptions> setupAction)
{
services.Configure(setupAction);
}
/// <summary> /// <summary>
/// Configures a set of <see cref="MvcFormatterMappingOptions"/> for the application. /// Configures a set of <see cref="MvcFormatterMappingOptions"/> for the application.
/// </summary> /// </summary>
@ -245,11 +233,6 @@ namespace Microsoft.Framework.DependencyInjection
services.TryAddSingleton<IViewComponentInvokerFactory, DefaultViewComponentInvokerFactory>(); services.TryAddSingleton<IViewComponentInvokerFactory, DefaultViewComponentInvokerFactory>();
services.TryAddTransient<IViewComponentHelper, DefaultViewComponentHelper>(); services.TryAddTransient<IViewComponentHelper, DefaultViewComponentHelper>();
// Security and Authorization
services.TryAddSingleton<IClaimUidExtractor, DefaultClaimUidExtractor>();
services.TryAddSingleton<AntiForgery, AntiForgery>();
services.TryAddSingleton<IAntiForgeryAdditionalDataProvider, DefaultAntiForgeryAdditionalDataProvider>();
// Api Description // Api Description
services.TryAddSingleton<IApiDescriptionGroupCollectionProvider, ApiDescriptionGroupCollectionProvider>(); services.TryAddSingleton<IApiDescriptionGroupCollectionProvider, ApiDescriptionGroupCollectionProvider>();
services.TryAddEnumerable( services.TryAddEnumerable(
@ -287,6 +270,7 @@ namespace Microsoft.Framework.DependencyInjection
private static void ConfigureDefaultServices(IServiceCollection services) private static void ConfigureDefaultServices(IServiceCollection services)
{ {
services.AddDataProtection(); services.AddDataProtection();
services.AddAntiforgery();
services.AddCors(); services.AddCors();
services.AddAuthorization(); services.AddAuthorization();
services.AddWebEncoders(); services.AddWebEncoders();

View File

@ -1,35 +0,0 @@
// 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 System;
using Xunit;
namespace Microsoft.AspNet.Mvc.Core.Test
{
public class AntiForgeryOptionsTests
{
[Fact]
public void CookieName_SettingNullValue_Throws()
{
// Arrange
var options = new AntiForgeryOptions();
// Act & Assert
var ex = Assert.Throws<ArgumentNullException>(() => options.CookieName = null);
Assert.Equal("The 'CookieName' property of 'Microsoft.AspNet.Mvc.AntiForgeryOptions' must not be null." +
Environment.NewLine + "Parameter name: value", ex.Message);
}
[Fact]
public void FormFieldName_SettingNullValue_Throws()
{
// Arrange
var options = new AntiForgeryOptions();
// Act & Assert
var ex = Assert.Throws<ArgumentNullException>(() => options.FormFieldName = null);
Assert.Equal("The 'FormFieldName' property of 'Microsoft.AspNet.Mvc.AntiForgeryOptions' must not be null." +
Environment.NewLine + "Parameter name: value", ex.Message);
}
}
}

View File

@ -1,181 +0,0 @@
// 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 System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.DataProtection;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Core.Test
{
public class AntiForgeryTokenSerializerTest
{
private static readonly Mock<IDataProtector> _dataProtector = GetDataProtector();
private static readonly BinaryBlob _claimUid = new BinaryBlob(256, new byte[] { 0x6F, 0x16, 0x48, 0xE9, 0x72, 0x49, 0xAA, 0x58, 0x75, 0x40, 0x36, 0xA6, 0x7E, 0x24, 0x8C, 0xF0, 0x44, 0xF0, 0x7E, 0xCF, 0xB0, 0xED, 0x38, 0x75, 0x56, 0xCE, 0x02, 0x9A, 0x4F, 0x9A, 0x40, 0xE0 });
private static readonly BinaryBlob _securityToken = new BinaryBlob(128, new byte[] { 0x70, 0x5E, 0xED, 0xCC, 0x7D, 0x42, 0xF1, 0xD6, 0xB3, 0xB9, 0x8A, 0x59, 0x36, 0x25, 0xBB, 0x4C });
private const byte _salt = 0x05;
[Theory]
[InlineData(
"01" // Version
+ "705EEDCC7D42F1D6B3B9" // SecurityToken
// (WRONG!) Stream ends too early
)]
[InlineData(
"01" // Version
+ "705EEDCC7D42F1D6B3B98A593625BB4C" // SecurityToken
+ "01" // IsSessionToken
+ "00" // (WRONG!) Too much data in stream
)]
[InlineData(
"02" // (WRONG! - must be 0x01) Version
+ "705EEDCC7D42F1D6B3B98A593625BB4C" // SecurityToken
+ "01" // IsSessionToken
)]
[InlineData(
"01" // Version
+ "705EEDCC7D42F1D6B3B98A593625BB4C" // SecurityToken
+ "00" // IsSessionToken
+ "00" // IsClaimsBased
+ "05" // Username length header
+ "0000" // (WRONG!) Too little data in stream
)]
public void Deserialize_BadToken_Throws(string serializedToken)
{
// Arrange
var testSerializer = new AntiForgeryTokenSerializer(_dataProtector.Object);
// Act & assert
var ex = Assert.Throws<InvalidOperationException>(() => testSerializer.Deserialize(serializedToken));
Assert.Equal(@"The anti-forgery token could not be decrypted.", ex.Message);
}
[Fact]
public void Serialize_FieldToken_WithClaimUid_TokenRoundTripSuccessful()
{
// Arrange
var testSerializer = new AntiForgeryTokenSerializer(_dataProtector.Object);
//"01" // Version
//+ "705EEDCC7D42F1D6B3B98A593625BB4C" // SecurityToken
//+ "00" // IsSessionToken
//+ "01" // IsClaimsBased
//+ "6F1648E97249AA58754036A67E248CF044F07ECFB0ED387556CE029A4F9A40E0" // ClaimUid
//+ "05" // AdditionalData length header
//+ "E282AC3437"; // AdditionalData ("€47") as UTF8
var token = new AntiForgeryToken()
{
SecurityToken = _securityToken,
IsSessionToken = false,
ClaimUid = _claimUid,
AdditionalData = "€47"
};
// Act
var actualSerializedData = testSerializer.Serialize(token);
var deserializedToken = testSerializer.Deserialize(actualSerializedData);
// Assert
AssertTokensEqual(token, deserializedToken);
_dataProtector.Verify();
}
[Fact]
public void Serialize_FieldToken_WithUsername_TokenRoundTripSuccessful()
{
// Arrange
var testSerializer = new AntiForgeryTokenSerializer(_dataProtector.Object);
//"01" // Version
//+ "705EEDCC7D42F1D6B3B98A593625BB4C" // SecurityToken
//+ "00" // IsSessionToken
//+ "00" // IsClaimsBased
//+ "08" // Username length header
//+ "4AC3A972C3B46D65" // Username ("Jérôme") as UTF8
//+ "05" // AdditionalData length header
//+ "E282AC3437"; // AdditionalData ("€47") as UTF8
var token = new AntiForgeryToken()
{
SecurityToken = _securityToken,
IsSessionToken = false,
Username = "Jérôme",
AdditionalData = "€47"
};
// Act
var actualSerializedData = testSerializer.Serialize(token);
var deserializedToken = testSerializer.Deserialize(actualSerializedData);
// Assert
AssertTokensEqual(token, deserializedToken);
_dataProtector.Verify();
}
[Fact]
public void Serialize_SessionToken_TokenRoundTripSuccessful()
{
// Arrange
var testSerializer = new AntiForgeryTokenSerializer(_dataProtector.Object);
//"01" // Version
//+ "705EEDCC7D42F1D6B3B98A593625BB4C" // SecurityToken
//+ "01"; // IsSessionToken
var token = new AntiForgeryToken()
{
SecurityToken = _securityToken,
IsSessionToken = true
};
// Act
string actualSerializedData = testSerializer.Serialize(token);
var deserializedToken = testSerializer.Deserialize(actualSerializedData);
// Assert
AssertTokensEqual(token, deserializedToken);
_dataProtector.Verify();
}
private static Mock<IDataProtector> GetDataProtector()
{
var mockCryptoSystem = new Mock<IDataProtector>();
mockCryptoSystem.Setup(o => o.Protect(It.IsAny<byte[]>()))
.Returns<byte[]>(Protect)
.Verifiable();
mockCryptoSystem.Setup(o => o.Unprotect(It.IsAny<byte[]>()))
.Returns<byte[]>(UnProtect)
.Verifiable();
return mockCryptoSystem;
}
private static byte[] Protect(byte[] data)
{
var input = new List<byte>(data);
input.Add(_salt);
return input.ToArray();
}
private static byte[] UnProtect(byte[] data)
{
var salt = data[data.Length - 1];
if (salt != _salt)
{
throw new ArgumentException("Invalid salt value in data");
}
return data.Take(data.Length - 1).ToArray();
}
private static void AssertTokensEqual(AntiForgeryToken expected, AntiForgeryToken actual)
{
Assert.NotNull(expected);
Assert.NotNull(actual);
Assert.Equal(expected.AdditionalData, actual.AdditionalData);
Assert.Equal(expected.ClaimUid, actual.ClaimUid);
Assert.Equal(expected.IsSessionToken, actual.IsSessionToken);
Assert.Equal(expected.SecurityToken, actual.SecurityToken);
Assert.Equal(expected.Username, actual.Username);
}
}
}

View File

@ -1,425 +0,0 @@
// 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 System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.Framework.DependencyInjection;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Core.Test
{
public class AntiForgeryTokenStoreTest
{
private readonly string _cookieName = "cookie-name";
[Fact]
public void GetCookieToken_CookieDoesNotExist_ReturnsNull()
{
// Arrange
var requestCookies = new Mock<IReadableStringCollection>();
requestCookies
.Setup(o => o.Get(It.IsAny<string>()))
.Returns(string.Empty);
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext
.Setup(o => o.Request.Cookies)
.Returns(requestCookies.Object);
var contextAccessor = new ScopedInstance<AntiForgeryContext>();
mockHttpContext.SetupGet(o => o.RequestServices)
.Returns(GetServiceProvider(contextAccessor));
var config = new AntiForgeryOptions()
{
CookieName = _cookieName
};
var tokenStore = new AntiForgeryTokenStore(
config: config,
serializer: null);
// Act
var token = tokenStore.GetCookieToken(mockHttpContext.Object);
// Assert
Assert.Null(token);
}
[Fact]
public void GetCookieToken_CookieIsMissingInRequest_LooksUpCookieInAntiForgeryContext()
{
// Arrange
var requestCookies = new Mock<IReadableStringCollection>();
requestCookies
.Setup(o => o.Get(It.IsAny<string>()))
.Returns(string.Empty);
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext
.Setup(o => o.Request.Cookies)
.Returns(requestCookies.Object);
var contextAccessor = new ScopedInstance<AntiForgeryContext>();
mockHttpContext.SetupGet(o => o.RequestServices)
.Returns(GetServiceProvider(contextAccessor));
// add a cookie explicitly.
var cookie = new AntiForgeryToken();
contextAccessor.Value = new AntiForgeryContext() { CookieToken = cookie };
var config = new AntiForgeryOptions()
{
CookieName = _cookieName
};
var tokenStore = new AntiForgeryTokenStore(
config: config,
serializer: null);
// Act
var token = tokenStore.GetCookieToken(mockHttpContext.Object);
// Assert
Assert.Equal(cookie, token);
}
[Fact]
public void GetCookieToken_CookieIsEmpty_ReturnsNull()
{
// Arrange
var mockHttpContext = GetMockHttpContext(_cookieName, string.Empty);
var config = new AntiForgeryOptions()
{
CookieName = _cookieName
};
var tokenStore = new AntiForgeryTokenStore(
config: config,
serializer: null);
// Act
var token = tokenStore.GetCookieToken(mockHttpContext);
// Assert
Assert.Null(token);
}
[Fact]
public void GetCookieToken_CookieIsInvalid_PropagatesException()
{
// Arrange
var mockHttpContext = GetMockHttpContext(_cookieName, "invalid-value");
var config = new AntiForgeryOptions()
{
CookieName = _cookieName
};
var expectedException = new InvalidOperationException("some exception");
var mockSerializer = new Mock<IAntiForgeryTokenSerializer>();
mockSerializer
.Setup(o => o.Deserialize("invalid-value"))
.Throws(expectedException);
var tokenStore = new AntiForgeryTokenStore(
config: config,
serializer: mockSerializer.Object);
// Act & assert
var ex = Assert.Throws<InvalidOperationException>(() => tokenStore.GetCookieToken(mockHttpContext));
Assert.Same(expectedException, ex);
}
[Fact]
public void GetCookieToken_CookieIsValid_ReturnsToken()
{
// Arrange
var expectedToken = new AntiForgeryToken();
var mockHttpContext = GetMockHttpContext(_cookieName, "valid-value");
var config = new AntiForgeryOptions()
{
CookieName = _cookieName
};
var mockSerializer = new Mock<IAntiForgeryTokenSerializer>();
mockSerializer
.Setup(o => o.Deserialize("valid-value"))
.Returns(expectedToken);
var tokenStore = new AntiForgeryTokenStore(
config: config,
serializer: mockSerializer.Object);
// Act
AntiForgeryToken retVal = tokenStore.GetCookieToken(mockHttpContext);
// Assert
Assert.Same(expectedToken, retVal);
}
[Fact]
public async Task GetFormToken_FormFieldIsEmpty_ReturnsNull()
{
// Arrange
var mockHttpContext = new Mock<HttpContext>();
var requestContext = new Mock<HttpRequest>();
var formCollection = new Mock<IFormCollection>();
formCollection.Setup(f => f["form-field-name"]).Returns(string.Empty);
requestContext.Setup(o => o.ReadFormAsync(CancellationToken.None))
.Returns(Task.FromResult(formCollection.Object));
mockHttpContext.Setup(o => o.Request)
.Returns(requestContext.Object);
var config = new AntiForgeryOptions()
{
FormFieldName = "form-field-name"
};
var tokenStore = new AntiForgeryTokenStore(
config: config,
serializer: null);
// Act
var token = await tokenStore.GetFormTokenAsync(mockHttpContext.Object);
// Assert
Assert.Null(token);
}
[Fact]
public async Task GetFormToken_FormFieldIsInvalid_PropagatesException()
{
// Arrange
var formCollection = new Mock<IFormCollection>();
formCollection.Setup(f => f["form-field-name"]).Returns("invalid-value");
var requestContext = new Mock<HttpRequest>();
requestContext.Setup(o => o.ReadFormAsync(CancellationToken.None))
.Returns(Task.FromResult(formCollection.Object));
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext.Setup(o => o.Request)
.Returns(requestContext.Object);
var config = new AntiForgeryOptions()
{
FormFieldName = "form-field-name"
};
var expectedException = new InvalidOperationException("some exception");
var mockSerializer = new Mock<IAntiForgeryTokenSerializer>();
mockSerializer.Setup(o => o.Deserialize("invalid-value"))
.Throws(expectedException);
var tokenStore = new AntiForgeryTokenStore(
config: config,
serializer: mockSerializer.Object);
// Act & assert
var ex =
await
Assert.ThrowsAsync<InvalidOperationException>(
async () => await tokenStore.GetFormTokenAsync(mockHttpContext.Object));
Assert.Same(expectedException, ex);
}
[Fact]
public async Task GetFormToken_FormFieldIsValid_ReturnsToken()
{
// Arrange
var expectedToken = new AntiForgeryToken();
// Arrange
var mockHttpContext = new Mock<HttpContext>();
var requestContext = new Mock<HttpRequest>();
var formCollection = new Mock<IFormCollection>();
formCollection.Setup(f => f["form-field-name"]).Returns("valid-value");
requestContext.Setup(o => o.ReadFormAsync(CancellationToken.None))
.Returns(Task.FromResult(formCollection.Object));
mockHttpContext.Setup(o => o.Request)
.Returns(requestContext.Object);
var config = new AntiForgeryOptions()
{
FormFieldName = "form-field-name"
};
var mockSerializer = new Mock<IAntiForgeryTokenSerializer>();
mockSerializer.Setup(o => o.Deserialize("valid-value"))
.Returns(expectedToken);
var tokenStore = new AntiForgeryTokenStore(
config: config,
serializer: mockSerializer.Object);
// Act
var retVal = await tokenStore.GetFormTokenAsync(mockHttpContext.Object);
// Assert
Assert.Same(expectedToken, retVal);
}
[Theory]
[InlineData(true, true)]
[InlineData(false, null)]
public void SaveCookieToken(bool requireSsl, bool? expectedCookieSecureFlag)
{
// Arrange
var token = new AntiForgeryToken();
var mockCookies = new Mock<IResponseCookies>();
bool defaultCookieSecureValue = expectedCookieSecureFlag ?? false; // pulled from config; set by ctor
var cookies = new MockResponseCookieCollection();
cookies.Count = 0;
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext.Setup(o => o.Response.Cookies)
.Returns(cookies);
var contextAccessor = new ScopedInstance<AntiForgeryContext>();
mockHttpContext.SetupGet(o => o.RequestServices)
.Returns(GetServiceProvider(contextAccessor));
var mockSerializer = new Mock<IAntiForgeryTokenSerializer>();
mockSerializer.Setup(o => o.Serialize(token))
.Returns("serialized-value");
var config = new AntiForgeryOptions()
{
CookieName = _cookieName,
RequireSSL = requireSsl
};
var tokenStore = new AntiForgeryTokenStore(
config: config,
serializer: mockSerializer.Object);
// Act
tokenStore.SaveCookieToken(mockHttpContext.Object, token);
// Assert
Assert.Equal(1, cookies.Count);
Assert.NotNull(contextAccessor.Value.CookieToken);
Assert.NotNull(cookies);
Assert.Equal(_cookieName, cookies.Key);
Assert.Equal("serialized-value", cookies.Value);
Assert.True(cookies.Options.HttpOnly);
Assert.Equal(defaultCookieSecureValue, cookies.Options.Secure);
}
private HttpContext GetMockHttpContext(string cookieName, string cookieValue)
{
var requestCookies = new MockCookieCollection(new Dictionary<string, string>() { { cookieName, cookieValue } });
var request = new Mock<HttpRequest>();
request.Setup(o => o.Cookies)
.Returns(requestCookies);
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext.Setup(o => o.Request)
.Returns(request.Object);
var contextAccessor = new ScopedInstance<AntiForgeryContext>();
mockHttpContext.SetupGet(o => o.RequestServices)
.Returns(GetServiceProvider(contextAccessor));
return mockHttpContext.Object;
}
private static IServiceProvider GetServiceProvider(IScopedInstance<AntiForgeryContext> contextAccessor)
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddInstance<IScopedInstance<AntiForgeryContext>>(contextAccessor);
return serviceCollection.BuildServiceProvider();
}
private class MockResponseCookieCollection : IResponseCookies
{
public string Key { get; set; }
public string Value { get; set; }
public CookieOptions Options { get; set; }
public int Count { get; set; }
public void Append(string key, string value, CookieOptions options)
{
this.Key = key;
this.Value = value;
this.Options = options;
this.Count++;
}
public void Append(string key, string value)
{
throw new NotImplementedException();
}
public void Delete(string key, CookieOptions options)
{
throw new NotImplementedException();
}
public void Delete(string key)
{
throw new NotImplementedException();
}
}
private class MockCookieCollection : IReadableStringCollection
{
private Dictionary<string, string> _dictionary;
public int Count
{
get
{
return _dictionary.Count;
}
}
public ICollection<string> Keys
{
get
{
return _dictionary.Keys;
}
}
public MockCookieCollection(Dictionary<string, string> dictionary)
{
_dictionary = dictionary;
}
public static MockCookieCollection GetDummyInstance(string key, string value)
{
return new MockCookieCollection(new Dictionary<string, string>() { { key, value } });
}
public string Get(string key)
{
return this[key];
}
public IList<string> GetValues(string key)
{
throw new NotImplementedException();
}
public bool ContainsKey(string key)
{
return _dictionary.ContainsKey(key);
}
public string this[string key]
{
get { return _dictionary[key]; }
}
public IEnumerator<KeyValuePair<string, string[]>> GetEnumerator()
{
throw new NotImplementedException();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
}
}

View File

@ -1,132 +0,0 @@
// 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 Xunit;
namespace Microsoft.AspNet.Mvc.Core.Test
{
public class AntiForgeryTokenTest
{
[Fact]
public void AdditionalDataProperty()
{
// Arrange
var token = new AntiForgeryToken();
// Act & assert - 1
Assert.Equal("", token.AdditionalData);
// Act & assert - 2
token.AdditionalData = "additional data";
Assert.Equal("additional data", token.AdditionalData);
// Act & assert - 3
token.AdditionalData = null;
Assert.Equal("", token.AdditionalData);
}
[Fact]
public void ClaimUidProperty()
{
// Arrange
var token = new AntiForgeryToken();
// Act & assert - 1
Assert.Null(token.ClaimUid);
// Act & assert - 2
BinaryBlob blob = new BinaryBlob(32);
token.ClaimUid = blob;
Assert.Equal(blob, token.ClaimUid);
// Act & assert - 3
token.ClaimUid = null;
Assert.Null(token.ClaimUid);
}
[Fact]
public void IsSessionTokenProperty()
{
// Arrange
var token = new AntiForgeryToken();
// Act & assert - 1
Assert.False(token.IsSessionToken);
// Act & assert - 2
token.IsSessionToken = true;
Assert.True(token.IsSessionToken);
// Act & assert - 3
token.IsSessionToken = false;
Assert.False(token.IsSessionToken);
}
[Fact]
public void UsernameProperty()
{
// Arrange
var token = new AntiForgeryToken();
// Act & assert - 1
Assert.Equal("", token.Username);
// Act & assert - 2
token.Username = "my username";
Assert.Equal("my username", token.Username);
// Act & assert - 3
token.Username = null;
Assert.Equal("", token.Username);
}
[Fact]
public void SecurityTokenProperty_GetsAutopopulated()
{
// Arrange
var token = new AntiForgeryToken();
// Act
var securityToken = token.SecurityToken;
// Assert
Assert.NotNull(securityToken);
Assert.Equal(AntiForgeryToken.SecurityTokenBitLength, securityToken.BitLength);
// check that we're not making a new one each property call
Assert.Equal(securityToken, token.SecurityToken);
}
[Fact]
public void SecurityTokenProperty_PropertySetter_DoesNotUseDefaults()
{
// Arrange
var token = new AntiForgeryToken();
// Act
var securityToken = new BinaryBlob(64);
token.SecurityToken = securityToken;
// Assert
Assert.Equal(securityToken, token.SecurityToken);
}
[Fact]
public void SecurityTokenProperty_PropertySetter_DoesNotAllowNulls()
{
// Arrange
var token = new AntiForgeryToken();
// Act
token.SecurityToken = null;
var securityToken = token.SecurityToken;
// Assert
Assert.NotNull(securityToken);
Assert.Equal(AntiForgeryToken.SecurityTokenBitLength, securityToken.BitLength);
// check that we're not making a new one each property call
Assert.Equal(securityToken, token.SecurityToken);
}
}
}

View File

@ -1,584 +0,0 @@
// 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 System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.Framework.WebEncoders.Testing;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Core.Test
{
public class AntiForgeryWorkerTest
{
[Fact]
public async Task ChecksSSL_ValidateAsync_Throws()
{
// Arrange
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext.Setup(o => o.Request.IsHttps)
.Returns(false);
var config = new AntiForgeryOptions()
{
RequireSSL = true
};
var worker = new AntiForgeryWorker(
config: config,
serializer: null,
tokenStore: null,
generator: null,
validator: null,
htmlEncoder: new CommonTestEncoder());
// Act & assert
var ex =
await
Assert.ThrowsAsync<InvalidOperationException>(
async () => await worker.ValidateAsync(mockHttpContext.Object));
Assert.Equal(
@"The anti-forgery system has the configuration value AntiForgeryOptions.RequireSsl = true, " +
"but the current request is not an SSL request.",
ex.Message);
}
[Fact]
public void ChecksSSL_Validate_Throws()
{
// Arrange
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext.Setup(o => o.Request.IsHttps)
.Returns(false);
var config = new AntiForgeryOptions()
{
RequireSSL = true
};
var worker = new AntiForgeryWorker(
config: config,
serializer: null,
tokenStore: null,
generator: null,
validator: null,
htmlEncoder: new CommonTestEncoder());
// Act & assert
var ex = Assert.Throws<InvalidOperationException>(
() => worker.Validate(mockHttpContext.Object, cookieToken: null, formToken: null));
Assert.Equal(
@"The anti-forgery system has the configuration value AntiForgeryOptions.RequireSsl = true, " +
"but the current request is not an SSL request.",
ex.Message);
}
[Fact]
public void ChecksSSL_GetFormInputElement_Throws()
{
// Arrange
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext.Setup(o => o.Request.IsHttps)
.Returns(false);
var config = new AntiForgeryOptions()
{
RequireSSL = true
};
var worker = new AntiForgeryWorker(
config: config,
serializer: null,
tokenStore: null,
generator: null,
validator: null,
htmlEncoder: new CommonTestEncoder());
// Act & assert
var ex = Assert.Throws<InvalidOperationException>(() => worker.GetFormInputElement(mockHttpContext.Object));
Assert.Equal(
@"The anti-forgery system has the configuration value AntiForgeryOptions.RequireSsl = true, " +
"but the current request is not an SSL request.",
ex.Message);
}
[Fact]
public void ChecksSSL_GetTokens_Throws()
{
// Arrange
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext.Setup(o => o.Request.IsHttps)
.Returns(false);
var config = new AntiForgeryOptions()
{
RequireSSL = true
};
var worker = new AntiForgeryWorker(
config: config,
serializer: null,
tokenStore: null,
generator: null,
validator: null,
htmlEncoder: new CommonTestEncoder());
// Act & assert
var ex = Assert.Throws<InvalidOperationException>(() =>
worker.GetTokens(mockHttpContext.Object, "cookie-token"));
Assert.Equal(
@"The anti-forgery system has the configuration value AntiForgeryOptions.RequireSsl = true, " +
"but the current request is not an SSL request.",
ex.Message);
}
[Fact]
public void GetFormInputElement_ExistingInvalidCookieToken_GeneratesANewCookieAndAnAntiForgeryToken()
{
// Arrange
var config = new AntiForgeryOptions()
{
FormFieldName = "form-field-name"
};
// Make sure the existing cookie is invalid.
var context = GetAntiForgeryWorkerContext(config, isOldCookieValid: false);
var worker = GetAntiForgeryWorker(context);
// Act
var inputElement = worker.GetFormInputElement(context.HttpContext.Object);
// Assert
Assert.Equal(@"<input name=""HtmlEncode[[form-field-name]]"" type=""HtmlEncode[[hidden]]"" " +
@"value=""HtmlEncode[[serialized-form-token]]"" />",
inputElement.ToString(TagRenderMode.SelfClosing));
context.TokenStore.Verify();
}
[Fact]
public void GetFormInputElement_ExistingInvalidCookieToken_SwallowsExceptions()
{
// Arrange
var config = new AntiForgeryOptions()
{
FormFieldName = "form-field-name"
};
// Make sure the existing cookie is invalid.
var context = GetAntiForgeryWorkerContext(config, isOldCookieValid: false);
var worker = GetAntiForgeryWorker(context);
// This will cause the cookieToken to be null.
context.TokenStore.Setup(o => o.GetCookieToken(context.HttpContext.Object))
.Throws(new Exception("should be swallowed"));
// Setup so that the null cookie token returned is treated as invalid.
context.TokenProvider.Setup(o => o.IsCookieTokenValid(null))
.Returns(false);
// Act
var inputElement = worker.GetFormInputElement(context.HttpContext.Object);
// Assert
Assert.Equal(@"<input name=""HtmlEncode[[form-field-name]]"" type=""HtmlEncode[[hidden]]"" " +
@"value=""HtmlEncode[[serialized-form-token]]"" />",
inputElement.ToString(TagRenderMode.SelfClosing));
context.TokenStore.Verify();
}
[Fact]
public void GetFormInputElement_ExistingValidCookieToken_GeneratesAnAntiForgeryToken()
{
// Arrange
var options = new AntiForgeryOptions()
{
FormFieldName = "form-field-name"
};
// Make sure the existing cookie is valid and use the same cookie for the mock Token Provider.
var context = GetAntiForgeryWorkerContext(options, useOldCookie: true, isOldCookieValid: true);
var worker = GetAntiForgeryWorker(context);
// Act
var inputElement = worker.GetFormInputElement(context.HttpContext.Object);
// Assert
Assert.Equal(@"<input name=""HtmlEncode[[form-field-name]]"" type=""HtmlEncode[[hidden]]"" " +
@"value=""HtmlEncode[[serialized-form-token]]"" />",
inputElement.ToString(TagRenderMode.SelfClosing));
}
[Theory]
[InlineData(false, "SAMEORIGIN")]
[InlineData(true, null)]
public void GetFormInputElement_AddsXFrameOptionsHeader(bool suppressXFrameOptions, string expectedHeaderValue)
{
// Arrange
var options = new AntiForgeryOptions()
{
SuppressXFrameOptionsHeader = suppressXFrameOptions
};
// Genreate a new cookie.
var context = GetAntiForgeryWorkerContext(options, useOldCookie: false, isOldCookieValid: false);
var worker = GetAntiForgeryWorker(context);
// Act
var inputElement = worker.GetFormInputElement(context.HttpContext.Object);
// Assert
string xFrameOptions = context.HttpContext.Object.Response.Headers["X-Frame-Options"];
Assert.Equal(expectedHeaderValue, xFrameOptions);
}
[Fact]
public void GetTokens_ExistingInvalidCookieToken_GeneratesANewCookieTokenAndANewFormToken()
{
// Arrange
// Genreate a new cookie.
var context = GetAntiForgeryWorkerContext(
new AntiForgeryOptions(),
useOldCookie: false,
isOldCookieValid: false);
var worker = GetAntiForgeryWorker(context);
// Act
var tokenset = worker.GetTokens(context.HttpContext.Object, "serialized-old-cookie-token");
// Assert
Assert.Equal("serialized-new-cookie-token", tokenset.CookieToken);
Assert.Equal("serialized-form-token", tokenset.FormToken);
}
[Fact]
public void GetTokens_ExistingInvalidCookieToken_SwallowsExceptions()
{
// Arrange
// Make sure the existing cookie is invalid.
var context = GetAntiForgeryWorkerContext(
new AntiForgeryOptions(),
useOldCookie: false,
isOldCookieValid: false);
// This will cause the cookieToken to be null.
context.TokenSerializer.Setup(o => o.Deserialize("serialized-old-cookie-token"))
.Throws(new Exception("should be swallowed"));
// Setup so that the null cookie token returned is treated as invalid.
context.TokenProvider.Setup(o => o.IsCookieTokenValid(null))
.Returns(false);
var worker = GetAntiForgeryWorker(context);
// Act
var tokenset = worker.GetTokens(context.HttpContext.Object, "serialized-old-cookie-token");
// Assert
Assert.Equal("serialized-new-cookie-token", tokenset.CookieToken);
Assert.Equal("serialized-form-token", tokenset.FormToken);
}
[Fact]
public void GetTokens_ExistingValidCookieToken_GeneratesANewFormToken()
{
// Arrange
var context = GetAntiForgeryWorkerContext(
new AntiForgeryOptions(),
useOldCookie: true,
isOldCookieValid: true);
context.TokenStore = null;
var worker = GetAntiForgeryWorker(context);
// Act
var tokenset = worker.GetTokens(context.HttpContext.Object, "serialized-old-cookie-token");
// Assert
Assert.Null(tokenset.CookieToken);
Assert.Equal("serialized-form-token", tokenset.FormToken);
}
[Fact]
public void Validate_FromInvalidStrings_Throws()
{
// Arrange
var context = GetAntiForgeryWorkerContext(new AntiForgeryOptions());
context.TokenSerializer.Setup(o => o.Deserialize("cookie-token"))
.Returns(context.TestTokenSet.OldCookieToken);
context.TokenSerializer.Setup(o => o.Deserialize("form-token"))
.Returns(context.TestTokenSet.FormToken);
context.TokenProvider.Setup(o => o.ValidateTokens(
context.HttpContext.Object,
context.HttpContext.Object.User.Identity as ClaimsIdentity,
context.TestTokenSet.OldCookieToken, context.TestTokenSet.FormToken))
.Throws(new InvalidOperationException("my-message"));
context.TokenStore = null;
var worker = GetAntiForgeryWorker(context);
// Act & assert
var ex =
Assert.Throws<InvalidOperationException>(
() => worker.Validate(context.HttpContext.Object, "cookie-token", "form-token"));
Assert.Equal("my-message", ex.Message);
}
[Fact]
public void Validate_FromValidStrings_TokensValidatedSuccessfully()
{
// Arrange
var context = GetAntiForgeryWorkerContext(new AntiForgeryOptions());
context.TokenSerializer.Setup(o => o.Deserialize("cookie-token"))
.Returns(context.TestTokenSet.OldCookieToken);
context.TokenSerializer.Setup(o => o.Deserialize("form-token"))
.Returns(context.TestTokenSet.FormToken);
context.TokenProvider.Setup(o => o.ValidateTokens(
context.HttpContext.Object,
context.HttpContext.Object.User.Identity as ClaimsIdentity,
context.TestTokenSet.OldCookieToken, context.TestTokenSet.FormToken))
.Verifiable();
context.TokenStore = null;
var worker = GetAntiForgeryWorker(context);
// Act
worker.Validate(context.HttpContext.Object, "cookie-token", "form-token");
// Assert
context.TokenProvider.Verify();
}
[Fact]
public async Task Validate_FromStore_Failure()
{
// Arrange
var context = GetAntiForgeryWorkerContext(new AntiForgeryOptions());
context.TokenProvider.Setup(o => o.ValidateTokens(
context.HttpContext.Object,
context.HttpContext.Object.User.Identity as ClaimsIdentity,
context.TestTokenSet.OldCookieToken, context.TestTokenSet.FormToken))
.Throws(new InvalidOperationException("my-message"));
context.TokenSerializer = null;
var worker = GetAntiForgeryWorker(context);
// Act & assert
var ex =
await
Assert.ThrowsAsync<InvalidOperationException>(
async () => await worker.ValidateAsync(context.HttpContext.Object));
Assert.Equal("my-message", ex.Message);
}
[Fact]
public async Task Validate_FromStore_Success()
{
// Arrange
var context = GetAntiForgeryWorkerContext(new AntiForgeryOptions());
context.TokenProvider.Setup(o => o.ValidateTokens(
context.HttpContext.Object,
context.HttpContext.Object.User.Identity as ClaimsIdentity,
context.TestTokenSet.OldCookieToken, context.TestTokenSet.FormToken))
.Verifiable();
context.TokenSerializer = null;
var worker = GetAntiForgeryWorker(context);
// Act
await worker.ValidateAsync(context.HttpContext.Object);
// Assert
context.TokenProvider.Verify();
}
[Theory]
[InlineData(false, "SAMEORIGIN")]
[InlineData(true, null)]
public void SetCookieTokenAndHeader_AddsXFrameOptionsHeader(
bool suppressXFrameOptions,
string expectedHeaderValue)
{
// Arrange
var options = new AntiForgeryOptions()
{
SuppressXFrameOptionsHeader = suppressXFrameOptions
};
// Genreate a new cookie.
var context = GetAntiForgeryWorkerContext(options, useOldCookie: false, isOldCookieValid: false);
var worker = GetAntiForgeryWorker(context);
// Act
worker.SetCookieTokenAndHeader(context.HttpContext.Object);
// Assert
var xFrameOptions = context.HttpContext.Object.Response.Headers["X-Frame-Options"];
Assert.Equal(expectedHeaderValue, xFrameOptions);
}
private AntiForgeryWorker GetAntiForgeryWorker(AntiForgeryWorkerContext context)
{
return new AntiForgeryWorker(
config: context.Options,
serializer: context.TokenSerializer != null ? context.TokenSerializer.Object : null,
tokenStore: context.TokenStore != null ? context.TokenStore.Object : null,
generator: context.TokenProvider != null ? context.TokenProvider.Object : null,
validator: context.TokenProvider != null ? context.TokenProvider.Object : null,
htmlEncoder: new CommonTestEncoder());
}
private Mock<HttpContext> GetHttpContext(bool setupResponse = true)
{
var identity = new ClaimsIdentity("some-auth");
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext.Setup(o => o.User)
.Returns(new ClaimsPrincipal(identity));
if (setupResponse)
{
var mockResponse = new Mock<HttpResponse>();
mockResponse.Setup(r => r.Headers)
.Returns(new HeaderDictionary(new Dictionary<string, string[]>()));
mockHttpContext.Setup(o => o.Response)
.Returns(mockResponse.Object);
}
return mockHttpContext;
}
private Mock<IAntiForgeryTokenProvider> GetTokenProvider(
HttpContext context,
TestTokenSet testTokenSet,
bool useOldCookie,
bool isOldCookieValid = true,
bool isNewCookieValid = true)
{
var oldCookieToken = testTokenSet.OldCookieToken;
var newCookieToken = testTokenSet.NewCookieToken;
var formToken = testTokenSet.FormToken;
var mockValidator = new Mock<IAntiForgeryTokenProvider>(MockBehavior.Strict);
mockValidator.Setup(o => o.GenerateFormToken(
context,
context.User.Identity as ClaimsIdentity,
useOldCookie ? oldCookieToken : newCookieToken))
.Returns(formToken);
mockValidator.Setup(o => o.IsCookieTokenValid(oldCookieToken))
.Returns(isOldCookieValid);
mockValidator.Setup(o => o.IsCookieTokenValid(newCookieToken))
.Returns(isNewCookieValid);
mockValidator.Setup(o => o.GenerateCookieToken())
.Returns(useOldCookie ? oldCookieToken : newCookieToken);
return mockValidator;
}
private Mock<IAntiForgeryTokenStore> GetTokenStore(
HttpContext context,
TestTokenSet testTokenSet,
bool saveNewCookie = true)
{
var oldCookieToken = testTokenSet.OldCookieToken;
var formToken = testTokenSet.FormToken;
var mockTokenStore = new Mock<IAntiForgeryTokenStore>(MockBehavior.Strict);
mockTokenStore.Setup(o => o.GetCookieToken(context))
.Returns(oldCookieToken);
mockTokenStore.Setup(o => o.GetFormTokenAsync(context))
.Returns(Task.FromResult(formToken));
if (saveNewCookie)
{
var newCookieToken = testTokenSet.NewCookieToken;
mockTokenStore.Setup(o => o.SaveCookieToken(context, newCookieToken))
.Verifiable();
}
return mockTokenStore;
}
private Mock<IAntiForgeryTokenSerializer> GetTokenSerializer(TestTokenSet testTokenSet)
{
var oldCookieToken = testTokenSet.OldCookieToken;
var newCookieToken = testTokenSet.NewCookieToken;
var formToken = testTokenSet.FormToken;
var mockSerializer = new Mock<IAntiForgeryTokenSerializer>(MockBehavior.Strict);
mockSerializer.Setup(o => o.Serialize(formToken))
.Returns("serialized-form-token");
mockSerializer.Setup(o => o.Deserialize("serialized-old-cookie-token"))
.Returns(oldCookieToken);
mockSerializer.Setup(o => o.Serialize(newCookieToken))
.Returns("serialized-new-cookie-token");
return mockSerializer;
}
private TestTokenSet GetTokenSet(bool isOldCookieTokenSessionToken = true, bool isNewCookieSessionToken = true)
{
return new TestTokenSet()
{
FormToken = new AntiForgeryToken() { IsSessionToken = false },
OldCookieToken = new AntiForgeryToken() { IsSessionToken = isOldCookieTokenSessionToken },
NewCookieToken = new AntiForgeryToken() { IsSessionToken = isNewCookieSessionToken },
};
}
private AntiForgeryWorkerContext GetAntiForgeryWorkerContext(
AntiForgeryOptions config,
bool useOldCookie = false,
bool isOldCookieValid = true)
{
// Arrange
var mockHttpContext = GetHttpContext();
var testTokenSet = GetTokenSet(isOldCookieTokenSessionToken: true, isNewCookieSessionToken: true);
var mockSerializer = GetTokenSerializer(testTokenSet);
var mockTokenStore = GetTokenStore(mockHttpContext.Object, testTokenSet);
var mockTokenProvider = GetTokenProvider(
mockHttpContext.Object,
testTokenSet,
useOldCookie: useOldCookie,
isOldCookieValid: isOldCookieValid);
return new AntiForgeryWorkerContext()
{
Options = config,
HttpContext = mockHttpContext,
TokenProvider = mockTokenProvider,
TokenSerializer = mockSerializer,
TokenStore = mockTokenStore,
TestTokenSet = testTokenSet
};
}
private class TestTokenSet
{
public AntiForgeryToken FormToken { get; set; }
public string FormTokenString { get; set; }
public AntiForgeryToken OldCookieToken { get; set; }
public string OldCookieTokenString { get; set; }
public AntiForgeryToken NewCookieToken { get; set; }
public string NewCookieTokenString { get; set; }
}
private class AntiForgeryWorkerContext
{
public AntiForgeryOptions Options { get; set; }
public TestTokenSet TestTokenSet { get; set; }
public Mock<HttpContext> HttpContext { get; set; }
public Mock<IAntiForgeryTokenProvider> TokenProvider { get; set; }
public Mock<IAntiForgeryTokenStore> TokenStore { get; set; }
public Mock<IAntiForgeryTokenSerializer> TokenSerializer { get; set; }
}
}
}

View File

@ -1,129 +0,0 @@
// 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 System;
using Xunit;
namespace Microsoft.AspNet.Mvc.Core.Test
{
public class BinaryBlobTest
{
[Fact]
public void Ctor_BitLength()
{
// Act
var blob = new BinaryBlob(bitLength: 64);
var data = blob.GetData();
// Assert
Assert.Equal(64, blob.BitLength);
Assert.Equal(64 / 8, data.Length);
Assert.NotEqual(new byte[64 / 8], data); // should not be a zero-filled array
}
[Theory]
[InlineData(24)]
[InlineData(33)]
public void Ctor_BitLength_Bad(int bitLength)
{
// Act & assert
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => new BinaryBlob(bitLength));
Assert.Equal("bitLength", ex.ParamName);
}
[Fact]
public void Ctor_BitLength_ProducesDifferentValues()
{
// Act
var blobA = new BinaryBlob(bitLength: 64);
var blobB = new BinaryBlob(bitLength: 64);
// Assert
Assert.NotEqual(blobA.GetData(), blobB.GetData());
}
[Fact]
public void Ctor_Data()
{
// Arrange
var expectedData = new byte[] { 0x01, 0x02, 0x03, 0x04 };
// Act
var blob = new BinaryBlob(32, expectedData);
// Assert
Assert.Equal(32, blob.BitLength);
Assert.Equal(expectedData, blob.GetData());
}
[Theory]
[InlineData((object[])null)]
[InlineData(new byte[] { 0x01, 0x02, 0x03 })]
public void Ctor_Data_Bad(byte[] data)
{
// Act & assert
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => new BinaryBlob(32, data));
Assert.Equal("data", ex.ParamName);
}
[Fact]
public void Equals_DifferentData_ReturnsFalse()
{
// Arrange
object blobA = new BinaryBlob(32, new byte[] { 0x01, 0x02, 0x03, 0x04 });
object blobB = new BinaryBlob(32, new byte[] { 0x04, 0x03, 0x02, 0x01 });
// Act & assert
Assert.NotEqual(blobA, blobB);
}
[Fact]
public void Equals_NotABlob_ReturnsFalse()
{
// Arrange
object blobA = new BinaryBlob(32);
object blobB = "hello";
// Act & assert
Assert.NotEqual(blobA, blobB);
}
[Fact]
public void Equals_Null_ReturnsFalse()
{
// Arrange
object blobA = new BinaryBlob(32);
object blobB = null;
// Act & assert
Assert.NotEqual(blobA, blobB);
}
[Fact]
public void Equals_SameData_ReturnsTrue()
{
// Arrange
object blobA = new BinaryBlob(32, new byte[] { 0x01, 0x02, 0x03, 0x04 });
object blobB = new BinaryBlob(32, new byte[] { 0x01, 0x02, 0x03, 0x04 });
// Act & assert
Assert.Equal(blobA, blobB);
}
[Fact]
public void GetHashCodeTest()
{
// Arrange
var blobData = new byte[] { 0x01, 0x02, 0x03, 0x04 };
var expectedHashCode = BitConverter.ToInt32(blobData, 0);
var blob = new BinaryBlob(32, blobData);
// Act
var actualHashCode = blob.GetHashCode();
// Assert
Assert.Equal(expectedHashCode, actualHashCode);
}
}
}

View File

@ -1,108 +0,0 @@
// 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 System;
using System.Linq;
using System.Security.Claims;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Core.Test
{
public class ClaimUidExtractorTest
{
[Fact]
public void ExtractClaimUid_NullIdentity()
{
// Arrange
IClaimUidExtractor extractor = new DefaultClaimUidExtractor();
// Act
var claimUid = extractor.ExtractClaimUid(null);
// Assert
Assert.Null(claimUid);
}
[Fact]
public void ExtractClaimUid_Unauthenticated()
{
// Arrange
IClaimUidExtractor extractor = new DefaultClaimUidExtractor();
var mockIdentity = new Mock<ClaimsIdentity>();
mockIdentity.Setup(o => o.IsAuthenticated)
.Returns(false);
// Act
var claimUid = extractor.ExtractClaimUid(mockIdentity.Object);
// Assert
Assert.Null(claimUid);
}
[Fact]
public void ExtractClaimUid_ClaimsIdentity()
{
// Arrange
var mockIdentity = new Mock<ClaimsIdentity>();
mockIdentity.Setup(o => o.IsAuthenticated)
.Returns(true);
IClaimUidExtractor extractor = new DefaultClaimUidExtractor();
// Act
var claimUid = extractor.ExtractClaimUid(mockIdentity.Object);
// Assert
Assert.NotNull(claimUid);
Assert.Equal("47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=", claimUid);
}
[Fact]
public void DefaultUniqueClaimTypes_NotPresent_SerializesAllClaimTypes()
{
var identity = new ClaimsIdentity();
identity.AddClaim(new Claim(ClaimTypes.Email, "someone@antifrogery.com"));
identity.AddClaim(new Claim(ClaimTypes.GivenName, "some"));
identity.AddClaim(new Claim(ClaimTypes.Surname, "one"));
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, String.Empty));
// Arrange
var claimsIdentity = (ClaimsIdentity)identity;
// Act
var identiferParameters = DefaultClaimUidExtractor.GetUniqueIdentifierParameters(claimsIdentity)
.ToArray();
var claims = claimsIdentity.Claims.ToList();
claims.Sort((a, b) => string.Compare(a.Type, b.Type, StringComparison.Ordinal));
// Assert
int index = 0;
foreach (var claim in claims)
{
Assert.True(String.Equals(identiferParameters[index++], claim.Type, StringComparison.Ordinal));
Assert.True(String.Equals(identiferParameters[index++], claim.Value, StringComparison.Ordinal));
}
}
[Fact]
public void DefaultUniqueClaimTypes_Present()
{
// Arrange
var identity = new ClaimsIdentity();
identity.AddClaim(new Claim("fooClaim", "fooClaimValue"));
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, "nameIdentifierValue"));
// Act
var uniqueIdentifierParameters = DefaultClaimUidExtractor.GetUniqueIdentifierParameters(identity);
// Assert
Assert.Equal(new string[]
{
ClaimTypes.NameIdentifier,
"nameIdentifierValue",
}, uniqueIdentifierParameters);
}
}
}

View File

@ -1,10 +0,0 @@
// 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.AspNet.Mvc.Core.Test
{
// A TokenProvider that can be passed to MoQ
internal interface IAntiForgeryTokenProvider : IAntiForgeryTokenValidator, IAntiForgeryTokenGenerator
{
}
}

View File

@ -1,582 +0,0 @@
// 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 System;
using System.Security.Claims;
using System.Security.Cryptography;
using Microsoft.AspNet.Http;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Core.Test
{
public class TokenProviderTest
{
[Fact]
public void GenerateCookieToken()
{
// Arrange
var tokenProvider = new AntiForgeryTokenProvider(
config: null,
claimUidExtractor: null,
additionalDataProvider: null);
// Act
var retVal = tokenProvider.GenerateCookieToken();
// Assert
Assert.NotNull(retVal);
}
[Fact]
public void GenerateFormToken_AnonymousUser()
{
// Arrange
var cookieToken = new AntiForgeryToken() { IsSessionToken = true };
var httpContext = new Mock<HttpContext>().Object;
var mockIdentity = new Mock<ClaimsIdentity>();
mockIdentity.Setup(o => o.IsAuthenticated)
.Returns(false);
var config = new AntiForgeryOptions();
var tokenProvider = new AntiForgeryTokenProvider(
config: config,
claimUidExtractor: null,
additionalDataProvider: null);
// Act
var fieldToken = tokenProvider.GenerateFormToken(httpContext, mockIdentity.Object, cookieToken);
// Assert
Assert.NotNull(fieldToken);
Assert.Equal(cookieToken.SecurityToken, fieldToken.SecurityToken);
Assert.False(fieldToken.IsSessionToken);
Assert.Empty(fieldToken.Username);
Assert.Null(fieldToken.ClaimUid);
Assert.Empty(fieldToken.AdditionalData);
}
[Fact]
public void GenerateFormToken_AuthenticatedWithoutUsernameAndNoAdditionalData_NoAdditionalData()
{
// Arrange
var cookieToken = new AntiForgeryToken()
{
IsSessionToken = true
};
var httpContext = new Mock<HttpContext>().Object;
ClaimsIdentity identity = new MyAuthenticatedIdentityWithoutUsername();
var config = new AntiForgeryOptions();
IClaimUidExtractor claimUidExtractor = new Mock<IClaimUidExtractor>().Object;
var tokenProvider = new AntiForgeryTokenProvider(
config: config,
claimUidExtractor: claimUidExtractor,
additionalDataProvider: null);
// Act & assert
var ex =
Assert.Throws<InvalidOperationException>(
() => tokenProvider.GenerateFormToken(httpContext, identity, cookieToken));
Assert.Equal(
"The provided identity of type " +
"'Microsoft.AspNet.Mvc.Core.Test.TokenProviderTest+MyAuthenticatedIdentityWithoutUsername' " +
"is marked IsAuthenticated = true but does not have a value for Name. " +
"By default, the anti-forgery system requires that all authenticated identities have a unique Name. " +
"If it is not possible to provide a unique Name for this identity, " +
"consider extending IAdditionalDataProvider by overriding the DefaultAdditionalDataProvider " +
"or a custom type that can provide some form of unique identifier for the current user.",
ex.Message);
}
[Fact]
public void GenerateFormToken_AuthenticatedWithoutUsername_WithAdditionalData()
{
// Arrange
var cookieToken = new AntiForgeryToken() { IsSessionToken = true };
var httpContext = new Mock<HttpContext>().Object;
ClaimsIdentity identity = new MyAuthenticatedIdentityWithoutUsername();
var mockAdditionalDataProvider = new Mock<IAntiForgeryAdditionalDataProvider>();
mockAdditionalDataProvider.Setup(o => o.GetAdditionalData(httpContext))
.Returns("additional-data");
var config = new AntiForgeryOptions();
IClaimUidExtractor claimUidExtractor = new Mock<IClaimUidExtractor>().Object;
var tokenProvider = new AntiForgeryTokenProvider(
config: config,
claimUidExtractor: claimUidExtractor,
additionalDataProvider: mockAdditionalDataProvider.Object);
// Act
var fieldToken = tokenProvider.GenerateFormToken(httpContext, identity, cookieToken);
// Assert
Assert.NotNull(fieldToken);
Assert.Equal(cookieToken.SecurityToken, fieldToken.SecurityToken);
Assert.False(fieldToken.IsSessionToken);
Assert.Empty(fieldToken.Username);
Assert.Null(fieldToken.ClaimUid);
Assert.Equal("additional-data", fieldToken.AdditionalData);
}
[Fact]
public void GenerateFormToken_ClaimsBasedIdentity()
{
// Arrange
var cookieToken = new AntiForgeryToken() { IsSessionToken = true };
var httpContext = new Mock<HttpContext>().Object;
var identity = GetAuthenticatedIdentity("some-identity");
var config = new AntiForgeryOptions();
byte[] data = new byte[256 / 8];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(data);
}
var base64ClaimUId = Convert.ToBase64String(data);
var expectedClaimUid = new BinaryBlob(256, data);
var mockClaimUidExtractor = new Mock<IClaimUidExtractor>();
mockClaimUidExtractor.Setup(o => o.ExtractClaimUid(identity))
.Returns(base64ClaimUId);
var tokenProvider = new AntiForgeryTokenProvider(
config: config,
claimUidExtractor: mockClaimUidExtractor.Object,
additionalDataProvider: null);
// Act
var fieldToken = tokenProvider.GenerateFormToken(httpContext, identity, cookieToken);
// Assert
Assert.NotNull(fieldToken);
Assert.Equal(cookieToken.SecurityToken, fieldToken.SecurityToken);
Assert.False(fieldToken.IsSessionToken);
Assert.Equal("", fieldToken.Username);
Assert.Equal(expectedClaimUid, fieldToken.ClaimUid);
Assert.Equal("", fieldToken.AdditionalData);
}
[Fact]
public void GenerateFormToken_RegularUserWithUsername()
{
// Arrange
var cookieToken = new AntiForgeryToken() { IsSessionToken = true };
var httpContext = new Mock<HttpContext>().Object;
var mockIdentity = new Mock<ClaimsIdentity>();
mockIdentity.Setup(o => o.IsAuthenticated)
.Returns(true);
mockIdentity.Setup(o => o.Name)
.Returns("my-username");
var config = new AntiForgeryOptions();
IClaimUidExtractor claimUidExtractor = new Mock<IClaimUidExtractor>().Object;
var tokenProvider = new AntiForgeryTokenProvider(
config: config,
claimUidExtractor: claimUidExtractor,
additionalDataProvider: null);
// Act
var fieldToken = tokenProvider.GenerateFormToken(httpContext, mockIdentity.Object, cookieToken);
// Assert
Assert.NotNull(fieldToken);
Assert.Equal(cookieToken.SecurityToken, fieldToken.SecurityToken);
Assert.False(fieldToken.IsSessionToken);
Assert.Equal("my-username", fieldToken.Username);
Assert.Null(fieldToken.ClaimUid);
Assert.Empty(fieldToken.AdditionalData);
}
[Fact]
public void IsCookieTokenValid_FieldToken_ReturnsFalse()
{
// Arrange
var cookieToken = new AntiForgeryToken()
{
IsSessionToken = false
};
var tokenProvider = new AntiForgeryTokenProvider(
config: null,
claimUidExtractor: null,
additionalDataProvider: null);
// Act
bool retVal = tokenProvider.IsCookieTokenValid(cookieToken);
// Assert
Assert.False(retVal);
}
[Fact]
public void IsCookieTokenValid_NullToken_ReturnsFalse()
{
// Arrange
AntiForgeryToken cookieToken = null;
var tokenProvider = new AntiForgeryTokenProvider(
config: null,
claimUidExtractor: null,
additionalDataProvider: null);
// Act
bool retVal = tokenProvider.IsCookieTokenValid(cookieToken);
// Assert
Assert.False(retVal);
}
[Fact]
public void IsCookieTokenValid_ValidToken_ReturnsTrue()
{
// Arrange
var cookieToken = new AntiForgeryToken()
{
IsSessionToken = true
};
var tokenProvider = new AntiForgeryTokenProvider(
config: null,
claimUidExtractor: null,
additionalDataProvider: null);
// Act
bool retVal = tokenProvider.IsCookieTokenValid(cookieToken);
// Assert
Assert.True(retVal);
}
[Fact]
public void ValidateTokens_SessionTokenMissing()
{
// Arrange
var httpContext = new Mock<HttpContext>().Object;
ClaimsIdentity identity = new Mock<ClaimsIdentity>().Object;
AntiForgeryToken sessionToken = null;
var fieldtoken = new AntiForgeryToken() { IsSessionToken = false };
var config = new AntiForgeryOptions()
{
CookieName = "my-cookie-name"
};
var tokenProvider = new AntiForgeryTokenProvider(
config: config,
claimUidExtractor: null,
additionalDataProvider: null);
// Act & assert
var ex =
Assert.Throws<InvalidOperationException>(
() => tokenProvider.ValidateTokens(httpContext, identity, sessionToken, fieldtoken));
Assert.Equal(@"The required anti-forgery cookie ""my-cookie-name"" is not present.", ex.Message);
}
[Fact]
public void ValidateTokens_FieldTokenMissing()
{
// Arrange
var httpContext = new Mock<HttpContext>().Object;
ClaimsIdentity identity = new Mock<ClaimsIdentity>().Object;
var sessionToken = new AntiForgeryToken() { IsSessionToken = true };
AntiForgeryToken fieldtoken = null;
var config = new AntiForgeryOptions()
{
FormFieldName = "my-form-field-name"
};
var tokenProvider = new AntiForgeryTokenProvider(
config: config,
claimUidExtractor: null,
additionalDataProvider: null);
// Act & assert
var ex =
Assert.Throws<InvalidOperationException>(
() => tokenProvider.ValidateTokens(httpContext, identity, sessionToken, fieldtoken));
Assert.Equal(@"The required anti-forgery form field ""my-form-field-name"" is not present.", ex.Message);
}
[Fact]
public void ValidateTokens_FieldAndSessionTokensSwapped()
{
// Arrange
var httpContext = new Mock<HttpContext>().Object;
ClaimsIdentity identity = new Mock<ClaimsIdentity>().Object;
var sessionToken = new AntiForgeryToken() { IsSessionToken = true };
var fieldtoken = new AntiForgeryToken() { IsSessionToken = false };
var config = new AntiForgeryOptions()
{
CookieName = "my-cookie-name",
FormFieldName = "my-form-field-name"
};
var tokenProvider = new AntiForgeryTokenProvider(
config: config,
claimUidExtractor: null,
additionalDataProvider: null);
// Act & assert
var ex1 =
Assert.Throws<InvalidOperationException>(
() => tokenProvider.ValidateTokens(httpContext, identity, fieldtoken, fieldtoken));
Assert.Equal(
"Validation of the provided anti-forgery token failed. " +
@"The cookie ""my-cookie-name"" and the form field ""my-form-field-name"" were swapped.",
ex1.Message);
var ex2 =
Assert.Throws<InvalidOperationException>(
() => tokenProvider.ValidateTokens(httpContext, identity, sessionToken, sessionToken));
Assert.Equal(
"Validation of the provided anti-forgery token failed. " +
@"The cookie ""my-cookie-name"" and the form field ""my-form-field-name"" were swapped.",
ex2.Message);
}
[Fact]
public void ValidateTokens_FieldAndSessionTokensHaveDifferentSecurityKeys()
{
// Arrange
var httpContext = new Mock<HttpContext>().Object;
ClaimsIdentity identity = new Mock<ClaimsIdentity>().Object;
var sessionToken = new AntiForgeryToken() { IsSessionToken = true };
var fieldtoken = new AntiForgeryToken() { IsSessionToken = false };
var tokenProvider = new AntiForgeryTokenProvider(
config: null,
claimUidExtractor: null,
additionalDataProvider: null);
// Act & assert
var ex =
Assert.Throws<InvalidOperationException>(
() => tokenProvider.ValidateTokens(httpContext, identity, sessionToken, fieldtoken));
Assert.Equal(@"The anti-forgery cookie token and form field token do not match.", ex.Message);
}
[Theory]
[InlineData("the-user", "the-other-user")]
[InlineData("http://example.com/uri-casing", "http://example.com/URI-casing")]
[InlineData("https://example.com/secure-uri-casing", "https://example.com/secure-URI-casing")]
public void ValidateTokens_UsernameMismatch(string identityUsername, string embeddedUsername)
{
// Arrange
var httpContext = new Mock<HttpContext>().Object;
var identity = GetAuthenticatedIdentity(identityUsername);
var sessionToken = new AntiForgeryToken() { IsSessionToken = true };
var fieldtoken = new AntiForgeryToken()
{
SecurityToken = sessionToken.SecurityToken,
Username = embeddedUsername,
IsSessionToken = false
};
var mockClaimUidExtractor = new Mock<IClaimUidExtractor>();
mockClaimUidExtractor.Setup(o => o.ExtractClaimUid(identity))
.Returns((string)null);
var tokenProvider = new AntiForgeryTokenProvider(
config: null,
claimUidExtractor: mockClaimUidExtractor.Object,
additionalDataProvider: null);
// Act & assert
var ex =
Assert.Throws<InvalidOperationException>(
() => tokenProvider.ValidateTokens(httpContext, identity, sessionToken, fieldtoken));
Assert.Equal(
@"The provided anti-forgery token was meant for user """ + embeddedUsername +
@""", but the current user is """ + identityUsername + @""".", ex.Message);
}
[Fact]
public void ValidateTokens_ClaimUidMismatch()
{
// Arrange
var httpContext = new Mock<HttpContext>().Object;
var identity = GetAuthenticatedIdentity("the-user");
var sessionToken = new AntiForgeryToken() { IsSessionToken = true };
var fieldtoken = new AntiForgeryToken()
{
SecurityToken = sessionToken.SecurityToken,
IsSessionToken = false,
ClaimUid = new BinaryBlob(256)
};
var differentToken = new BinaryBlob(256);
var mockClaimUidExtractor = new Mock<IClaimUidExtractor>();
mockClaimUidExtractor.Setup(o => o.ExtractClaimUid(identity))
.Returns(Convert.ToBase64String(differentToken.GetData()));
var tokenProvider = new AntiForgeryTokenProvider(
config: null,
claimUidExtractor: mockClaimUidExtractor.Object,
additionalDataProvider: null);
// Act & assert
var ex =
Assert.Throws<InvalidOperationException>(
() => tokenProvider.ValidateTokens(httpContext, identity, sessionToken, fieldtoken));
Assert.Equal(
@"The provided anti-forgery token was meant for a different claims-based user than the current user.",
ex.Message);
}
[Fact]
public void ValidateTokens_AdditionalDataRejected()
{
// Arrange
var httpContext = new Mock<HttpContext>().Object;
var identity = new ClaimsIdentity();
var sessionToken = new AntiForgeryToken() { IsSessionToken = true };
var fieldtoken = new AntiForgeryToken()
{
SecurityToken = sessionToken.SecurityToken,
Username = String.Empty,
IsSessionToken = false,
AdditionalData = "some-additional-data"
};
var mockAdditionalDataProvider = new Mock<IAntiForgeryAdditionalDataProvider>();
mockAdditionalDataProvider.Setup(o => o.ValidateAdditionalData(httpContext, "some-additional-data"))
.Returns(false);
var config = new AntiForgeryOptions();
var tokenProvider = new AntiForgeryTokenProvider(
config: config,
claimUidExtractor: null,
additionalDataProvider: mockAdditionalDataProvider.Object);
// Act & assert
var ex =
Assert.Throws<InvalidOperationException>(
() => tokenProvider.ValidateTokens(httpContext, identity, sessionToken, fieldtoken));
Assert.Equal(@"The provided anti-forgery token failed a custom data check.", ex.Message);
}
[Fact]
public void ValidateTokens_Success_AnonymousUser()
{
// Arrange
var httpContext = new Mock<HttpContext>().Object;
var identity = new ClaimsIdentity();
var sessionToken = new AntiForgeryToken() { IsSessionToken = true };
var fieldtoken = new AntiForgeryToken()
{
SecurityToken = sessionToken.SecurityToken,
Username = String.Empty,
IsSessionToken = false,
AdditionalData = "some-additional-data"
};
var mockAdditionalDataProvider = new Mock<IAntiForgeryAdditionalDataProvider>();
mockAdditionalDataProvider.Setup(o => o.ValidateAdditionalData(httpContext, "some-additional-data"))
.Returns(true);
var config = new AntiForgeryOptions();
var tokenProvider = new AntiForgeryTokenProvider(
config: config,
claimUidExtractor: null,
additionalDataProvider: mockAdditionalDataProvider.Object);
// Act
tokenProvider.ValidateTokens(httpContext, identity, sessionToken, fieldtoken);
// Assert
// Nothing to assert - if we got this far, success!
}
[Fact]
public void ValidateTokens_Success_AuthenticatedUserWithUsername()
{
// Arrange
var httpContext = new Mock<HttpContext>().Object;
var identity = GetAuthenticatedIdentity("the-user");
var sessionToken = new AntiForgeryToken() { IsSessionToken = true };
var fieldtoken = new AntiForgeryToken()
{
SecurityToken = sessionToken.SecurityToken,
Username = "THE-USER",
IsSessionToken = false,
AdditionalData = "some-additional-data"
};
var mockAdditionalDataProvider = new Mock<IAntiForgeryAdditionalDataProvider>();
mockAdditionalDataProvider.Setup(o => o.ValidateAdditionalData(httpContext, "some-additional-data"))
.Returns(true);
var config = new AntiForgeryOptions();
var tokenProvider = new AntiForgeryTokenProvider(
config: config,
claimUidExtractor: new Mock<IClaimUidExtractor>().Object,
additionalDataProvider: mockAdditionalDataProvider.Object);
// Act
tokenProvider.ValidateTokens(httpContext, identity, sessionToken, fieldtoken);
// Assert
// Nothing to assert - if we got this far, success!
}
[Fact]
public void ValidateTokens_Success_ClaimsBasedUser()
{
// Arrange
var httpContext = new Mock<HttpContext>().Object;
var identity = GetAuthenticatedIdentity("the-user");
var sessionToken = new AntiForgeryToken() { IsSessionToken = true };
var fieldtoken = new AntiForgeryToken()
{
SecurityToken = sessionToken.SecurityToken,
IsSessionToken = false,
ClaimUid = new BinaryBlob(256)
};
var mockClaimUidExtractor = new Mock<IClaimUidExtractor>();
mockClaimUidExtractor.Setup(o => o.ExtractClaimUid(identity))
.Returns(Convert.ToBase64String(fieldtoken.ClaimUid.GetData()));
var config = new AntiForgeryOptions();
var tokenProvider = new AntiForgeryTokenProvider(
config: config,
claimUidExtractor: mockClaimUidExtractor.Object,
additionalDataProvider: null);
// Act
tokenProvider.ValidateTokens(httpContext, identity, sessionToken, fieldtoken);
// Assert
// Nothing to assert - if we got this far, success!
}
private static ClaimsIdentity GetAuthenticatedIdentity(string identityUsername)
{
var claim = new Claim(ClaimsIdentity.DefaultNameClaimType, identityUsername);
return new ClaimsIdentity(new[] { claim }, "Some-Authentication");
}
private sealed class MyAuthenticatedIdentityWithoutUsername : ClaimsIdentity
{
public override bool IsAuthenticated
{
get { return true; }
}
public override string Name
{
get { return String.Empty; }
}
}
}
}

View File

@ -1,51 +0,0 @@
// 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.AspNet.DataProtection;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.OptionsModel;
using Microsoft.Framework.WebEncoders.Testing;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Core.Test
{
public class ValidateAntiForgeryTokenAttributeTest
{
[Fact]
public void ValidationAttribute_ForwardsCallToValidateAntiForgeryTokenAuthorizationFilter()
{
// Arrange
var serviceCollection = new ServiceCollection();
serviceCollection.AddInstance<AntiForgery>(GetAntiForgeryInstance());
var serviceProvider = serviceCollection.BuildServiceProvider();
var attribute = new ValidateAntiForgeryTokenAttribute();
// Act
var filter = attribute.CreateInstance(serviceProvider);
// Assert
var validationFilter = filter as ValidateAntiForgeryTokenAuthorizationFilter;
Assert.NotNull(validationFilter);
}
private AntiForgery GetAntiForgeryInstance()
{
var claimExtractor = new Mock<IClaimUidExtractor>();
var dataProtectionProvider = new Mock<IDataProtectionProvider>();
var additionalDataProvider = new Mock<IAntiForgeryAdditionalDataProvider>();
var optionsAccessor = new Mock<IOptions<AntiForgeryOptions>>();
var mockDataProtectionOptions = new Mock<IOptions<DataProtectionOptions>>();
mockDataProtectionOptions
.SetupGet(options => options.Options)
.Returns(Mock.Of<DataProtectionOptions>());
optionsAccessor.SetupGet(o => o.Options).Returns(new AntiForgeryOptions());
return new AntiForgery(claimExtractor.Object,
dataProtectionProvider.Object,
additionalDataProvider.Object,
optionsAccessor.Object,
new CommonTestEncoder(),
mockDataProtectionOptions.Object);
}
}
}

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Microsoft.AspNet.Antiforgery;
using Microsoft.AspNet.DataProtection; using Microsoft.AspNet.DataProtection;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.Framework.OptionsModel; using Microsoft.Framework.OptionsModel;
@ -544,20 +545,10 @@ namespace Microsoft.AspNet.Mvc.Rendering
// GetCurrentValues uses only the IModelMetadataProvider passed to the DefaultHtmlGenerator constructor. // GetCurrentValues uses only the IModelMetadataProvider passed to the DefaultHtmlGenerator constructor.
private static IHtmlGenerator GetGenerator(IModelMetadataProvider metadataProvider) private static IHtmlGenerator GetGenerator(IModelMetadataProvider metadataProvider)
{ {
var antiforgeryOptionsAccessor = new Mock<IOptions<AntiForgeryOptions>>();
antiforgeryOptionsAccessor.SetupGet(accessor => accessor.Options).Returns(new AntiForgeryOptions());
var mvcViewOptionsAccessor = new Mock<IOptions<MvcViewOptions>>(); var mvcViewOptionsAccessor = new Mock<IOptions<MvcViewOptions>>();
mvcViewOptionsAccessor.SetupGet(accessor => accessor.Options).Returns(new MvcViewOptions()); mvcViewOptionsAccessor.SetupGet(accessor => accessor.Options).Returns(new MvcViewOptions());
var htmlEncoder = Mock.Of<IHtmlEncoder>(); var htmlEncoder = Mock.Of<IHtmlEncoder>();
var dataOptionsAccessor = new Mock<IOptions<DataProtectionOptions>>(); var antiforgery = Mock.Of<IAntiforgery>();
dataOptionsAccessor.SetupGet(accessor => accessor.Options).Returns(new DataProtectionOptions());
var antiForgery = new AntiForgery(
Mock.Of<IClaimUidExtractor>(),
Mock.Of<IDataProtectionProvider>(),
Mock.Of<IAntiForgeryAdditionalDataProvider>(),
antiforgeryOptionsAccessor.Object,
htmlEncoder,
dataOptionsAccessor.Object);
var optionsAccessor = new Mock<IOptions<MvcOptions>>(); var optionsAccessor = new Mock<IOptions<MvcOptions>>();
optionsAccessor optionsAccessor
@ -565,7 +556,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
.Returns(new MvcOptions()); .Returns(new MvcOptions());
return new DefaultHtmlGenerator( return new DefaultHtmlGenerator(
antiForgery, antiforgery,
mvcViewOptionsAccessor.Object, mvcViewOptionsAccessor.Object,
metadataProvider, metadataProvider,
Mock.Of<IUrlHelper>(), Mock.Of<IUrlHelper>(),

View File

@ -7,6 +7,7 @@ using System.ComponentModel.DataAnnotations;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Antiforgery;
using Microsoft.AspNet.DataProtection; using Microsoft.AspNet.DataProtection;
using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
@ -236,7 +237,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
if (htmlGenerator == null) if (htmlGenerator == null)
{ {
htmlGenerator = new DefaultHtmlGenerator( htmlGenerator = new DefaultHtmlGenerator(
GetAntiForgeryInstance(), Mock.Of<IAntiforgery>(),
optionsAccessor.Object, optionsAccessor.Object,
provider, provider,
urlHelper, urlHelper,
@ -307,26 +308,6 @@ namespace Microsoft.AspNet.Mvc.Rendering
return viewEngine.Object; return viewEngine.Object;
} }
private static AntiForgery GetAntiForgeryInstance()
{
var claimExtractor = new Mock<IClaimUidExtractor>();
var dataProtectionProvider = new Mock<IDataProtectionProvider>();
var additionalDataProvider = new Mock<IAntiForgeryAdditionalDataProvider>();
var optionsAccessor = new Mock<IOptions<AntiForgeryOptions>>();
var mockDataProtectionOptions = new Mock<IOptions<DataProtectionOptions>>();
mockDataProtectionOptions
.SetupGet(options => options.Options)
.Returns(Mock.Of<DataProtectionOptions>());
optionsAccessor.SetupGet(o => o.Options).Returns(new AntiForgeryOptions());
return new AntiForgery(
claimExtractor.Object,
dataProtectionProvider.Object,
additionalDataProvider.Object,
optionsAccessor.Object,
new CommonTestEncoder(),
mockDataProtectionOptions.Object);
}
private static string FormatOutput(ModelExplorer modelExplorer) private static string FormatOutput(ModelExplorer modelExplorer)
{ {
var metadata = modelExplorer.Metadata; var metadata = modelExplorer.Metadata;

View File

@ -10,18 +10,18 @@ using System.Xml.Linq;
namespace Microsoft.AspNet.Mvc.FunctionalTests namespace Microsoft.AspNet.Mvc.FunctionalTests
{ {
public static class AntiForgeryTestHelper public static class AntiforgeryTestHelper
{ {
public static string RetrieveAntiForgeryToken(string htmlContent, string actionUrl) public static string RetrieveAntiforgeryToken(string htmlContent, string actionUrl)
{ {
return RetrieveAntiForgeryTokens( return RetrieveAntiforgeryTokens(
htmlContent, htmlContent,
attribute => attribute.Value.EndsWith(actionUrl, StringComparison.OrdinalIgnoreCase) || attribute => attribute.Value.EndsWith(actionUrl, StringComparison.OrdinalIgnoreCase) ||
attribute.Value.EndsWith($"HtmlEncode[[{ actionUrl }]]", StringComparison.OrdinalIgnoreCase)) attribute.Value.EndsWith($"HtmlEncode[[{ actionUrl }]]", StringComparison.OrdinalIgnoreCase))
.FirstOrDefault(); .FirstOrDefault();
} }
public static IEnumerable<string> RetrieveAntiForgeryTokens( public static IEnumerable<string> RetrieveAntiforgeryTokens(
string htmlContent, string htmlContent,
Func<XAttribute, bool> predicate = null) Func<XAttribute, bool> predicate = null)
{ {
@ -54,7 +54,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
} }
} }
public static CookieMetadata RetrieveAntiForgeryCookie(HttpResponseMessage response) public static CookieMetadata RetrieveAntiforgeryCookie(HttpResponseMessage response)
{ {
var setCookieArray = response.Headers.GetValues("Set-Cookie").ToArray(); var setCookieArray = response.Headers.GetValues("Set-Cookie").ToArray();
var cookie = setCookieArray[0].Split(';').First().Split('='); var cookie = setCookieArray[0].Split(';').First().Split('=');

View File

@ -13,11 +13,11 @@ using Xunit;
namespace Microsoft.AspNet.Mvc.FunctionalTests namespace Microsoft.AspNet.Mvc.FunctionalTests
{ {
public class AntiForgeryTests public class AntiforgeryTests
{ {
private const string SiteName = nameof(AntiForgeryWebSite); private const string SiteName = nameof(AntiforgeryTokenWebSite);
private readonly Action<IApplicationBuilder> _app = new AntiForgeryWebSite.Startup().Configure; private readonly Action<IApplicationBuilder> _app = new AntiforgeryTokenWebSite.Startup().Configure;
private readonly Action<IServiceCollection> _configureServices = new AntiForgeryWebSite.Startup().ConfigureServices; private readonly Action<IServiceCollection> _configureServices = new AntiforgeryTokenWebSite.Startup().ConfigureServices;
[Fact] [Fact]
public async Task MultipleAFTokensWithinTheSamePage_GeneratesASingleCookieToken() public async Task MultipleAFTokensWithinTheSamePage_GeneratesASingleCookieToken()
@ -50,12 +50,12 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// do a get response. // do a get response.
var getResponse = await client.GetAsync("http://localhost/Account/Login"); var getResponse = await client.GetAsync("http://localhost/Account/Login");
var resposneBody = await getResponse.Content.ReadAsStringAsync(); var responseBody = await getResponse.Content.ReadAsStringAsync();
// Get the AF token for the second login. If the cookies are generated twice(i.e are different), // Get the AF token for the second login. If the cookies are generated twice(i.e are different),
// this AF token will not work with the first cookie. // this AF token will not work with the first cookie.
var formToken = AntiForgeryTestHelper.RetrieveAntiForgeryToken(resposneBody, "Account/UseFacebookLogin"); var formToken = AntiforgeryTestHelper.RetrieveAntiforgeryToken(responseBody, "Account/UseFacebookLogin");
var cookieToken = AntiForgeryTestHelper.RetrieveAntiForgeryCookie(getResponse); var cookieToken = AntiforgeryTestHelper.RetrieveAntiforgeryCookie(getResponse);
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Account/Login"); var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Account/Login");
request.Headers.Add("Cookie", cookieToken.Key + "=" + cookieToken.Value); request.Headers.Add("Cookie", cookieToken.Key + "=" + cookieToken.Value);
@ -84,10 +84,10 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var client = server.CreateClient(); var client = server.CreateClient();
var getResponse = await client.GetAsync("http://localhost/Account/Login"); var getResponse = await client.GetAsync("http://localhost/Account/Login");
var resposneBody = await getResponse.Content.ReadAsStringAsync(); var responseBody = await getResponse.Content.ReadAsStringAsync();
var formToken = AntiForgeryTestHelper.RetrieveAntiForgeryToken(resposneBody, "Account/Login"); var formToken = AntiforgeryTestHelper.RetrieveAntiforgeryToken(responseBody, "Account/Login");
var cookieToken = AntiForgeryTestHelper.RetrieveAntiForgeryCookie(getResponse); var cookieToken = AntiforgeryTestHelper.RetrieveAntiforgeryCookie(getResponse);
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Account/Login"); var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Account/Login");
request.Headers.Add("Cookie", cookieToken.Key + "=invalidCookie"); request.Headers.Add("Cookie", cookieToken.Key + "=invalidCookie");
@ -105,7 +105,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert // Assert
var exception = response.GetServerException(); var exception = response.GetServerException();
Assert.Equal("The anti-forgery token could not be decrypted.", exception.ExceptionMessage); Assert.Equal("The antiforgery token could not be decrypted.", exception.ExceptionMessage);
} }
[Fact] [Fact]
@ -116,8 +116,8 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var client = server.CreateClient(); var client = server.CreateClient();
var getResponse = await client.GetAsync("http://localhost/Account/Login"); var getResponse = await client.GetAsync("http://localhost/Account/Login");
var resposneBody = await getResponse.Content.ReadAsStringAsync(); var responseBody = await getResponse.Content.ReadAsStringAsync();
var cookieToken = AntiForgeryTestHelper.RetrieveAntiForgeryCookie(getResponse); var cookieToken = AntiforgeryTestHelper.RetrieveAntiforgeryCookie(getResponse);
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Account/Login"); var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Account/Login");
var formToken = "adsad"; var formToken = "adsad";
request.Headers.Add("Cookie", cookieToken.Key + "=" + cookieToken.Value); request.Headers.Add("Cookie", cookieToken.Key + "=" + cookieToken.Value);
@ -135,7 +135,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert // Assert
var exception = response.GetServerException(); var exception = response.GetServerException();
Assert.Equal("The anti-forgery token could not be decrypted.", exception.ExceptionMessage); Assert.Equal("The antiforgery token could not be decrypted.", exception.ExceptionMessage);
} }
[Fact] [Fact]
@ -146,14 +146,14 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var client = server.CreateClient(); var client = server.CreateClient();
// do a get response. // do a get response.
// We do two requests to get two different sets of anti forgery cookie and token values. // We do two requests to get two different sets of antiforgery cookie and token values.
var getResponse1 = await client.GetAsync("http://localhost/Account/Login"); var getResponse1 = await client.GetAsync("http://localhost/Account/Login");
var resposneBody1 = await getResponse1.Content.ReadAsStringAsync(); var responseBody1 = await getResponse1.Content.ReadAsStringAsync();
var formToken1 = AntiForgeryTestHelper.RetrieveAntiForgeryToken(resposneBody1, "Account/Login"); var formToken1 = AntiforgeryTestHelper.RetrieveAntiforgeryToken(responseBody1, "Account/Login");
var getResponse2 = await client.GetAsync("http://localhost/Account/Login"); var getResponse2 = await client.GetAsync("http://localhost/Account/Login");
var resposneBody2 = await getResponse2.Content.ReadAsStringAsync(); var responseBody2 = await getResponse2.Content.ReadAsStringAsync();
var cookieToken2 = AntiForgeryTestHelper.RetrieveAntiForgeryCookie(getResponse2); var cookieToken2 = AntiforgeryTestHelper.RetrieveAntiforgeryCookie(getResponse2);
var cookieToken = cookieToken2.Value; var cookieToken = cookieToken2.Value;
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Account/Login"); var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Account/Login");
@ -173,7 +173,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert // Assert
var exception = response.GetServerException(); var exception = response.GetServerException();
Assert.Equal("The anti-forgery cookie token and form field token do not match.", exception.ExceptionMessage); Assert.Equal("The antiforgery cookie token and form field token do not match.", exception.ExceptionMessage);
} }
[Fact] [Fact]
@ -185,9 +185,9 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// do a get response. // do a get response.
var getResponse = await client.GetAsync("http://localhost/Account/Login"); var getResponse = await client.GetAsync("http://localhost/Account/Login");
var resposneBody = await getResponse.Content.ReadAsStringAsync(); var responseBody = await getResponse.Content.ReadAsStringAsync();
var formToken = AntiForgeryTestHelper.RetrieveAntiForgeryToken(resposneBody, "Account/Login"); var formToken = AntiforgeryTestHelper.RetrieveAntiforgeryToken(responseBody, "Account/Login");
var cookieTokenKey = AntiForgeryTestHelper.RetrieveAntiForgeryCookie(getResponse).Key; var cookieTokenKey = AntiforgeryTestHelper.RetrieveAntiforgeryCookie(getResponse).Key;
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Account/Login"); var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Account/Login");
var nameValueCollection = new List<KeyValuePair<string, string>> var nameValueCollection = new List<KeyValuePair<string, string>>
@ -205,7 +205,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert // Assert
var exception = response.GetServerException(); var exception = response.GetServerException();
Assert.Equal( Assert.Equal(
"The required anti-forgery cookie \"" + cookieTokenKey + "\" is not present.", "The required antiforgery cookie \"" + cookieTokenKey + "\" is not present.",
exception.ExceptionMessage); exception.ExceptionMessage);
} }
@ -216,8 +216,8 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var server = TestHelper.CreateServer(_app, SiteName, _configureServices); var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient(); var client = server.CreateClient();
var getResponse = await client.GetAsync("http://localhost/Account/Login"); var getResponse = await client.GetAsync("http://localhost/Account/Login");
var resposneBody = await getResponse.Content.ReadAsStringAsync(); var responseBody = await getResponse.Content.ReadAsStringAsync();
var cookieToken = AntiForgeryTestHelper.RetrieveAntiForgeryCookie(getResponse); var cookieToken = AntiforgeryTestHelper.RetrieveAntiforgeryCookie(getResponse);
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Account/Login"); var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Account/Login");
request.Headers.Add("Cookie", cookieToken.Key + "=" + cookieToken.Value); request.Headers.Add("Cookie", cookieToken.Key + "=" + cookieToken.Value);
@ -234,7 +234,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert // Assert
var exception = response.GetServerException(); var exception = response.GetServerException();
Assert.Equal("The required anti-forgery form field \"__RequestVerificationToken\" is not present.", Assert.Equal("The required antiforgery form field \"__RequestVerificationToken\" is not present.",
exception.ExceptionMessage); exception.ExceptionMessage);
} }
@ -265,10 +265,10 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// do a get response. // do a get response.
var getResponse = await client.GetAsync("http://localhost/Account/FlushAsyncLogin"); var getResponse = await client.GetAsync("http://localhost/Account/FlushAsyncLogin");
var resposneBody = await getResponse.Content.ReadAsStringAsync(); var responseBody = await getResponse.Content.ReadAsStringAsync();
var formToken = AntiForgeryTestHelper.RetrieveAntiForgeryToken(resposneBody, "Account/FlushAsyncLogin"); var formToken = AntiforgeryTestHelper.RetrieveAntiforgeryToken(responseBody, "Account/FlushAsyncLogin");
var cookieToken = AntiForgeryTestHelper.RetrieveAntiForgeryCookie(getResponse); var cookieToken = AntiforgeryTestHelper.RetrieveAntiforgeryCookie(getResponse);
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Account/FlushAsyncLogin"); var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Account/FlushAsyncLogin");
request.Headers.Add("Cookie", cookieToken.Key + "=" + cookieToken.Value); request.Headers.Add("Cookie", cookieToken.Key + "=" + cookieToken.Value);

View File

@ -52,7 +52,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
[InlineData("Image", null)] [InlineData("Image", null)]
// Testing InputTagHelper with File // Testing InputTagHelper with File
[InlineData("Input", null)] [InlineData("Input", null)]
public async Task HtmlGenerationWebSite_GeneratesExpectedResults(string action, string antiForgeryPath) public async Task HtmlGenerationWebSite_GeneratesExpectedResults(string action, string antiforgeryPath)
{ {
// Arrange // Arrange
var server = TestHelper.CreateServer(_app, SiteName, _configureServices); var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
@ -72,7 +72,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
Assert.Equal(expectedMediaType, response.Content.Headers.ContentType); Assert.Equal(expectedMediaType, response.Content.Headers.ContentType);
responseContent = responseContent.Trim(); responseContent = responseContent.Trim();
if (antiForgeryPath == null) if (antiforgeryPath == null)
{ {
#if GENERATE_BASELINES #if GENERATE_BASELINES
ResourceFile.UpdateFile(_resourcesAssembly, outputFile, expectedContent, responseContent); ResourceFile.UpdateFile(_resourcesAssembly, outputFile, expectedContent, responseContent);
@ -82,7 +82,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
} }
else else
{ {
var forgeryToken = AntiForgeryTestHelper.RetrieveAntiForgeryToken(responseContent, antiForgeryPath); var forgeryToken = AntiforgeryTestHelper.RetrieveAntiforgeryToken(responseContent, antiforgeryPath);
#if GENERATE_BASELINES #if GENERATE_BASELINES
// Reverse usual substitution and insert a format item into the new file content. // Reverse usual substitution and insert a format item into the new file content.
responseContent = responseContent.Replace(forgeryToken, "{0}"); responseContent = responseContent.Replace(forgeryToken, "{0}");
@ -102,7 +102,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
[InlineData("OrderUsingHtmlHelpers", "/HtmlGeneration_Order/Submit")] [InlineData("OrderUsingHtmlHelpers", "/HtmlGeneration_Order/Submit")]
[InlineData("Product", null)] [InlineData("Product", null)]
[InlineData("Script", null)] [InlineData("Script", null)]
public async Task HtmlGenerationWebSite_GenerateEncodedResults(string action, string antiForgeryPath) public async Task HtmlGenerationWebSite_GenerateEncodedResults(string action, string antiforgeryPath)
{ {
// Arrange // Arrange
var server = TestHelper.CreateServer(_app, SiteName, services => var server = TestHelper.CreateServer(_app, SiteName, services =>
@ -128,7 +128,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
Assert.Equal(expectedMediaType, response.Content.Headers.ContentType); Assert.Equal(expectedMediaType, response.Content.Headers.ContentType);
responseContent = responseContent.Trim(); responseContent = responseContent.Trim();
if (antiForgeryPath == null) if (antiforgeryPath == null)
{ {
#if GENERATE_BASELINES #if GENERATE_BASELINES
ResourceFile.UpdateFile(_resourcesAssembly, outputFile, expectedContent, responseContent); ResourceFile.UpdateFile(_resourcesAssembly, outputFile, expectedContent, responseContent);
@ -138,7 +138,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
} }
else else
{ {
var forgeryToken = AntiForgeryTestHelper.RetrieveAntiForgeryToken(responseContent, antiForgeryPath); var forgeryToken = AntiforgeryTestHelper.RetrieveAntiforgeryToken(responseContent, antiforgeryPath);
#if GENERATE_BASELINES #if GENERATE_BASELINES
// Reverse usual substitution and insert a format item into the new file content. // Reverse usual substitution and insert a format item into the new file content.
responseContent = responseContent.Replace(forgeryToken, "{0}"); responseContent = responseContent.Replace(forgeryToken, "{0}");
@ -180,7 +180,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
responseContent = responseContent.Trim(); responseContent = responseContent.Trim();
var forgeryToken = var forgeryToken =
AntiForgeryTestHelper.RetrieveAntiForgeryToken(responseContent, "Customer/HtmlGeneration_Customer"); AntiforgeryTestHelper.RetrieveAntiforgeryToken(responseContent, "Customer/HtmlGeneration_Customer");
#if GENERATE_BASELINES #if GENERATE_BASELINES
// Reverse usual substitution and insert a format item into the new file content. // Reverse usual substitution and insert a format item into the new file content.
@ -461,11 +461,11 @@ Products: Laptops (3)";
[InlineData(null)] [InlineData(null)]
[InlineData(true)] [InlineData(true)]
[InlineData(false)] [InlineData(false)]
public async Task FormTagHelper_GeneratesExpectedContent(bool? optionsAntiForgery) public async Task FormTagHelper_GeneratesExpectedContent(bool? optionsAntiforgery)
{ {
// Arrange // Arrange
var newServices = new ServiceCollection(); var newServices = new ServiceCollection();
newServices.InitializeTagHelper<FormTagHelper>((helper, _) => helper.AntiForgery = optionsAntiForgery); newServices.InitializeTagHelper<FormTagHelper>((helper, _) => helper.Antiforgery = optionsAntiforgery);
var server = TestHelper.CreateServer(_app, SiteName, var server = TestHelper.CreateServer(_app, SiteName,
services => services =>
{ {
@ -476,8 +476,8 @@ Products: Laptops (3)";
var expectedMediaType = MediaTypeHeaderValue.Parse("text/html; charset=utf-8"); var expectedMediaType = MediaTypeHeaderValue.Parse("text/html; charset=utf-8");
var outputFile = string.Format( var outputFile = string.Format(
"compiler/resources/HtmlGenerationWebSite.HtmlGeneration_Home.Form.Options.AntiForgery.{0}.html", "compiler/resources/HtmlGenerationWebSite.HtmlGeneration_Home.Form.Options.Antiforgery.{0}.html",
optionsAntiForgery?.ToString() ?? "null"); optionsAntiforgery?.ToString() ?? "null");
var expectedContent = var expectedContent =
await ResourceFile.ReadResourceAsync(_resourcesAssembly, outputFile, sourceFile: false); await ResourceFile.ReadResourceAsync(_resourcesAssembly, outputFile, sourceFile: false);
@ -491,7 +491,7 @@ Products: Laptops (3)";
Assert.Equal(expectedMediaType, response.Content.Headers.ContentType); Assert.Equal(expectedMediaType, response.Content.Headers.ContentType);
responseContent = responseContent.Trim(); responseContent = responseContent.Trim();
var forgeryTokens = AntiForgeryTestHelper.RetrieveAntiForgeryTokens(responseContent).ToArray(); var forgeryTokens = AntiforgeryTestHelper.RetrieveAntiforgeryTokens(responseContent).ToArray();
#if GENERATE_BASELINES #if GENERATE_BASELINES
// Reverse usual substitutions and insert format items into the new file content. // Reverse usual substitutions and insert format items into the new file content.

View File

@ -11,7 +11,7 @@
"ActionResultsWebSite": "1.0.0", "ActionResultsWebSite": "1.0.0",
"ActivatorWebSite": "1.0.0", "ActivatorWebSite": "1.0.0",
"AddServicesWebSite": "1.0.0", "AddServicesWebSite": "1.0.0",
"AntiForgeryWebSite": "1.0.0", "AntiforgeryTokenWebSite": "1.0.0",
"ApiExplorerWebSite": "1.0.0", "ApiExplorerWebSite": "1.0.0",
"ApplicationModelWebSite": "1.0.0", "ApplicationModelWebSite": "1.0.0",
"BasicWebSite": "1.0.0", "BasicWebSite": "1.0.0",

View File

@ -33,7 +33,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ "asp-action", "index" }, { "asp-action", "index" },
{ "asp-controller", "home" }, { "asp-controller", "home" },
{ "method", "post" }, { "method", "post" },
{ "asp-anti-forgery", true } { "asp-antiforgery", true }
}, },
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: "test", uniqueId: "test",
@ -58,12 +58,11 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var viewContext = TestableHtmlGenerator.GetViewContext(model: null, var viewContext = TestableHtmlGenerator.GetViewContext(model: null,
htmlGenerator: htmlGenerator, htmlGenerator: htmlGenerator,
metadataProvider: metadataProvider); metadataProvider: metadataProvider);
var expectedPostContent = "Something" + htmlGenerator.GenerateAntiForgery(viewContext) var expectedPostContent = "Something" + htmlGenerator.GenerateAntiforgery(viewContext);
.ToString(TagRenderMode.SelfClosing);
var formTagHelper = new FormTagHelper(htmlGenerator) var formTagHelper = new FormTagHelper(htmlGenerator)
{ {
Action = "index", Action = "index",
AntiForgery = true, Antiforgery = true,
Controller = "home", Controller = "home",
ViewContext = viewContext, ViewContext = viewContext,
RouteValues = RouteValues =
@ -93,8 +92,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
[InlineData(null, "<input />")] [InlineData(null, "<input />")]
[InlineData(true, "<input />")] [InlineData(true, "<input />")]
[InlineData(false, "")] [InlineData(false, "")]
public async Task ProcessAsync_GeneratesAntiForgeryCorrectly( public async Task ProcessAsync_GeneratesAntiforgeryCorrectly(
bool? antiForgery, bool? antiforgery,
string expectedPostContent) string expectedPostContent)
{ {
// Arrange // Arrange
@ -124,12 +123,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
It.IsAny<object>())) It.IsAny<object>()))
.Returns(new TagBuilder("form", new CommonTestEncoder())); .Returns(new TagBuilder("form", new CommonTestEncoder()));
generator.Setup(mock => mock.GenerateAntiForgery(viewContext)) generator.Setup(mock => mock.GenerateAntiforgery(viewContext))
.Returns(new TagBuilder("input", new CommonTestEncoder())); .Returns(new HtmlString("<input />"));
var formTagHelper = new FormTagHelper(generator.Object) var formTagHelper = new FormTagHelper(generator.Object)
{ {
Action = "Index", Action = "Index",
AntiForgery = antiForgery, Antiforgery = antiforgery,
ViewContext = viewContext, ViewContext = viewContext,
}; };
@ -195,7 +194,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var formTagHelper = new FormTagHelper(generator.Object) var formTagHelper = new FormTagHelper(generator.Object)
{ {
Action = "Index", Action = "Index",
AntiForgery = false, Antiforgery = false,
ViewContext = testViewContext, ViewContext = testViewContext,
RouteValues = RouteValues =
{ {
@ -250,7 +249,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var formTagHelper = new FormTagHelper(generator.Object) var formTagHelper = new FormTagHelper(generator.Object)
{ {
Action = "Index", Action = "Index",
AntiForgery = false, Antiforgery = false,
Controller = "Home", Controller = "Home",
ViewContext = viewContext, ViewContext = viewContext,
}; };
@ -299,7 +298,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
.Verifiable(); .Verifiable();
var formTagHelper = new FormTagHelper(generator.Object) var formTagHelper = new FormTagHelper(generator.Object)
{ {
AntiForgery = false, Antiforgery = false,
Route = "Default", Route = "Default",
ViewContext = viewContext, ViewContext = viewContext,
RouteValues = RouteValues =
@ -326,19 +325,19 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
[InlineData(true, "<input />")] [InlineData(true, "<input />")]
[InlineData(false, "")] [InlineData(false, "")]
[InlineData(null, "")] [InlineData(null, "")]
public async Task ProcessAsync_SupportsAntiForgeryIfActionIsSpecified( public async Task ProcessAsync_SupportsAntiforgeryIfActionIsSpecified(
bool? antiForgery, bool? antiforgery,
string expectedPostContent) string expectedPostContent)
{ {
// Arrange // Arrange
var viewContext = CreateViewContext(); var viewContext = CreateViewContext();
var generator = new Mock<IHtmlGenerator>(); var generator = new Mock<IHtmlGenerator>();
generator.Setup(mock => mock.GenerateAntiForgery(It.IsAny<ViewContext>())) generator.Setup(mock => mock.GenerateAntiforgery(It.IsAny<ViewContext>()))
.Returns(new TagBuilder("input", new CommonTestEncoder())); .Returns(new HtmlString("<input />"));
var formTagHelper = new FormTagHelper(generator.Object) var formTagHelper = new FormTagHelper(generator.Object)
{ {
AntiForgery = antiForgery, Antiforgery = antiforgery,
ViewContext = viewContext, ViewContext = viewContext,
}; };

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using Microsoft.AspNet.Antiforgery;
using Microsoft.AspNet.DataProtection; using Microsoft.AspNet.DataProtection;
using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
@ -38,7 +39,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
IOptions<MvcViewOptions> options, IOptions<MvcViewOptions> options,
IUrlHelper urlHelper, IUrlHelper urlHelper,
IDictionary<string, object> validationAttributes) IDictionary<string, object> validationAttributes)
: base(GetAntiForgery(), options, metadataProvider, urlHelper, new CommonTestEncoder()) : base(Mock.Of<IAntiforgery>(), options, metadataProvider, urlHelper, new CommonTestEncoder())
{ {
_validationAttributes = validationAttributes; _validationAttributes = validationAttributes;
} }
@ -69,9 +70,9 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
return viewContext; return viewContext;
} }
public override TagBuilder GenerateAntiForgery(ViewContext viewContext) public override HtmlString GenerateAntiforgery(ViewContext viewContext)
{ {
return new TagBuilder("input", new CommonTestEncoder()) var tagBuilder = new TagBuilder("input", new CommonTestEncoder())
{ {
Attributes = Attributes =
{ {
@ -80,6 +81,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ "value", "olJlUDjrouRNWLen4tQJhauj1Z1rrvnb3QD65cmQU1Ykqi6S4" }, // 50 chars of a token. { "value", "olJlUDjrouRNWLen4tQJhauj1Z1rrvnb3QD65cmQU1Ykqi6S4" }, // 50 chars of a token.
}, },
}; };
return tagBuilder.ToHtmlString(TagRenderMode.SelfClosing);
} }
protected override IDictionary<string, object> GetValidationAttributes( protected override IDictionary<string, object> GetValidationAttributes(
@ -99,26 +102,5 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
return mockOptions.Object; return mockOptions.Object;
} }
private static AntiForgery GetAntiForgery()
{
// AntiForgery must be passed to TestableHtmlGenerator constructor but will never be called.
var optionsAccessor = new Mock<IOptions<AntiForgeryOptions>>();
var mockDataProtectionOptions = new Mock<IOptions<DataProtectionOptions>>();
mockDataProtectionOptions
.SetupGet(options => options.Options)
.Returns(Mock.Of<DataProtectionOptions>());
optionsAccessor
.SetupGet(o => o.Options)
.Returns(new AntiForgeryOptions());
var antiForgery = new AntiForgery(
Mock.Of<IClaimUidExtractor>(),
Mock.Of<IDataProtectionProvider>(),
Mock.Of<IAntiForgeryAdditionalDataProvider>(),
optionsAccessor.Object,
new CommonTestEncoder(),
mockDataProtectionOptions.Object);
return antiForgery;
}
} }
} }

View File

@ -1,5 +0,0 @@
AntiForgeryWebSite
===
This web site illustrates how to use anti forgery system to prevent CSRF attacks. The web site has an
`AccountsController` which uses an anti forgery token to validate incoming form posts.

View File

@ -10,6 +10,9 @@
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath> <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath> <OutputPath Condition="'$(OutputPath)'=='' ">..\..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Label="Configuration">
<RootNamespace>AntiforgeryTokenWebSite</RootNamespace>
</PropertyGroup>
<PropertyGroup> <PropertyGroup>
<SchemaVersion>2.0</SchemaVersion> <SchemaVersion>2.0</SchemaVersion>
<DevelopmentServerPort>49637</DevelopmentServerPort> <DevelopmentServerPort>49637</DevelopmentServerPort>

View File

@ -3,7 +3,7 @@
using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc;
namespace AntiForgeryWebSite namespace AntiforgeryTokenWebSite
{ {
// This controller is reachable via traditional routing. // This controller is reachable via traditional routing.
public class AccountController : Controller public class AccountController : Controller

View File

@ -3,7 +3,7 @@
using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc;
namespace AntiForgeryWebSite namespace AntiforgeryTokenWebSite
{ {
// This controller is reachable via traditional routing. // This controller is reachable via traditional routing.
public class HomeController : Controller public class HomeController : Controller

View File

@ -3,7 +3,7 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
namespace AntiForgeryWebSite namespace AntiforgeryTokenWebSite
{ {
public class LoginViewModel public class LoginViewModel
{ {

View File

@ -4,7 +4,7 @@
using Microsoft.AspNet.Builder; using Microsoft.AspNet.Builder;
using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.DependencyInjection;
namespace AntiForgeryWebSite namespace AntiforgeryTokenWebSite
{ {
public class Startup public class Startup
{ {

View File

@ -1,4 +1,4 @@
@model AntiForgeryWebSite.LoginViewModel @model AntiforgeryTokenWebSite.LoginViewModel
@{ @{
ViewBag.Title = "Log in"; ViewBag.Title = "Log in";

View File

@ -1,4 +1,4 @@
@model AntiForgeryWebSite.LoginViewModel @model AntiforgeryTokenWebSite.LoginViewModel
@{ @{
ViewBag.Title = "Log in"; ViewBag.Title = "Log in";

View File

@ -1,8 +1,8 @@
<html> <html>
<head> <head>
<title>@ViewBag.Title AntiForgery Functional Tests</title> <title>@ViewBag.Title Antiforgery Functional Tests</title>
</head> </head>
@SetAntiForgeryCookieAndHeader() @SetAntiforgeryCookieAndHeader()
@await FlushAsync() @await FlushAsync()
<body> <body>

View File

@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title AntiForgery Functional Tests</title> <title>@ViewBag.Title Antiforgery Functional Tests</title>
</head> </head>
<body> <body>
<div class="navbar navbar-inverse navbar-fixed-top"> <div class="navbar navbar-inverse navbar-fixed-top">
@ -11,7 +11,7 @@
<div class="navbar-header"> <div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
</button> </button>
@Html.ActionLink("ASP.NET Anti Forgery tests", "Index", "Home", null, new { @class = "navbar-brand" }) @Html.ActionLink("ASP.NET Antiforgery tests", "Index", "Home", null, new { @class = "navbar-brand" })
</div> </div>
<div class="navbar-collapse collapse"> <div class="navbar-collapse collapse">
@await Html.PartialAsync("_LoginPartial") @await Html.PartialAsync("_LoginPartial")

View File

@ -0,0 +1,5 @@
AntiforgeryTokenWebSite
===
This web site illustrates how to use the antiforgery system to prevent CSRF attacks. The web site has an
`AccountsController` which uses an antiforgery token to validate incoming form posts.

View File

@ -8,7 +8,7 @@
<html> <html>
<body> <body>
<form asp-controller="HtmlGeneration_Home" asp-action="EditWarehouse" asp-anti-forgery="false"> <form asp-controller="HtmlGeneration_Home" asp-action="EditWarehouse" asp-antiforgery="false">
<div> <div>
@Html.DisplayFor(m => m.City) @Html.DisplayFor(m => m.City)
<input asp-for="City" type="text" /> <input asp-for="City" type="text" />

View File

@ -12,7 +12,7 @@
<form></form> <form></form>
<form asp-controller="HtmlGeneration_Home" asp-action="Form"></form> <form asp-controller="HtmlGeneration_Home" asp-action="Form"></form>
<form asp-controller="HtmlGeneration_Home" asp-action="Form" asp-anti-forgery="true"></form> <form asp-controller="HtmlGeneration_Home" asp-action="Form" asp-antiforgery="true"></form>
<form asp-controller="HtmlGeneration_Home" asp-action="Form" asp-anti-forgery="false"></form> <form asp-controller="HtmlGeneration_Home" asp-action="Form" asp-antiforgery="false"></form>
</body> </body>
</html> </html>

View File

@ -18,7 +18,7 @@
<title></title> <title></title>
</head> </head>
<body> <body>
<form asp-controller="HtmlGeneration_Order" asp-action="Submit" asp-anti-forgery=" true"> <form asp-controller="HtmlGeneration_Order" asp-action="Submit" asp-antiforgery=" true">
<div> <div>
<label asp-for="Shipping" class="order"></label> <label asp-for="Shipping" class="order"></label>
<input asp-for="Shipping" type="text" asp-format="Your shipping method is {0}" size="50" /> <input asp-for="Shipping" type="text" asp-format="Your shipping method is {0}" size="50" />

View File

@ -12,7 +12,7 @@
<title></title> <title></title>
</head> </head>
<body> <body>
<form asp-controller="HtmlGeneration_Home" asp-route-action="ProductSubmit" asp-anti-forgery="false" method="get"> <form asp-controller="HtmlGeneration_Home" asp-route-action="ProductSubmit" asp-antiforgery="false" method="get">
<div> <div>
<label asp-for="HomePage" class="product"></label> <label asp-for="HomePage" class="product"></label>
<input asp-for="HomePage" type="url" size="50" /> <input asp-for="HomePage" type="url" size="50" />

View File

@ -17,7 +17,7 @@
</head> </head>
<body> <body>
<form asp-anti-forgery="false" asp-action="Create"> <form asp-antiforgery="false" asp-action="Create">
<div class="form-horizontal"> <div class="form-horizontal">
<h4>Employee</h4> <h4>Employee</h4>