From b47abeda04883f00866f983c4339c75e19e96165 Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Mon, 31 Oct 2016 16:43:09 -0700 Subject: [PATCH] [Fixes #104] Expose cookie options via Antiforgery options --- .../AntiforgeryOptions.cs | 11 +++ .../Internal/DefaultAntiforgeryTokenStore.cs | 3 +- .../DefaultAntiforgeryTokenStoreTest.cs | 70 +++++++++++++++++++ 3 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.AspNetCore.Antiforgery/AntiforgeryOptions.cs b/src/Microsoft.AspNetCore.Antiforgery/AntiforgeryOptions.cs index 2c05e1d..d436f88 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,16 @@ public string CookieName } } + /// + /// The path set on the cookie. Defaults to current request's value. + /// + public PathString? CookiePath { get; set; } + + /// + /// The domain set on the cookie. Defaults to null. + /// + 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 4b30e8c..9e3658f 100644 --- a/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgeryTokenStore.cs +++ b/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgeryTokenStore.cs @@ -71,7 +71,8 @@ public void SaveCookieToken(HttpContext httpContext, string token) 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 c48c0c9..fb6927f 100644 --- a/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/DefaultAntiforgeryTokenStoreTest.cs +++ b/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/DefaultAntiforgeryTokenStoreTest.cs @@ -308,6 +308,76 @@ public void SaveCookieToken_SetsCookieWithApproriatePathBase(string requestPathB 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