a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
404 lines
21 KiB
C#
404 lines
21 KiB
C#
// 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<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
|
|
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<InvalidOperationException>(() => 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<InvalidOperationException>(() => 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<InvalidOperationException>(() => 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<InvalidOperationException>(() => { 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<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
|
|
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<MockableAntiForgeryTokenSerializer> mockSerializer = new Mock<MockableAntiForgeryTokenSerializer>(MockBehavior.Strict);
|
|
mockSerializer.Setup(o => o.Serialize(formToken)).Returns("serialized-form-token");
|
|
|
|
Mock<MockableTokenStore> mockTokenStore = new Mock<MockableTokenStore>(MockBehavior.Strict);
|
|
mockTokenStore.Setup(o => o.GetCookieToken(mockHttpContext.Object)).Returns(oldCookieToken);
|
|
mockTokenStore.Setup(o => o.SaveCookieToken(mockHttpContext.Object, newCookieToken)).Verifiable();
|
|
|
|
Mock<MockableTokenValidator> mockValidator = new Mock<MockableTokenValidator>(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(@"<input name=""form-field-name"" type=""hidden"" value=""serialized-form-token"" />", retVal.ToString(TagRenderMode.SelfClosing));
|
|
mockTokenStore.Verify();
|
|
}
|
|
|
|
[Fact]
|
|
public void GetFormInputElement_ExistingInvalidCookieToken_SwallowsExceptions()
|
|
{
|
|
// Arrange
|
|
GenericIdentity identity = new GenericIdentity("some-user");
|
|
Mock<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
|
|
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<MockableAntiForgeryTokenSerializer> mockSerializer = new Mock<MockableAntiForgeryTokenSerializer>(MockBehavior.Strict);
|
|
mockSerializer.Setup(o => o.Serialize(formToken)).Returns("serialized-form-token");
|
|
|
|
Mock<MockableTokenStore> mockTokenStore = new Mock<MockableTokenStore>(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<MockableTokenValidator> mockValidator = new Mock<MockableTokenValidator>(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(@"<input name=""form-field-name"" type=""hidden"" value=""serialized-form-token"" />", retVal.ToString(TagRenderMode.SelfClosing));
|
|
mockTokenStore.Verify();
|
|
}
|
|
|
|
[Fact]
|
|
public void GetFormInputElement_ExistingValidCookieToken()
|
|
{
|
|
// Arrange
|
|
GenericIdentity identity = new GenericIdentity("some-user");
|
|
Mock<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
|
|
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<MockableAntiForgeryTokenSerializer> mockSerializer = new Mock<MockableAntiForgeryTokenSerializer>(MockBehavior.Strict);
|
|
mockSerializer.Setup(o => o.Serialize(formToken)).Returns("serialized-form-token");
|
|
|
|
Mock<MockableTokenStore> mockTokenStore = new Mock<MockableTokenStore>(MockBehavior.Strict);
|
|
mockTokenStore.Setup(o => o.GetCookieToken(mockHttpContext.Object)).Returns(cookieToken);
|
|
|
|
Mock<MockableTokenValidator> mockValidator = new Mock<MockableTokenValidator>(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(@"<input name=""form-field-name"" type=""hidden"" value=""serialized-form-token"" />", retVal.ToString(TagRenderMode.SelfClosing));
|
|
}
|
|
|
|
[Fact]
|
|
public void GetTokens_ExistingInvalidCookieToken()
|
|
{
|
|
// Arrange
|
|
GenericIdentity identity = new GenericIdentity("some-user");
|
|
Mock<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
|
|
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<MockableAntiForgeryTokenSerializer> mockSerializer = new Mock<MockableAntiForgeryTokenSerializer>(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<MockableTokenValidator> mockValidator = new Mock<MockableTokenValidator>(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<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
|
|
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<MockableAntiForgeryTokenSerializer> mockSerializer = new Mock<MockableAntiForgeryTokenSerializer>(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<MockableTokenValidator> mockValidator = new Mock<MockableTokenValidator>(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<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
|
|
mockHttpContext.Setup(o => o.User).Returns(new GenericPrincipal(identity, new string[0]));
|
|
|
|
AntiForgeryToken cookieToken = new AntiForgeryToken() { IsSessionToken = true };
|
|
AntiForgeryToken formToken = new AntiForgeryToken();
|
|
|
|
Mock<MockableAntiForgeryTokenSerializer> mockSerializer = new Mock<MockableAntiForgeryTokenSerializer>(MockBehavior.Strict);
|
|
mockSerializer.Setup(o => o.Deserialize("serialized-old-cookie-token")).Returns(cookieToken);
|
|
mockSerializer.Setup(o => o.Serialize(formToken)).Returns("serialized-form-token");
|
|
|
|
Mock<MockableTokenValidator> mockValidator = new Mock<MockableTokenValidator>(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<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
|
|
mockHttpContext.Setup(o => o.User).Returns(new GenericPrincipal(identity, new string[0]));
|
|
|
|
AntiForgeryToken cookieToken = new AntiForgeryToken();
|
|
AntiForgeryToken formToken = new AntiForgeryToken();
|
|
|
|
Mock<MockableAntiForgeryTokenSerializer> mockSerializer = new Mock<MockableAntiForgeryTokenSerializer>();
|
|
mockSerializer.Setup(o => o.Deserialize("cookie-token")).Returns(cookieToken);
|
|
mockSerializer.Setup(o => o.Deserialize("form-token")).Returns(formToken);
|
|
|
|
Mock<MockableTokenValidator> mockValidator = new Mock<MockableTokenValidator>();
|
|
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<HttpAntiForgeryException>(() => 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<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
|
|
mockHttpContext.Setup(o => o.User).Returns(new GenericPrincipal(identity, new string[0]));
|
|
|
|
AntiForgeryToken cookieToken = new AntiForgeryToken();
|
|
AntiForgeryToken formToken = new AntiForgeryToken();
|
|
|
|
Mock<MockableAntiForgeryTokenSerializer> mockSerializer = new Mock<MockableAntiForgeryTokenSerializer>();
|
|
mockSerializer.Setup(o => o.Deserialize("cookie-token")).Returns(cookieToken);
|
|
mockSerializer.Setup(o => o.Deserialize("form-token")).Returns(formToken);
|
|
|
|
Mock<MockableTokenValidator> mockValidator = new Mock<MockableTokenValidator>();
|
|
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<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
|
|
mockHttpContext.Setup(o => o.User).Returns(new GenericPrincipal(identity, new string[0]));
|
|
|
|
AntiForgeryToken cookieToken = new AntiForgeryToken();
|
|
AntiForgeryToken formToken = new AntiForgeryToken();
|
|
|
|
Mock<MockableTokenStore> mockTokenStore = new Mock<MockableTokenStore>();
|
|
mockTokenStore.Setup(o => o.GetCookieToken(mockHttpContext.Object)).Returns(cookieToken);
|
|
mockTokenStore.Setup(o => o.GetFormToken(mockHttpContext.Object)).Returns(formToken);
|
|
|
|
Mock<MockableTokenValidator> mockValidator = new Mock<MockableTokenValidator>();
|
|
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<HttpAntiForgeryException>(() => worker.Validate(mockHttpContext.Object));
|
|
Assert.Equal("my-message", ex.Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void Validate_FromStore_Success()
|
|
{
|
|
// Arrange
|
|
GenericIdentity identity = new GenericIdentity("some-user");
|
|
Mock<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
|
|
mockHttpContext.Setup(o => o.User).Returns(new GenericPrincipal(identity, new string[0]));
|
|
|
|
AntiForgeryToken cookieToken = new AntiForgeryToken();
|
|
AntiForgeryToken formToken = new AntiForgeryToken();
|
|
|
|
Mock<MockableTokenStore> mockTokenStore = new Mock<MockableTokenStore>();
|
|
mockTokenStore.Setup(o => o.GetCookieToken(mockHttpContext.Object)).Returns(cookieToken);
|
|
mockTokenStore.Setup(o => o.GetFormToken(mockHttpContext.Object)).Returns(formToken);
|
|
|
|
Mock<MockableTokenValidator> mockValidator = new Mock<MockableTokenValidator>();
|
|
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();
|
|
}
|
|
}
|
|
}
|