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();
options.HttpOnly = true;
options.Path = _options.CookiePath ?? httpContext.Request.PathBase;
options.Path = _options.CookiePath ?? GetPathBase(httpContext);
options.Domain = _options.CookieDomain;
// Note: don't use "newCookie.Secure = _options.RequireSSL;" since the default
// 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);
}
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.Http;
using System.Threading.Tasks;
using Microsoft.Net.Http.Headers;
using Xunit;
namespace Microsoft.AspNetCore.Antiforgery.FunctionalTests
@ -26,11 +27,19 @@ namespace Microsoft.AspNetCore.Antiforgery.FunctionalTests
var response = await Client.GetAsync("http://localhost/Index.html");
// Assert
var cookie = RetrieveAntiforgeryCookie(response);
Assert.NotNull(cookie.Value);
var setCookieHeaderValue = RetrieveAntiforgeryCookie(response);
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);
Assert.NotNull(token.Value);
setCookieHeaderValue = RetrieveAntiforgeryToken(response);
Assert.NotNull(setCookieHeaderValue);
Assert.False(string.IsNullOrEmpty(setCookieHeaderValue.Value));
Assert.Null(setCookieHeaderValue.Domain);
Assert.Equal("/", setCookieHeaderValue.Path);
Assert.False(setCookieHeaderValue.Secure);
}
[Fact]
@ -49,7 +58,7 @@ namespace Microsoft.AspNetCore.Antiforgery.FunctionalTests
});
// 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]
@ -63,8 +72,8 @@ namespace Microsoft.AspNetCore.Antiforgery.FunctionalTests
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("Cookie", $"{cookie.Key}={cookie.Value}");
// Act
var response = await Client.SendAsync(httpRequestMessage);
@ -73,24 +82,20 @@ namespace Microsoft.AspNetCore.Antiforgery.FunctionalTests
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);
}
private static KeyValuePair<string, string> 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<string, string>(cookieKey, cookieData);
return response.Headers.GetValues(HeaderNames.SetCookie)
.Select(setCookieValue => SetCookieHeaderValue.Parse(setCookieValue))
.Where(setCookieHeaderValue => setCookieHeaderValue.Name.StartsWith(".AspNetCore.Antiforgery."))
.FirstOrDefault();
}
}
}

View File

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