From a281b2e3698df209a46fabeb2068b9a9505bc024 Mon Sep 17 00:00:00 2001 From: ryanbrandenburg Date: Wed, 30 Dec 2015 13:46:09 -0800 Subject: [PATCH] * Add functional tests for sample --- .bowerrc | 3 + Antiforgery.sln | 9 +- samples/AntiforgerySample/wwwroot/Index.html | 4 +- .../AntiForgerySampleTestFixture.cs | 45 +++++++++ .../AntiforgerySampleTest.cs | 98 +++++++++++++++++++ ...t.AspNet.Antiforgery.FunctionalTests.xproj | 21 ++++ .../project.json | 25 +++++ 7 files changed, 202 insertions(+), 3 deletions(-) create mode 100644 .bowerrc create mode 100644 test/Microsoft.AspNet.Antiforgery.FunctionalTests/AntiForgerySampleTestFixture.cs create mode 100644 test/Microsoft.AspNet.Antiforgery.FunctionalTests/AntiforgerySampleTest.cs create mode 100644 test/Microsoft.AspNet.Antiforgery.FunctionalTests/Microsoft.AspNet.Antiforgery.FunctionalTests.xproj create mode 100644 test/Microsoft.AspNet.Antiforgery.FunctionalTests/project.json diff --git a/.bowerrc b/.bowerrc new file mode 100644 index 0000000000..eae11312d8 --- /dev/null +++ b/.bowerrc @@ -0,0 +1,3 @@ +{ + "directory": "wwwroot/lib" +} \ No newline at end of file diff --git a/Antiforgery.sln b/Antiforgery.sln index 3074ae4f3d..48fb0ca448 100644 --- a/Antiforgery.sln +++ b/Antiforgery.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.22808.1 +VisualStudioVersion = 14.0.24720.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{71D070C4-B325-48F7-9F25-DD4E91C2BBCA}" EndProject @@ -15,6 +15,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{D8C4 EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "AntiforgerySample", "samples\AntiforgerySample\AntiforgerySample.xproj", "{AF9E0784-5EDB-494F-B46C-1A8DA785C49C}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Antiforgery.FunctionalTests", "test\Microsoft.AspNet.Antiforgery.FunctionalTests\Microsoft.AspNet.Antiforgery.FunctionalTests.xproj", "{8B288810-5A96-4AF5-9836-8BA2D2953203}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -33,6 +35,10 @@ Global {AF9E0784-5EDB-494F-B46C-1A8DA785C49C}.Debug|Any CPU.Build.0 = Debug|Any CPU {AF9E0784-5EDB-494F-B46C-1A8DA785C49C}.Release|Any CPU.ActiveCfg = Release|Any CPU {AF9E0784-5EDB-494F-B46C-1A8DA785C49C}.Release|Any CPU.Build.0 = Release|Any CPU + {8B288810-5A96-4AF5-9836-8BA2D2953203}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8B288810-5A96-4AF5-9836-8BA2D2953203}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8B288810-5A96-4AF5-9836-8BA2D2953203}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8B288810-5A96-4AF5-9836-8BA2D2953203}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -41,5 +47,6 @@ Global {46FB03FB-7A44-4106-BDDE-D6F5417544AB} = {71D070C4-B325-48F7-9F25-DD4E91C2BBCA} {415E83F8-6002-47E4-AA8E-CD5169C06F28} = {6EDD8B57-4DE8-4246-A6A3-47ECD92740B4} {AF9E0784-5EDB-494F-B46C-1A8DA785C49C} = {D8C46ADF-E40A-4B48-ADE9-E1FA80466FE3} + {8B288810-5A96-4AF5-9836-8BA2D2953203} = {6EDD8B57-4DE8-4246-A6A3-47ECD92740B4} EndGlobalSection EndGlobal diff --git a/samples/AntiforgerySample/wwwroot/Index.html b/samples/AntiforgerySample/wwwroot/Index.html index b9a1fc0182..7789fe514b 100644 --- a/samples/AntiforgerySample/wwwroot/Index.html +++ b/samples/AntiforgerySample/wwwroot/Index.html @@ -4,7 +4,7 @@ Todo List Antiforgery Sample - +
@@ -38,7 +38,7 @@
- + diff --git a/test/Microsoft.AspNet.Antiforgery.FunctionalTests/AntiForgerySampleTestFixture.cs b/test/Microsoft.AspNet.Antiforgery.FunctionalTests/AntiForgerySampleTestFixture.cs new file mode 100644 index 0000000000..dd43b79399 --- /dev/null +++ b/test/Microsoft.AspNet.Antiforgery.FunctionalTests/AntiForgerySampleTestFixture.cs @@ -0,0 +1,45 @@ +// 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.Net.Http; +using Microsoft.AspNet.Hosting; +using Microsoft.AspNet.TestHost; +using Microsoft.Extensions.Configuration; + +namespace Microsoft.AspNet.Antiforgery.FunctionalTests +{ + public class AntiForgerySampleTestFixture : IDisposable + { + private readonly TestServer _server; + + public AntiForgerySampleTestFixture() + { + var configurationBuilder = new ConfigurationBuilder(); + + configurationBuilder.AddInMemoryCollection(new[] + { + new KeyValuePair("webroot", "wwwroot") + }); + + var builder = new WebApplicationBuilder() + .UseConfiguration(configurationBuilder.Build()) + .UseStartup(typeof(AntiforgerySample.Startup)) + .UseApplicationBasePath("../../samples/AntiforgerySample"); + + _server = new TestServer(builder); + + Client = _server.CreateClient(); + Client.BaseAddress = new Uri("http://localhost"); + } + + public HttpClient Client { get; } + + public void Dispose() + { + Client.Dispose(); + _server.Dispose(); + } + } +} diff --git a/test/Microsoft.AspNet.Antiforgery.FunctionalTests/AntiforgerySampleTest.cs b/test/Microsoft.AspNet.Antiforgery.FunctionalTests/AntiforgerySampleTest.cs new file mode 100644 index 0000000000..4135a56bd3 --- /dev/null +++ b/test/Microsoft.AspNet.Antiforgery.FunctionalTests/AntiforgerySampleTest.cs @@ -0,0 +1,98 @@ +// 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 System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNet.Antiforgery.FunctionalTests +{ + public class AntiforgerySampleTests : IClassFixture + { + public AntiforgerySampleTests(AntiForgerySampleTestFixture fixture) + { + Client = fixture.Client; + } + + public HttpClient Client { get; } + + [Fact] + public async Task ItemsPage_SetsXSRFTokens() + { + // Arrange & Act + var response = await Client.GetAsync("http://localhost/Index.html"); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + + var cookie = RetrieveAntiforgeryCookie(response); + Assert.NotNull(cookie.Value); + + var token = RetrieveAntiforgeryToken(response); + Assert.NotNull(token.Value); + } + + [Fact] + public async Task PostItem_NeedsHeader() + { + // Arrange + var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "http://localhost/api/items"); + + // Act + var exception = await Assert.ThrowsAsync(async () => + { + var response = await Client.SendAsync(httpRequestMessage); + }); + + // Assert + Assert.Contains("required antiforgery cookie", exception.Message); + } + + [Fact] + public async Task PostItem_XSRFWorks() + { + // Arrange + var content = new StringContent("{'name': 'Todoitem'}"); + var httpResponse = await Client.GetAsync("http://localhost/Index.html"); + + var cookie = RetrieveAntiforgeryCookie(httpResponse); + var token = RetrieveAntiforgeryToken(httpResponse); + + var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "http://localhost/api/items"); + + httpRequestMessage.Headers.Add("X-XSRF-TOKEN", token.Value); + httpRequestMessage.Headers.Add("Cookie", $"{cookie.Key}={cookie.Value}"); + + // Act + var response = await Client.SendAsync(httpRequestMessage); + + // Assert + Assert.Equal(HttpStatusCode.OK, httpResponse.StatusCode); + Assert.Equal(HttpStatusCode.NoContent, response.StatusCode); + } + + private static KeyValuePair RetrieveAntiforgeryToken(HttpResponseMessage response) + { + return GetCookie(response, 1); + } + + private static KeyValuePair RetrieveAntiforgeryCookie(HttpResponseMessage response) + { + return GetCookie(response, 0); + } + + private static KeyValuePair GetCookie(HttpResponseMessage response, int index) + { + var setCookieArray = response.Headers.GetValues("Set-Cookie").ToArray(); + var cookie = setCookieArray[index].Split(';').First().Split('='); + var cookieKey = cookie[0]; + var cookieData = cookie[1]; + + return new KeyValuePair(cookieKey, cookieData); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Antiforgery.FunctionalTests/Microsoft.AspNet.Antiforgery.FunctionalTests.xproj b/test/Microsoft.AspNet.Antiforgery.FunctionalTests/Microsoft.AspNet.Antiforgery.FunctionalTests.xproj new file mode 100644 index 0000000000..775501b0ed --- /dev/null +++ b/test/Microsoft.AspNet.Antiforgery.FunctionalTests/Microsoft.AspNet.Antiforgery.FunctionalTests.xproj @@ -0,0 +1,21 @@ + + + + 14.0.24720 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 8b288810-5a96-4af5-9836-8ba2d2953203 + FunctionalTests + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + 2.0 + + + + + + \ No newline at end of file diff --git a/test/Microsoft.AspNet.Antiforgery.FunctionalTests/project.json b/test/Microsoft.AspNet.Antiforgery.FunctionalTests/project.json new file mode 100644 index 0000000000..0df539fa57 --- /dev/null +++ b/test/Microsoft.AspNet.Antiforgery.FunctionalTests/project.json @@ -0,0 +1,25 @@ +{ + "dependencies": { + "AntiforgerySample": "1.0.0-*", + "Microsoft.AspNet.TestHost": "1.0.0-*", + "Microsoft.AspNet.Testing": "1.0.0-*", + "xunit.runner.aspnet": "2.0.0-aspnet-*" + }, + "commands": { + "run": "xunit.runner.aspnet", + "test": "xunit.runner.aspnet" + }, + "frameworks": { + "dnx451": { + "dependencies": { + "Moq": "4.2.1312.1622", + "System.Net.Http": "4.0.1-rc2-23621" + } + }, + "dnxcore50": { + "dependencies": { + "moq.netcore": "4.4.0-beta8" + } + } + } +}