Exemple #1
0
        internal void StoreToCache(AuthenticationResultEx result, string authority, string resource, string clientId, TokenSubjectType subjectType, CallState callState)
        {
            lock (cacheLock)
            {
                PlatformPlugin.Logger.Verbose(callState, "Storing token in the cache...");

                string uniqueId      = (result.Result.UserInfo != null) ? result.Result.UserInfo.UniqueId : null;
                string displayableId = (result.Result.UserInfo != null) ? result.Result.UserInfo.DisplayableId : null;

                this.OnBeforeWrite(new TokenCacheNotificationArgs
                {
                    Resource      = resource,
                    ClientId      = clientId,
                    UniqueId      = uniqueId,
                    DisplayableId = displayableId
                });

                TokenCacheKey tokenCacheKey = new TokenCacheKey(authority, resource, clientId, subjectType,
                                                                result.Result.UserInfo);
                this.tokenCacheDictionary[tokenCacheKey] = result;
                PlatformPlugin.Logger.Verbose(callState, "An item was stored in the cache");
                this.UpdateCachedMrrtRefreshTokens(result, clientId, subjectType);

                this.HasStateChanged = true;
            }
        }
Exemple #2
0
 internal bool Match(TokenCacheKey key)
 {
     return(key.Authority == this.Authority && key.ResourceEquals(this.Resource) &&
            key.ClientIdEquals(this.ClientId) &&
            key.TokenSubjectType == this.TokenSubjectType && key.UniqueId == this.UniqueId &&
            key.DisplayableIdEquals(this.DisplayableId));
 }
        public static TokenCacheKey DecodeCacheKey(string cacheKey)
        {
            var elements = new TokenCacheKey();
            IDictionary<TokenCacheKeyElement, string> elementDictionary = Decode(cacheKey);
            elements.Authority = elementDictionary.ContainsKey(TokenCacheKeyElement.Authority) ? elementDictionary[TokenCacheKeyElement.Authority] : null;
            elements.ClientId = elementDictionary.ContainsKey(TokenCacheKeyElement.ClientId) ? elementDictionary[TokenCacheKeyElement.ClientId] : null;
            elements.FamilyName = elementDictionary.ContainsKey(TokenCacheKeyElement.FamilyName) ? elementDictionary[TokenCacheKeyElement.FamilyName] : null;
            elements.GivenName = elementDictionary.ContainsKey(TokenCacheKeyElement.GivenName) ? elementDictionary[TokenCacheKeyElement.GivenName] : null;
            elements.IdentityProviderName = elementDictionary.ContainsKey(TokenCacheKeyElement.IdentityProviderName) ? elementDictionary[TokenCacheKeyElement.IdentityProviderName] : null;
            elements.Resource = elementDictionary.ContainsKey(TokenCacheKeyElement.Resource) ? elementDictionary[TokenCacheKeyElement.Resource] : null;
            elements.TenantId = elementDictionary.ContainsKey(TokenCacheKeyElement.TenantId) ? elementDictionary[TokenCacheKeyElement.TenantId] : null;
            elements.UserId = elementDictionary.ContainsKey(TokenCacheKeyElement.UserId) ? elementDictionary[TokenCacheKeyElement.UserId] : null;

            if (elementDictionary.ContainsKey(TokenCacheKeyElement.ExpiresOn))
            {
                elements.ExpiresOn = DateTimeOffset.Parse(elementDictionary[TokenCacheKeyElement.ExpiresOn]);
            }

            if (elementDictionary.ContainsKey(TokenCacheKeyElement.IsUserIdDisplayable))
            {
                elements.IsUserIdDisplayable = bool.Parse(elementDictionary[TokenCacheKeyElement.IsUserIdDisplayable]);
            }

            if (elementDictionary.ContainsKey(TokenCacheKeyElement.IsMultipleResourceRefreshToken))
            {
                elements.IsMultipleResourceRefreshToken = bool.Parse(elementDictionary[TokenCacheKeyElement.IsMultipleResourceRefreshToken]);
            }

            return elements;
        }
        public void DeleteItem(TokenCacheItem item)
#endif
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            TokenCacheNotificationArgs args = new TokenCacheNotificationArgs
            {
                TokenCache    = this,
                Resource      = item.Resource,
                ClientId      = item.ClientId,
                UniqueId      = item.UniqueId,
                DisplayableId = item.DisplayableId
            };

            this.OnBeforeAccess(args);
            this.OnBeforeWrite(args);

            TokenCacheKey toRemoveKey = this.tokenCacheDictionary.Keys.FirstOrDefault(item.Match);

            if (toRemoveKey != null)
            {
                this.tokenCacheDictionary.Remove(toRemoveKey);
            }

            this.HasStateChanged = true;
            this.OnAfterAccess(args);
        }
        public async Task AcquireTokenSilentServiceErrorTestAsync()
        {
            Sts sts = new AadSts();
            TokenCache cache = new TokenCache();
            TokenCacheKey key = new TokenCacheKey(sts.Authority, sts.ValidResource, sts.ValidClientId, TokenSubjectType.User, "unique_id", "*****@*****.**");
            cache.tokenCacheDictionary[key] = new AuthenticationResult("Bearer", "some-access-token",
                "invalid-refresh-token", DateTimeOffset.UtcNow);

            AuthenticationContext context = new AuthenticationContext(sts.Authority, sts.ValidateAuthority, cache);

            try
            {
                await context.AcquireTokenSilentAsync(sts.ValidResource, sts.ValidClientId, new UserIdentifier("unique_id", UserIdentifierType.UniqueId));
                Verify.Fail("AdalSilentTokenAcquisitionException was expected");
            }
            catch (AdalSilentTokenAcquisitionException ex)
            {
                Verify.AreEqual(AdalError.FailedToAcquireTokenSilently, ex.ErrorCode);
                Verify.AreEqual(AdalErrorMessage.FailedToRefreshToken, ex.Message);
                Verify.IsNotNull(ex.InnerException);
                Verify.IsTrue(ex.InnerException is AdalException);
                Verify.AreEqual(((AdalException)ex.InnerException).ErrorCode, "invalid_grant");
            }
            catch
            {
                Verify.Fail("AdalSilentTokenAcquisitionException was expected");
            }

        }
Exemple #6
0
        internal AuthenticationResult LoadFromCache(string authority, string resource, string clientId, TokenSubjectType subjectType, string uniqueId, string displayableId, CallState callState)
        {
            AuthenticationResult result = null;

            KeyValuePair <TokenCacheKey, AuthenticationResult>?kvp = this.LoadSingleItemFromCache(authority, resource, clientId, subjectType, uniqueId, displayableId);

            if (kvp.HasValue)
            {
                TokenCacheKey cacheKey = kvp.Value.Key;
                result = kvp.Value.Value;
                bool tokenMarginallyExpired = (result.ExpiresOn <= DateTime.UtcNow + TimeSpan.FromMinutes(ExpirationMarginInMinutes));

                if (tokenMarginallyExpired || !cacheKey.ResourceEquals(resource))
                {
                    result.AccessToken = null;
                }

                if (result.AccessToken == null && result.RefreshToken == null)
                {
                    this.tokenCacheDictionary.Remove(cacheKey);
                    this.HasStateChanged = true;
                    result = null;
                }

                if (result != null)
                {
                    Logger.Verbose(callState, "A matching token was found in the cache");
                }
            }

            return(result);
        }
        public static string EncodeCacheKey(TokenCacheKey cacheKey)
        {
            var keyElements = new SortedDictionary<TokenCacheKeyElement, string>();

            keyElements[TokenCacheKeyElement.Authority] = cacheKey.Authority;

            if (!String.IsNullOrEmpty(cacheKey.Resource))
            {
                keyElements[TokenCacheKeyElement.Resource] = cacheKey.Resource;
            }

            if (!String.IsNullOrEmpty(cacheKey.ClientId))
            {
                keyElements[TokenCacheKeyElement.ClientId] = cacheKey.ClientId;
            }

            if (null != cacheKey.ExpiresOn)
            {
                keyElements[TokenCacheKeyElement.ExpiresOn] = cacheKey.ExpiresOn.ToString();
            }

            if (!String.IsNullOrEmpty(cacheKey.FamilyName))
            {
                keyElements[TokenCacheKeyElement.FamilyName] = cacheKey.FamilyName;
            }

            if (!String.IsNullOrEmpty(cacheKey.GivenName))
            {
                keyElements[TokenCacheKeyElement.GivenName] = cacheKey.GivenName;
            }

            if (!String.IsNullOrEmpty(cacheKey.IdentityProviderName))
            {
                keyElements[TokenCacheKeyElement.IdentityProviderName] = cacheKey.IdentityProviderName;
            }

            if (cacheKey.IsMultipleResourceRefreshToken)
            {
                keyElements[TokenCacheKeyElement.IsMultipleResourceRefreshToken] = cacheKey.IsMultipleResourceRefreshToken.ToString();
            }

            if (cacheKey.IsUserIdDisplayable)
            {
                keyElements[TokenCacheKeyElement.IsUserIdDisplayable] = cacheKey.IsUserIdDisplayable.ToString();
            }

            if (!String.IsNullOrEmpty(cacheKey.TenantId))
            {
                keyElements[TokenCacheKeyElement.TenantId] = cacheKey.TenantId;
            }

            if (!String.IsNullOrEmpty(cacheKey.UserId))
            {
                keyElements[TokenCacheKeyElement.UserId] = cacheKey.UserId;
            }

            return CreateFromKeyElements(keyElements);
        }
 /// <summary>
 /// Determines whether the specified TokenCacheKey is equal to the current object.
 /// </summary>
 /// <returns>
 /// true if the specified TokenCacheKey is equal to the current object; otherwise, false.
 /// </returns>
 /// <param name="other">The TokenCacheKey to compare with the current object. </param><filterpriority>2</filterpriority>
 public bool Equals(TokenCacheKey other)
 {
     return(ReferenceEquals(this, other) ||
            (other != null &&
             (other.Authority == this.Authority) &&
             this.ResourceEquals(other.Resource) &&
             this.ClientIdEquals(other.ClientId) &&
             (other.UniqueId == this.UniqueId) &&
             this.DisplayableIdEquals(other.DisplayableId) &&
             (other.TokenSubjectType == this.TokenSubjectType)));
 }
        internal AuthenticationResult LoadFromCache(string authority, string resource, string clientId, TokenSubjectType subjectType, string uniqueId, string displayableId, CallState callState)
        {
            Logger.Verbose(callState, "Looking up cache for a token...");

            AuthenticationResult result = null;

            KeyValuePair <TokenCacheKey, AuthenticationResult>?kvp = this.LoadSingleItemFromCache(authority, resource, clientId, subjectType, uniqueId, displayableId, callState);

            if (kvp.HasValue)
            {
                TokenCacheKey cacheKey = kvp.Value.Key;
                result = kvp.Value.Value;
                bool tokenNearExpiry = (result.ExpiresOn <= DateTime.UtcNow + TimeSpan.FromMinutes(ExpirationMarginInMinutes));

                if (tokenNearExpiry)
                {
                    result.AccessToken = null;
                    Logger.Verbose(callState, "An expired or near expiry token was found in the cache");
                }
                else if (!cacheKey.ResourceEquals(resource))
                {
                    Logger.Verbose(callState,
                                   string.Format("Multi resource refresh token for resource '{0}' will be used to acquire token for '{1}'", cacheKey.Resource, resource));
                    var newResult = new AuthenticationResult(null, null, result.RefreshToken, DateTimeOffset.MinValue);
                    newResult.UpdateTenantAndUserInfo(result.TenantId, result.IdToken, result.UserInfo);
                    result = newResult;
                }
                else
                {
                    Logger.Verbose(callState, string.Format("{0} minutes left until token in cache expires", (result.ExpiresOn - DateTime.UtcNow).TotalMinutes));
                }

                if (result.AccessToken == null && result.RefreshToken == null)
                {
                    this.tokenCacheDictionary.Remove(cacheKey);
                    Logger.Information(callState, "An old item was removed from the cache");
                    this.HasStateChanged = true;
                    result = null;
                }

                if (result != null)
                {
                    Logger.Information(callState, "A matching item (access token or refresh token or both) was found in the cache");
                }
            }
            else
            {
                Logger.Information(callState, "No matching token was found in the cache");
            }

            return(result);
        }
Exemple #10
0
        /// <summary>
        /// Deserializes state of the cache. The state should be the blob received earlier by calling the method Serialize.
        /// </summary>
        /// <param name="state">State of the cache as a blob</param>
        public void Deserialize(byte[] state)
        {
            lock (cacheLock)
            {
                if (state == null)
                {
                    this.tokenCacheDictionary.Clear();
                    return;
                }

                using (Stream stream = new MemoryStream())
                {
                    BinaryWriter writer = new BinaryWriter(stream);
                    writer.Write(state);
                    writer.Flush();
                    stream.Position = 0;

                    BinaryReader reader        = new BinaryReader(stream);
                    int          schemaVersion = reader.ReadInt32();
                    if (schemaVersion != SchemaVersion)
                    {
                        CallState.Default.Logger.Warning(null,
                                                         "The version of the persistent state of the cache does not match the current schema, so skipping deserialization.");
                        return;
                    }

                    this.tokenCacheDictionary.Clear();
                    int count = reader.ReadInt32();
                    for (int n = 0; n < count; n++)
                    {
                        string keyString = reader.ReadString();

                        string[] kvpElements            = keyString.Split(new[] { Delimiter }, StringSplitOptions.None);
                        AuthenticationResultEx resultEx = AuthenticationResultEx.Deserialize(reader.ReadString());
                        TokenCacheKey          key      = new TokenCacheKey(kvpElements[0], kvpElements[1], kvpElements[2],
                                                                            (TokenSubjectType)int.Parse(kvpElements[3], CultureInfo.CurrentCulture),
                                                                            resultEx.Result.UserInfo);

                        this.tokenCacheDictionary.Add(key, resultEx);
                    }

                    CallState.Default.Logger.Information(null,
                                                         string.Format(CultureInfo.CurrentCulture, "Deserialized {0} items to token cache.", count));
                }
            }
        }
        /// <summary>
        /// Default constructor.
        /// </summary>
        internal TokenCacheItem(TokenCacheKey key, AuthenticationResult result)
        {
            this.Authority        = key.Authority;
            this.Resource         = key.Resource;
            this.ClientId         = key.ClientId;
            this.TokenSubjectType = key.TokenSubjectType;
            this.UniqueId         = key.UniqueId;
            this.DisplayableId    = key.DisplayableId;
            this.TenantId         = result.TenantId;
            this.ExpiresOn        = result.ExpiresOn;
            this.AccessToken      = result.AccessToken;
            this.IdToken          = result.IdToken;

            if (result.UserInfo != null)
            {
                this.FamilyName       = result.UserInfo.FamilyName;
                this.GivenName        = result.UserInfo.GivenName;
                this.IdentityProvider = result.UserInfo.IdentityProvider;
            }
        }
Exemple #12
0
        internal void StoreToCache(AuthenticationResult result, string authority, string resource, string clientId, TokenSubjectType subjectType)
        {
            string uniqueId      = (result.UserInfo != null) ? result.UserInfo.UniqueId : null;
            string displayableId = (result.UserInfo != null) ? result.UserInfo.DisplayableId : null;

            this.OnBeforeWrite(new TokenCacheNotificationArgs
            {
                Resource      = resource,
                ClientId      = clientId,
                UniqueId      = uniqueId,
                DisplayableId = displayableId
            });

            TokenCacheKey tokenCacheKey = new TokenCacheKey(authority, resource, clientId, subjectType, result.UserInfo);

            this.tokenCacheDictionary[tokenCacheKey] = result;
            this.UpdateCachedMrrtRefreshTokens(result, authority, clientId, subjectType);

            this.HasStateChanged = true;
        }
        /// <summary>
        /// Default constructor.
        /// </summary>
        internal TokenCacheItem(TokenCacheKey key, AuthenticationResult result)
        {
            this.Authority = key.Authority;
            this.Resource = key.Resource;
            this.ClientId = key.ClientId;
            this.TokenSubjectType = key.TokenSubjectType;
            this.UniqueId = key.UniqueId;
            this.DisplayableId = key.DisplayableId;
            this.TenantId = result.TenantId;
            this.ExpiresOn = result.ExpiresOn;
            this.AccessToken = result.AccessToken;
            this.IdToken = result.IdToken;

            if (result.UserInfo != null)
            {
                this.FamilyName = result.UserInfo.FamilyName;
                this.GivenName = result.UserInfo.GivenName;
                this.IdentityProvider = result.UserInfo.IdentityProvider;
            }
        }
Exemple #14
0
        /// <summary>
        /// Deserializes state of the cache. The state should be the blob received earlier by calling the method Serialize.
        /// </summary>
        /// <param name="state">State of the cache as a blob</param>
        public void Deserialize([ReadOnlyArray] byte[] state)
        {
            if (state == null)
            {
                this.tokenCacheDictionary.Clear();
                return;
            }

            using (Stream stream = new MemoryStream())
            {
                BinaryWriter writer = new BinaryWriter(stream);
                writer.Write(state);
                writer.Flush();
                stream.Position = 0;

                BinaryReader reader        = new BinaryReader(stream);
                int          schemaVersion = reader.ReadInt32();
                if (schemaVersion != SchemaVersion)
                {
                    // The version of the serialized cache does not match the current schema
                    return;
                }

                this.tokenCacheDictionary.Clear();
                int count = reader.ReadInt32();
                for (int n = 0; n < count; n++)
                {
                    string keyString = reader.ReadString();

                    string[]             kvpElements = keyString.Split(new[] { Delimiter }, StringSplitOptions.None);
                    AuthenticationResult result      = AuthenticationResult.Deserialize(reader.ReadString());
                    TokenCacheKey        key         = new TokenCacheKey(kvpElements[0], kvpElements[1], kvpElements[2], (TokenSubjectType)int.Parse(kvpElements[3]), result.UserInfo);

                    this.tokenCacheDictionary.Add(key, result);
                }
            }
        }
Exemple #15
0
        public void DeleteItem(TokenCacheItem item)
#endif
        {
            lock (cacheLock)
            {
                if (item == null)
                {
                    throw new ArgumentNullException("item");
                }

                TokenCacheNotificationArgs args = new TokenCacheNotificationArgs
                {
                    TokenCache    = this,
                    Resource      = item.Resource,
                    ClientId      = item.ClientId,
                    UniqueId      = item.UniqueId,
                    DisplayableId = item.DisplayableId
                };

                this.OnBeforeAccess(args);
                this.OnBeforeWrite(args);

                TokenCacheKey toRemoveKey = this.tokenCacheDictionary.Keys.FirstOrDefault(item.Match);
                if (toRemoveKey != null)
                {
                    this.tokenCacheDictionary.Remove(toRemoveKey);
                    Logger.Information(null, "One item removed successfully");
                }
                else
                {
                    Logger.Information(null, "Item not Present in the Cache");
                }

                this.HasStateChanged = true;
                this.OnAfterAccess(args);
            }
        }
        private static bool RemoveFromDictionary(TokenCache tokenCache, TokenCacheKey key)
        {
            bool result;
            tokenCache.OnBeforeAccess(null);
            tokenCache.OnBeforeWrite(null);
            result = tokenCache.tokenCacheDictionary.Remove(key);
            tokenCache.HasStateChanged = true;
            tokenCache.OnAfterAccess(null);

            return result;
        }
        private static void AddToDictionary(TokenCache tokenCache, TokenCacheKey key, AuthenticationResult value)
        {
            tokenCache.OnBeforeAccess(null);
            tokenCache.OnBeforeWrite(null);
            tokenCache.tokenCacheDictionary.Add(key, value);
            tokenCache.HasStateChanged = true;
            tokenCache.OnAfterAccess(null);

        }
 private static bool AreEqual(TokenCacheItem item, TokenCacheKey key)
 {
     return item.Match(key);
 }
        private static void VerifyCacheItems(TokenCache cache, int expectedCount, TokenCacheKey firstKey, TokenCacheKey secondKey)
        {
            var items = cache.ReadItems().ToList();
            Verify.AreEqual(expectedCount, items.Count);

            if (firstKey != null)
            {
                Verify.IsTrue(AreEqual(items[0], firstKey) || AreEqual(items[0], secondKey));
            }

            if (secondKey != null)
            {
                Verify.IsTrue(AreEqual(items[1], firstKey) || AreEqual(items[1], secondKey));
            }
        }
 private static void VerifyCacheItems(TokenCache cache, int expectedCount, TokenCacheKey firstKey)
 {
     VerifyCacheItems(cache, expectedCount, firstKey, null);
 }
        internal void StoreToCache(AuthenticationResultEx result, string authority, string[] scope, string clientId,
            TokenSubjectType subjectType, CallState callState)
        {
            PlatformPlugin.Logger.Verbose(callState, "Storing token in the cache...");

            if (ADALScopeHelper.IsNullOrEmpty(scope) || ADALScopeHelper.CreateSetFromArray(scope).Contains("openid"))
            {
                scope = new[] {clientId};
            }

            string uniqueId = (result.Result.UserInfo != null) ? result.Result.UserInfo.UniqueId : null;
            string displayableId = (result.Result.UserInfo != null) ? result.Result.UserInfo.DisplayableId : null;

            this.OnBeforeWrite(new TokenCacheNotificationArgs
            {
                Scope = scope,
                ClientId = clientId,
                UniqueId = uniqueId,
                DisplayableId = displayableId
            });

            TokenCacheKey tokenCacheKey = new TokenCacheKey(authority, scope, clientId, subjectType,
                result.Result.UserInfo);
            // First identify all potential tokens.
            List<KeyValuePair<TokenCacheKey, AuthenticationResultEx>> items = this.QueryCache(authority, clientId,
                subjectType, uniqueId, displayableId);
            List<KeyValuePair<TokenCacheKey, AuthenticationResultEx>> itemsToRemove =
                items.Where(p => p.Key.ScopeIntersects(scope)).ToList();

            if (!itemsToRemove.Any())
            {
                this.tokenCacheDictionary[tokenCacheKey] = result;
                PlatformPlugin.Logger.Verbose(callState, "An item was stored in the cache");
            }
            else
            {
                //remove all intersections
                foreach (var itemToRemove in itemsToRemove)
                {
                    this.tokenCacheDictionary.Remove(itemToRemove);
                }

                this.tokenCacheDictionary[tokenCacheKey] = result;
                PlatformPlugin.Logger.Verbose(callState, "An item was updated in the cache");
            }

            this.UpdateCachedMrrtRefreshTokens(result, authority, clientId, subjectType);
            this.HasStateChanged = true;
        }
Exemple #22
0
        internal AuthenticationResultEx LoadFromCache(CacheQueryData cacheQueryData, CallState callState)
        {
            lock (cacheLock)
            {
                PlatformPlugin.Logger.Verbose(callState, "Looking up cache for a token...");

                AuthenticationResultEx resultEx = null;
                KeyValuePair <TokenCacheKey, AuthenticationResultEx>?kvp = this.LoadSingleItemFromCache(cacheQueryData, callState);

                if (kvp.HasValue)
                {
                    TokenCacheKey cacheKey = kvp.Value.Key;
                    resultEx = kvp.Value.Value.Clone();

                    bool tokenNearExpiry = (resultEx.Result.ExpiresOn <=
                                            DateTime.UtcNow + TimeSpan.FromMinutes(ExpirationMarginInMinutes));
                    bool tokenExtendedLifeTimeExpired = (resultEx.Result.ExtendedExpiresOn <=
                                                         DateTime.UtcNow);

                    //check for cross-tenant authority
                    if (!cacheKey.Authority.Equals(cacheQueryData.Authority))
                    {
                        // this is a cross-tenant result. use RT only
                        resultEx.Result.AccessToken = null;
                        PlatformPlugin.Logger.Information(callState,
                                                          "Cross Tenant refresh token was found in the cache");
                    }
                    else if (tokenNearExpiry && !cacheQueryData.ExtendedLifeTimeEnabled)
                    {
                        resultEx.Result.AccessToken = null;
                        PlatformPlugin.Logger.Information(callState,
                                                          "An expired or near expiry token was found in the cache");
                    }
                    else if (!cacheKey.ResourceEquals(cacheQueryData.Resource))
                    {
                        PlatformPlugin.Logger.Information(callState,
                                                          string.Format(CultureInfo.CurrentCulture,
                                                                        "Multi resource refresh token for resource '{0}' will be used to acquire token for '{1}'",
                                                                        cacheKey.Resource, cacheQueryData.Resource));
                        var newResultEx = new AuthenticationResultEx
                        {
                            Result             = new AuthenticationResult(null, null, DateTimeOffset.MinValue),
                            RefreshToken       = resultEx.RefreshToken,
                            ResourceInResponse = resultEx.ResourceInResponse
                        };

                        newResultEx.Result.UpdateTenantAndUserInfo(resultEx.Result.TenantId, resultEx.Result.IdToken,
                                                                   resultEx.Result.UserInfo);
                        resultEx = newResultEx;
                    }
                    else if (!tokenExtendedLifeTimeExpired && cacheQueryData.ExtendedLifeTimeEnabled && tokenNearExpiry)
                    {
                        resultEx.Result.ExtendedLifeTimeToken = true;
                        resultEx.Result.ExpiresOn             = resultEx.Result.ExtendedExpiresOn;
                        PlatformPlugin.Logger.Information(callState,
                                                          "The extendedLifeTime is enabled and a stale AT with extendedLifeTimeEnabled is returned.");
                    }
                    else if (tokenExtendedLifeTimeExpired)
                    {
                        resultEx.Result.AccessToken = null;
                        PlatformPlugin.Logger.Information(callState,
                                                          "The AT has expired its ExtendedLifeTime");
                    }
                    else
                    {
                        PlatformPlugin.Logger.Information(callState,
                                                          string.Format(CultureInfo.CurrentCulture, "{0} minutes left until token in cache expires",
                                                                        (resultEx.Result.ExpiresOn - DateTime.UtcNow).TotalMinutes));
                    }

                    if (resultEx.Result.AccessToken == null && resultEx.RefreshToken == null)
                    {
                        this.tokenCacheDictionary.Remove(cacheKey);
                        PlatformPlugin.Logger.Information(callState, "An old item was removed from the cache");
                        this.HasStateChanged = true;
                        resultEx             = null;
                    }

                    if (resultEx != null)
                    {
                        PlatformPlugin.Logger.Information(callState,
                                                          "A matching item (access token or refresh token or both) was found in the cache");
                    }
                }
                else
                {
                    PlatformPlugin.Logger.Information(callState, "No matching token was found in the cache");
                }

                return(resultEx);
            }
        }
        private static bool RemoveFromDictionary(TokenCache tokenCache, TokenCacheKey key)
        {
            tokenCache.OnBeforeAccess(new TokenCacheNotificationArgs { TokenCache = tokenCache });
            tokenCache.OnBeforeWrite(new TokenCacheNotificationArgs { TokenCache = tokenCache });
            bool result = tokenCache.tokenCacheDictionary.Remove(key);
            tokenCache.HasStateChanged = true;
            tokenCache.OnAfterAccess(new TokenCacheNotificationArgs { TokenCache = tokenCache });

            return result;
        }
        public static void DefaultTokenCacheTest()
        {
            AuthenticationContext context = new AuthenticationContext("https://login.windows.net/dummy", false);
            var cache = context.TokenCache;
            cache.Clear();
            Log.Comment("====== Verifying that cache is empty...");
            VerifyCacheItemCount(cache, 0);

            const string DisplayableId = "*****@*****.**";
            Log.Comment("====== Creating a set of keys and values for the test...");
            TokenCacheKey key = new TokenCacheKey("https://localhost/MockSts", ValidResource, ValidClientId, TokenSubjectType.User, null, DisplayableId);
            var value = CreateCacheValue(key.UniqueId, key.DisplayableId);
            Log.Comment(string.Format("Cache Key (with User): {0}", key));
            Log.Comment(string.Format("Cache Value 1: {0}", value));
            TokenCacheKey key2 = new TokenCacheKey("https://localhost/MockSts", InvalidResource, ValidClientId, TokenSubjectType.User, null, DisplayableId);
            var value2 = CreateCacheValue(null, DisplayableId);
            Log.Comment(string.Format("Cache Key (with User): {0}", key));
            Log.Comment(string.Format("Cache Value 2: {0}", value2));
            TokenCacheKey userlessKey = new TokenCacheKey("https://localhost/MockSts", ValidResource, ValidClientId, TokenSubjectType.User, null, null);
            var userlessValue = CreateCacheValue(null, null);
            Log.Comment(string.Format("Cache Key (withoutUser): {0}", userlessKey));
            Log.Comment(string.Format("Cache Value 3: {0}", userlessValue));

            TokenCacheKey incorrectUserKey = new TokenCacheKey("https://localhost/MockSts", InvalidResource, ValidClientId, TokenSubjectType.User, null, "*****@*****.**");

            Log.Comment("====== Verifying that cache stores the first key/value pair...");
            AddToDictionary(cache, key, value);
            VerifyCacheItems(cache, 1, key);

            Log.Comment("====== Verifying that the only existing value (with user) is retrieved when requested with user and NOT without...");
            Log.Comment("Retrieving with user...");
            var valueInCache = cache.tokenCacheDictionary[key];
            VerifyAuthenticationResultsAreEqual(value, valueInCache);
            Log.Comment("Retrieving without user...");
            cache.tokenCacheDictionary.TryGetValue(userlessKey, out valueInCache);
            Verify.IsNull(valueInCache);

            Log.Comment("====== Verifying that two entries can exist at the same time, one with user and one without...");
            AddToDictionary(cache, userlessKey, userlessValue);
            VerifyCacheItems(cache, 2, key, userlessKey);

            Log.Comment("====== Verifying that correct values are retrieved when requested with and without user (when two entries exist)...");
            Log.Comment("Retrieving without user...");
            valueInCache = cache.tokenCacheDictionary[userlessKey];
            VerifyAuthenticationResultsAreEqual(userlessValue, valueInCache);
            Log.Comment("Retrieving with user...");
            valueInCache = cache.tokenCacheDictionary[key];
            VerifyAuthenticationResultsAreEqual(value, valueInCache);

            Log.Comment("====== Verifying that correct entry is deleted when the key with user is passed...");
            RemoveFromDictionary(cache, key);
            VerifyCacheItems(cache, 1, userlessKey);

            Log.Comment("====== Verifying that correct entry is deleted when the key without user is passed...");
            AddToDictionary(cache, key, value);
            RemoveFromDictionary(cache, userlessKey);
            VerifyCacheItems(cache, 1, key);

            Log.Comment("====== Verifying that correct entry is retrieve and later deleted when the key with user is passed, even if entries are in reverse order...");
            cache.Clear();
            Log.Comment("Storing without user first and then with user...");
            AddToDictionary(cache, userlessKey, userlessValue);
            AddToDictionary(cache, key2, value2);
            valueInCache = cache.tokenCacheDictionary[key2];
            VerifyAuthenticationResultsAreEqual(value2, valueInCache);
            RemoveFromDictionary(cache, key2);
            VerifyCacheItems(cache, 1, userlessKey);

            Log.Comment("====== Verifying that the userless entry is retrieved ONLY when requested without user...");
            cache.Clear();
            AddToDictionary(cache, userlessKey, value);
            Log.Comment("Retrieving with user...");
            cache.tokenCacheDictionary.TryGetValue(key, out valueInCache);
            Verify.IsNull(valueInCache);
            Log.Comment("Retrieving without user...");
            valueInCache = cache.tokenCacheDictionary[userlessKey];
            VerifyAuthenticationResultsAreEqual(value, valueInCache);

            Log.Comment("====== Verifying that entry cannot be retrieved with incorrect key...");
            cache.Clear();
            AddToDictionary(cache, key, value);
            Log.Comment("Retrieving with incorrect key...");
            cache.tokenCacheDictionary.TryGetValue(key2, out valueInCache);
            Verify.IsNull(valueInCache);
            Log.Comment("Retrieving with incorrect user...");
            cache.tokenCacheDictionary.TryGetValue(incorrectUserKey, out valueInCache);
            Verify.IsNull(valueInCache);
            Log.Comment("Retrieving with correct user...");
            valueInCache = cache.tokenCacheDictionary[key];
            VerifyAuthenticationResultsAreEqual(value, valueInCache);

            Log.Comment("====== Verifying that removing items from an empty cache will not throw...");
            Log.Comment("Clearing cache...");
            cache.Clear();
            Log.Comment("Storing an entry...");
            AddToDictionary(cache, key, value);
            VerifyCacheItemCount(cache, 1);
            Log.Comment("Remvoing the only entry...");
            RemoveFromDictionary(cache, key);
            VerifyCacheItemCount(cache, 0);
            Log.Comment("Trying to remove from an empty cache...");
            RemoveFromDictionary(cache, key);
            VerifyCacheItemCount(cache, 0);
        }
        internal static void TokenCacheOperationsTest()
        {
            var tokenCache = new TokenCache();

            var cacheDictionary = tokenCache.tokenCacheDictionary;

            tokenCache.Clear();

            TokenCacheKey key = new TokenCacheKey("https://localhost/MockSts", "resource1", "client1", TokenSubjectType.User, null, "user1");
            TokenCacheKey key2 = new TokenCacheKey("https://localhost/MockSts", "resource1", "client1", TokenSubjectType.User, null, "user2");
            TokenCacheKey key3 = new TokenCacheKey("https://localhost/MockSts", "resource1", "client1", TokenSubjectType.UserPlusClient, null, "user1");
            Verify.AreNotEqual(key, key3);

            var value = CreateCacheValue(null, "user1");
            AuthenticationResult value2;
            do
            {
                value2 = CreateCacheValue(null, "user2");
            }
            while (value2 == value);

            Verify.AreEqual(0, cacheDictionary.Count);
            AddToDictionary(tokenCache, key, value);
            Verify.AreEqual(1, cacheDictionary.Count);
            var valueInCache = cacheDictionary[key];
            VerifyAuthenticationResultsAreEqual(valueInCache, value);
            VerifyAuthenticationResultsAreNotEqual(valueInCache, value2);
            cacheDictionary[key] = value2;
            Verify.AreEqual(1, cacheDictionary.Count);
            valueInCache = cacheDictionary[key];
            VerifyAuthenticationResultsAreEqual(valueInCache, value2);
            VerifyAuthenticationResultsAreNotEqual(valueInCache, value);
            try
            {
                AddToDictionary(tokenCache, key, value);
                Verify.Fail("Exception expected due to duplicate key");
            }
            catch (ArgumentException)
            {
                // Expected
            }

            Verify.IsTrue(RemoveFromDictionary(tokenCache, key));
            Verify.IsFalse(RemoveFromDictionary(tokenCache, key));
            Verify.AreEqual(0, cacheDictionary.Count);

            AddToDictionary(tokenCache, key, value);
            AddToDictionary(tokenCache, key2, value2);
            Verify.AreEqual(2, cacheDictionary.Count);
            Verify.AreEqual(cacheDictionary[key], value);
            Verify.AreEqual(cacheDictionary[key2], value2);

            try
            {
                AddToDictionary(tokenCache, null, value);
                Verify.Fail("Exception expected due to duplicate key");
            }
            catch (ArgumentNullException)
            {
                // Expected
            }

            try
            {
                cacheDictionary[null] = value;
                Verify.Fail("Exception expected due to duplicate key");
            }
            catch (ArgumentNullException)
            {
                // Expected
            }

            Verify.IsFalse(cacheDictionary.IsReadOnly);

            var keys = cacheDictionary.Keys.ToList();
            var values = cacheDictionary.Values.ToList();
            Verify.AreEqual(2, keys.Count);
            Verify.AreEqual(2, values.Count);
            if (keys[0].Equals(key))
            {
                Verify.AreEqual(keys[1], key2);
                Verify.AreEqual(values[0], value);
                Verify.AreEqual(values[1], value2);
            }
            else
            {
                Verify.AreEqual(keys[0], key2);
                Verify.AreEqual(keys[1], key);
                Verify.AreEqual(values[0], value2);
                Verify.AreEqual(values[1], value);
            }

            Verify.IsTrue(cacheDictionary.ContainsKey(key));
            Verify.IsTrue(cacheDictionary.ContainsKey(key2));
            Verify.IsFalse(cacheDictionary.ContainsKey(key3));

            Verify.IsTrue(cacheDictionary.Contains(new KeyValuePair<TokenCacheKey, AuthenticationResult>(key, value)));
            Verify.IsTrue(cacheDictionary.Contains(new KeyValuePair<TokenCacheKey, AuthenticationResult>(key2, value2)));
            Verify.IsFalse(cacheDictionary.Contains(new KeyValuePair<TokenCacheKey, AuthenticationResult>(key, value2)));
            Verify.IsFalse(cacheDictionary.Contains(new KeyValuePair<TokenCacheKey, AuthenticationResult>(key2, value)));

            try
            {
                AddToDictionary(tokenCache, key, value);
                Verify.Fail("Exception expected due to duplicate key");
            }
            catch (ArgumentException)
            {
                // Expected
            }

            AddToDictionary(tokenCache, key3, value);
            Verify.AreEqual(3, cacheDictionary.Keys.Count);
            Verify.IsTrue(cacheDictionary.ContainsKey(key3));

            var cacheItemsCopy = new KeyValuePair<TokenCacheKey, AuthenticationResult>[cacheDictionary.Count + 1];
            cacheDictionary.CopyTo(cacheItemsCopy, 1);
            for (int i = 0; i < cacheDictionary.Count; i++)
            {
                Verify.AreEqual(cacheItemsCopy[i + 1].Value, cacheDictionary[cacheItemsCopy[i + 1].Key]);
            }

            try
            {
                cacheDictionary.CopyTo(cacheItemsCopy, 2);
                Verify.Fail("Exception expected");
            }
            catch (ArgumentException)
            {
                // Expected
            }

            try
            {
                cacheDictionary.CopyTo(cacheItemsCopy, -1);
                Verify.Fail("Exception expected");
            }
            catch (ArgumentOutOfRangeException)
            {
                // Expected
            }

            RemoveFromDictionary(tokenCache, key2);
            Verify.AreEqual(2, cacheDictionary.Keys.Count);

            foreach (var kvp in cacheDictionary)
            {
                Verify.IsTrue(kvp.Key.Equals(key) || kvp.Key.Equals(key3));
                Verify.IsTrue(kvp.Value.Equals(value));
            }

            AuthenticationResult cacheValue;
            Verify.IsTrue(cacheDictionary.TryGetValue(key, out cacheValue));
            Verify.AreEqual(cacheValue, value);
            Verify.IsTrue(cacheDictionary.TryGetValue(key3, out cacheValue));
            Verify.AreEqual(cacheValue, value);
            Verify.IsFalse(cacheDictionary.TryGetValue(key2, out cacheValue));

            cacheDictionary.Clear();
            Verify.AreEqual(0, cacheDictionary.Keys.Count);
        }
        public static async Task TokenCacheKeyTestAsync()
        {
            CheckPublicGetSets();

            string authority = "https://www.gotJwt.com/";
            string clientId = Guid.NewGuid().ToString();
            string resource = Guid.NewGuid().ToString();
            string tenantId = Guid.NewGuid().ToString();
            string uniqueId = Guid.NewGuid().ToString();
            string displayableId = Guid.NewGuid().ToString();
            Uri redirectUri = new Uri("https://www.GetJwt.com");

            var authenticationResult = CreateCacheValue(uniqueId, displayableId);
            authority = authority + tenantId + "/";
            UserCredential credential = new UserCredential(displayableId);
            AuthenticationContext tempContext = new AuthenticationContext(authority, false);
            var localCache = tempContext.TokenCache;
            localCache.Clear();

            // @Resource, Credential
            TokenCacheKey tokenCacheKey = new TokenCacheKey(authority, resource, clientId, TokenSubjectType.User, uniqueId, displayableId);
            AddToDictionary(localCache, tokenCacheKey, authenticationResult);
            AuthenticationContext acWithLocalCache = new AuthenticationContext(authority, false, localCache);
            AuthenticationResult authenticationResultFromCache = await acWithLocalCache.AcquireTokenAsync(resource, clientId, credential);
            AreAuthenticationResultsEqual(authenticationResult, authenticationResultFromCache);

            // Duplicate throws error
            authenticationResult.UserInfo.UniqueId = null;
            AddToDictionary(localCache, new TokenCacheKey(authority, resource, clientId, TokenSubjectType.User, null, displayableId), authenticationResult);

            try
            {
                var result = await acWithLocalCache.AcquireTokenAsync(resource, clientId, credential);
#if TEST_ADAL_WINRT_UNIT
    // ADAL WinRT does not throw exception. It returns error.
                Verify.AreEqual("multiple_matching_tokens_detected", result.Error);
#else
                Verify.Fail("Exception expected");
#endif
            }
            catch (AdalException adae)
            {
                Verify.IsTrue(adae.ErrorCode == "multiple_matching_tokens_detected" && adae.Message.Contains("The cache contains multiple tokens satisfying the requirements"));
            }

            try
            {
                AuthenticationContext acWithDefaultCache = new AuthenticationContext(authority, false);
                var result = await acWithDefaultCache.AcquireTokenAsync(resource, clientId, credential);
#if TEST_ADAL_WINRT_UNIT
                Verify.AreEqual("multiple_matching_tokens_detected", result.Error);
#else
                Verify.Fail("Exception expected");
#endif
            }
            catch (AdalException adae)
            {
                Verify.IsTrue(adae.ErrorCode == "multiple_matching_tokens_detected" && adae.Message.Contains("The cache contains multiple tokens satisfying the requirements"));
            }

            // @resource && @clientId
            acWithLocalCache = new AuthenticationContext(authority, false, localCache);
            localCache.Clear();
            var cacheValue = CreateCacheValue(uniqueId, displayableId);
            resource = Guid.NewGuid().ToString();
            clientId = Guid.NewGuid().ToString();

            TokenCacheKey tempKey = new TokenCacheKey(authority, resource, clientId, TokenSubjectType.User, null, null);
            AddToDictionary(localCache, tempKey, cacheValue);
            RemoveFromDictionary(localCache, tempKey);
            Verify.IsFalse(localCache.tokenCacheDictionary.ContainsKey(tempKey));
            AddToDictionary(localCache, tempKey, cacheValue);

#if TEST_ADAL_WINRT_UNIT
            authenticationResultFromCache = await acWithLocalCache.AcquireTokenAsync(resource, clientId, redirectUri);
#else
            authenticationResultFromCache = await acWithLocalCache.AcquireTokenSilentAsync(resource, clientId);
#endif
            VerifyAuthenticationResultsAreEqual(cacheValue, authenticationResultFromCache);

            // @resource && @clientId && userId
            acWithLocalCache = new AuthenticationContext(authority, false, localCache);
            localCache.Clear();
            resource = Guid.NewGuid().ToString();
            clientId = Guid.NewGuid().ToString();
            uniqueId = Guid.NewGuid().ToString();
            displayableId = Guid.NewGuid().ToString();
            cacheValue = CreateCacheValue(uniqueId, displayableId);
            AddToDictionary(localCache, new TokenCacheKey(authority, resource, clientId, TokenSubjectType.User, uniqueId, displayableId), cacheValue);

            var userId = new UserIdentifier(uniqueId, UserIdentifierType.UniqueId);
            var userIdUpper = new UserIdentifier(displayableId.ToUpper(), UserIdentifierType.RequiredDisplayableId);

#if TEST_ADAL_WINRT_UNIT
            authenticationResultFromCache = await acWithLocalCache.AcquireTokenAsync(resource, clientId, redirectUri, PromptBehavior.Auto, userId);
#else
            authenticationResultFromCache = await acWithLocalCache.AcquireTokenSilentAsync(resource, clientId, userId);
#endif
            VerifyAuthenticationResultsAreEqual(cacheValue, authenticationResultFromCache);

#if TEST_ADAL_WINRT_UNIT
            authenticationResultFromCache = await acWithLocalCache.AcquireTokenAsync(resource, clientId, redirectUri, PromptBehavior.Auto, userIdUpper);
#else
            authenticationResultFromCache = await acWithLocalCache.AcquireTokenSilentAsync(resource, clientId, userIdUpper);
#endif
            VerifyAuthenticationResultsAreEqual(cacheValue, authenticationResultFromCache);

#if TEST_ADAL_WINRT_UNIT
            authenticationResultFromCache = await acWithLocalCache.AcquireTokenAsync(resource, clientId, redirectUri);
#else
            authenticationResultFromCache = await acWithLocalCache.AcquireTokenSilentAsync(resource, clientId);
#endif
            VerifyAuthenticationResultsAreEqual(cacheValue, authenticationResultFromCache);

        }
        /// <summary>
        /// Determines whether the specified object is equal to the current object.
        /// </summary>
        /// <returns>
        /// true if the specified object is equal to the current object; otherwise, false.
        /// </returns>
        /// <param name="obj">The object to compare with the current object. </param><filterpriority>2</filterpriority>
        public override bool Equals(object obj)
        {
            TokenCacheKey other = obj as TokenCacheKey;

            return((other != null) && this.Equals(other));
        }
 internal bool Match(TokenCacheKey key)
 {
     return (key.Authority == this.Authority && key.ResourceEquals(this.Resource) && key.ClientIdEquals(this.ClientId)
             && key.TokenSubjectType == this.TokenSubjectType && key.UniqueId == this.UniqueId && key.DisplayableIdEquals(this.DisplayableId));
 }
        /// <summary>
        /// Deserializes state of the cache. The state should be the blob received earlier by calling the method Serialize.
        /// </summary>
        /// <param name="state">State of the cache as a blob</param>
        public void Deserialize([ReadOnlyArray] byte[] state)
        {
            lock (cacheLock)
            {
                if (state == null)
                {
                    this.tokenCacheDictionary.Clear();
                    return;
                }

                using (Stream stream = new MemoryStream())
                {
                    BinaryWriter writer = new BinaryWriter(stream);
                    writer.Write(state);
                    writer.Flush();
                    stream.Position = 0;

                    BinaryReader reader = new BinaryReader(stream);
                    int schemaVersion = reader.ReadInt32();
                    if (schemaVersion != SchemaVersion)
                    {
                        Logger.Warning(null,
                            "The version of the persistent state of the cache does not match the current schema, so skipping deserialization.");
                        return;
                    }

                    this.tokenCacheDictionary.Clear();
                    int count = reader.ReadInt32();
                    for (int n = 0; n < count; n++)
                    {
                        string keyString = reader.ReadString();

                        string[] kvpElements = keyString.Split(new[] {Delimiter}, StringSplitOptions.None);
                        AuthenticationResult result = AuthenticationResult.Deserialize(reader.ReadString());
                        TokenCacheKey key = new TokenCacheKey(kvpElements[0], kvpElements[1], kvpElements[2],
                            (TokenSubjectType) int.Parse(kvpElements[3]), result.UserInfo);

                        this.tokenCacheDictionary.Add(key, result);
                    }

                    Logger.Information(null, "Deserialized {0} items to token cache.", count);
                }
            }
        }
        internal static void TokenCacheValueSplitTest()
        {
            var tokenCache = new TokenCache();
            TokenCacheKey key = new TokenCacheKey("https://localhost/MockSts", "resourc1", "client1", TokenSubjectType.User, null, "user1");

            tokenCache.Clear();
            AddToDictionary(tokenCache, key, null);
            Verify.AreEqual(tokenCache.tokenCacheDictionary[key], null);
            for (int len = 0; len < 3000; len++)
            {
                var value = CreateCacheValue(null, "user1");
                tokenCache.Clear();
                AddToDictionary(tokenCache, key, value);
                Verify.AreEqual(tokenCache.tokenCacheDictionary[key], value);
            }
        }
        internal void StoreToCache(AuthenticationResult result, string authority, string resource, string clientId, TokenSubjectType subjectType, CallState callState)
        {
            lock (cacheLock)
            {
                Logger.Verbose(callState, "Storing token in the cache...");

                string uniqueId = (result.UserInfo != null) ? result.UserInfo.UniqueId : null;
                string displayableId = (result.UserInfo != null) ? result.UserInfo.DisplayableId : null;

                this.OnBeforeWrite(new TokenCacheNotificationArgs
                {
                    Resource = resource,
                    ClientId = clientId,
                    UniqueId = uniqueId,
                    DisplayableId = displayableId
                });

                TokenCacheKey tokenCacheKey = new TokenCacheKey(authority, resource, clientId, subjectType,
                    result.UserInfo);
                this.tokenCacheDictionary[tokenCacheKey] = result;
                Logger.Verbose(callState, "An item was stored in the cache");
                this.UpdateCachedMrrtRefreshTokens(result, authority, clientId, subjectType);

                this.HasStateChanged = true;
            }
        }
        public static void CheckPublicGetSets()
        {
            DateTimeOffset now = DateTimeOffset.UtcNow;
            TokenCacheKey tokenCacheKey = new TokenCacheKey("Authority", "Resource", "ClientId", TokenSubjectType.User, "UniqueId", "DisplayableId");

            Verify.IsTrue(tokenCacheKey.Authority == "Authority");
            Verify.IsTrue(tokenCacheKey.ClientId == "ClientId");
            Verify.IsTrue(tokenCacheKey.Resource == "Resource");
            Verify.IsTrue(tokenCacheKey.UniqueId == "UniqueId");
            Verify.IsTrue(tokenCacheKey.DisplayableId == "DisplayableId");
            Verify.IsTrue(tokenCacheKey.TokenSubjectType == TokenSubjectType.User);
        }
        internal static void TokenCacheCapacityTest()
        {
            var tokenCache = new TokenCache();

            tokenCache.Clear();

            const int MaxItemCount = 100;
            const int MaxFieldSize = 256;
            TokenCacheKey[] keys = new TokenCacheKey[MaxItemCount];
            AuthenticationResult[] values = new AuthenticationResult[MaxItemCount];

            for (int i = 0; i < MaxItemCount; i++)
            {
                keys[i] = GenerateRandomTokenCacheKey(MaxFieldSize);

                values[i] = CreateCacheValue(null, null);
                AddToDictionary(tokenCache, keys[i], values[i]);
            }

            Verify.AreEqual(MaxItemCount, tokenCache.Count);

            for (int i = 0; i < MaxItemCount; i++)
            {
                AuthenticationResult cacheValue;
                int index = MaxItemCount - i - 1;
                Verify.IsTrue(tokenCache.tokenCacheDictionary.TryGetValue(keys[index], out cacheValue));
                Verify.AreEqual(values[index], cacheValue);
                RemoveFromDictionary(tokenCache, keys[index]);
                Verify.AreEqual(index, tokenCache.Count);
            }

            tokenCache.Clear();
        }
 /// <summary>
 /// Determines whether the specified TokenCacheKey is equal to the current object.
 /// </summary>
 /// <returns>
 /// true if the specified TokenCacheKey is equal to the current object; otherwise, false.
 /// </returns>
 /// <param name="other">The TokenCacheKey to compare with the current object. </param><filterpriority>2</filterpriority>
 public bool Equals(TokenCacheKey other)
 {
     return ReferenceEquals(this, other) ||
        (other != null
        && (other.Authority == this.Authority)
        && this.ResourceEquals(other.Resource)
        && this.ClientIdEquals(other.ClientId)
        && (other.UniqueId == this.UniqueId)
        && this.DisplayableIdEquals(other.DisplayableId)
        && (other.TokenSubjectType == this.TokenSubjectType));
 }