Fix cookie from being set to empty pathbase

Found with issue: https://github.com/aspnet/Mvc/issues/5512
This commit is contained in:
Kiran Challa 2016-11-08 09:01:48 -08:00
parent 968ea59ce4
commit a5c0e505c1
3 changed files with 43 additions and 26 deletions

View File

@ -71,7 +71,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
var options = new CookieOptions(); var options = new CookieOptions();
options.HttpOnly = true; options.HttpOnly = true;
options.Path = _options.CookiePath ?? httpContext.Request.PathBase; options.Path = _options.CookiePath ?? GetPathBase(httpContext);
options.Domain = _options.CookieDomain; options.Domain = _options.CookieDomain;
// Note: don't use "newCookie.Secure = _options.RequireSSL;" since the default // Note: don't use "newCookie.Secure = _options.RequireSSL;" since the default
// value of newCookie.Secure is populated out of band. // value of newCookie.Secure is populated out of band.
@ -82,5 +82,15 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
httpContext.Response.Cookies.Append(_options.CookieName, token, options); httpContext.Response.Cookies.Append(_options.CookieName, token, options);
} }
private string GetPathBase(HttpContext httpContext)
{
var pathBase = httpContext.Request.PathBase.ToString();
if (string.IsNullOrEmpty(pathBase))
{
pathBase = "/";
}
return pathBase;
}
} }
} }

View File

@ -6,6 +6,7 @@ using System.Linq;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Net.Http.Headers;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Antiforgery.FunctionalTests namespace Microsoft.AspNetCore.Antiforgery.FunctionalTests
@ -26,11 +27,19 @@ namespace Microsoft.AspNetCore.Antiforgery.FunctionalTests
var response = await Client.GetAsync("http://localhost/Index.html"); var response = await Client.GetAsync("http://localhost/Index.html");
// Assert // Assert
var cookie = RetrieveAntiforgeryCookie(response); var setCookieHeaderValue = RetrieveAntiforgeryCookie(response);
Assert.NotNull(cookie.Value); Assert.NotNull(setCookieHeaderValue);
Assert.False(string.IsNullOrEmpty(setCookieHeaderValue.Value));
Assert.Null(setCookieHeaderValue.Domain);
Assert.Equal("/", setCookieHeaderValue.Path);
Assert.False(setCookieHeaderValue.Secure);
var token = RetrieveAntiforgeryToken(response); setCookieHeaderValue = RetrieveAntiforgeryToken(response);
Assert.NotNull(token.Value); Assert.NotNull(setCookieHeaderValue);
Assert.False(string.IsNullOrEmpty(setCookieHeaderValue.Value));
Assert.Null(setCookieHeaderValue.Domain);
Assert.Equal("/", setCookieHeaderValue.Path);
Assert.False(setCookieHeaderValue.Secure);
} }
[Fact] [Fact]
@ -49,7 +58,7 @@ namespace Microsoft.AspNetCore.Antiforgery.FunctionalTests
}); });
// Assert // Assert
Assert.Contains($"The required antiforgery cookie \"{cookie.Key}\" is not present.", exception.Message); Assert.Contains($"The required antiforgery cookie \"{cookie.Name}\" is not present.", exception.Message);
} }
[Fact] [Fact]
@ -63,8 +72,8 @@ namespace Microsoft.AspNetCore.Antiforgery.FunctionalTests
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "http://localhost/api/items"); var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "http://localhost/api/items");
httpRequestMessage.Headers.Add("Cookie", $"{cookie.Name}={cookie.Value}");
httpRequestMessage.Headers.Add("X-XSRF-TOKEN", token.Value); httpRequestMessage.Headers.Add("X-XSRF-TOKEN", token.Value);
httpRequestMessage.Headers.Add("Cookie", $"{cookie.Key}={cookie.Value}");
// Act // Act
var response = await Client.SendAsync(httpRequestMessage); var response = await Client.SendAsync(httpRequestMessage);
@ -73,24 +82,20 @@ namespace Microsoft.AspNetCore.Antiforgery.FunctionalTests
Assert.Equal(HttpStatusCode.NoContent, response.StatusCode); Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
} }
private static KeyValuePair<string, string> RetrieveAntiforgeryToken(HttpResponseMessage response) private static SetCookieHeaderValue RetrieveAntiforgeryToken(HttpResponseMessage response)
{ {
return GetCookie(response, 1); return response.Headers.GetValues(HeaderNames.SetCookie)
.Select(setCookieValue => SetCookieHeaderValue.Parse(setCookieValue))
.Where(setCookieHeaderValue => setCookieHeaderValue.Name == "XSRF-TOKEN")
.FirstOrDefault();
} }
private static KeyValuePair<string, string> RetrieveAntiforgeryCookie(HttpResponseMessage response) private static SetCookieHeaderValue RetrieveAntiforgeryCookie(HttpResponseMessage response)
{ {
return GetCookie(response, 0); return response.Headers.GetValues(HeaderNames.SetCookie)
} .Select(setCookieValue => SetCookieHeaderValue.Parse(setCookieValue))
.Where(setCookieHeaderValue => setCookieHeaderValue.Name.StartsWith(".AspNetCore.Antiforgery."))
private static KeyValuePair<string, string> GetCookie(HttpResponseMessage response, int index) .FirstOrDefault();
{
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<string, string>(cookieKey, cookieData);
} }
} }
} }

View File

@ -274,10 +274,12 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
} }
[Theory] [Theory]
[InlineData("/")] [InlineData(null, "/")]
[InlineData("/vdir1")] [InlineData("", "/")]
[InlineData("/vdir1/vdir2")] [InlineData("/", "/")]
public void SaveCookieToken_SetsCookieWithApproriatePathBase(string requestPathBase) [InlineData("/vdir1", "/vdir1")]
[InlineData("/vdir1/vdir2", "/vdir1/vdir2")]
public void SaveCookieToken_SetsCookieWithApproriatePathBase(string requestPathBase, string expectedCookiePath)
{ {
// Arrange // Arrange
var token = "serialized-value"; var token = "serialized-value";
@ -305,7 +307,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
Assert.Equal(_cookieName, cookies.Key); Assert.Equal(_cookieName, cookies.Key);
Assert.Equal("serialized-value", cookies.Value); Assert.Equal("serialized-value", cookies.Value);
Assert.True(cookies.Options.HttpOnly); Assert.True(cookies.Options.HttpOnly);
Assert.Equal(requestPathBase, cookies.Options.Path); Assert.Equal(expectedCookiePath, cookies.Options.Path);
} }
[Fact] [Fact]