diff --git a/src/Microsoft.AspNetCore.Antiforgery/AntiforgeryOptions.cs b/src/Microsoft.AspNetCore.Antiforgery/AntiforgeryOptions.cs
index 2c05e1dc1c..98f4968c1e 100644
--- a/src/Microsoft.AspNetCore.Antiforgery/AntiforgeryOptions.cs
+++ b/src/Microsoft.AspNetCore.Antiforgery/AntiforgeryOptions.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Antiforgery
{
@@ -45,6 +46,18 @@ namespace Microsoft.AspNetCore.Antiforgery
}
}
+ ///
+ /// The path set on the cookie. If it's null, the "path" attribute on the cookie is set to current
+ /// request's value.
+ ///
+ public PathString? CookiePath { get; set; }
+
+ ///
+ /// The domain set on the cookie. By default its null which results in the "domain" attribute not being
+ /// set.
+ ///
+ public string CookieDomain { get; set; }
+
///
/// Specifies the name of the antiforgery token field that is used by the antiforgery system.
///
diff --git a/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgeryTokenStore.cs b/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgeryTokenStore.cs
index 4b30e8ced9..9e3658fa93 100644
--- a/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgeryTokenStore.cs
+++ b/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgeryTokenStore.cs
@@ -71,7 +71,8 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
var options = new CookieOptions();
options.HttpOnly = true;
- options.Path = httpContext.Request.PathBase;
+ options.Path = _options.CookiePath ?? httpContext.Request.PathBase;
+ options.Domain = _options.CookieDomain;
// Note: don't use "newCookie.Secure = _options.RequireSSL;" since the default
// value of newCookie.Secure is populated 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 c48c0c9ead..fb6927f535 100644
--- a/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/DefaultAntiforgeryTokenStoreTest.cs
+++ b/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/DefaultAntiforgeryTokenStoreTest.cs
@@ -308,6 +308,76 @@ namespace Microsoft.AspNetCore.Antiforgery.Internal
Assert.Equal(requestPathBase, cookies.Options.Path);
}
+ [Fact]
+ public void SaveCookieToken_NonNullAntiforgeryOptionsCookiePath_UsesOptionsCookiePath()
+ {
+ // Arrange
+ var expectedCookiePath = "/";
+ var requestPathBase = "/vdir1";
+ 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;
+ options.CookiePath = expectedCookiePath;
+ 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(expectedCookiePath, cookies.Options.Path);
+ }
+
+ [Fact]
+ public void SaveCookieToken_NonNullAntiforgeryOptionsCookieDomain_UsesOptionsCookieDomain()
+ {
+ // Arrange
+ var expectedCookieDomain = "microsoft.com";
+ 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("/vdir1");
+ httpContext
+ .SetupGet(hc => hc.Request.Path)
+ .Returns("/index.html");
+ var options = new AntiforgeryOptions();
+ options.CookieName = _cookieName;
+ options.CookieDomain = expectedCookieDomain;
+ 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("/vdir1", cookies.Options.Path);
+ Assert.Equal(expectedCookieDomain, cookies.Options.Domain);
+ }
+
private HttpContext GetHttpContext(string cookieName, string cookieValue)
{
var cookies = new RequestCookieCollection(new Dictionary