public void GenerateRequestToken_AnonymousUser()
    {
        // Arrange
        var cookieToken = new AntiforgeryToken()
        {
            IsCookieToken = true
        };
        var httpContext = new DefaultHttpContext();

        httpContext.User = new ClaimsPrincipal(new ClaimsIdentity());
        Assert.False(httpContext.User.Identity.IsAuthenticated);

        var tokenProvider = new DefaultAntiforgeryTokenGenerator(
            claimUidExtractor: null,
            additionalDataProvider: null);

        // Act
        var fieldToken = tokenProvider.GenerateRequestToken(httpContext, cookieToken);

        // Assert
        Assert.NotNull(fieldToken);
        Assert.Equal(cookieToken.SecurityToken, fieldToken.SecurityToken);
        Assert.False(fieldToken.IsCookieToken);
        Assert.Empty(fieldToken.Username);
        Assert.Null(fieldToken.ClaimUid);
        Assert.Empty(fieldToken.AdditionalData);
    }
    public void GenerateRequestToken_RegularUserWithUsername()
    {
        // Arrange
        var cookieToken = new AntiforgeryToken()
        {
            IsCookieToken = true
        };

        var httpContext  = new DefaultHttpContext();
        var mockIdentity = new Mock <ClaimsIdentity>();

        mockIdentity.Setup(o => o.IsAuthenticated)
        .Returns(true);
        mockIdentity.Setup(o => o.Name)
        .Returns("my-username");

        httpContext.User = new ClaimsPrincipal(mockIdentity.Object);

        var claimUidExtractor = new Mock <IClaimUidExtractor>().Object;

        var tokenProvider = new DefaultAntiforgeryTokenGenerator(
            claimUidExtractor: claimUidExtractor,
            additionalDataProvider: null);

        // Act
        var fieldToken = tokenProvider.GenerateRequestToken(httpContext, cookieToken);

        // Assert
        Assert.NotNull(fieldToken);
        Assert.Equal(cookieToken.SecurityToken, fieldToken.SecurityToken);
        Assert.False(fieldToken.IsCookieToken);
        Assert.Equal("my-username", fieldToken.Username);
        Assert.Null(fieldToken.ClaimUid);
        Assert.Empty(fieldToken.AdditionalData);
    }
    public void TryValidateTokenSet_FieldAndCookieTokensSwapped_CookieDuplicated()
    {
        // Arrange
        var httpContext = new DefaultHttpContext();

        httpContext.User = new ClaimsPrincipal(new ClaimsIdentity());

        var cookieToken = new AntiforgeryToken()
        {
            IsCookieToken = true
        };
        var fieldtoken = new AntiforgeryToken()
        {
            IsCookieToken = false
        };

        var tokenProvider = new DefaultAntiforgeryTokenGenerator(
            claimUidExtractor: null,
            additionalDataProvider: null);

        string expectedMessage =
            "Validation of the provided antiforgery token failed. " +
            "The cookie token and the request token were swapped.";

        // Act
        string message;
        var    result = tokenProvider.TryValidateTokenSet(httpContext, cookieToken, cookieToken, out message);

        // Assert
        Assert.False(result);
        Assert.Equal(expectedMessage, message);
    }
    public void GenerateRequestToken_AuthenticatedWithoutUsernameAndNoAdditionalData_NoAdditionalData()
    {
        // Arrange
        var cookieToken = new AntiforgeryToken()
        {
            IsCookieToken = true
        };

        var httpContext = new DefaultHttpContext();

        httpContext.User = new ClaimsPrincipal(new MyAuthenticatedIdentityWithoutUsername());

        var options           = new AntiforgeryOptions();
        var claimUidExtractor = new Mock <IClaimUidExtractor>().Object;

        var tokenProvider = new DefaultAntiforgeryTokenGenerator(
            claimUidExtractor: claimUidExtractor,
            additionalDataProvider: null);

        // Act & assert
        var exception = Assert.Throws <InvalidOperationException>(
            () => tokenProvider.GenerateRequestToken(httpContext, cookieToken));

        Assert.Equal(
            "The provided identity of type " +
            $"'{typeof(MyAuthenticatedIdentityWithoutUsername).FullName}' " +
            "is marked IsAuthenticated = true but does not have a value for Name. " +
            "By default, the antiforgery 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 IAntiforgeryAdditionalDataProvider by overriding the " +
            "DefaultAntiforgeryAdditionalDataProvider " +
            "or a custom type that can provide some form of unique identifier for the current user.",
            exception.Message);
    }
Example #5
0
    private void DeserializeTokens(
        HttpContext httpContext,
        AntiforgeryTokenSet antiforgeryTokenSet,
        out AntiforgeryToken cookieToken,
        out AntiforgeryToken requestToken)
    {
        var antiforgeryFeature = GetAntiforgeryFeature(httpContext);

        if (antiforgeryFeature.HaveDeserializedCookieToken)
        {
            cookieToken = antiforgeryFeature.CookieToken !;
        }
        else
        {
            cookieToken = _tokenSerializer.Deserialize(antiforgeryTokenSet.CookieToken !);

            antiforgeryFeature.CookieToken = cookieToken;
            antiforgeryFeature.HaveDeserializedCookieToken = true;
        }

        if (antiforgeryFeature.HaveDeserializedRequestToken)
        {
            requestToken = antiforgeryFeature.RequestToken !;
        }
        else
        {
            requestToken = _tokenSerializer.Deserialize(antiforgeryTokenSet.RequestToken !);

            antiforgeryFeature.RequestToken = requestToken;
            antiforgeryFeature.HaveDeserializedRequestToken = true;
        }
    }
    public void GenerateRequestToken_AuthenticatedWithoutUsername_WithAdditionalData()
    {
        // Arrange
        var cookieToken = new AntiforgeryToken()
        {
            IsCookieToken = true
        };

        var httpContext = new DefaultHttpContext();

        httpContext.User = new ClaimsPrincipal(new MyAuthenticatedIdentityWithoutUsername());

        var mockAdditionalDataProvider = new Mock <IAntiforgeryAdditionalDataProvider>();

        mockAdditionalDataProvider.Setup(o => o.GetAdditionalData(httpContext))
        .Returns("additional-data");

        var claimUidExtractor = new Mock <IClaimUidExtractor>().Object;

        var tokenProvider = new DefaultAntiforgeryTokenGenerator(
            claimUidExtractor: claimUidExtractor,
            additionalDataProvider: mockAdditionalDataProvider.Object);

        // Act
        var fieldToken = tokenProvider.GenerateRequestToken(httpContext, cookieToken);

        // Assert
        Assert.NotNull(fieldToken);
        Assert.Equal(cookieToken.SecurityToken, fieldToken.SecurityToken);
        Assert.False(fieldToken.IsCookieToken);
        Assert.Empty(fieldToken.Username);
        Assert.Null(fieldToken.ClaimUid);
        Assert.Equal("additional-data", fieldToken.AdditionalData);
    }
Example #7
0
    public void Serialize_FieldToken_WithClaimUid_TokenRoundTripSuccessful()
    {
        // Arrange
        var testSerializer = new DefaultAntiforgeryTokenSerializer(_dataProtector.Object, _pool);

        //"01" // Version
        //+ "705EEDCC7D42F1D6B3B98A593625BB4C" // SecurityToken
        //+ "00" // IsCookieToken
        //+ "01" // IsClaimsBased
        //+ "6F1648E97249AA58754036A67E248CF044F07ECFB0ED387556CE029A4F9A40E0" // ClaimUid
        //+ "05" // AdditionalData length header
        //+ "E282AC3437"; // AdditionalData ("€47") as UTF8
        var token = new AntiforgeryToken()
        {
            SecurityToken  = _securityToken,
            IsCookieToken  = false,
            ClaimUid       = _claimUid,
            AdditionalData = "€47"
        };

        // Act
        var actualSerializedData = testSerializer.Serialize(token);
        var deserializedToken    = testSerializer.Deserialize(actualSerializedData);

        // Assert
        AssertTokensEqual(token, deserializedToken);
        _dataProtector.Verify();
    }
Example #8
0
    public void Serialize_FieldToken_WithUsername_TokenRoundTripSuccessful()
    {
        // Arrange
        var testSerializer = new DefaultAntiforgeryTokenSerializer(_dataProtector.Object, _pool);

        //"01" // Version
        //+ "705EEDCC7D42F1D6B3B98A593625BB4C" // SecurityToken
        //+ "00" // IsCookieToken
        //+ "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,
            IsCookieToken  = false,
            Username       = "******",
            AdditionalData = "€47"
        };

        // Act
        var actualSerializedData = testSerializer.Serialize(token);
        var deserializedToken    = testSerializer.Deserialize(actualSerializedData);

        // Assert
        AssertTokensEqual(token, deserializedToken);
        _dataProtector.Verify();
    }
    public void TryValidateTokenSet_FieldAndCookieTokensHaveDifferentSecurityKeys()
    {
        // Arrange
        var httpContext = new DefaultHttpContext();

        httpContext.User = new ClaimsPrincipal(new ClaimsIdentity());

        var cookieToken = new AntiforgeryToken()
        {
            IsCookieToken = true
        };
        var fieldtoken = new AntiforgeryToken()
        {
            IsCookieToken = false
        };

        var tokenProvider = new DefaultAntiforgeryTokenGenerator(
            claimUidExtractor: null,
            additionalDataProvider: null);

        string expectedMessage = "The antiforgery cookie token and request token do not match.";

        // Act
        string message;
        var    result = tokenProvider.TryValidateTokenSet(httpContext, cookieToken, fieldtoken, out message);

        // Assert
        Assert.False(result);
        Assert.Equal(expectedMessage, message);
    }
Example #10
0
 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.IsCookieToken, actual.IsCookieToken);
     Assert.Equal(expected.SecurityToken, actual.SecurityToken);
     Assert.Equal(expected.Username, actual.Username);
 }
    public string Serialize(AntiforgeryToken token)
    {
        if (token == null)
        {
            throw new ArgumentNullException(nameof(token));
        }

        var serializationContext = _pool.Get();

        try
        {
            var writer = serializationContext.Writer;
            writer.Write(TokenVersion);
            writer.Write(token.SecurityToken !.GetData());
            writer.Write(token.IsCookieToken);

            if (!token.IsCookieToken)
            {
                if (token.ClaimUid != null)
                {
                    writer.Write(true /* isClaimsBased */);
                    writer.Write(token.ClaimUid.GetData());
                }
                else
                {
                    writer.Write(false /* isClaimsBased */);
                    writer.Write(token.Username !);
                }

                writer.Write(token.AdditionalData);
            }

            writer.Flush();
            var stream = serializationContext.Stream;
            var bytes  = _cryptoSystem.Protect(stream.ToArray());

            var count         = bytes.Length;
            var charsRequired = WebEncoders.GetArraySizeRequiredToEncode(count);
            var chars         = serializationContext.GetChars(charsRequired);
            var outputLength  = WebEncoders.Base64UrlEncode(
                bytes,
                offset: 0,
                output: chars,
                outputOffset: 0,
                count: count);

            return(new string(chars, startIndex : 0, length : outputLength));
        }
        finally
        {
            _pool.Return(serializationContext);
        }
    }
    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);
    }
    public void IsCookieTokenValid_NullToken_ReturnsFalse()
    {
        // Arrange
        AntiforgeryToken cookieToken = null;
        var tokenProvider            = new DefaultAntiforgeryTokenGenerator(
            claimUidExtractor: null,
            additionalDataProvider: null);

        // Act
        var isValid = tokenProvider.IsCookieTokenValid(cookieToken);

        // Assert
        Assert.False(isValid);
    }
    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);
    }
    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);
    }
    public void UsernameProperty()
    {
        // Arrange
        var token = new AntiforgeryToken();

        // Act & assert - 1
        Assert.Equal("", token.Username);

        // Act & assert - 2
        token.Username = "******";
        Assert.Equal("my username", token.Username);

        // Act & assert - 3
        token.Username = null;
        Assert.Equal("", token.Username);
    }
    public void IsCookieTokenProperty()
    {
        // Arrange
        var token = new AntiforgeryToken();

        // Act & assert - 1
        Assert.False(token.IsCookieToken);

        // Act & assert - 2
        token.IsCookieToken = true;
        Assert.True(token.IsCookieToken);

        // Act & assert - 3
        token.IsCookieToken = false;
        Assert.False(token.IsCookieToken);
    }
    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);
    }
    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);
    }
    public void IsCookieTokenValid_ValidToken_ReturnsTrue()
    {
        // Arrange
        var cookieToken = new AntiforgeryToken()
        {
            IsCookieToken = true
        };

        var tokenProvider = new DefaultAntiforgeryTokenGenerator(
            claimUidExtractor: null,
            additionalDataProvider: null);

        // Act
        var isValid = tokenProvider.IsCookieTokenValid(cookieToken);

        // Assert
        Assert.True(isValid);
    }
    /* The serialized format of the anti-XSRF token is as follows:
     * Version: 1 byte integer
     * SecurityToken: 16 byte binary blob
     * IsCookieToken: 1 byte Boolean
     * [if IsCookieToken != true]
     *   +- IsClaimsBased: 1 byte Boolean
     *   |  [if IsClaimsBased = true]
     *   |    `- ClaimUid: 32 byte binary blob
     *   |  [if IsClaimsBased = false]
     *   |    `- Username: UTF-8 string with 7-bit integer length prefix
     *   `- AdditionalData: UTF-8 string with 7-bit integer length prefix
     */
    private static AntiforgeryToken?Deserialize(BinaryReader reader)
    {
        // we can only consume tokens of the same serialized version that we generate
        var embeddedVersion = reader.ReadByte();

        if (embeddedVersion != TokenVersion)
        {
            return(null);
        }

        var deserializedToken  = new AntiforgeryToken();
        var securityTokenBytes = reader.ReadBytes(AntiforgeryToken.SecurityTokenBitLength / 8);

        deserializedToken.SecurityToken =
            new BinaryBlob(AntiforgeryToken.SecurityTokenBitLength, securityTokenBytes);
        deserializedToken.IsCookieToken = reader.ReadBoolean();

        if (!deserializedToken.IsCookieToken)
        {
            var isClaimsBased = reader.ReadBoolean();
            if (isClaimsBased)
            {
                var claimUidBytes = reader.ReadBytes(AntiforgeryToken.ClaimUidBitLength / 8);
                deserializedToken.ClaimUid = new BinaryBlob(AntiforgeryToken.ClaimUidBitLength, claimUidBytes);
            }
            else
            {
                deserializedToken.Username = reader.ReadString();
            }

            deserializedToken.AdditionalData = reader.ReadString();
        }

        // if there's still unconsumed data in the stream, fail
        if (reader.BaseStream.ReadByte() != -1)
        {
            return(null);
        }

        // success
        return(deserializedToken);
    }
    public void TryValidateTokenSet_ClaimUidMismatch()
    {
        // Arrange
        var httpContext = new DefaultHttpContext();
        var identity    = GetAuthenticatedIdentity("the-user");

        httpContext.User = new ClaimsPrincipal(identity);

        var cookieToken = new AntiforgeryToken()
        {
            IsCookieToken = true
        };
        var fieldtoken = new AntiforgeryToken()
        {
            SecurityToken = cookieToken.SecurityToken,
            IsCookieToken = false,
            ClaimUid      = new BinaryBlob(256)
        };

        var differentToken        = new BinaryBlob(256);
        var mockClaimUidExtractor = new Mock <IClaimUidExtractor>();

        mockClaimUidExtractor.Setup(o => o.ExtractClaimUid(It.Is <ClaimsPrincipal>(c => c.Identity == identity)))
        .Returns(Convert.ToBase64String(differentToken.GetData()));

        var tokenProvider = new DefaultAntiforgeryTokenGenerator(
            claimUidExtractor: mockClaimUidExtractor.Object,
            additionalDataProvider: null);

        string expectedMessage =
            "The provided antiforgery token was meant for a different " +
            "claims-based user than the current user.";

        // Act
        string message;
        var    result = tokenProvider.TryValidateTokenSet(httpContext, cookieToken, fieldtoken, out message);

        // Assert
        Assert.False(result);
        Assert.Equal(expectedMessage, message);
    }
    public void TryValidateTokenSet_AdditionalDataRejected()
    {
        // Arrange
        var httpContext = new DefaultHttpContext();
        var identity    = new ClaimsIdentity();

        httpContext.User = new ClaimsPrincipal(identity);

        var cookieToken = new AntiforgeryToken()
        {
            IsCookieToken = true
        };
        var fieldtoken = new AntiforgeryToken()
        {
            SecurityToken  = cookieToken.SecurityToken,
            Username       = String.Empty,
            IsCookieToken  = false,
            AdditionalData = "some-additional-data"
        };

        var mockAdditionalDataProvider = new Mock <IAntiforgeryAdditionalDataProvider>();

        mockAdditionalDataProvider
        .Setup(o => o.ValidateAdditionalData(httpContext, "some-additional-data"))
        .Returns(false);

        var tokenProvider = new DefaultAntiforgeryTokenGenerator(
            claimUidExtractor: null,
            additionalDataProvider: mockAdditionalDataProvider.Object);

        string expectedMessage = "The provided antiforgery token failed a custom data check.";

        // Act
        string message;
        var    result = tokenProvider.TryValidateTokenSet(httpContext, cookieToken, fieldtoken, out message);

        // Assert
        Assert.False(result);
        Assert.Equal(expectedMessage, message);
    }
    public void TryValidateTokenSet_UsernameMismatch(string identityUsername, string embeddedUsername)
    {
        // Arrange
        var httpContext = new DefaultHttpContext();
        var identity    = GetAuthenticatedIdentity(identityUsername);

        httpContext.User = new ClaimsPrincipal(identity);

        var cookieToken = new AntiforgeryToken()
        {
            IsCookieToken = true
        };
        var fieldtoken = new AntiforgeryToken()
        {
            SecurityToken = cookieToken.SecurityToken,
            Username      = embeddedUsername,
            IsCookieToken = false
        };

        var mockClaimUidExtractor = new Mock <IClaimUidExtractor>();

        mockClaimUidExtractor.Setup(o => o.ExtractClaimUid(It.Is <ClaimsPrincipal>(c => c.Identity == identity)))
        .Returns((string)null);

        var tokenProvider = new DefaultAntiforgeryTokenGenerator(
            claimUidExtractor: mockClaimUidExtractor.Object,
            additionalDataProvider: null);

        string expectedMessage =
            $"The provided antiforgery token was meant for user \"{embeddedUsername}\", " +
            $"but the current user is \"{identityUsername}\".";

        // Act
        string message;
        var    result = tokenProvider.TryValidateTokenSet(httpContext, cookieToken, fieldtoken, out message);

        // Assert
        Assert.False(result);
        Assert.Equal(expectedMessage, message);
    }
Example #25
0
    public void Serialize_CookieToken_TokenRoundTripSuccessful()
    {
        // Arrange
        var testSerializer = new DefaultAntiforgeryTokenSerializer(_dataProtector.Object, _pool);

        //"01" // Version
        //+ "705EEDCC7D42F1D6B3B98A593625BB4C" // SecurityToken
        //+ "01"; // IsCookieToken
        var token = new AntiforgeryToken()
        {
            SecurityToken = _securityToken,
            IsCookieToken = true
        };

        // Act
        string actualSerializedData = testSerializer.Serialize(token);
        var    deserializedToken    = testSerializer.Deserialize(actualSerializedData);

        // Assert
        AssertTokensEqual(token, deserializedToken);
        _dataProtector.Verify();
    }
    public void GenerateRequestToken_InvalidCookieToken()
    {
        // Arrange
        var cookieToken = new AntiforgeryToken()
        {
            IsCookieToken = false
        };
        var httpContext = new DefaultHttpContext();

        httpContext.User = new ClaimsPrincipal(new ClaimsIdentity());
        Assert.False(httpContext.User.Identity.IsAuthenticated);

        var tokenProvider = new DefaultAntiforgeryTokenGenerator(
            claimUidExtractor: null,
            additionalDataProvider: null);

        // Act & Assert
        ExceptionAssert.ThrowsArgument(
            () => tokenProvider.GenerateRequestToken(httpContext, cookieToken),
            "cookieToken",
            "The antiforgery cookie token is invalid.");
    }
    public void GenerateRequestToken_ClaimsBasedIdentity()
    {
        // Arrange
        var cookieToken = new AntiforgeryToken()
        {
            IsCookieToken = true
        };

        var identity    = GetAuthenticatedIdentity("some-identity");
        var httpContext = new DefaultHttpContext();

        httpContext.User = new ClaimsPrincipal(identity);

        byte[] data = new byte[256 / 8];
        RandomNumberGenerator.Fill(data);
        var base64ClaimUId   = Convert.ToBase64String(data);
        var expectedClaimUid = new BinaryBlob(256, data);

        var mockClaimUidExtractor = new Mock <IClaimUidExtractor>();

        mockClaimUidExtractor.Setup(o => o.ExtractClaimUid(It.Is <ClaimsPrincipal>(c => c.Identity == identity)))
        .Returns(base64ClaimUId);

        var tokenProvider = new DefaultAntiforgeryTokenGenerator(
            claimUidExtractor: mockClaimUidExtractor.Object,
            additionalDataProvider: null);

        // Act
        var fieldToken = tokenProvider.GenerateRequestToken(httpContext, cookieToken);

        // Assert
        Assert.NotNull(fieldToken);
        Assert.Equal(cookieToken.SecurityToken, fieldToken.SecurityToken);
        Assert.False(fieldToken.IsCookieToken);
        Assert.Equal("", fieldToken.Username);
        Assert.Equal(expectedClaimUid, fieldToken.ClaimUid);
        Assert.Equal("", fieldToken.AdditionalData);
    }
    public void TryValidateTokenSet_CookieTokenMissing()
    {
        // Arrange
        var httpContext = new DefaultHttpContext();

        httpContext.User = new ClaimsPrincipal(new ClaimsIdentity());

        var fieldtoken = new AntiforgeryToken()
        {
            IsCookieToken = false
        };

        var tokenProvider = new DefaultAntiforgeryTokenGenerator(
            claimUidExtractor: null,
            additionalDataProvider: null);

        // Act & Assert
        string message;
        var    ex = Assert.Throws <ArgumentNullException>(
            () => tokenProvider.TryValidateTokenSet(httpContext, null, fieldtoken, out message));

        Assert.StartsWith(@"The required antiforgery cookie token must be provided.", ex.Message);
    }
    public void TryValidateTokenSet_Success_AuthenticatedUserWithUsername()
    {
        // Arrange
        var httpContext = new DefaultHttpContext();
        var identity    = GetAuthenticatedIdentity("the-user");

        httpContext.User = new ClaimsPrincipal(identity);

        var cookieToken = new AntiforgeryToken()
        {
            IsCookieToken = true
        };
        var fieldtoken = new AntiforgeryToken()
        {
            SecurityToken  = cookieToken.SecurityToken,
            Username       = "******",
            IsCookieToken  = false,
            AdditionalData = "some-additional-data"
        };

        var mockAdditionalDataProvider = new Mock <IAntiforgeryAdditionalDataProvider>();

        mockAdditionalDataProvider.Setup(o => o.ValidateAdditionalData(httpContext, "some-additional-data"))
        .Returns(true);

        var tokenProvider = new DefaultAntiforgeryTokenGenerator(
            claimUidExtractor: new Mock <IClaimUidExtractor>().Object,
            additionalDataProvider: mockAdditionalDataProvider.Object);

        // Act
        string message;
        var    result = tokenProvider.TryValidateTokenSet(httpContext, cookieToken, fieldtoken, out message);

        // Assert
        Assert.True(result);
        Assert.Null(message);
    }
    public void TryValidateTokenSet_Success_ClaimsBasedUser()
    {
        // Arrange
        var httpContext = new DefaultHttpContext();
        var identity    = GetAuthenticatedIdentity("the-user");

        httpContext.User = new ClaimsPrincipal(identity);

        var cookieToken = new AntiforgeryToken()
        {
            IsCookieToken = true
        };
        var fieldtoken = new AntiforgeryToken()
        {
            SecurityToken = cookieToken.SecurityToken,
            IsCookieToken = false,
            ClaimUid      = new BinaryBlob(256)
        };

        var mockClaimUidExtractor = new Mock <IClaimUidExtractor>();

        mockClaimUidExtractor.Setup(o => o.ExtractClaimUid(It.Is <ClaimsPrincipal>(c => c.Identity == identity)))
        .Returns(Convert.ToBase64String(fieldtoken.ClaimUid.GetData()));

        var tokenProvider = new DefaultAntiforgeryTokenGenerator(
            claimUidExtractor: mockClaimUidExtractor.Object,
            additionalDataProvider: null);

        // Act
        string message;
        var    result = tokenProvider.TryValidateTokenSet(httpContext, cookieToken, fieldtoken, out message);

        // Assert
        Assert.True(result);
        Assert.Null(message);
    }