Tests for AntiForgery System.
This commit is contained in:
parent
b444f66689
commit
bbafa0a29a
|
|
@ -30,6 +30,9 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
|
|
||||||
FormToken = formToken;
|
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;
|
CookieToken = cookieToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -177,6 +177,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
return new AntiForgeryTokenSetInternal()
|
return new AntiForgeryTokenSetInternal()
|
||||||
{
|
{
|
||||||
|
// Note : The new cookie would be null if the old cookie is valid.
|
||||||
CookieToken = newCookieToken,
|
CookieToken = newCookieToken,
|
||||||
FormToken = formToken
|
FormToken = formToken
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
return Convert.ToBase64String(claimUidBytes);
|
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.
|
// TODO: Need to enable support for special casing acs identities.
|
||||||
var nameIdentifierClaim = claimsIdentity.FindFirst(claim =>
|
var nameIdentifierClaim = claimsIdentity.FindFirst(claim =>
|
||||||
|
|
|
||||||
|
|
@ -52,3 +52,4 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyVersion("1.0.0.0")]
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
[assembly: InternalsVisibleTo("Microsoft.AspNet.Mvc.Core.Test")]
|
[assembly: InternalsVisibleTo("Microsoft.AspNet.Mvc.Core.Test")]
|
||||||
|
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
|
||||||
|
|
@ -76,7 +76,7 @@ namespace Microsoft.AspNet.Mvc.Core
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <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 <machineKey> configuration specifies explicit encryption and validation keys. AutoGenerate cannot be used in a cluster.
|
/// The anti-forgery token could not be decrypted.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string AntiForgeryToken_DeserializationFailed
|
internal static string AntiForgeryToken_DeserializationFailed
|
||||||
{
|
{
|
||||||
|
|
@ -84,7 +84,7 @@ namespace Microsoft.AspNet.Mvc.Core
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <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 <machineKey> configuration specifies explicit encryption and validation keys. AutoGenerate cannot be used in a cluster.
|
/// The anti-forgery token could not be decrypted.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string FormatAntiForgeryToken_DeserializationFailed()
|
internal static string FormatAntiForgeryToken_DeserializationFailed()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@
|
||||||
<value>The required anti-forgery cookie "{0}" is not present.</value>
|
<value>The required anti-forgery cookie "{0}" is not present.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AntiForgeryToken_DeserializationFailed" xml:space="preserve">
|
<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 <machineKey> 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>
|
||||||
<data name="AntiForgeryToken_FormFieldMissing" xml:space="preserve">
|
<data name="AntiForgeryToken_FormFieldMissing" xml:space="preserve">
|
||||||
<value>The required anti-forgery form field "{0}" is not present.</value>
|
<value>The required anti-forgery form field "{0}" is not present.</value>
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -26,12 +26,24 @@
|
||||||
<Compile Include="ActionResults\RedirectToActionResultTest.cs" />
|
<Compile Include="ActionResults\RedirectToActionResultTest.cs" />
|
||||||
<Compile Include="ActionResults\RedirectToRouteResultTest.cs" />
|
<Compile Include="ActionResults\RedirectToRouteResultTest.cs" />
|
||||||
<Compile Include="ActionSelectionConventionTests.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\AuthorizeAttributeTests.cs" />
|
||||||
<Compile Include="Filters\AuthorizeAttributeTestsBase.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="ControllerTests.cs" />
|
||||||
<Compile Include="DefaultActionSelectorTest.cs" />
|
<Compile Include="DefaultActionSelectorTest.cs" />
|
||||||
<Compile Include="DefaultControllerAssemblyProviderTests.cs" />
|
<Compile Include="DefaultControllerAssemblyProviderTests.cs" />
|
||||||
<Compile Include="DefaultControllerFactoryTest.cs" />
|
<Compile Include="DefaultControllerFactoryTest.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="PropertyHelperTest.cs" />
|
<Compile Include="PropertyHelperTest.cs" />
|
||||||
<Compile Include="ReflectedActionInvokerTest.cs" />
|
<Compile Include="ReflectedActionInvokerTest.cs" />
|
||||||
<Compile Include="Rendering\HtmlAttributePropertyHelperTest.cs" />
|
<Compile Include="Rendering\HtmlAttributePropertyHelperTest.cs" />
|
||||||
|
|
|
||||||
|
|
@ -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")]
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.AspNet.Http": "0.1-alpha-*",
|
"Microsoft.AspNet.Http": "0.1-alpha-*",
|
||||||
|
"Microsoft.AspNet.PipelineCore": "0.1-alpha-*",
|
||||||
"Microsoft.AspNet.Mvc.Core" : "",
|
"Microsoft.AspNet.Mvc.Core" : "",
|
||||||
"Microsoft.AspNet.Mvc" : "",
|
"Microsoft.AspNet.Mvc" : "",
|
||||||
"Microsoft.AspNet.Routing": "0.1-alpha-*",
|
"Microsoft.AspNet.Routing": "0.1-alpha-*",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue