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);
        }
        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);
        }
Пример #3
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();
        }
Пример #4
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 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);
        }
Пример #6
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();
        }
        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 TryValidateTokenSet_FieldTokenMissing()
        {
            // Arrange
            var httpContext = new DefaultHttpContext();

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

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

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


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

            var trimmed = ex.Message.Substring(0, ex.Message.IndexOf(Environment.NewLine));

            Assert.Equal("The required antiforgery request token must be provided.", trimmed);
        }
        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);
        }
        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);
        }
        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);
        }
Пример #12
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);
 }
Пример #13
0
        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);
            }
        }
Пример #14
0
        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);
        }
Пример #16
0
        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);
        }
Пример #17
0
        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);
        }
Пример #18
0
        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);
        }
Пример #19
0
        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);
        }
Пример #20
0
        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);
        }
Пример #21
0
        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);
        }
Пример #23
0
        /* 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);
        }
Пример #24
0
        private bool TryDeserializeTokens(
            HttpContext httpContext,
            AntiforgeryTokenSet antiforgeryTokenSet,
            out AntiforgeryToken cookieToken,
            out AntiforgeryToken requestToken)
        {
            try
            {
                DeserializeTokens(httpContext, antiforgeryTokenSet, out cookieToken, out requestToken);
                return(true);
            }
            catch (AntiforgeryValidationException ex)
            {
                _logger.FailedToDeserialzeTokens(ex);

                cookieToken  = null;
                requestToken = null;
                return(false);
            }
        }
        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];
            using (var rng = RandomNumberGenerator.Create())
            {
                rng.GetBytes(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_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);
        }
Пример #29
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_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 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_FieldAndCookieTokensSwapped_FieldTokenDuplicated()
        {
            // 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, fieldtoken, fieldtoken, out message);

            // Assert
            Assert.False(result);
            Assert.Equal(expectedMessage, message);
        }
        /* 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 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];
            using (var rng = RandomNumberGenerator.Create())
            {
                rng.GetBytes(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 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);
        }
        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 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);
        }
        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);
        }
        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_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_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 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);
        }
        public void TryValidateTokenSet_FieldTokenMissing()
        {
            // Arrange
            var httpContext = new DefaultHttpContext();
            httpContext.User = new ClaimsPrincipal(new ClaimsIdentity());

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

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

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

            var trimmed = ex.Message.Substring(0, ex.Message.IndexOf(Environment.NewLine));
            Assert.Equal("The required antiforgery request token must be provided.", trimmed);
        }
        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_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);
        }
Пример #48
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;
            }
        }