From b922d816be89975a78ba87d1a696e595766464b1 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 6 Aug 2015 10:29:16 -0700 Subject: [PATCH] Fix aspnet/Mvc#2749 - fail gracefully with non-form content This change will report a more specific error when antiforgery is used with non-form content than "invalid content type". --- .../DefaultAntiforgeryTokenStore.cs | 8 +++++ .../DefaultAntiforgeryTokenStoreTest.cs | 34 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/Microsoft.AspNet.Antiforgery/DefaultAntiforgeryTokenStore.cs b/src/Microsoft.AspNet.Antiforgery/DefaultAntiforgeryTokenStore.cs index 7a566d4295..a0fb2085e1 100644 --- a/src/Microsoft.AspNet.Antiforgery/DefaultAntiforgeryTokenStore.cs +++ b/src/Microsoft.AspNet.Antiforgery/DefaultAntiforgeryTokenStore.cs @@ -53,6 +53,14 @@ namespace Microsoft.AspNet.Antiforgery Resources.FormatAntiforgery_CookieToken_MustBeProvided(_options.CookieName)); } + if (!httpContext.Request.HasFormContentType) + { + // Check the content-type before accessing the form collection to make sure + // we throw gracefully. + throw new InvalidOperationException( + Resources.FormatAntiforgery_FormToken_MustBeProvided(_options.FormFieldName)); + } + var form = await httpContext.Request.ReadFormAsync(); var formField = form[_options.FormFieldName]; if (string.IsNullOrEmpty(formField)) diff --git a/test/Microsoft.AspNet.Antiforgery.Test/DefaultAntiforgeryTokenStoreTest.cs b/test/Microsoft.AspNet.Antiforgery.Test/DefaultAntiforgeryTokenStoreTest.cs index a3cf81ce87..5c12c500d6 100644 --- a/test/Microsoft.AspNet.Antiforgery.Test/DefaultAntiforgeryTokenStoreTest.cs +++ b/test/Microsoft.AspNet.Antiforgery.Test/DefaultAntiforgeryTokenStoreTest.cs @@ -186,11 +186,44 @@ namespace Microsoft.AspNet.Antiforgery Assert.Equal("The required antiforgery cookie \"cookie-name\" is not present.", exception.Message); } + [Fact] + public async Task GetRequestTokens_NonFormContentType_Throws() + { + // Arrange + var httpContext = new DefaultHttpContext(); + httpContext.Request.ContentType = "application/json"; + + // Will not be accessed + httpContext.Request.Form = null; + httpContext.Request.Cookies = new ReadableStringCollection(new Dictionary() + { + { "cookie-name", new string[] { "cookie-value" } }, + }); + + var options = new AntiforgeryOptions() + { + CookieName = "cookie-name", + FormFieldName = "form-field-name", + }; + + var tokenStore = new DefaultAntiforgeryTokenStore( + optionsAccessor: new TestOptionsManager(options), + tokenSerializer: null); + + // Act + var exception = await Assert.ThrowsAsync( + async () => await tokenStore.GetRequestTokensAsync(httpContext)); + + // Assert + Assert.Equal("The required antiforgery form field \"form-field-name\" is not present.", exception.Message); + } + [Fact] public async Task GetRequestTokens_FormFieldIsEmpty_Throws() { // Arrange var httpContext = new DefaultHttpContext(); + httpContext.Request.ContentType = "application/x-www-form-urlencoded"; httpContext.Request.Form = new FormCollection(new Dictionary()); httpContext.Request.Cookies = new ReadableStringCollection(new Dictionary() { @@ -220,6 +253,7 @@ namespace Microsoft.AspNet.Antiforgery { // Arrange var httpContext = new DefaultHttpContext(); + httpContext.Request.ContentType = "application/x-www-form-urlencoded"; httpContext.Request.Form = new FormCollection(new Dictionary() { { "form-field-name", new string[] { "form-value" } },