/// <summary>
        /// Algorithm to delete:
        ///
        /// DisplayableId cannot be null
        /// Removal is scoped by enviroment and clientId;
        ///
        /// If accountId != null then delete everything with the same clientInfo
        /// otherwise, delete everything with the same displayableId
        ///
        /// Notes:
        /// - displayableId can change rarely
        /// - ClientCredential Grant uses the app token cache, not the user token cache, so this algorithm does not apply
        /// (nor will GetAccounts / RemoveAccount work)
        ///
        /// </summary>
        public static void RemoveAdalUser(
            ILegacyCachePersistence legacyCachePersistence,
            string clientId,
            string displayableId,
            string accountOrUserId)
        {
            try
            {
                IDictionary <AdalTokenCacheKey, AdalResultWrapper> adalCache =
                    AdalCacheOperations.Deserialize(legacyCachePersistence.LoadCache());

                if (!string.IsNullOrEmpty(accountOrUserId))
                {
                    RemoveEntriesWithMatchingId(clientId, accountOrUserId, adalCache);
                }

                RemoveEntriesWithMatchingName(clientId, displayableId, adalCache);
                legacyCachePersistence.WriteCache(AdalCacheOperations.Serialize(adalCache));
            }
            catch (Exception ex)
            {
                MsalLogger.Default.WarningPiiWithPrefix(ex, "An error occurred while deleting account in ADAL format from the cache. " +
                                                        "For details please see https://aka.ms/net-cache-persistence-errors. ");
            }
        }
        public static MsalRefreshTokenCacheItem GetAdalEntryForMsal(
            ICoreLogger logger,
            ILegacyCachePersistence legacyCachePersistence,
            IEnumerable <string> environmentAliases,
            string clientId,
            string upn,
            string uniqueId)
        {
            IEnumerable <MsalRefreshTokenCacheItem> adalRts = GetAllAdalEntriesForMsal(
                logger,
                legacyCachePersistence,
                environmentAliases,
                clientId,
                upn,
                uniqueId);

            IEnumerable <IGrouping <string, MsalRefreshTokenCacheItem> > rtGroupsByEnv = adalRts.GroupBy(rt => rt.Environment.ToLowerInvariant());

            // if we have more than 1 RT per env, there is smth wrong with the ADAL cache
            if (rtGroupsByEnv.Any(g => g.Count() > 1))
            {
                //Due to the fact that there is a problem with the ADAL cache that causes this exception, The ADAL cache will be removed when
                //this exception is triggered so that users can sign in interactivly and repopulate the cache.
                IDictionary <AdalTokenCacheKey, AdalResultWrapper> adalCache =
                    AdalCacheOperations.Deserialize(logger, legacyCachePersistence.LoadCache());

                adalCache.Clear();
                logger.Error(MsalErrorMessage.InvalidAdalCacheMultipleRTs);
                legacyCachePersistence.WriteCache(AdalCacheOperations.Serialize(logger, adalCache));
                return(null);
            }

            return(adalRts.FirstOrDefault());
        }
        public static void WriteAdalRefreshToken(
            ILegacyCachePersistence legacyCachePersistence,
            MsalRefreshTokenCacheItem rtItem,
            MsalIdTokenCacheItem idItem,
            string authority,
            string uniqueId,
            string scope)
        {
            try
            {
                if (rtItem == null)
                {
                    MsalLogger.Default.Info("No refresh token available. Skipping MSAL refresh token cache write");
                    return;
                }

                //Using scope instead of resource because that value does not exist. STS should return it.
                AdalTokenCacheKey key = new AdalTokenCacheKey(authority, scope, rtItem.ClientId, TokenSubjectType.User,
                                                              uniqueId, idItem.IdToken.PreferredUsername);
                AdalResultWrapper wrapper = new AdalResultWrapper()
                {
                    Result = new AdalResult(null, null, DateTimeOffset.MinValue)
                    {
                        UserInfo = new AdalUserInfo()
                        {
                            UniqueId      = uniqueId,
                            DisplayableId = idItem.IdToken.PreferredUsername
                        }
                    },
                    RefreshToken  = rtItem.Secret,
                    RawClientInfo = rtItem.RawClientInfo,
                    //ResourceInResponse is needed to treat RT as an MRRT. See IsMultipleResourceRefreshToken
                    //property in AdalResultWrapper and its usage. Stronger design would be for the STS to return resource
                    //for which the token was issued as well on v2 endpoint.
                    ResourceInResponse = scope
                };

                IDictionary <AdalTokenCacheKey, AdalResultWrapper> dictionary = AdalCacheOperations.Deserialize(legacyCachePersistence.LoadCache());
                dictionary[key] = wrapper;
                legacyCachePersistence.WriteCache(AdalCacheOperations.Serialize(dictionary));
            }
            catch (Exception ex)
            {
                if (!string.Equals(rtItem?.Environment, idItem?.Environment, StringComparison.OrdinalIgnoreCase))
                {
                    MsalLogger.Default.Error(DifferentEnvError);
                }

                if (!string.Equals(rtItem?.Environment, new Uri(authority).Host, StringComparison.OrdinalIgnoreCase))
                {
                    MsalLogger.Default.Error(DifferentAuthorityError);
                }

                MsalLogger.Default.WarningPiiWithPrefix(ex, "An error occurred while writing MSAL refresh token to the cache in ADAL format. " +
                                                        "For details please see https://aka.ms/net-cache-persistence-errors. ");
            }
        }