// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. using System.Security.Principal; using System.Web.Helpers.Test; using System.Web.Mvc; using Moq; using Xunit; using Assert = Microsoft.TestCommon.AssertEx; namespace System.Web.Helpers.AntiXsrf.Test { public class AntiForgeryWorkerTest { [Fact] public void ChecksSSL() { // Arrange Mock mockHttpContext = new Mock(); mockHttpContext.Setup(o => o.Request.IsSecureConnection).Returns(false); IAntiForgeryConfig config = new MockAntiForgeryConfig() { RequireSSL = true }; AntiForgeryWorker worker = new AntiForgeryWorker( config: config, serializer: null, tokenStore: null, validator: null); // Act & assert var ex = Assert.Throws(() => worker.Validate(mockHttpContext.Object, "session-token", "field-token")); Assert.Equal(@"The anti-forgery system has the configuration value AntiForgeryConfig.RequireSsl = true, but the current request is not an SSL request.", ex.Message); ex = Assert.Throws(() => worker.Validate(mockHttpContext.Object)); Assert.Equal(@"The anti-forgery system has the configuration value AntiForgeryConfig.RequireSsl = true, but the current request is not an SSL request.", ex.Message); ex = Assert.Throws(() => worker.GetFormInputElement(mockHttpContext.Object)); Assert.Equal(@"The anti-forgery system has the configuration value AntiForgeryConfig.RequireSsl = true, but the current request is not an SSL request.", ex.Message); ex = Assert.Throws(() => { string dummy1, dummy2; worker.GetTokens(mockHttpContext.Object, "cookie-token", out dummy1, out dummy2); }); Assert.Equal(@"The anti-forgery system has the configuration value AntiForgeryConfig.RequireSsl = true, but the current request is not an SSL request.", ex.Message); } [Fact] public void GetFormInputElement_ExistingInvalidCookieToken() { // Arrange GenericIdentity identity = new GenericIdentity("some-user"); Mock mockHttpContext = new Mock(); mockHttpContext.Setup(o => o.User).Returns(new GenericPrincipal(identity, new string[0])); AntiForgeryToken oldCookieToken = new AntiForgeryToken() { IsSessionToken = true }; AntiForgeryToken newCookieToken = new AntiForgeryToken() { IsSessionToken = true }; AntiForgeryToken formToken = new AntiForgeryToken(); MockAntiForgeryConfig config = new MockAntiForgeryConfig() { FormFieldName = "form-field-name" }; Mock mockSerializer = new Mock(MockBehavior.Strict); mockSerializer.Setup(o => o.Serialize(formToken)).Returns("serialized-form-token"); Mock mockTokenStore = new Mock(MockBehavior.Strict); mockTokenStore.Setup(o => o.GetCookieToken(mockHttpContext.Object)).Returns(oldCookieToken); mockTokenStore.Setup(o => o.SaveCookieToken(mockHttpContext.Object, newCookieToken)).Verifiable(); Mock mockValidator = new Mock(MockBehavior.Strict); mockValidator.Setup(o => o.GenerateFormToken(mockHttpContext.Object, identity, newCookieToken)).Returns(formToken); mockValidator.Setup(o => o.IsCookieTokenValid(oldCookieToken)).Returns(false); mockValidator.Setup(o => o.IsCookieTokenValid(newCookieToken)).Returns(true); mockValidator.Setup(o => o.GenerateCookieToken()).Returns(newCookieToken); AntiForgeryWorker worker = new AntiForgeryWorker( config: config, serializer: mockSerializer.Object, tokenStore: mockTokenStore.Object, validator: mockValidator.Object); // Act TagBuilder retVal = worker.GetFormInputElement(mockHttpContext.Object); // Assert Assert.Equal(@"", retVal.ToString(TagRenderMode.SelfClosing)); mockTokenStore.Verify(); } [Fact] public void GetFormInputElement_ExistingInvalidCookieToken_SwallowsExceptions() { // Arrange GenericIdentity identity = new GenericIdentity("some-user"); Mock mockHttpContext = new Mock(); mockHttpContext.Setup(o => o.User).Returns(new GenericPrincipal(identity, new string[0])); AntiForgeryToken oldCookieToken = new AntiForgeryToken() { IsSessionToken = true }; AntiForgeryToken newCookieToken = new AntiForgeryToken() { IsSessionToken = true }; AntiForgeryToken formToken = new AntiForgeryToken(); MockAntiForgeryConfig config = new MockAntiForgeryConfig() { FormFieldName = "form-field-name" }; Mock mockSerializer = new Mock(MockBehavior.Strict); mockSerializer.Setup(o => o.Serialize(formToken)).Returns("serialized-form-token"); Mock mockTokenStore = new Mock(MockBehavior.Strict); mockTokenStore.Setup(o => o.GetCookieToken(mockHttpContext.Object)).Throws(new Exception("should be swallowed")); mockTokenStore.Setup(o => o.SaveCookieToken(mockHttpContext.Object, newCookieToken)).Verifiable(); Mock mockValidator = new Mock(MockBehavior.Strict); mockValidator.Setup(o => o.GenerateFormToken(mockHttpContext.Object, identity, newCookieToken)).Returns(formToken); mockValidator.Setup(o => o.IsCookieTokenValid(null)).Returns(false); mockValidator.Setup(o => o.IsCookieTokenValid(newCookieToken)).Returns(true); mockValidator.Setup(o => o.GenerateCookieToken()).Returns(newCookieToken); AntiForgeryWorker worker = new AntiForgeryWorker( config: config, serializer: mockSerializer.Object, tokenStore: mockTokenStore.Object, validator: mockValidator.Object); // Act TagBuilder retVal = worker.GetFormInputElement(mockHttpContext.Object); // Assert Assert.Equal(@"", retVal.ToString(TagRenderMode.SelfClosing)); mockTokenStore.Verify(); } [Fact] public void GetFormInputElement_ExistingValidCookieToken() { // Arrange GenericIdentity identity = new GenericIdentity("some-user"); Mock mockHttpContext = new Mock(); mockHttpContext.Setup(o => o.User).Returns(new GenericPrincipal(identity, new string[0])); AntiForgeryToken cookieToken = new AntiForgeryToken() { IsSessionToken = true }; AntiForgeryToken formToken = new AntiForgeryToken(); MockAntiForgeryConfig config = new MockAntiForgeryConfig() { FormFieldName = "form-field-name" }; Mock mockSerializer = new Mock(MockBehavior.Strict); mockSerializer.Setup(o => o.Serialize(formToken)).Returns("serialized-form-token"); Mock mockTokenStore = new Mock(MockBehavior.Strict); mockTokenStore.Setup(o => o.GetCookieToken(mockHttpContext.Object)).Returns(cookieToken); Mock mockValidator = new Mock(MockBehavior.Strict); mockValidator.Setup(o => o.GenerateFormToken(mockHttpContext.Object, identity, cookieToken)).Returns(formToken); mockValidator.Setup(o => o.IsCookieTokenValid(cookieToken)).Returns(true); AntiForgeryWorker worker = new AntiForgeryWorker( config: config, serializer: mockSerializer.Object, tokenStore: mockTokenStore.Object, validator: mockValidator.Object); // Act TagBuilder retVal = worker.GetFormInputElement(mockHttpContext.Object); // Assert Assert.Equal(@"", retVal.ToString(TagRenderMode.SelfClosing)); } [Fact] public void GetTokens_ExistingInvalidCookieToken() { // Arrange GenericIdentity identity = new GenericIdentity("some-user"); Mock mockHttpContext = new Mock(); mockHttpContext.Setup(o => o.User).Returns(new GenericPrincipal(identity, new string[0])); AntiForgeryToken oldCookieToken = new AntiForgeryToken() { IsSessionToken = true }; AntiForgeryToken newCookieToken = new AntiForgeryToken() { IsSessionToken = true }; AntiForgeryToken formToken = new AntiForgeryToken(); Mock mockSerializer = new Mock(MockBehavior.Strict); mockSerializer.Setup(o => o.Deserialize("serialized-old-cookie-token")).Returns(oldCookieToken); mockSerializer.Setup(o => o.Serialize(newCookieToken)).Returns("serialized-new-cookie-token"); mockSerializer.Setup(o => o.Serialize(formToken)).Returns("serialized-form-token"); Mock mockValidator = new Mock(MockBehavior.Strict); mockValidator.Setup(o => o.GenerateFormToken(mockHttpContext.Object, identity, newCookieToken)).Returns(formToken); mockValidator.Setup(o => o.IsCookieTokenValid(oldCookieToken)).Returns(false); mockValidator.Setup(o => o.IsCookieTokenValid(newCookieToken)).Returns(true); mockValidator.Setup(o => o.GenerateCookieToken()).Returns(newCookieToken); AntiForgeryWorker worker = new AntiForgeryWorker( config: new MockAntiForgeryConfig(), serializer: mockSerializer.Object, tokenStore: null, validator: mockValidator.Object); // Act string serializedNewCookieToken, serializedFormToken; worker.GetTokens(mockHttpContext.Object, "serialized-old-cookie-token", out serializedNewCookieToken, out serializedFormToken); // Assert Assert.Equal("serialized-new-cookie-token", serializedNewCookieToken); Assert.Equal("serialized-form-token", serializedFormToken); } [Fact] public void GetTokens_ExistingInvalidCookieToken_SwallowsExceptions() { // Arrange GenericIdentity identity = new GenericIdentity("some-user"); Mock mockHttpContext = new Mock(); mockHttpContext.Setup(o => o.User).Returns(new GenericPrincipal(identity, new string[0])); AntiForgeryToken oldCookieToken = new AntiForgeryToken() { IsSessionToken = true }; AntiForgeryToken newCookieToken = new AntiForgeryToken() { IsSessionToken = true }; AntiForgeryToken formToken = new AntiForgeryToken(); Mock mockSerializer = new Mock(MockBehavior.Strict); mockSerializer.Setup(o => o.Deserialize("serialized-old-cookie-token")).Throws(new Exception("should be swallowed")); mockSerializer.Setup(o => o.Serialize(newCookieToken)).Returns("serialized-new-cookie-token"); mockSerializer.Setup(o => o.Serialize(formToken)).Returns("serialized-form-token"); Mock mockValidator = new Mock(MockBehavior.Strict); mockValidator.Setup(o => o.GenerateFormToken(mockHttpContext.Object, identity, newCookieToken)).Returns(formToken); mockValidator.Setup(o => o.IsCookieTokenValid(null)).Returns(false); mockValidator.Setup(o => o.IsCookieTokenValid(newCookieToken)).Returns(true); mockValidator.Setup(o => o.GenerateCookieToken()).Returns(newCookieToken); AntiForgeryWorker worker = new AntiForgeryWorker( config: new MockAntiForgeryConfig(), serializer: mockSerializer.Object, tokenStore: null, validator: mockValidator.Object); // Act string serializedNewCookieToken, serializedFormToken; worker.GetTokens(mockHttpContext.Object, "serialized-old-cookie-token", out serializedNewCookieToken, out serializedFormToken); // Assert Assert.Equal("serialized-new-cookie-token", serializedNewCookieToken); Assert.Equal("serialized-form-token", serializedFormToken); } [Fact] public void GetTokens_ExistingValidCookieToken() { // Arrange GenericIdentity identity = new GenericIdentity("some-user"); Mock mockHttpContext = new Mock(); mockHttpContext.Setup(o => o.User).Returns(new GenericPrincipal(identity, new string[0])); AntiForgeryToken cookieToken = new AntiForgeryToken() { IsSessionToken = true }; AntiForgeryToken formToken = new AntiForgeryToken(); Mock mockSerializer = new Mock(MockBehavior.Strict); mockSerializer.Setup(o => o.Deserialize("serialized-old-cookie-token")).Returns(cookieToken); mockSerializer.Setup(o => o.Serialize(formToken)).Returns("serialized-form-token"); Mock mockValidator = new Mock(MockBehavior.Strict); mockValidator.Setup(o => o.GenerateFormToken(mockHttpContext.Object, identity, cookieToken)).Returns(formToken); mockValidator.Setup(o => o.IsCookieTokenValid(cookieToken)).Returns(true); AntiForgeryWorker worker = new AntiForgeryWorker( config: new MockAntiForgeryConfig(), serializer: mockSerializer.Object, tokenStore: null, validator: mockValidator.Object); // Act string serializedNewCookieToken, serializedFormToken; worker.GetTokens(mockHttpContext.Object, "serialized-old-cookie-token", out serializedNewCookieToken, out serializedFormToken); // Assert Assert.Null(serializedNewCookieToken); Assert.Equal("serialized-form-token", serializedFormToken); } [Fact] public void Validate_FromStrings_Failure() { // Arrange GenericIdentity identity = new GenericIdentity("some-user"); Mock mockHttpContext = new Mock(); mockHttpContext.Setup(o => o.User).Returns(new GenericPrincipal(identity, new string[0])); AntiForgeryToken cookieToken = new AntiForgeryToken(); AntiForgeryToken formToken = new AntiForgeryToken(); Mock mockSerializer = new Mock(); mockSerializer.Setup(o => o.Deserialize("cookie-token")).Returns(cookieToken); mockSerializer.Setup(o => o.Deserialize("form-token")).Returns(formToken); Mock mockValidator = new Mock(); mockValidator.Setup(o => o.ValidateTokens(mockHttpContext.Object, identity, cookieToken, formToken)).Throws(new HttpAntiForgeryException("my-message")); AntiForgeryWorker worker = new AntiForgeryWorker( config: new MockAntiForgeryConfig(), serializer: mockSerializer.Object, tokenStore: null, validator: mockValidator.Object); // Act & assert var ex = Assert.Throws(() => worker.Validate(mockHttpContext.Object, "cookie-token", "form-token")); Assert.Equal("my-message", ex.Message); } [Fact] public void Validate_FromStrings_Success() { // Arrange GenericIdentity identity = new GenericIdentity("some-user"); Mock mockHttpContext = new Mock(); mockHttpContext.Setup(o => o.User).Returns(new GenericPrincipal(identity, new string[0])); AntiForgeryToken cookieToken = new AntiForgeryToken(); AntiForgeryToken formToken = new AntiForgeryToken(); Mock mockSerializer = new Mock(); mockSerializer.Setup(o => o.Deserialize("cookie-token")).Returns(cookieToken); mockSerializer.Setup(o => o.Deserialize("form-token")).Returns(formToken); Mock mockValidator = new Mock(); mockValidator.Setup(o => o.ValidateTokens(mockHttpContext.Object, identity, cookieToken, formToken)).Verifiable(); AntiForgeryWorker worker = new AntiForgeryWorker( config: new MockAntiForgeryConfig(), serializer: mockSerializer.Object, tokenStore: null, validator: mockValidator.Object); // Act worker.Validate(mockHttpContext.Object, "cookie-token", "form-token"); // Assert mockValidator.Verify(); } [Fact] public void Validate_FromStore_Failure() { // Arrange GenericIdentity identity = new GenericIdentity("some-user"); Mock mockHttpContext = new Mock(); mockHttpContext.Setup(o => o.User).Returns(new GenericPrincipal(identity, new string[0])); AntiForgeryToken cookieToken = new AntiForgeryToken(); AntiForgeryToken formToken = new AntiForgeryToken(); Mock mockTokenStore = new Mock(); mockTokenStore.Setup(o => o.GetCookieToken(mockHttpContext.Object)).Returns(cookieToken); mockTokenStore.Setup(o => o.GetFormToken(mockHttpContext.Object)).Returns(formToken); Mock mockValidator = new Mock(); mockValidator.Setup(o => o.ValidateTokens(mockHttpContext.Object, identity, cookieToken, formToken)).Throws(new HttpAntiForgeryException("my-message")); AntiForgeryWorker worker = new AntiForgeryWorker( config: new MockAntiForgeryConfig(), serializer: null, tokenStore: mockTokenStore.Object, validator: mockValidator.Object); // Act & assert var ex = Assert.Throws(() => worker.Validate(mockHttpContext.Object)); Assert.Equal("my-message", ex.Message); } [Fact] public void Validate_FromStore_Success() { // Arrange GenericIdentity identity = new GenericIdentity("some-user"); Mock mockHttpContext = new Mock(); mockHttpContext.Setup(o => o.User).Returns(new GenericPrincipal(identity, new string[0])); AntiForgeryToken cookieToken = new AntiForgeryToken(); AntiForgeryToken formToken = new AntiForgeryToken(); Mock mockTokenStore = new Mock(); mockTokenStore.Setup(o => o.GetCookieToken(mockHttpContext.Object)).Returns(cookieToken); mockTokenStore.Setup(o => o.GetFormToken(mockHttpContext.Object)).Returns(formToken); Mock mockValidator = new Mock(); mockValidator.Setup(o => o.ValidateTokens(mockHttpContext.Object, identity, cookieToken, formToken)).Verifiable(); AntiForgeryWorker worker = new AntiForgeryWorker( config: new MockAntiForgeryConfig(), serializer: null, tokenStore: mockTokenStore.Object, validator: mockValidator.Object); // Act worker.Validate(mockHttpContext.Object); // Assert mockValidator.Verify(); } } }