// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. using System.Collections.Generic; using System.Reflection; using System.Security.Principal; using System.Web.Helpers.Claims; using System.Web.Helpers.Claims.Test; using System.Web.Helpers.Test; using Moq; using Xunit; using Xunit.Extensions; using Assert = Microsoft.TestCommon.AssertEx; namespace System.Web.Helpers.AntiXsrf.Test { public class ClaimUidExtractorTest { [Fact] public void ExtractClaimUid_NullIdentity() { // Arrange ClaimUidExtractor extractor = new ClaimUidExtractor( config: null, claimsIdentityConverter: null); // Act BinaryBlob retVal = extractor.ExtractClaimUid(null); // Assert Assert.Null(retVal); } [Fact] public void ExtractClaimUid_Unauthenticated() { // Arrange ClaimUidExtractor extractor = new ClaimUidExtractor( config: null, claimsIdentityConverter: null); Mock mockIdentity = new Mock(); mockIdentity.Setup(o => o.IsAuthenticated).Returns(false); // Act BinaryBlob retVal = extractor.ExtractClaimUid(mockIdentity.Object); // Assert Assert.Null(retVal); } [Fact] public void ExtractClaimUid_ClaimsIdentityHeuristicsSuppressed() { // Arrange GenericIdentity identity = new GenericIdentity("the-user"); MockAntiForgeryConfig config = new MockAntiForgeryConfig() { SuppressIdentityHeuristicChecks = true }; ClaimUidExtractor extractor = new ClaimUidExtractor( config: config, claimsIdentityConverter: null); // Act BinaryBlob retVal = extractor.ExtractClaimUid(identity); // Assert Assert.Null(retVal); } [Fact] public void ExtractClaimUid_NotAClaimsIdentity() { // Arrange Mock mockIdentity = new Mock(); mockIdentity.Setup(o => o.IsAuthenticated).Returns(true); MockAntiForgeryConfig config = new MockAntiForgeryConfig(); ClaimsIdentityConverter converter = new ClaimsIdentityConverter(new Func[0]); ClaimUidExtractor extractor = new ClaimUidExtractor( config: config, claimsIdentityConverter: converter); // Act BinaryBlob retVal = extractor.ExtractClaimUid(mockIdentity.Object); // Assert Assert.Null(retVal); } [Fact] public void ExtractClaimUid_ClaimsIdentity() { // Arrange Mock mockIdentity = new Mock(); mockIdentity.Setup(o => o.IsAuthenticated).Returns(true); MockAntiForgeryConfig config = new MockAntiForgeryConfig() { UniqueClaimTypeIdentifier = "unique-identifier" }; ClaimsIdentityConverter converter = new ClaimsIdentityConverter(new Func[] { identity => { Assert.Equal(mockIdentity.Object, identity); MockClaimsIdentity claimsIdentity = new MockClaimsIdentity(); claimsIdentity.AddClaim("unique-identifier", "some-value"); return claimsIdentity; } }); ClaimUidExtractor extractor = new ClaimUidExtractor( config: config, claimsIdentityConverter: converter); // Act BinaryBlob retVal = extractor.ExtractClaimUid(mockIdentity.Object); // Assert Assert.NotNull(retVal); Assert.Equal("CA9CCFF86F903FBB7505BAAA9F222E49EC2A1E8FAD630AE73DE180BD679751ED", HexUtil.HexEncode(retVal.GetData())); } [Theory] [DefaultUniqueClaimTypes_NotPresent_Data] public void DefaultUniqueClaimTypes_NotPresent_Throws(object identity) { // Arrange ClaimsIdentity claimsIdentity = (ClaimsIdentity)identity; // Act & assert var ex = Assert.Throws(() => ClaimUidExtractor.GetUniqueIdentifierParameters(claimsIdentity, null)); Assert.Equal(@"A claim of type 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier' or 'http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider' was not present on the provided ClaimsIdentity. To enable anti-forgery token support with claims-based authentication, please verify that the configured claims provider is providing both of these claims on the ClaimsIdentity instances it generates. If the configured claims provider instead uses a different claim type as a unique identifier, it can be configured by setting the static property AntiForgeryConfig.UniqueClaimTypeIdentifier.", ex.Message); } [Fact] public void DefaultUniqueClaimTypes_Present() { // Arrange MockClaimsIdentity identity = new MockClaimsIdentity(); identity.AddClaim("fooClaim", "fooClaimValue"); identity.AddClaim(ClaimUidExtractor.NameIdentifierClaimType, "nameIdentifierValue"); identity.AddClaim(ClaimUidExtractor.IdentityProviderClaimType, "identityProviderValue"); // Act var retVal = ClaimUidExtractor.GetUniqueIdentifierParameters(identity, null); // Assert Assert.Equal(new string[] { ClaimUidExtractor.NameIdentifierClaimType, "nameIdentifierValue", ClaimUidExtractor.IdentityProviderClaimType, "identityProviderValue" }, retVal); } [Fact] public void ExplicitUniqueClaimType_Present() { // Arrange MockClaimsIdentity identity = new MockClaimsIdentity(); identity.AddClaim("fooClaim", "fooClaimValue"); identity.AddClaim(ClaimUidExtractor.NameIdentifierClaimType, "nameIdentifierValue"); identity.AddClaim(ClaimUidExtractor.IdentityProviderClaimType, "identityProviderValue"); // Act var retVal = ClaimUidExtractor.GetUniqueIdentifierParameters(identity, "fooClaim"); // Assert Assert.Equal(new string[] { "fooClaim", "fooClaimValue" }, retVal); } [Theory] [ExplicitUniqueClaimType_NotPresent_Data] public void ExplicitUniqueClaimType_NotPresent_Throws(object identity) { // Arrange ClaimsIdentity claimsIdentity = (ClaimsIdentity)identity; // Act & assert var ex = Assert.Throws(() => ClaimUidExtractor.GetUniqueIdentifierParameters(claimsIdentity, "fooClaim")); Assert.Equal(@"A claim of type 'fooClaim' was not present on the provided ClaimsIdentity.", ex.Message); } private sealed class DefaultUniqueClaimTypes_NotPresent_DataAttribute : DataAttribute { public override IEnumerable GetData(MethodInfo methodUnderTest, Type[] parameterTypes) { MockClaimsIdentity identity1 = new MockClaimsIdentity(); identity1.AddClaim(ClaimUidExtractor.IdentityProviderClaimType, "identityProviderValue"); yield return new object[] { identity1 }; MockClaimsIdentity identity2 = new MockClaimsIdentity(); identity2.AddClaim(ClaimUidExtractor.NameIdentifierClaimType, String.Empty); identity2.AddClaim(ClaimUidExtractor.IdentityProviderClaimType, "identityProviderValue"); yield return new object[] { identity2 }; MockClaimsIdentity identity3 = new MockClaimsIdentity(); identity3.AddClaim(ClaimUidExtractor.NameIdentifierClaimType, "nameIdentifierValue"); yield return new object[] { identity3 }; MockClaimsIdentity identity4 = new MockClaimsIdentity(); identity4.AddClaim(ClaimUidExtractor.NameIdentifierClaimType, "nameIdentifierValue"); identity4.AddClaim(ClaimUidExtractor.IdentityProviderClaimType, String.Empty); yield return new object[] { identity4 }; MockClaimsIdentity identity5 = new MockClaimsIdentity(); identity5.AddClaim(ClaimUidExtractor.NameIdentifierClaimType.ToUpper(), "nameIdentifierValue"); identity5.AddClaim(ClaimUidExtractor.IdentityProviderClaimType.ToUpper(), "identityProviderValue"); yield return new object[] { identity5 }; } } private sealed class ExplicitUniqueClaimType_NotPresent_DataAttribute : DataAttribute { public override IEnumerable GetData(MethodInfo methodUnderTest, Type[] parameterTypes) { MockClaimsIdentity identity1 = new MockClaimsIdentity(); yield return new object[] { identity1 }; MockClaimsIdentity identity2 = new MockClaimsIdentity(); identity2.AddClaim("fooClaim", String.Empty); yield return new object[] { identity2 }; MockClaimsIdentity identity3 = new MockClaimsIdentity(); identity3.AddClaim("FOOCLAIM", "fooClaimValue"); yield return new object[] { identity3 }; MockClaimsIdentity identity4 = new MockClaimsIdentity(); identity4.AddClaim(ClaimUidExtractor.NameIdentifierClaimType, "nameIdentifierValue"); identity4.AddClaim(ClaimUidExtractor.IdentityProviderClaimType, "identityProviderValue"); yield return new object[] { identity4 }; } } } }