Tests for AntiForgery System.

This commit is contained in:
harshgMSFT 2014-04-21 19:33:13 -07:00
parent b444f66689
commit bbafa0a29a
20 changed files with 2308 additions and 4 deletions

View File

@ -30,6 +30,9 @@ namespace Microsoft.AspNet.Mvc
}
FormToken = formToken;
// Cookie Token is allowed to be null in the case when the old cookie is valid
// and there is no new cookieToken generated.
CookieToken = cookieToken;
}

View File

@ -177,6 +177,7 @@ namespace Microsoft.AspNet.Mvc
return new AntiForgeryTokenSetInternal()
{
// Note : The new cookie would be null if the old cookie is valid.
CookieToken = newCookieToken,
FormToken = formToken
};

View File

@ -40,7 +40,7 @@ namespace Microsoft.AspNet.Mvc
return Convert.ToBase64String(claimUidBytes);
}
private static IEnumerable<string> GetUniqueIdentifierParameters(ClaimsIdentity claimsIdentity)
internal static IEnumerable<string> GetUniqueIdentifierParameters(ClaimsIdentity claimsIdentity)
{
// TODO: Need to enable support for special casing acs identities.
var nameIdentifierClaim = claimsIdentity.FindFirst(claim =>

View File

@ -52,3 +52,4 @@ using System.Runtime.InteropServices;
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: InternalsVisibleTo("Microsoft.AspNet.Mvc.Core.Test")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

View File

@ -76,7 +76,7 @@ namespace Microsoft.AspNet.Mvc.Core
}
/// <summary>
/// The anti-forgery token could not be decrypted. If this application is hosted by a Web Farm or cluster, ensure that all machines are running the same version of ASP.NET Web Pages and that the &lt;machineKey&gt; configuration specifies explicit encryption and validation keys. AutoGenerate cannot be used in a cluster.
/// The anti-forgery token could not be decrypted.
/// </summary>
internal static string AntiForgeryToken_DeserializationFailed
{
@ -84,7 +84,7 @@ namespace Microsoft.AspNet.Mvc.Core
}
/// <summary>
/// The anti-forgery token could not be decrypted. If this application is hosted by a Web Farm or cluster, ensure that all machines are running the same version of ASP.NET Web Pages and that the &lt;machineKey&gt; configuration specifies explicit encryption and validation keys. AutoGenerate cannot be used in a cluster.
/// The anti-forgery token could not be decrypted.
/// </summary>
internal static string FormatAntiForgeryToken_DeserializationFailed()
{

View File

@ -127,7 +127,7 @@
<value>The required anti-forgery cookie "{0}" is not present.</value>
</data>
<data name="AntiForgeryToken_DeserializationFailed" xml:space="preserve">
<value>The anti-forgery token could not be decrypted. If this application is hosted by a Web Farm or cluster, ensure that all machines are running the same version of ASP.NET Web Pages and that the &lt;machineKey&gt; configuration specifies explicit encryption and validation keys. AutoGenerate cannot be used in a cluster.</value>
<value>The anti-forgery token could not be decrypted.</value>
</data>
<data name="AntiForgeryToken_FormFieldMissing" xml:space="preserve">
<value>The required anti-forgery form field "{0}" is not present.</value>

View File

@ -0,0 +1,198 @@
// Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR
// NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing
// permissions and limitations under the License.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Security.Claims;
using System.Text;
using Microsoft.AspNet.Security.DataProtection;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Core.Test
{
public class AntiForgeryTokenSerializerTest
{
private static readonly Mock<IDataProtector> _dataProtector = GetDataProtector();
private static readonly BinaryBlob _claimUid = new BinaryBlob(256, new byte[] { 0x6F, 0x16, 0x48, 0xE9, 0x72, 0x49, 0xAA, 0x58, 0x75, 0x40, 0x36, 0xA6, 0x7E, 0x24, 0x8C, 0xF0, 0x44, 0xF0, 0x7E, 0xCF, 0xB0, 0xED, 0x38, 0x75, 0x56, 0xCE, 0x02, 0x9A, 0x4F, 0x9A, 0x40, 0xE0 });
private static readonly BinaryBlob _securityToken = new BinaryBlob(128, new byte[] { 0x70, 0x5E, 0xED, 0xCC, 0x7D, 0x42, 0xF1, 0xD6, 0xB3, 0xB9, 0x8A, 0x59, 0x36, 0x25, 0xBB, 0x4C });
private const byte _salt = 0x05;
[Theory]
[InlineData(
"01" // Version
+ "705EEDCC7D42F1D6B3B9" // SecurityToken
// (WRONG!) Stream ends too early
)]
[InlineData(
"01" // Version
+ "705EEDCC7D42F1D6B3B98A593625BB4C" // SecurityToken
+ "01" // IsSessionToken
+ "00" // (WRONG!) Too much data in stream
)]
[InlineData(
"02" // (WRONG! - must be 0x01) Version
+ "705EEDCC7D42F1D6B3B98A593625BB4C" // SecurityToken
+ "01" // IsSessionToken
)]
[InlineData(
"01" // Version
+ "705EEDCC7D42F1D6B3B98A593625BB4C" // SecurityToken
+ "00" // IsSessionToken
+ "00" // IsClaimsBased
+ "05" // Username length header
+ "0000" // (WRONG!) Too little data in stream
)]
public void Deserialize_BadToken_Throws(string serializedToken)
{
// Arrange
var testSerializer = new AntiForgeryTokenSerializer(_dataProtector.Object);
// Act & assert
var ex = Assert.Throws<InvalidOperationException>(() => testSerializer.Deserialize(serializedToken));
Assert.Equal(@"The anti-forgery token could not be decrypted.", ex.Message);
}
[Fact]
public void Serialize_FieldToken_WithClaimUid_TokenRoundTripSuccessful()
{
// Arrange
var testSerializer = new AntiForgeryTokenSerializer(_dataProtector.Object);
//"01" // Version
//+ "705EEDCC7D42F1D6B3B98A593625BB4C" // SecurityToken
//+ "00" // IsSessionToken
//+ "01" // IsClaimsBased
//+ "6F1648E97249AA58754036A67E248CF044F07ECFB0ED387556CE029A4F9A40E0" // ClaimUid
//+ "05" // AdditionalData length header
//+ "E282AC3437"; // AdditionalData ("€47") as UTF8
var token = new AntiForgeryToken()
{
SecurityToken = _securityToken,
IsSessionToken = false,
ClaimUid = _claimUid,
AdditionalData = "€47"
};
// Act
var actualSerializedData = testSerializer.Serialize(token);
var deserializedToken = testSerializer.Deserialize(actualSerializedData);
// Assert
AssertTokensEqual(token, deserializedToken);
_dataProtector.Verify();
}
[Fact]
public void Serialize_FieldToken_WithUsername_TokenRoundTripSuccessful()
{
// Arrange
var testSerializer = new AntiForgeryTokenSerializer(_dataProtector.Object);
//"01" // Version
//+ "705EEDCC7D42F1D6B3B98A593625BB4C" // SecurityToken
//+ "00" // IsSessionToken
//+ "00" // IsClaimsBased
//+ "08" // Username length header
//+ "4AC3A972C3B46D65" // Username ("Jérôme") as UTF8
//+ "05" // AdditionalData length header
//+ "E282AC3437"; // AdditionalData ("€47") as UTF8
var token = new AntiForgeryToken()
{
SecurityToken = _securityToken,
IsSessionToken = false,
Username = "Jérôme",
AdditionalData = "€47"
};
// Act
var actualSerializedData = testSerializer.Serialize(token);
var deserializedToken = testSerializer.Deserialize(actualSerializedData);
// Assert
AssertTokensEqual(token, deserializedToken);
_dataProtector.Verify();
}
[Fact]
public void Serialize_SessionToken_TokenRoundTripSuccessful()
{
// Arrange
var testSerializer = new AntiForgeryTokenSerializer(_dataProtector.Object);
//"01" // Version
//+ "705EEDCC7D42F1D6B3B98A593625BB4C" // SecurityToken
//+ "01"; // IsSessionToken
var token = new AntiForgeryToken()
{
SecurityToken = _securityToken,
IsSessionToken = true
};
// Act
string actualSerializedData = testSerializer.Serialize(token);
var deserializedToken = testSerializer.Deserialize(actualSerializedData);
// Assert
AssertTokensEqual(token, deserializedToken);
_dataProtector.Verify();
}
private static Mock<IDataProtector> GetDataProtector()
{
var mockCryptoSystem = new Mock<IDataProtector>();
mockCryptoSystem.Setup(o => o.Protect(It.IsAny<byte[]>()))
.Returns<byte[]>(Protect)
.Verifiable();
mockCryptoSystem.Setup(o => o.Unprotect(It.IsAny<byte[]>()))
.Returns<byte[]>(UnProtect)
.Verifiable();
return mockCryptoSystem;
}
private static byte[] Protect(byte[] data)
{
var input = new List<byte>(data);
input.Add(_salt);
return input.ToArray();
}
private static byte[] UnProtect(byte[] data)
{
var salt = data[data.Length - 1];
if (salt != _salt)
{
throw new ArgumentException("Invalid salt value in data");
}
return data.Take(data.Length - 1).ToArray();
}
private static void AssertTokensEqual(AntiForgeryToken expected, AntiForgeryToken actual)
{
Assert.NotNull(expected);
Assert.NotNull(actual);
Assert.Equal(expected.AdditionalData, actual.AdditionalData);
Assert.Equal(expected.ClaimUid, actual.ClaimUid);
Assert.Equal(expected.IsSessionToken, actual.IsSessionToken);
Assert.Equal(expected.SecurityToken, actual.SecurityToken);
Assert.Equal(expected.Username, actual.Username);
}
}
}

View File

@ -0,0 +1,366 @@
// Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR
// NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing
// permissions and limitations under the License.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Core.Test
{
public class AntiForgeryTokenStoreTest
{
private readonly string _cookieName = "cookie-name";
[Fact]
public void GetCookieToken_CookieDoesNotExist_ReturnsNull()
{
// Arrange
var requestCookies = new Mock<IReadableStringCollection>();
requestCookies
.Setup(o => o.Get(It.IsAny<string>()))
.Returns(string.Empty);
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext
.Setup(o => o.Request.Cookies)
.Returns(requestCookies.Object);
var config = new MockAntiForgeryConfig()
{
CookieName = _cookieName
};
var tokenStore = new AntiForgeryTokenStore(
config: config,
serializer: null);
// Act
var token = tokenStore.GetCookieToken(mockHttpContext.Object);
// Assert
Assert.Null(token);
}
[Fact]
public void GetCookieToken_CookieIsEmpty_ReturnsNull()
{
// Arrange
var mockHttpContext = GetMockHttpContext(_cookieName, string.Empty);
var config = new MockAntiForgeryConfig()
{
CookieName = _cookieName
};
var tokenStore = new AntiForgeryTokenStore(
config: config,
serializer: null);
// Act
var token = tokenStore.GetCookieToken(mockHttpContext);
// Assert
Assert.Null(token);
}
[Fact]
public void GetCookieToken_CookieIsInvalid_PropagatesException()
{
// Arrange
var mockHttpContext = GetMockHttpContext(_cookieName, "invalid-value");
var config = new MockAntiForgeryConfig()
{
CookieName = _cookieName
};
var expectedException = new InvalidOperationException("some exception");
var mockSerializer = new Mock<IAntiForgeryTokenSerializer>();
mockSerializer
.Setup(o => o.Deserialize("invalid-value"))
.Throws(expectedException);
var tokenStore = new AntiForgeryTokenStore(
config: config,
serializer: mockSerializer.Object);
// Act & assert
var ex = Assert.Throws<InvalidOperationException>(() => tokenStore.GetCookieToken(mockHttpContext));
Assert.Same(expectedException, ex);
}
[Fact]
public void GetCookieToken_CookieIsValid_ReturnsToken()
{
// Arrange
var expectedToken = new AntiForgeryToken();
var mockHttpContext = GetMockHttpContext(_cookieName, "valid-value");
MockAntiForgeryConfig config = new MockAntiForgeryConfig()
{
CookieName = _cookieName
};
var mockSerializer = new Mock<IAntiForgeryTokenSerializer>();
mockSerializer
.Setup(o => o.Deserialize("valid-value"))
.Returns(expectedToken);
var tokenStore = new AntiForgeryTokenStore(
config: config,
serializer: mockSerializer.Object);
// Act
AntiForgeryToken retVal = tokenStore.GetCookieToken(mockHttpContext);
// Assert
Assert.Same(expectedToken, retVal);
}
[Fact]
public async Task GetFormToken_FormFieldIsEmpty_ReturnsNull()
{
// Arrange
var mockHttpContext = new Mock<HttpContext>();
var requestContext = new Mock<HttpRequest>();
IReadableStringCollection formsCollection =
new MockCookieCollection(new Dictionary<string, string>() { { "form-field-name", string.Empty } });
requestContext.Setup(o => o.GetFormAsync())
.Returns(Task.FromResult(formsCollection));
mockHttpContext.Setup(o => o.Request)
.Returns(requestContext.Object);
var config = new MockAntiForgeryConfig()
{
FormFieldName = "form-field-name"
};
var tokenStore = new AntiForgeryTokenStore(
config: config,
serializer: null);
// Act
var token = await tokenStore.GetFormTokenAsync(mockHttpContext.Object);
// Assert
Assert.Null(token);
}
[Fact]
public async Task GetFormToken_FormFieldIsInvalid_PropagatesException()
{
// Arrange
IReadableStringCollection formsCollection =
new MockCookieCollection(new Dictionary<string, string>() { { "form-field-name", "invalid-value" } });
var requestContext = new Mock<HttpRequest>();
requestContext.Setup(o => o.GetFormAsync())
.Returns(Task.FromResult(formsCollection));
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext.Setup(o => o.Request)
.Returns(requestContext.Object);
var config = new MockAntiForgeryConfig()
{
FormFieldName = "form-field-name"
};
var expectedException = new InvalidOperationException("some exception");
var mockSerializer = new Mock<IAntiForgeryTokenSerializer>();
mockSerializer.Setup(o => o.Deserialize("invalid-value"))
.Throws(expectedException);
var tokenStore = new AntiForgeryTokenStore(
config: config,
serializer: mockSerializer.Object);
// Act & assert
var ex =
await
Assert.ThrowsAsync<InvalidOperationException>(
async () => await tokenStore.GetFormTokenAsync(mockHttpContext.Object));
Assert.Same(expectedException, ex);
}
[Fact]
public async Task GetFormToken_FormFieldIsValid_ReturnsToken()
{
// Arrange
var expectedToken = new AntiForgeryToken();
// Arrange
var mockHttpContext = new Mock<HttpContext>();
var requestContext = new Mock<HttpRequest>();
IReadableStringCollection formsCollection =
new MockCookieCollection(new Dictionary<string, string>() { { "form-field-name", "valid-value" } });
requestContext.Setup(o => o.GetFormAsync())
.Returns(Task.FromResult(formsCollection));
mockHttpContext.Setup(o => o.Request)
.Returns(requestContext.Object);
var config = new MockAntiForgeryConfig()
{
FormFieldName = "form-field-name"
};
var mockSerializer = new Mock<IAntiForgeryTokenSerializer>();
mockSerializer.Setup(o => o.Deserialize("valid-value"))
.Returns(expectedToken);
var tokenStore = new AntiForgeryTokenStore(
config: config,
serializer: mockSerializer.Object);
// Act
var retVal = await tokenStore.GetFormTokenAsync(mockHttpContext.Object);
// Assert
Assert.Same(expectedToken, retVal);
}
[Theory]
[InlineData(true, true)]
[InlineData(false, null)]
public void SaveCookieToken(bool requireSsl, bool? expectedCookieSecureFlag)
{
// Arrange
var token = new AntiForgeryToken();
var mockCookies = new Mock<IResponseCookies>();
// TODO : Once we decide on where to pick this value from enable this.
bool defaultCookieSecureValue = expectedCookieSecureFlag ?? false; // pulled from config; set by ctor
var cookies = new MockResponseCookieCollection();
cookies.Count = 0;
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext.Setup(o => o.Response.Cookies)
.Returns(cookies);
var mockSerializer = new Mock<IAntiForgeryTokenSerializer>();
mockSerializer.Setup(o => o.Serialize(token))
.Returns("serialized-value");
var config = new MockAntiForgeryConfig()
{
CookieName = _cookieName,
RequireSSL = requireSsl
};
var tokenStore = new AntiForgeryTokenStore(
config: config,
serializer: mockSerializer.Object);
// Act
tokenStore.SaveCookieToken(mockHttpContext.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(defaultCookieSecureValue, cookies.Options.Secure);
}
private HttpContext GetMockHttpContext(string cookieName, string cookieValue)
{
var requestCookies = new MockCookieCollection(new Dictionary<string, string>() { { cookieName, cookieValue } });
var request = new Mock<HttpRequest>();
request.Setup(o => o.Cookies)
.Returns(requestCookies);
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext.Setup(o => o.Request)
.Returns(request.Object);
return mockHttpContext.Object;
}
private class MockResponseCookieCollection : IResponseCookies
{
public string Key { get; set; }
public string Value { get; set; }
public CookieOptions Options { get; set; }
public int Count { get; set; }
public void Append(string key, string value, CookieOptions options)
{
this.Key = key;
this.Value = value;
this.Options = options;
this.Count++;
}
public void Append(string key, string value)
{
throw new NotImplementedException();
}
public void Delete(string key, CookieOptions options)
{
throw new NotImplementedException();
}
public void Delete(string key)
{
throw new NotImplementedException();
}
}
private class MockCookieCollection : IReadableStringCollection
{
private Dictionary<string, string> dictionary;
public MockCookieCollection(Dictionary<string, string> dictionary)
{
this.dictionary = dictionary;
}
public static MockCookieCollection GetDummyInstance(string key, string value)
{
return new MockCookieCollection(new Dictionary<string, string>() { { key, value } });
}
public string Get(string key)
{
return this[key];
}
public IList<string> GetValues(string key)
{
throw new NotImplementedException();
}
public string this[string key]
{
get { return this.dictionary[key]; }
}
public IEnumerator<KeyValuePair<string, string[]>> GetEnumerator()
{
throw new NotImplementedException();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
}
}

View File

@ -0,0 +1,146 @@
// Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR
// NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing
// permissions and limitations under the License.
using Xunit;
namespace Microsoft.AspNet.Mvc.Core.Test
{
public class AntiForgeryTokenTest
{
[Fact]
public void AdditionalDataProperty()
{
// Arrange
var token = new AntiForgeryToken();
// Act & assert - 1
Assert.Equal("", token.AdditionalData);
// Act & assert - 2
token.AdditionalData = "additional data";
Assert.Equal("additional data", token.AdditionalData);
// Act & assert - 3
token.AdditionalData = null;
Assert.Equal("", token.AdditionalData);
}
[Fact]
public void ClaimUidProperty()
{
// Arrange
var token = new AntiForgeryToken();
// Act & assert - 1
Assert.Null(token.ClaimUid);
// Act & assert - 2
BinaryBlob blob = new BinaryBlob(32);
token.ClaimUid = blob;
Assert.Equal(blob, token.ClaimUid);
// Act & assert - 3
token.ClaimUid = null;
Assert.Null(token.ClaimUid);
}
[Fact]
public void IsSessionTokenProperty()
{
// Arrange
var token = new AntiForgeryToken();
// Act & assert - 1
Assert.False(token.IsSessionToken);
// Act & assert - 2
token.IsSessionToken = true;
Assert.True(token.IsSessionToken);
// Act & assert - 3
token.IsSessionToken = false;
Assert.False(token.IsSessionToken);
}
[Fact]
public void UsernameProperty()
{
// Arrange
var token = new AntiForgeryToken();
// Act & assert - 1
Assert.Equal("", token.Username);
// Act & assert - 2
token.Username = "my username";
Assert.Equal("my username", token.Username);
// Act & assert - 3
token.Username = null;
Assert.Equal("", token.Username);
}
[Fact]
public void SecurityTokenProperty_GetsAutopopulated()
{
// Arrange
var token = new AntiForgeryToken();
// Act
var securityToken = token.SecurityToken;
// Assert
Assert.NotNull(securityToken);
Assert.Equal(AntiForgeryToken.SecurityTokenBitLength, securityToken.BitLength);
// check that we're not making a new one each property call
Assert.Equal(securityToken, token.SecurityToken);
}
[Fact]
public void SecurityTokenProperty_PropertySetter_DoesNotUseDefaults()
{
// Arrange
var token = new AntiForgeryToken();
// Act
var securityToken = new BinaryBlob(64);
token.SecurityToken = securityToken;
// Assert
Assert.Equal(securityToken, token.SecurityToken);
}
[Fact]
public void SecurityTokenProperty_PropertySetter_DoesNotAllowNulls()
{
// Arrange
var token = new AntiForgeryToken();
// Act
token.SecurityToken = null;
var securityToken = token.SecurityToken;
// Assert
Assert.NotNull(securityToken);
Assert.Equal(AntiForgeryToken.SecurityTokenBitLength, securityToken.BitLength);
// check that we're not making a new one each property call
Assert.Equal(securityToken, token.SecurityToken);
}
}
}

View File

@ -0,0 +1,539 @@
// Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR
// NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing
// permissions and limitations under the License.
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.PipelineCore.Collections;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Core.Test
{
public class AntiForgeryWorkerTest
{
[Fact]
public async Task ChecksSSL_ValidateAsync_Throws()
{
// Arrange
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext.Setup(o => o.Request.IsSecure)
.Returns(false);
var config = new MockAntiForgeryConfig()
{
RequireSSL = true
};
var worker = new AntiForgeryWorker(
config: config,
serializer: null,
tokenStore: null,
generator: null,
validator: null);
// Act & assert
var ex =
await
Assert.ThrowsAsync<InvalidOperationException>(
async () => await worker.ValidateAsync(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);
}
[Fact]
public void ChecksSSL_Validate_Throws()
{
// Arrange
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext.Setup(o => o.Request.IsSecure)
.Returns(false);
var config = new MockAntiForgeryConfig()
{
RequireSSL = true
};
var worker = new AntiForgeryWorker(
config: config,
serializer: null,
tokenStore: null,
generator: null,
validator: null);
// Act & assert
var ex = Assert.Throws<InvalidOperationException>(
() => worker.Validate(mockHttpContext.Object, cookieToken: null, formToken: null));
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 ChecksSSL_GetFormInputElement_Throws()
{
// Arrange
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext.Setup(o => o.Request.IsSecure)
.Returns(false);
var config = new MockAntiForgeryConfig()
{
RequireSSL = true
};
var worker = new AntiForgeryWorker(
config: config,
serializer: null,
tokenStore: null,
generator: null,
validator: null);
// Act & assert
var 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);
}
[Fact]
public void ChecksSSL_GetTokens_Throws()
{
// Arrange
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext.Setup(o => o.Request.IsSecure)
.Returns(false);
var config = new MockAntiForgeryConfig()
{
RequireSSL = true
};
var worker = new AntiForgeryWorker(
config: config,
serializer: null,
tokenStore: null,
generator: null,
validator: null);
// Act & assert
var ex = Assert.Throws<InvalidOperationException>(() => worker.GetTokens(mockHttpContext.Object, "cookie-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);
}
[Fact]
public void GetFormInputElement_ExistingInvalidCookieToken_GeneratesANewCookieAndAnAntiForgeryToken()
{
// Arrange
var config = new MockAntiForgeryConfig()
{
FormFieldName = "form-field-name"
};
// Make sure the existing cookie is invalid.
var context = GetAntiForgeryWorkerContext(config, isOldCookieValid: false);
var worker = GetAntiForgeryWorker(context);
// Act
var inputElement = worker.GetFormInputElement(context.HttpContext.Object);
// Assert
Assert.Equal(@"<input name=""form-field-name"" type=""hidden"" value=""serialized-form-token"" />",
inputElement.ToString(TagRenderMode.SelfClosing));
context.TokenStore.Verify();
}
[Fact]
public void GetFormInputElement_ExistingInvalidCookieToken_SwallowsExceptions()
{
// Arrange
var config = new MockAntiForgeryConfig()
{
FormFieldName = "form-field-name"
};
// Make sure the existing cookie is invalid.
var context = GetAntiForgeryWorkerContext(config, isOldCookieValid: false);
var worker = GetAntiForgeryWorker(context);
// This will cause the cookieToken to be null.
context.TokenStore.Setup(o => o.GetCookieToken(context.HttpContext.Object))
.Throws(new Exception("should be swallowed"));
// Setup so that the null cookie token returned is treated as invalid.
context.TokenProvider.Setup(o => o.IsCookieTokenValid(null))
.Returns(false);
// Act
var inputElement = worker.GetFormInputElement(context.HttpContext.Object);
// Assert
Assert.Equal(@"<input name=""form-field-name"" type=""hidden"" value=""serialized-form-token"" />",
inputElement.ToString(TagRenderMode.SelfClosing));
context.TokenStore.Verify();
}
[Fact]
public void GetFormInputElement_ExistingValidCookieToken_GeneratesAnAntiForgeryToken()
{
// Arrange
var config = new MockAntiForgeryConfig()
{
FormFieldName = "form-field-name"
};
// Make sure the existing cookie is valid and use the same cookie for the mock Token Provider.
var context = GetAntiForgeryWorkerContext(config, useOldCookie: true, isOldCookieValid: true);
var worker = GetAntiForgeryWorker(context);
// Act
var inputElement = worker.GetFormInputElement(context.HttpContext.Object);
// Assert
Assert.Equal(@"<input name=""form-field-name"" type=""hidden"" value=""serialized-form-token"" />",
inputElement.ToString(TagRenderMode.SelfClosing));
}
[Theory]
[InlineData(false, "SAMEORIGIN")]
[InlineData(true, null)]
public void GetFormInputElement_AddsXFrameOptionsHeader(bool suppressXFrameOptions, string expectedHeaderValue)
{
// Arrange
var config = new MockAntiForgeryConfig()
{
SuppressXFrameOptionsHeader = suppressXFrameOptions
};
// Genreate a new cookie.
var context = GetAntiForgeryWorkerContext(config, useOldCookie: false, isOldCookieValid: false);
var worker = GetAntiForgeryWorker(context);
// Act
var inputElement = worker.GetFormInputElement(context.HttpContext.Object);
// Assert
string xFrameOptions = context.HttpContext.Object.Response.Headers["X-Frame-Options"];
Assert.Equal(expectedHeaderValue, xFrameOptions);
}
[Fact]
public void GetTokens_ExistingInvalidCookieToken_GeneratesANewCookieTokenAndANewFormToken()
{
// Arrange
// Genreate a new cookie.
var context = GetAntiForgeryWorkerContext(new MockAntiForgeryConfig(), useOldCookie: false, isOldCookieValid: false);
var worker = GetAntiForgeryWorker(context);
// Act
var tokenset = worker.GetTokens(context.HttpContext.Object, "serialized-old-cookie-token");
// Assert
Assert.Equal("serialized-new-cookie-token", tokenset.CookieToken);
Assert.Equal("serialized-form-token", tokenset.FormToken);
}
[Fact]
public void GetTokens_ExistingInvalidCookieToken_SwallowsExceptions()
{
// Arrange
// Make sure the existing cookie is invalid.
var context = GetAntiForgeryWorkerContext(new MockAntiForgeryConfig(), useOldCookie: false, isOldCookieValid: false);
// This will cause the cookieToken to be null.
context.TokenSerializer.Setup(o => o.Deserialize("serialized-old-cookie-token"))
.Throws(new Exception("should be swallowed"));
// Setup so that the null cookie token returned is treated as invalid.
context.TokenProvider.Setup(o => o.IsCookieTokenValid(null))
.Returns(false);
var worker = GetAntiForgeryWorker(context);
// Act
var tokenset = worker.GetTokens(context.HttpContext.Object, "serialized-old-cookie-token");
// Assert
Assert.Equal("serialized-new-cookie-token", tokenset.CookieToken);
Assert.Equal("serialized-form-token", tokenset.FormToken);
}
[Fact]
public void GetTokens_ExistingValidCookieToken_GeneratesANewFormToken()
{
// Arrange
var context = GetAntiForgeryWorkerContext(new MockAntiForgeryConfig(), useOldCookie: true, isOldCookieValid: true);
context.TokenStore = null;
var worker = GetAntiForgeryWorker(context);
// Act
var tokenset = worker.GetTokens(context.HttpContext.Object, "serialized-old-cookie-token");
// Assert
Assert.Null(tokenset.CookieToken);
Assert.Equal("serialized-form-token", tokenset.FormToken);
}
[Fact]
public void Validate_FromInvalidStrings_Throws()
{
// Arrange
var context = GetAntiForgeryWorkerContext(new MockAntiForgeryConfig());
context.TokenSerializer.Setup(o => o.Deserialize("cookie-token"))
.Returns(context.TestTokenSet.OldCookieToken);
context.TokenSerializer.Setup(o => o.Deserialize("form-token"))
.Returns(context.TestTokenSet.FormToken);
context.TokenProvider.Setup(o => o.ValidateTokens(
context.HttpContext.Object,
context.HttpContext.Object.User.Identity as ClaimsIdentity,
context.TestTokenSet.OldCookieToken, context.TestTokenSet.FormToken))
.Throws(new InvalidOperationException("my-message"));
context.TokenStore = null;
var worker = GetAntiForgeryWorker(context);
// Act & assert
var ex =
Assert.Throws<InvalidOperationException>(
() => worker.Validate(context.HttpContext.Object, "cookie-token", "form-token"));
Assert.Equal("my-message", ex.Message);
}
[Fact]
public void Validate_FromValidStrings_TokensValidatedSuccessfully()
{
// Arrange
var context = GetAntiForgeryWorkerContext(new MockAntiForgeryConfig());
context.TokenSerializer.Setup(o => o.Deserialize("cookie-token"))
.Returns(context.TestTokenSet.OldCookieToken);
context.TokenSerializer.Setup(o => o.Deserialize("form-token"))
.Returns(context.TestTokenSet.FormToken);
context.TokenProvider.Setup(o => o.ValidateTokens(
context.HttpContext.Object,
context.HttpContext.Object.User.Identity as ClaimsIdentity,
context.TestTokenSet.OldCookieToken, context.TestTokenSet.FormToken))
.Verifiable();
context.TokenStore = null;
var worker = GetAntiForgeryWorker(context);
// Act
worker.Validate(context.HttpContext.Object, "cookie-token", "form-token");
// Assert
context.TokenProvider.Verify();
}
[Fact]
public async Task Validate_FromStore_Failure()
{
// Arrange
var context = GetAntiForgeryWorkerContext(new MockAntiForgeryConfig());
context.TokenProvider.Setup(o => o.ValidateTokens(
context.HttpContext.Object,
context.HttpContext.Object.User.Identity as ClaimsIdentity,
context.TestTokenSet.OldCookieToken, context.TestTokenSet.FormToken))
.Throws(new InvalidOperationException("my-message"));
context.TokenSerializer = null;
var worker = GetAntiForgeryWorker(context);
// Act & assert
var ex =
await
Assert.ThrowsAsync<InvalidOperationException>(
async () => await worker.ValidateAsync(context.HttpContext.Object));
Assert.Equal("my-message", ex.Message);
}
[Fact]
public async Task Validate_FromStore_Success()
{
// Arrange
var context = GetAntiForgeryWorkerContext(new MockAntiForgeryConfig());
context.TokenProvider.Setup(o => o.ValidateTokens(
context.HttpContext.Object,
context.HttpContext.Object.User.Identity as ClaimsIdentity,
context.TestTokenSet.OldCookieToken, context.TestTokenSet.FormToken))
.Verifiable();
context.TokenSerializer = null;
var worker = GetAntiForgeryWorker(context);
// Act
await worker.ValidateAsync(context.HttpContext.Object);
// Assert
context.TokenProvider.Verify();
}
private AntiForgeryWorker GetAntiForgeryWorker(AntiForgeryWorkerContext context)
{
return new AntiForgeryWorker(
config: context.Config,
serializer: context.TokenSerializer != null ? context.TokenSerializer.Object : null,
tokenStore: context.TokenStore != null ? context.TokenStore.Object : null,
generator: context.TokenProvider != null ? context.TokenProvider.Object : null,
validator: context.TokenProvider != null ? context.TokenProvider.Object : null);
}
private Mock<HttpContext> GetHttpContext(bool setupResponse = true)
{
var identity = new GenericIdentity("some-user");
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext.Setup(o => o.User)
.Returns(new GenericPrincipal(identity, new string[0]));
if (setupResponse)
{
var mockResponse = new Mock<HttpResponse>();
mockResponse.Setup(r => r.Headers)
.Returns(new HeaderDictionary(new Dictionary<string, string[]>()));
mockHttpContext.Setup(o => o.Response)
.Returns(mockResponse.Object);
}
return mockHttpContext;
}
private Mock<ITokenProvider> GetTokenProvider(HttpContext context, TestTokenSet testTokenSet, bool useOldCookie, bool isOldCookieValid = true, bool isNewCookieValid = true)
{
var oldCookieToken = testTokenSet.OldCookieToken;
var newCookieToken = testTokenSet.NewCookieToken;
var formToken = testTokenSet.FormToken;
var mockValidator = new Mock<ITokenProvider>(MockBehavior.Strict);
mockValidator.Setup(o => o.GenerateFormToken(context, context.User.Identity as ClaimsIdentity, useOldCookie ? oldCookieToken : newCookieToken))
.Returns(formToken);
mockValidator.Setup(o => o.IsCookieTokenValid(oldCookieToken))
.Returns(isOldCookieValid);
mockValidator.Setup(o => o.IsCookieTokenValid(newCookieToken))
.Returns(isNewCookieValid);
mockValidator.Setup(o => o.GenerateCookieToken())
.Returns(useOldCookie ? oldCookieToken : newCookieToken);
return mockValidator;
}
private Mock<ITokenStore> GetTokenStore(HttpContext context, TestTokenSet testTokenSet, bool saveNewCookie = true)
{
var oldCookieToken = testTokenSet.OldCookieToken;
var formToken = testTokenSet.FormToken;
var mockTokenStore = new Mock<ITokenStore>(MockBehavior.Strict);
mockTokenStore.Setup(o => o.GetCookieToken(context))
.Returns(oldCookieToken);
mockTokenStore.Setup(o => o.GetFormTokenAsync(context))
.Returns(Task.FromResult(formToken));
if (saveNewCookie)
{
var newCookieToken = testTokenSet.NewCookieToken;
mockTokenStore.Setup(o => o.SaveCookieToken(context, newCookieToken))
.Verifiable();
}
return mockTokenStore;
}
private Mock<IAntiForgeryTokenSerializer> GetTokenSerializer(TestTokenSet testTokenSet)
{
var oldCookieToken = testTokenSet.OldCookieToken;
var newCookieToken = testTokenSet.NewCookieToken;
var formToken = testTokenSet.FormToken;
var mockSerializer = new Mock<IAntiForgeryTokenSerializer>(MockBehavior.Strict);
mockSerializer.Setup(o => o.Serialize(formToken))
.Returns("serialized-form-token");
mockSerializer.Setup(o => o.Deserialize("serialized-old-cookie-token"))
.Returns(oldCookieToken);
mockSerializer.Setup(o => o.Serialize(newCookieToken))
.Returns("serialized-new-cookie-token");
return mockSerializer;
}
private TestTokenSet GetTokenSet(bool isOldCookieTokenSessionToken = true, bool isNewCookieSessionToken = true)
{
return new TestTokenSet()
{
FormToken = new AntiForgeryToken() { IsSessionToken = false },
OldCookieToken = new AntiForgeryToken() { IsSessionToken = isOldCookieTokenSessionToken },
NewCookieToken = new AntiForgeryToken() { IsSessionToken = isNewCookieSessionToken },
};
}
private AntiForgeryWorkerContext GetAntiForgeryWorkerContext(MockAntiForgeryConfig config, bool useOldCookie = false, bool isOldCookieValid = true)
{
// Arrange
var mockHttpContext = GetHttpContext();
var testTokenSet = GetTokenSet(isOldCookieTokenSessionToken: true, isNewCookieSessionToken: true);
var mockSerializer = GetTokenSerializer(testTokenSet);
var mockTokenStore = GetTokenStore(mockHttpContext.Object, testTokenSet);
var mockTokenProvider = GetTokenProvider(mockHttpContext.Object, testTokenSet, useOldCookie: useOldCookie, isOldCookieValid: isOldCookieValid);
return new AntiForgeryWorkerContext()
{
Config = config,
HttpContext = mockHttpContext,
TokenProvider = mockTokenProvider,
TokenSerializer = mockSerializer,
TokenStore = mockTokenStore,
TestTokenSet = testTokenSet
};
}
private class TestTokenSet
{
public AntiForgeryToken FormToken { get; set; }
public string FormTokenString { get; set; }
public AntiForgeryToken OldCookieToken { get; set; }
public string OldCookieTokenString { get; set; }
public AntiForgeryToken NewCookieToken { get; set; }
public string NewCookieTokenString { get; set; }
}
private class AntiForgeryWorkerContext
{
public MockAntiForgeryConfig Config { get; set; }
public TestTokenSet TestTokenSet { get; set; }
public Mock<HttpContext> HttpContext { get; set; }
public Mock<ITokenProvider> TokenProvider { get; set; }
public Mock<ITokenStore> TokenStore { get; set; }
public Mock<IAntiForgeryTokenSerializer> TokenSerializer { get; set; }
}
}
}

View File

@ -0,0 +1,143 @@
// Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR
// NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing
// permissions and limitations under the License.
using System;
using Xunit;
namespace Microsoft.AspNet.Mvc.Core.Test
{
public class BinaryBlobTest
{
[Fact]
public void Ctor_BitLength()
{
// Act
var blob = new BinaryBlob(bitLength: 64);
var data = blob.GetData();
// Assert
Assert.Equal(64, blob.BitLength);
Assert.Equal(64 / 8, data.Length);
Assert.NotEqual(new byte[64 / 8], data); // should not be a zero-filled array
}
[Theory]
[InlineData(24)]
[InlineData(33)]
public void Ctor_BitLength_Bad(int bitLength)
{
// Act & assert
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => new BinaryBlob(bitLength));
Assert.Equal("bitLength", ex.ParamName);
}
[Fact]
public void Ctor_BitLength_ProducesDifferentValues()
{
// Act
var blobA = new BinaryBlob(bitLength: 64);
var blobB = new BinaryBlob(bitLength: 64);
// Assert
Assert.NotEqual(blobA.GetData(), blobB.GetData());
}
[Fact]
public void Ctor_Data()
{
// Arrange
var expectedData = new byte[] { 0x01, 0x02, 0x03, 0x04 };
// Act
var blob = new BinaryBlob(32, expectedData);
// Assert
Assert.Equal(32, blob.BitLength);
Assert.Equal(expectedData, blob.GetData());
}
[Theory]
[InlineData((object[])null)]
[InlineData(new byte[] { 0x01, 0x02, 0x03 })]
public void Ctor_Data_Bad(byte[] data)
{
// Act & assert
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => new BinaryBlob(32, data));
Assert.Equal("data", ex.ParamName);
}
[Fact]
public void Equals_DifferentData_ReturnsFalse()
{
// Arrange
object blobA = new BinaryBlob(32, new byte[] { 0x01, 0x02, 0x03, 0x04 });
object blobB = new BinaryBlob(32, new byte[] { 0x04, 0x03, 0x02, 0x01 });
// Act & assert
Assert.NotEqual(blobA, blobB);
}
[Fact]
public void Equals_NotABlob_ReturnsFalse()
{
// Arrange
object blobA = new BinaryBlob(32);
object blobB = "hello";
// Act & assert
Assert.NotEqual(blobA, blobB);
}
[Fact]
public void Equals_Null_ReturnsFalse()
{
// Arrange
object blobA = new BinaryBlob(32);
object blobB = null;
// Act & assert
Assert.NotEqual(blobA, blobB);
}
[Fact]
public void Equals_SameData_ReturnsTrue()
{
// Arrange
object blobA = new BinaryBlob(32, new byte[] { 0x01, 0x02, 0x03, 0x04 });
object blobB = new BinaryBlob(32, new byte[] { 0x01, 0x02, 0x03, 0x04 });
// Act & assert
Assert.Equal(blobA, blobB);
}
[Fact]
public void GetHashCodeTest()
{
// Arrange
var blobData = new byte[] { 0x01, 0x02, 0x03, 0x04 };
var expectedHashCode = BitConverter.ToInt32(blobData, 0);
var blob = new BinaryBlob(32, blobData);
// Act
var actualHashCode = blob.GetHashCode();
// Assert
Assert.Equal(expectedHashCode, actualHashCode);
}
}
}

View File

@ -0,0 +1,122 @@
// Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR
// NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing
// permissions and limitations under the License.
using System;
using System.Linq;
using System.Security.Claims;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Core.Test
{
public class ClaimUidExtractorTest
{
[Fact]
public void ExtractClaimUid_NullIdentity()
{
// Arrange
IClaimUidExtractor extractor = new DefaultClaimUidExtractor();
// Act
var claimUid = extractor.ExtractClaimUid(null);
// Assert
Assert.Null(claimUid);
}
[Fact]
public void ExtractClaimUid_Unauthenticated()
{
// Arrange
IClaimUidExtractor extractor = new DefaultClaimUidExtractor();
var mockIdentity = new Mock<ClaimsIdentity>();
mockIdentity.Setup(o => o.IsAuthenticated)
.Returns(false);
// Act
var claimUid = extractor.ExtractClaimUid(mockIdentity.Object);
// Assert
Assert.Null(claimUid);
}
[Fact]
public void ExtractClaimUid_ClaimsIdentity()
{
// Arrange
var mockIdentity = new Mock<ClaimsIdentity>();
mockIdentity.Setup(o => o.IsAuthenticated)
.Returns(true);
IClaimUidExtractor extractor = new DefaultClaimUidExtractor();
// Act
var claimUid = extractor.ExtractClaimUid(mockIdentity.Object);
// Assert
Assert.NotNull(claimUid);
Assert.Equal("47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=", claimUid);
}
[Fact]
public void DefaultUniqueClaimTypes_NotPresent_SerializesAllClaimTypes()
{
var identity = new MockClaimsIdentity();
identity.AddClaim(ClaimTypes.Email, "someone@antifrogery.com");
identity.AddClaim(ClaimTypes.GivenName, "some");
identity.AddClaim(ClaimTypes.Surname, "one");
identity.AddClaim(ClaimTypes.NameIdentifier, String.Empty);
// Arrange
var claimsIdentity = (ClaimsIdentity)identity;
// Act
var identiferParameters = DefaultClaimUidExtractor.GetUniqueIdentifierParameters(claimsIdentity)
.ToArray();
var claims = claimsIdentity.Claims.ToList();
claims.Sort((a, b) => string.Compare(a.Type, b.Type, StringComparison.Ordinal));
// Assert
int index = 0;
foreach (var claim in claims)
{
Assert.True(String.Equals(identiferParameters[index++], claim.Type, StringComparison.Ordinal));
Assert.True(String.Equals(identiferParameters[index++], claim.Value, StringComparison.Ordinal));
}
}
[Fact]
public void DefaultUniqueClaimTypes_Present()
{
// Arrange
var identity = new MockClaimsIdentity();
identity.AddClaim("fooClaim", "fooClaimValue");
identity.AddClaim(ClaimTypes.NameIdentifier, "nameIdentifierValue");
// Act
var uniqueIdentifierParameters = DefaultClaimUidExtractor.GetUniqueIdentifierParameters(identity);
// Assert
Assert.Equal(new string[]
{
ClaimTypes.NameIdentifier,
"nameIdentifierValue",
}, uniqueIdentifierParameters);
}
}
}

View File

@ -0,0 +1,24 @@
// Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR
// NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing
// permissions and limitations under the License.
namespace Microsoft.AspNet.Mvc.Core.Test
{
// A TokenProvider that can be passed to MoQ
internal interface ITokenProvider : ITokenValidator, ITokenGenerator
{
}
}

View File

@ -0,0 +1,46 @@
// Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR
// NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing
// permissions and limitations under the License.
namespace Microsoft.AspNet.Mvc.Core.Test
{
public sealed class MockAntiForgeryConfig : IAntiForgeryConfig
{
public string CookieName
{
get;
set;
}
public string FormFieldName
{
get;
set;
}
public bool RequireSSL
{
get;
set;
}
public bool SuppressXFrameOptionsHeader
{
get;
set;
}
}
}

View File

@ -0,0 +1,39 @@
// Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR
// NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing
// permissions and limitations under the License.
using System.Collections.Generic;
using System.Security.Claims;
namespace Microsoft.AspNet.Mvc.Core.Test
{
// Convenient class for mocking a ClaimsIdentity instance given some
// prefabricated Claim instances.
internal sealed class MockClaimsIdentity : ClaimsIdentity
{
private readonly List<Claim> _claims = new List<Claim>();
public void AddClaim(string claimType, string value)
{
_claims.Add(new Claim(claimType, value));
}
public override IEnumerable<Claim> Claims
{
get { return _claims; }
}
}
}

View File

@ -0,0 +1,588 @@
// Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR
// NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing
// permissions and limitations under the License.
using System;
using System.Security.Claims;
using System.Security.Principal;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Security.DataProtection;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Core.Test
{
public class TokenProviderTest
{
[Fact]
public void GenerateCookieToken()
{
// Arrange
var tokenProvider = new TokenProvider(
config: null,
claimUidExtractor: null,
additionalDataProvider: null);
// Act
var retVal = tokenProvider.GenerateCookieToken();
// Assert
Assert.NotNull(retVal);
}
[Fact]
public void GenerateFormToken_AnonymousUser()
{
// Arrange
var cookieToken = new AntiForgeryToken() { IsSessionToken = true };
var httpContext = new Mock<HttpContext>().Object;
var mockIdentity = new Mock<ClaimsIdentity>();
mockIdentity.Setup(o => o.IsAuthenticated)
.Returns(false);
IAntiForgeryConfig config = new MockAntiForgeryConfig();
var tokenProvider = new TokenProvider(
config: config,
claimUidExtractor: null,
additionalDataProvider: null);
// Act
var fieldToken = tokenProvider.GenerateFormToken(httpContext, mockIdentity.Object, cookieToken);
// Assert
Assert.NotNull(fieldToken);
Assert.Equal(cookieToken.SecurityToken, fieldToken.SecurityToken);
Assert.False(fieldToken.IsSessionToken);
Assert.Equal("", fieldToken.Username);
Assert.Equal(null, fieldToken.ClaimUid);
Assert.Equal("", fieldToken.AdditionalData);
}
[Fact]
public void GenerateFormToken_AuthenticatedWithoutUsernameAndNoAdditionalData_NoAdditionalData()
{
// Arrange
var cookieToken = new AntiForgeryToken()
{
IsSessionToken = true
};
var httpContext = new Mock<HttpContext>().Object;
ClaimsIdentity identity = new MyAuthenticatedIdentityWithoutUsername();
IAntiForgeryConfig config = new MockAntiForgeryConfig();
IClaimUidExtractor claimUidExtractor = new Mock<IClaimUidExtractor>().Object;
var tokenProvider = new TokenProvider(
config: config,
claimUidExtractor: claimUidExtractor,
additionalDataProvider: null);
// Act & assert
var ex =
Assert.Throws<InvalidOperationException>(
() => tokenProvider.GenerateFormToken(httpContext, identity, cookieToken));
Assert.Equal(
"The provided identity of type "+
"'Microsoft.AspNet.Mvc.Core.Test.TokenProviderTest+MyAuthenticatedIdentityWithoutUsername' "+
"is marked IsAuthenticated = true but does not have a value for Name. "+
"By default, the anti-forgery system requires that all authenticated identities have a unique Name. " +
"If it is not possible to provide a unique Name for this identity, " +
"consider extending IAdditionalDataProvider by overriding the DefaultAdditionalDataProvider " +
"or a custom type that can provide some form of unique identifier for the current user.",
ex.Message);
}
[Fact]
public void GenerateFormToken_AuthenticatedWithoutUsername_WithAdditionalData()
{
// Arrange
var cookieToken = new AntiForgeryToken() { IsSessionToken = true };
var httpContext = new Mock<HttpContext>().Object;
ClaimsIdentity identity = new MyAuthenticatedIdentityWithoutUsername();
var mockAdditionalDataProvider = new Mock<IAntiForgeryAdditionalDataProvider>();
mockAdditionalDataProvider.Setup(o => o.GetAdditionalData(httpContext))
.Returns("additional-data");
IAntiForgeryConfig config = new AntiForgeryConfigWrapper();
IClaimUidExtractor claimUidExtractor = new Mock<IClaimUidExtractor>().Object;
var tokenProvider = new TokenProvider(
config: config,
claimUidExtractor: claimUidExtractor,
additionalDataProvider: mockAdditionalDataProvider.Object);
// Act
var fieldToken = tokenProvider.GenerateFormToken(httpContext, identity, cookieToken);
// Assert
Assert.NotNull(fieldToken);
Assert.Equal(cookieToken.SecurityToken, fieldToken.SecurityToken);
Assert.False(fieldToken.IsSessionToken);
Assert.Equal("", fieldToken.Username);
Assert.Equal(null, fieldToken.ClaimUid);
Assert.Equal("additional-data", fieldToken.AdditionalData);
}
[Fact]
public void GenerateFormToken_ClaimsBasedIdentity()
{
// Arrange
var cookieToken = new AntiForgeryToken() { IsSessionToken = true };
var httpContext = new Mock<HttpContext>().Object;
ClaimsIdentity identity = new GenericIdentity("some-identity");
var config = new MockAntiForgeryConfig();
byte[] data = new byte[256 / 8];
CryptRand.FillBuffer(new ArraySegment<byte>(data));
var base64ClaimUId = Convert.ToBase64String(data);
var expectedClaimUid = new BinaryBlob(256, data);
var mockClaimUidExtractor = new Mock<IClaimUidExtractor>();
mockClaimUidExtractor.Setup(o => o.ExtractClaimUid(identity))
.Returns(base64ClaimUId);
var tokenProvider = new TokenProvider(
config: config,
claimUidExtractor: mockClaimUidExtractor.Object,
additionalDataProvider: null);
// Act
var fieldToken = tokenProvider.GenerateFormToken(httpContext, identity, cookieToken);
// Assert
Assert.NotNull(fieldToken);
Assert.Equal(cookieToken.SecurityToken, fieldToken.SecurityToken);
Assert.False(fieldToken.IsSessionToken);
Assert.Equal("", fieldToken.Username);
Assert.Equal(expectedClaimUid, fieldToken.ClaimUid);
Assert.Equal("", fieldToken.AdditionalData);
}
[Fact]
public void GenerateFormToken_RegularUserWithUsername()
{
// Arrange
var cookieToken = new AntiForgeryToken() { IsSessionToken = true };
var httpContext = new Mock<HttpContext>().Object;
var mockIdentity = new Mock<ClaimsIdentity>();
mockIdentity.Setup(o => o.IsAuthenticated)
.Returns(true);
mockIdentity.Setup(o => o.Name)
.Returns("my-username");
IAntiForgeryConfig config = new MockAntiForgeryConfig();
IClaimUidExtractor claimUidExtractor = new Mock<IClaimUidExtractor>().Object;
var tokenProvider = new TokenProvider(
config: config,
claimUidExtractor: claimUidExtractor,
additionalDataProvider: null);
// Act
var fieldToken = tokenProvider.GenerateFormToken(httpContext, mockIdentity.Object, cookieToken);
// Assert
Assert.NotNull(fieldToken);
Assert.Equal(cookieToken.SecurityToken, fieldToken.SecurityToken);
Assert.False(fieldToken.IsSessionToken);
Assert.Equal("my-username", fieldToken.Username);
Assert.Equal(null, fieldToken.ClaimUid);
Assert.Equal("", fieldToken.AdditionalData);
}
[Fact]
public void IsCookieTokenValid_FieldToken_ReturnsFalse()
{
// Arrange
var cookieToken = new AntiForgeryToken()
{
IsSessionToken = false
};
var tokenProvider = new TokenProvider(
config: null,
claimUidExtractor: null,
additionalDataProvider: null);
// Act
bool retVal = tokenProvider.IsCookieTokenValid(cookieToken);
// Assert
Assert.False(retVal);
}
[Fact]
public void IsCookieTokenValid_NullToken_ReturnsFalse()
{
// Arrange
AntiForgeryToken cookieToken = null;
var tokenProvider = new TokenProvider(
config: null,
claimUidExtractor: null,
additionalDataProvider: null);
// Act
bool retVal = tokenProvider.IsCookieTokenValid(cookieToken);
// Assert
Assert.False(retVal);
}
[Fact]
public void IsCookieTokenValid_ValidToken_ReturnsTrue()
{
// Arrange
var cookieToken = new AntiForgeryToken()
{
IsSessionToken = true
};
var tokenProvider = new TokenProvider(
config: null,
claimUidExtractor: null,
additionalDataProvider: null);
// Act
bool retVal = tokenProvider.IsCookieTokenValid(cookieToken);
// Assert
Assert.True(retVal);
}
[Fact]
public void ValidateTokens_SessionTokenMissing()
{
// Arrange
var httpContext = new Mock<HttpContext>().Object;
ClaimsIdentity identity = new Mock<ClaimsIdentity>().Object;
AntiForgeryToken sessionToken = null;
var fieldtoken = new AntiForgeryToken() { IsSessionToken = false };
var config = new MockAntiForgeryConfig()
{
CookieName = "my-cookie-name"
};
var tokenProvider = new TokenProvider(
config: config,
claimUidExtractor: null,
additionalDataProvider: null);
// Act & assert
var ex =
Assert.Throws<InvalidOperationException>(
() => tokenProvider.ValidateTokens(httpContext, identity, sessionToken, fieldtoken));
Assert.Equal(@"The required anti-forgery cookie ""my-cookie-name"" is not present.", ex.Message);
}
[Fact]
public void ValidateTokens_FieldTokenMissing()
{
// Arrange
var httpContext = new Mock<HttpContext>().Object;
ClaimsIdentity identity = new Mock<ClaimsIdentity>().Object;
var sessionToken = new AntiForgeryToken() { IsSessionToken = true };
AntiForgeryToken fieldtoken = null;
var config = new MockAntiForgeryConfig()
{
FormFieldName = "my-form-field-name"
};
var tokenProvider = new TokenProvider(
config: config,
claimUidExtractor: null,
additionalDataProvider: null);
// Act & assert
var ex =
Assert.Throws<InvalidOperationException>(
() => tokenProvider.ValidateTokens(httpContext, identity, sessionToken, fieldtoken));
Assert.Equal(@"The required anti-forgery form field ""my-form-field-name"" is not present.", ex.Message);
}
[Fact]
public void ValidateTokens_FieldAndSessionTokensSwapped()
{
// Arrange
var httpContext = new Mock<HttpContext>().Object;
ClaimsIdentity identity = new Mock<ClaimsIdentity>().Object;
var sessionToken = new AntiForgeryToken() { IsSessionToken = true };
var fieldtoken = new AntiForgeryToken() { IsSessionToken = false };
var config = new MockAntiForgeryConfig()
{
CookieName = "my-cookie-name",
FormFieldName = "my-form-field-name"
};
var tokenProvider = new TokenProvider(
config: config,
claimUidExtractor: null,
additionalDataProvider: null);
// Act & assert
var ex1 =
Assert.Throws<InvalidOperationException>(
() => tokenProvider.ValidateTokens(httpContext, identity, fieldtoken, fieldtoken));
Assert.Equal(
"Validation of the provided anti-forgery token failed. "+
@"The cookie ""my-cookie-name"" and the form field ""my-form-field-name"" were swapped.",
ex1.Message);
var ex2 =
Assert.Throws<InvalidOperationException>(
() => tokenProvider.ValidateTokens(httpContext, identity, sessionToken, sessionToken));
Assert.Equal(
"Validation of the provided anti-forgery token failed. " +
@"The cookie ""my-cookie-name"" and the form field ""my-form-field-name"" were swapped.",
ex2.Message);
}
[Fact]
public void ValidateTokens_FieldAndSessionTokensHaveDifferentSecurityKeys()
{
// Arrange
var httpContext = new Mock<HttpContext>().Object;
ClaimsIdentity identity = new Mock<ClaimsIdentity>().Object;
var sessionToken = new AntiForgeryToken() { IsSessionToken = true };
var fieldtoken = new AntiForgeryToken() { IsSessionToken = false };
var tokenProvider = new TokenProvider(
config: null,
claimUidExtractor: null,
additionalDataProvider: null);
// Act & assert
var ex =
Assert.Throws<InvalidOperationException>(
() => tokenProvider.ValidateTokens(httpContext, identity, sessionToken, fieldtoken));
Assert.Equal(@"The anti-forgery cookie token and form field token do not match.", ex.Message);
}
[Theory]
[InlineData("the-user", "the-other-user")]
[InlineData("http://example.com/uri-casing", "http://example.com/URI-casing")]
[InlineData("https://example.com/secure-uri-casing", "https://example.com/secure-URI-casing")]
public void ValidateTokens_UsernameMismatch(string identityUsername, string embeddedUsername)
{
// Arrange
var httpContext = new Mock<HttpContext>().Object;
ClaimsIdentity identity = new GenericIdentity(identityUsername);
var sessionToken = new AntiForgeryToken() { IsSessionToken = true };
var fieldtoken = new AntiForgeryToken()
{
SecurityToken = sessionToken.SecurityToken,
Username = embeddedUsername,
IsSessionToken = false
};
var mockClaimUidExtractor = new Mock<IClaimUidExtractor>();
mockClaimUidExtractor.Setup(o => o.ExtractClaimUid(identity))
.Returns((string)null);
var tokenProvider = new TokenProvider(
config: null,
claimUidExtractor: mockClaimUidExtractor.Object,
additionalDataProvider: null);
// Act & assert
var ex =
Assert.Throws<InvalidOperationException>(
() => tokenProvider.ValidateTokens(httpContext, identity, sessionToken, fieldtoken));
Assert.Equal(
@"The provided anti-forgery token was meant for user """ + embeddedUsername +
@""", but the current user is """ + identityUsername + @""".", ex.Message);
}
[Fact]
public void ValidateTokens_ClaimUidMismatch()
{
// Arrange
var httpContext = new Mock<HttpContext>().Object;
ClaimsIdentity identity = new GenericIdentity("the-user");
var sessionToken = new AntiForgeryToken() { IsSessionToken = true };
var fieldtoken = new AntiForgeryToken()
{
SecurityToken = sessionToken.SecurityToken,
IsSessionToken = false,
ClaimUid = new BinaryBlob(256)
};
var differentToken = new BinaryBlob(256);
var mockClaimUidExtractor = new Mock<IClaimUidExtractor>();
mockClaimUidExtractor.Setup(o => o.ExtractClaimUid(identity))
.Returns(Convert.ToBase64String(differentToken.GetData()));
var tokenProvider = new TokenProvider(
config: null,
claimUidExtractor: mockClaimUidExtractor.Object,
additionalDataProvider: null);
// Act & assert
var ex =
Assert.Throws<InvalidOperationException>(
() => tokenProvider.ValidateTokens(httpContext, identity, sessionToken, fieldtoken));
Assert.Equal(
@"The provided anti-forgery token was meant for a different claims-based user than the current user.",
ex.Message);
}
[Fact]
public void ValidateTokens_AdditionalDataRejected()
{
// Arrange
var httpContext = new Mock<HttpContext>().Object;
ClaimsIdentity identity = new GenericIdentity(String.Empty);
var sessionToken = new AntiForgeryToken() { IsSessionToken = true };
var fieldtoken = new AntiForgeryToken()
{
SecurityToken = sessionToken.SecurityToken,
Username = String.Empty,
IsSessionToken = false,
AdditionalData = "some-additional-data"
};
var mockAdditionalDataProvider = new Mock<IAntiForgeryAdditionalDataProvider>();
mockAdditionalDataProvider.Setup(o => o.ValidateAdditionalData(httpContext, "some-additional-data"))
.Returns(false);
var config = new MockAntiForgeryConfig();
var tokenProvider = new TokenProvider(
config: config,
claimUidExtractor: null,
additionalDataProvider: mockAdditionalDataProvider.Object);
// Act & assert
var ex =
Assert.Throws<InvalidOperationException>(
() => tokenProvider.ValidateTokens(httpContext, identity, sessionToken, fieldtoken));
Assert.Equal(@"The provided anti-forgery token failed a custom data check.", ex.Message);
}
[Fact]
public void ValidateTokens_Success_AnonymousUser()
{
// Arrange
var httpContext = new Mock<HttpContext>().Object;
ClaimsIdentity identity = new GenericIdentity(String.Empty);
var sessionToken = new AntiForgeryToken() { IsSessionToken = true };
var fieldtoken = new AntiForgeryToken()
{
SecurityToken = sessionToken.SecurityToken,
Username = String.Empty,
IsSessionToken = false,
AdditionalData = "some-additional-data"
};
var mockAdditionalDataProvider = new Mock<IAntiForgeryAdditionalDataProvider>();
mockAdditionalDataProvider.Setup(o => o.ValidateAdditionalData(httpContext, "some-additional-data"))
.Returns(true);
var config = new MockAntiForgeryConfig();
var tokenProvider = new TokenProvider(
config: config,
claimUidExtractor: null,
additionalDataProvider: mockAdditionalDataProvider.Object);
// Act
tokenProvider.ValidateTokens(httpContext, identity, sessionToken, fieldtoken);
// Assert
// Nothing to assert - if we got this far, success!
}
[Fact]
public void ValidateTokens_Success_AuthenticatedUserWithUsername()
{
// Arrange
var httpContext = new Mock<HttpContext>().Object;
ClaimsIdentity identity = new GenericIdentity("the-user");
var sessionToken = new AntiForgeryToken() { IsSessionToken = true };
var fieldtoken = new AntiForgeryToken()
{
SecurityToken = sessionToken.SecurityToken,
Username = "THE-USER",
IsSessionToken = false,
AdditionalData = "some-additional-data"
};
var mockAdditionalDataProvider = new Mock<IAntiForgeryAdditionalDataProvider>();
mockAdditionalDataProvider.Setup(o => o.ValidateAdditionalData(httpContext, "some-additional-data"))
.Returns(true);
var config = new MockAntiForgeryConfig();
var tokenProvider = new TokenProvider(
config: config,
claimUidExtractor: new Mock<IClaimUidExtractor>().Object,
additionalDataProvider: mockAdditionalDataProvider.Object);
// Act
tokenProvider.ValidateTokens(httpContext, identity, sessionToken, fieldtoken);
// Assert
// Nothing to assert - if we got this far, success!
}
[Fact]
public void ValidateTokens_Success_ClaimsBasedUser()
{
// Arrange
var httpContext = new Mock<HttpContext>().Object;
ClaimsIdentity identity = new GenericIdentity("the-user");
var sessionToken = new AntiForgeryToken() { IsSessionToken = true };
var fieldtoken = new AntiForgeryToken()
{
SecurityToken = sessionToken.SecurityToken,
IsSessionToken = false,
ClaimUid = new BinaryBlob(256)
};
var mockClaimUidExtractor = new Mock<IClaimUidExtractor>();
mockClaimUidExtractor.Setup(o => o.ExtractClaimUid(identity))
.Returns(Convert.ToBase64String(fieldtoken.ClaimUid.GetData()));
var config = new MockAntiForgeryConfig();
var tokenProvider = new TokenProvider(
config: config,
claimUidExtractor: mockClaimUidExtractor.Object,
additionalDataProvider: null);
// Act
tokenProvider.ValidateTokens(httpContext, identity, sessionToken, fieldtoken);
// Assert
// Nothing to assert - if we got this far, success!
}
private sealed class MyAuthenticatedIdentityWithoutUsername : ClaimsIdentity
{
public override bool IsAuthenticated
{
get { return true; }
}
public override string Name
{
get { return String.Empty; }
}
}
}
}

View File

@ -0,0 +1,55 @@
// Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR
// NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing
// permissions and limitations under the License.
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.DependencyInjection.Fallback;
using Microsoft.AspNet.Security.DataProtection;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Core.Test
{
public class ValidateAntiForgeryTokenAttributeTest
{
[Fact]
public void ValidationAttribute_ForwardsCallToValidateAntiForgeryTokenAuthorizationFilter()
{
// Arrange
var serviceCollection = new ServiceCollection();
serviceCollection.AddInstance<AntiForgery>(GetAntiForgeryInstance());
var serviceProvider = serviceCollection.BuildServiceProvider();
var attribute = new ValidateAntiForgeryTokenAttribute();
// Act
var filter = attribute.CreateInstance(serviceProvider);
// Assert
var validationFilter = filter as ValidateAntiForgeryTokenAuthorizationFilter;
Assert.NotNull(validationFilter);
}
private AntiForgery GetAntiForgeryInstance()
{
var claimExtractor = new Mock<IClaimUidExtractor>();
var dataProtectionProvider = new Mock<IDataProtectionProvider>();
var additionalDataProvider = new Mock<IAntiForgeryAdditionalDataProvider>();
return new AntiForgery(claimExtractor.Object,
dataProtectionProvider.Object,
additionalDataProvider.Object);
}
}
}

View File

@ -26,12 +26,24 @@
<Compile Include="ActionResults\RedirectToActionResultTest.cs" />
<Compile Include="ActionResults\RedirectToRouteResultTest.cs" />
<Compile Include="ActionSelectionConventionTests.cs" />
<Compile Include="AntiXsrf\AntiForgeryTokenSerializerTest.cs" />
<Compile Include="AntiXsrf\ITokenProvider.cs" />
<Compile Include="AntiXsrf\ValidateAntiForgeryTokenAttributeTest.cs" />
<Compile Include="Filters\AuthorizeAttributeTests.cs" />
<Compile Include="Filters\AuthorizeAttributeTestsBase.cs" />
<Compile Include="AntiXsrf\AntiForgeryTokenStoreTest.cs" />
<Compile Include="AntiXsrf\AntiForgeryTokenTest.cs" />
<Compile Include="AntiXsrf\AntiForgeryWorkerTests.cs" />
<Compile Include="AntiXsrf\BinaryBlobTest.cs" />
<Compile Include="AntiXsrf\ClaimUidExtractorTest.cs" />
<Compile Include="AntiXsrf\MockAntiForgeryConfig.cs" />
<Compile Include="AntiXsrf\MockClaimsIdentity.cs" />
<Compile Include="AntiXsrf\TokenProviderTests.cs" />
<Compile Include="ControllerTests.cs" />
<Compile Include="DefaultActionSelectorTest.cs" />
<Compile Include="DefaultControllerAssemblyProviderTests.cs" />
<Compile Include="DefaultControllerFactoryTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PropertyHelperTest.cs" />
<Compile Include="ReflectedActionInvokerTest.cs" />
<Compile Include="Rendering\HtmlAttributePropertyHelperTest.cs" />

View File

@ -0,0 +1,20 @@
// Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR
// NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing
// permissions and limitations under the License.
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

View File

@ -5,6 +5,7 @@
},
"dependencies": {
"Microsoft.AspNet.Http": "0.1-alpha-*",
"Microsoft.AspNet.PipelineCore": "0.1-alpha-*",
"Microsoft.AspNet.Mvc.Core" : "",
"Microsoft.AspNet.Mvc" : "",
"Microsoft.AspNet.Routing": "0.1-alpha-*",