// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. using System.Web.Mvc; using Moq; using Xunit; using Xunit.Extensions; using Assert = Microsoft.TestCommon.AssertEx; namespace System.Web.Helpers.AntiXsrf.Test { public class AntiForgeryTokenStoreTest { [Fact] public void GetCookieToken_CookieDoesNotExist_ReturnsNull() { // Arrange Mock mockHttpContext = new Mock(); mockHttpContext.Setup(o => o.Request.Cookies).Returns(new HttpCookieCollection()); MockAntiForgeryConfig config = new MockAntiForgeryConfig() { CookieName = "cookie-name" }; AntiForgeryTokenStore tokenStore = new AntiForgeryTokenStore( config: config, serializer: null); // Act AntiForgeryToken token = tokenStore.GetCookieToken(mockHttpContext.Object); // Assert Assert.Null(token); } [Fact] public void GetCookieToken_CookieIsEmpty_ReturnsNull() { // Arrange Mock mockHttpContext = new Mock(); mockHttpContext.Setup(o => o.Request.Cookies).Returns(new HttpCookieCollection() { new HttpCookie("cookie-name", "") }); MockAntiForgeryConfig config = new MockAntiForgeryConfig() { CookieName = "cookie-name" }; AntiForgeryTokenStore tokenStore = new AntiForgeryTokenStore( config: config, serializer: null); // Act AntiForgeryToken token = tokenStore.GetCookieToken(mockHttpContext.Object); // Assert Assert.Null(token); } [Fact] public void GetCookieToken_CookieIsInvalid_PropagatesException() { // Arrange Mock mockHttpContext = new Mock(); mockHttpContext.Setup(o => o.Request.Cookies).Returns(new HttpCookieCollection() { new HttpCookie("cookie-name", "invalid-value") }); MockAntiForgeryConfig config = new MockAntiForgeryConfig() { CookieName = "cookie-name" }; HttpAntiForgeryException expectedException = new HttpAntiForgeryException("some exception"); Mock mockSerializer = new Mock(); mockSerializer.Setup(o => o.Deserialize("invalid-value")).Throws(expectedException); AntiForgeryTokenStore tokenStore = new AntiForgeryTokenStore( config: config, serializer: mockSerializer.Object); // Act & assert var ex = Assert.Throws(() => tokenStore.GetCookieToken(mockHttpContext.Object)); Assert.Equal(expectedException, ex); } [Fact] public void GetCookieToken_CookieIsValid_ReturnsToken() { // Arrange AntiForgeryToken expectedToken = new AntiForgeryToken(); Mock mockHttpContext = new Mock(); mockHttpContext.Setup(o => o.Request.Cookies).Returns(new HttpCookieCollection() { new HttpCookie("cookie-name", "valid-value") }); MockAntiForgeryConfig config = new MockAntiForgeryConfig() { CookieName = "cookie-name" }; Mock mockSerializer = new Mock(); mockSerializer.Setup(o => o.Deserialize("valid-value")).Returns((object)expectedToken); AntiForgeryTokenStore tokenStore = new AntiForgeryTokenStore( config: config, serializer: mockSerializer.Object); // Act AntiForgeryToken retVal = tokenStore.GetCookieToken(mockHttpContext.Object); // Assert Assert.Same(expectedToken, retVal); } [Fact] public void GetFormToken_FormFieldIsEmpty_ReturnsNull() { // Arrange Mock mockHttpContext = new Mock(); mockHttpContext.Setup(o => o.Request.Form.Get("form-field-name")).Returns(""); MockAntiForgeryConfig config = new MockAntiForgeryConfig() { FormFieldName = "form-field-name" }; AntiForgeryTokenStore tokenStore = new AntiForgeryTokenStore( config: config, serializer: null); // Act AntiForgeryToken token = tokenStore.GetFormToken(mockHttpContext.Object); // Assert Assert.Null(token); } [Fact] public void GetFormToken_FormFieldIsInvalid_PropagatesException() { // Arrange Mock mockHttpContext = new Mock(); mockHttpContext.Setup(o => o.Request.Form.Get("form-field-name")).Returns("invalid-value"); MockAntiForgeryConfig config = new MockAntiForgeryConfig() { FormFieldName = "form-field-name" }; HttpAntiForgeryException expectedException = new HttpAntiForgeryException("some exception"); Mock mockSerializer = new Mock(); mockSerializer.Setup(o => o.Deserialize("invalid-value")).Throws(expectedException); AntiForgeryTokenStore tokenStore = new AntiForgeryTokenStore( config: config, serializer: mockSerializer.Object); // Act & assert var ex = Assert.Throws(() => tokenStore.GetFormToken(mockHttpContext.Object)); Assert.Same(expectedException, ex); } [Fact] public void GetFormToken_FormFieldIsValid_ReturnsToken() { // Arrange AntiForgeryToken expectedToken = new AntiForgeryToken(); Mock mockHttpContext = new Mock(); mockHttpContext.Setup(o => o.Request.Form.Get("form-field-name")).Returns("valid-value"); MockAntiForgeryConfig config = new MockAntiForgeryConfig() { FormFieldName = "form-field-name" }; Mock mockSerializer = new Mock(); mockSerializer.Setup(o => o.Deserialize("valid-value")).Returns((object)expectedToken); AntiForgeryTokenStore tokenStore = new AntiForgeryTokenStore( config: config, serializer: mockSerializer.Object); // Act AntiForgeryToken retVal = tokenStore.GetFormToken(mockHttpContext.Object); // Assert Assert.Same(expectedToken, retVal); } [Theory] [InlineData(true, true)] [InlineData(false, null)] public void SaveCookieToken(bool requireSsl, bool? expectedCookieSecureFlag) { // Arrange AntiForgeryToken token = new AntiForgeryToken(); HttpCookieCollection cookies = new HttpCookieCollection(); bool defaultCookieSecureValue = expectedCookieSecureFlag ?? new HttpCookie("name", "value").Secure; // pulled from config; set by ctor Mock mockHttpContext = new Mock(); mockHttpContext.Setup(o => o.Response.Cookies).Returns(cookies); Mock mockSerializer = new Mock(); mockSerializer.Setup(o => o.Serialize(token)).Returns("serialized-value"); MockAntiForgeryConfig config = new MockAntiForgeryConfig() { CookieName = "cookie-name", RequireSSL = requireSsl }; AntiForgeryTokenStore tokenStore = new AntiForgeryTokenStore( config: config, serializer: mockSerializer.Object); // Act tokenStore.SaveCookieToken(mockHttpContext.Object, token); // Assert Assert.Equal(1, cookies.Count); HttpCookie cookie = cookies["cookie-name"]; Assert.NotNull(cookie); Assert.Equal("serialized-value", cookie.Value); Assert.True(cookie.HttpOnly); Assert.Equal(defaultCookieSecureValue, cookie.Secure); } } }