/// <summary>
        /// </summary>
        /// 
        /// <remarks>
        /// In order to avoid unnecessary authentication actions, it is 
        /// expected that the caller will first call 
        /// <cref name="IsAuthenticationExpired"/> before calling this.
        /// </remarks>
        /// 
        /// <param name="result">
        /// The authenticated session token.
        /// </param>
        /// 
        internal void Update(
            CreateAuthenticationTokenResult result)
        {
            LastRefreshed = DateTime.UtcNow;
            RefreshCounter++;

            AuthenticationResult = result;

            IsAuthenticationResultExpired = false;
        }
 /// <summary>
 /// Gets a value indicating whether the result contains a successfully 
 /// authenticated token.
 /// </summary>
 /// 
 /// <param name="result">
 /// The result to query.
 /// </param>
 /// 
 /// <returns>
 /// <b>true</b> if the result contains a successfully 
 /// authenticated token; otherwise, <b>false</b>.
 /// </returns> 
 /// 
 internal static bool IsAuthenticated(CreateAuthenticationTokenResult result)
 {
     return (result != null
             && result.Status == AuthenticationTokenCreationStatus.Success
             && result.ApplicationRecordAuthorizationAction ==
                 ApplicationRecordAuthorizationAction.NoActionRequired
             && !String.IsNullOrEmpty(result.AuthenticationToken));
 }
        /// <summary>
        /// Gets one or more authorization tokens from the response XML.
        /// </summary>
        /// 
        /// <param name="navTokenIterator">
        /// The path to the token or tokens.
        /// </param>
        /// 
        /// <param name="createAuthTokenResult">
        /// The token results.
        /// </param>
        /// 
        private static void GetTokenByParseResponse(
            XPathNodeIterator navTokenIterator,
            CreateAuthenticationTokenResult createAuthTokenResult)
        {
            foreach (XPathNavigator tokenNav in navTokenIterator)
            {
                Guid applicationId = new Guid(tokenNav.GetAttribute("app-id",
                            String.Empty));

                ApplicationRecordAuthorizationAction action =
                    ApplicationRecordAuthorizationAction.Unknown;
                try
                {
                    action =
                        (ApplicationRecordAuthorizationAction)Enum.Parse(
                            typeof(ApplicationRecordAuthorizationAction),
                            tokenNav.GetAttribute("app-record-auth-action",
                                String.Empty));
                }
                catch (ArgumentException)
                {
                }

                createAuthTokenResult.ApplicationId = applicationId;
                createAuthTokenResult.Status = AuthenticationTokenCreationStatus.Success;
                createAuthTokenResult.AuthenticationToken = tokenNav.Value;
                createAuthTokenResult.ApplicationRecordAuthorizationAction = action;
            }
        }
        /// <summary>
        /// Extracts the absence reasons from the response XML.
        /// </summary>
        /// 
        private void GetAbsenceReasons(
            CreateAuthenticationTokenResult createAuthTokenResult,
            XPathNavigator nav)
        {
            XPathExpression absenceReasonPath = GetAbsenceReasonXPath(nav);
            XPathNodeIterator navTokenIterator = nav.Select(absenceReasonPath);

            GetAbsenceReasonByParseResponse(
                navTokenIterator,
                createAuthTokenResult);
        }
 /// <summary>
 /// Inserts a dictionary of authentication results.
 /// </summary>
 /// 
 /// <param name="result">
 /// The authentication result.
 /// </param>
 /// 
 internal virtual void UpdateAuthenticationResults(
     CreateAuthenticationTokenResult result)
 {
     AddAuthenticationResult(result);
 }
        /// <summary>
        /// Gets absence reasons regarding why there are no auth tokens 
        /// from the response XML.
        /// </summary>
        /// 
        /// <param name="navTokenIterator">
        /// The path to the token or tokens.
        /// </param>
        /// 
        /// <param name="createAuthTokenResult">
        /// The token results.
        /// </param>
        /// 
        private static void GetAbsenceReasonByParseResponse(
            XPathNodeIterator navTokenIterator,
            CreateAuthenticationTokenResult createAuthTokenResult)
        {
            foreach (XPathNavigator tokenNav in navTokenIterator)
            {
                Guid applicationId = new Guid(tokenNav.GetAttribute("app-id",
                            String.Empty));

                try
                {
                    createAuthTokenResult.Status =
                        (AuthenticationTokenCreationStatus)Enum.Parse(
                            typeof(AuthenticationTokenCreationStatus),
                            tokenNav.Value);
                }
                catch (ArgumentException)
                {
                    createAuthTokenResult.Status = AuthenticationTokenCreationStatus.Unknown;
                }

                createAuthTokenResult.ApplicationId = applicationId;
                createAuthTokenResult.AuthenticationToken = null;
            }
        }
        /// <summary>
        /// Gets authentication token absence reasons from response XML.
        /// </summary>
        /// 
        /// <param name="nav">
        /// The response XML path navigator.
        /// </param>
        /// 
        /// <returns>
        /// The dictionary of updated authentication results.
        /// </returns>
        /// 
        internal CreateAuthenticationTokenResult GetAuthTokenAndAbsenceReasons(
            XPathNavigator nav)
        {
            CreateAuthenticationTokenResult createAuthTokenResult = new CreateAuthenticationTokenResult();

            GetAuthenticationToken(createAuthTokenResult, nav);

            if (createAuthTokenResult.AuthenticationToken == null)
            {
                GetStsPayload(createAuthTokenResult, nav);
            }

            if (createAuthTokenResult.AuthenticationToken == null &&
                createAuthTokenResult.StsTokenPayload == null)
            {
                GetAbsenceReasons(createAuthTokenResult, nav);
            }

            return createAuthTokenResult;
        }
 /// <summary>
 /// Inserts a new authentication result into the authentication results 
 /// dictionary.
 /// </summary>
 /// 
 /// <param name="result">
 /// The authentication result to add to the results for the specified
 /// application.
 /// </param>
 /// 
 internal virtual void AddAuthenticationResult(
     CreateAuthenticationTokenResult result)
 {
     if (_authResults == null)
     {
         _authResults = new Dictionary<Guid, CreateAuthenticationTokenResult>();
     }
     if (_authResults.ContainsKey(result.ApplicationId))
     {
         _authResults.Remove(result.ApplicationId);
     }
     _authResults.Add(result.ApplicationId, result);
 }
        /// <summary>
        /// Extracts the STS payload.
        /// </summary>
        /// 
        private void GetStsPayload(
            CreateAuthenticationTokenResult createAuthTokenResult,
            XPathNavigator nav)
        {
            XPathExpression stsPayloadPath = GetStsPayloadPath(nav);
            XPathNavigator stsNav = nav.SelectSingleNode(stsPayloadPath);

            if (stsNav != null)
            {
                Guid applicationId = new Guid(stsNav.GetAttribute("app-id", String.Empty));

                ApplicationRecordAuthorizationAction action =
                    ApplicationRecordAuthorizationAction.Unknown;
                try
                {
                    action =
                        (ApplicationRecordAuthorizationAction)Enum.Parse(
                            typeof(ApplicationRecordAuthorizationAction),
                            stsNav.GetAttribute("app-record-auth-action",
                                String.Empty));
                }
                catch (ArgumentException)
                {
                }

                createAuthTokenResult.StsTokenPayload = stsNav.Value;
                createAuthTokenResult.ApplicationId = applicationId;
                createAuthTokenResult.ApplicationRecordAuthorizationAction = action;
                createAuthTokenResult.Status = AuthenticationTokenCreationStatus.Success;
            }
        }
        /// <summary>
        /// Gets the cached authentication keyset pair for the application id.
        /// </summary>
        /// 
        /// <param name="applicationId"></param>
        /// <param name="refreshCounter"></param>
        /// <param name="keySet"></param>
        /// <param name="result"></param>
        /// 
        private static bool GetAuthTokenPair(
            Guid applicationId,
            out Int64 refreshCounter,
            out AuthenticatedSessionKeySet keySet,
            out CreateAuthenticationTokenResult result)
        {
            keySet = null;
            result = null;
            refreshCounter = 0;

            if (_liveKeySetPairs == null)
            {
                return false;
            }

            AuthenticationTokenKeySetPair pair = _liveKeySetPairs.GetPair(applicationId);

            if (pair == null)
            {
                // create a new unauthenticated pair so that we at least
                // have the KeySet
                pair = _liveKeySetPairs.CreatePair(applicationId);

                keySet = pair.KeySet.Clone();

                return false;
            }

            lock(pair)
            {
                if (!pair.IsAuthenticated())
                {
                    keySet = pair.KeySet.Clone();

                    return false;
                }

                refreshCounter = pair.RefreshCounter;
                keySet = pair.KeySet.Clone();
                result = pair.AuthenticationResult;

                return true;
            }
        }
        /// <summary>
        /// Inserts a dictionary of authentication results.
        /// </summary>
        /// 
        /// <remarks>
        /// This may be called from two primary code paths:
        /// 
        /// 1) WebApplicationCredential.AuthenticateKeySetPair
        ///     pair is already locked by calling thread.
        /// 2) and CreateAuthenticatedSessionToken
        ///     a) the credential could be totally unintialized, including the
        ///         static credentials, so there will not be a lock on the pair.
        ///         But it doesn't matter since there are no contending threads
        ///         to grab the pair during this call.  The lock call is a slight
        ///         overhead in this very rare case.
        ///     b) the credential already has an existing token, including
        ///         the static credentials.  This call will update the credentials
        ///         so it's possible the pair is being used by another thread.
        /// 
        /// This method only update results for the application id for the web 
        /// app.
        /// </remarks>
        /// 
        /// <param name="result">
        /// The result of the authentication request.
        /// </param>
        /// 
        internal override void UpdateAuthenticationResults(
            CreateAuthenticationTokenResult result)
        {
            if (result.ApplicationId == ApplicationId)
            {
                if (CreateAuthenticationTokenResult.IsAuthenticated(result))
                {
                    AuthenticationTokenKeySetPair pair = _liveKeySetPairs.GetPair(ApplicationId);

                    if (pair == null)
                    {
                        // this should only be true for a call to
                        // CreateAuthenticatedSessionToken on an
                        // unitialized WebApplicationCredential state -
                        // both static and instance.
                        pair = _liveKeySetPairs.CreatePair(ApplicationId);
                    }

                    lock(pair)
                    {
                        // update the static keyset pair
                        pair.KeySet = KeySet.Clone();
                        pair.Update(result);
                    }

                    // update the instance with the authentication info
                    LoadAuthTokenPair(ApplicationId);
                }
            }
        }