diff --git a/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgeryTokenStore.cs b/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgeryTokenStore.cs index 17c2e1465a..896961bb41 100644 --- a/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgeryTokenStore.cs +++ b/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgeryTokenStore.cs @@ -69,8 +69,9 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal Debug.Assert(httpContext != null); Debug.Assert(token != null); - var options = new CookieOptions() { HttpOnly = true }; - + var options = new CookieOptions(); + options.HttpOnly = true; + options.Path = httpContext.Request.PathBase; // Note: don't use "newCookie.Secure = _options.RequireSSL;" since the default // value of newCookie.Secure is poulated out of band. if (_options.RequireSsl) diff --git a/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/DefaultAntiforgeryTokenStoreTest.cs b/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/DefaultAntiforgeryTokenStoreTest.cs index adf466aa05..c48c0c9ead 100644 --- a/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/DefaultAntiforgeryTokenStoreTest.cs +++ b/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/DefaultAntiforgeryTokenStoreTest.cs @@ -245,10 +245,13 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal bool defaultCookieSecureValue = expectedCookieSecureFlag ?? false; // pulled from config; set by ctor var cookies = new MockResponseCookieCollection(); - var mockHttpContext = new Mock(); - mockHttpContext + var httpContext = new Mock(); + httpContext .Setup(o => o.Response.Cookies) .Returns(cookies); + httpContext + .SetupGet(hc => hc.Request.PathBase) + .Returns("/"); var options = new AntiforgeryOptions() { @@ -259,7 +262,7 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal var tokenStore = new DefaultAntiforgeryTokenStore(new TestOptionsManager(options)); // Act - tokenStore.SaveCookieToken(mockHttpContext.Object, token); + tokenStore.SaveCookieToken(httpContext.Object, token); // Assert Assert.Equal(1, cookies.Count); @@ -270,6 +273,41 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal Assert.Equal(defaultCookieSecureValue, cookies.Options.Secure); } + [Theory] + [InlineData("/")] + [InlineData("/vdir1")] + [InlineData("/vdir1/vdir2")] + public void SaveCookieToken_SetsCookieWithApproriatePathBase(string requestPathBase) + { + // Arrange + var token = "serialized-value"; + var cookies = new MockResponseCookieCollection(); + var httpContext = new Mock(); + httpContext + .Setup(hc => hc.Response.Cookies) + .Returns(cookies); + httpContext + .SetupGet(hc => hc.Request.PathBase) + .Returns(requestPathBase); + httpContext + .SetupGet(hc => hc.Request.Path) + .Returns("/index.html"); + var options = new AntiforgeryOptions(); + options.CookieName = _cookieName; + var tokenStore = new DefaultAntiforgeryTokenStore(new TestOptionsManager(options)); + + // Act + tokenStore.SaveCookieToken(httpContext.Object, token); + + // Assert + Assert.Equal(1, cookies.Count); + Assert.NotNull(cookies); + Assert.Equal(_cookieName, cookies.Key); + Assert.Equal("serialized-value", cookies.Value); + Assert.True(cookies.Options.HttpOnly); + Assert.Equal(requestPathBase, cookies.Options.Path); + } + private HttpContext GetHttpContext(string cookieName, string cookieValue) { var cookies = new RequestCookieCollection(new Dictionary