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;
            }
        }
Example #2
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);
            }
        }
Example #3
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);
        }
        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);
            }
        }
Example #5
0
        /// <inheritdoc />
        public AntiforgeryToken GenerateRequestToken(
            HttpContext httpContext,
            AntiforgeryToken cookieToken)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException(nameof(httpContext));
            }

            if (cookieToken == null)
            {
                throw new ArgumentNullException(nameof(cookieToken));
            }

            if (!IsCookieTokenValid(cookieToken))
            {
                throw new ArgumentException(
                          Resources.Antiforgery_CookieToken_IsInvalid,
                          nameof(cookieToken));
            }

            var requestToken = new AntiforgeryToken()
            {
                SecurityToken = cookieToken.SecurityToken,
                IsCookieToken = false
            };

            var isIdentityAuthenticated = false;

            // populate Username and ClaimUid
            var authenticatedIdentity = GetAuthenticatedIdentity(httpContext.User);

            if (authenticatedIdentity != null)
            {
                isIdentityAuthenticated = true;
                requestToken.ClaimUid   = GetClaimUidBlob(_claimUidExtractor.ExtractClaimUid(httpContext.User));

                if (requestToken.ClaimUid == null)
                {
                    requestToken.Username = authenticatedIdentity.Name;
                }
            }

            // populate AdditionalData
            if (_additionalDataProvider != null)
            {
                requestToken.AdditionalData = _additionalDataProvider.GetAdditionalData(httpContext);
            }

            if (isIdentityAuthenticated &&
                string.IsNullOrEmpty(requestToken.Username) &&
                requestToken.ClaimUid == null &&
                string.IsNullOrEmpty(requestToken.AdditionalData))
            {
                // Application says user is authenticated, but we have no identifier for the user.
                throw new InvalidOperationException(
                          Resources.FormatAntiforgeryTokenValidator_AuthenticatedUserWithoutUsername(
                              authenticatedIdentity.GetType(),
                              nameof(IIdentity.IsAuthenticated),
                              "true",
                              nameof(IIdentity.Name),
                              nameof(IAntiforgeryAdditionalDataProvider),
                              nameof(DefaultAntiforgeryAdditionalDataProvider)));
            }

            return(requestToken);
        }
Example #6
0
        /// <inheritdoc />
        public bool TryValidateTokenSet(
            HttpContext httpContext,
            AntiforgeryToken cookieToken,
            AntiforgeryToken requestToken,
            out string message)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException(nameof(httpContext));
            }

            if (cookieToken == null)
            {
                throw new ArgumentNullException(
                          nameof(cookieToken),
                          Resources.Antiforgery_CookieToken_MustBeProvided_Generic);
            }

            if (requestToken == null)
            {
                throw new ArgumentNullException(
                          nameof(requestToken),
                          Resources.Antiforgery_RequestToken_MustBeProvided_Generic);
            }

            // Do the tokens have the correct format?
            if (!cookieToken.IsCookieToken || requestToken.IsCookieToken)
            {
                message = Resources.AntiforgeryToken_TokensSwapped;
                return(false);
            }

            // Are the security tokens embedded in each incoming token identical?
            if (!object.Equals(cookieToken.SecurityToken, requestToken.SecurityToken))
            {
                message = Resources.AntiforgeryToken_SecurityTokenMismatch;
                return(false);
            }

            // Is the incoming token meant for the current user?
            var        currentUsername = string.Empty;
            BinaryBlob currentClaimUid = null;

            var authenticatedIdentity = GetAuthenticatedIdentity(httpContext.User);

            if (authenticatedIdentity != null)
            {
                currentClaimUid = GetClaimUidBlob(_claimUidExtractor.ExtractClaimUid(httpContext.User));
                if (currentClaimUid == null)
                {
                    currentUsername = authenticatedIdentity.Name ?? string.Empty;
                }
            }

            // OpenID and other similar authentication schemes use URIs for the username.
            // These should be treated as case-sensitive.
            var comparer = StringComparer.OrdinalIgnoreCase;

            if (currentUsername.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ||
                currentUsername.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
            {
                comparer = StringComparer.Ordinal;
            }

            if (!comparer.Equals(requestToken.Username, currentUsername))
            {
                message = Resources.FormatAntiforgeryToken_UsernameMismatch(requestToken.Username, currentUsername);
                return(false);
            }

            if (!object.Equals(requestToken.ClaimUid, currentClaimUid))
            {
                message = Resources.AntiforgeryToken_ClaimUidMismatch;
                return(false);
            }

            // Is the AdditionalData valid?
            if (_additionalDataProvider != null &&
                !_additionalDataProvider.ValidateAdditionalData(httpContext, requestToken.AdditionalData))
            {
                message = Resources.AntiforgeryToken_AdditionalDataCheckFailed;
                return(false);
            }

            message = null;
            return(true);
        }
Example #7
0
 /// <inheritdoc />
 public bool IsCookieTokenValid(AntiforgeryToken cookieToken)
 {
     return(cookieToken != null && cookieToken.IsCookieToken);
 }