예제 #1
0
        /// <summary>
        /// Gets a singleton instance of the TokenCacheHelper
        /// </summary>
        /// <param name="tokenCache">Token Cache</param>
        /// <returns>token cache helper</returns>
        public void RegisterCache(ITokenCache tokenCache)
        {
            lock (_lockObject)
            {
                _userTokenCache = tokenCache ?? throw new ArgumentNullException(nameof(tokenCache));

                _userTokenCache.SetBeforeAccess(BeforeAccessNotification);
                _userTokenCache.SetAfterAccess(AfterAccessNotification);

                _logger.TraceEvent(TraceEventType.Information, /*id*/ 0, $"Initializing msal cache");

                byte[] data = _store.ReadData();

                _logger.TraceEvent(TraceEventType.Information, /*id*/ 0, $"Read '{data?.Length}' bytes from storage");

                if (data != null && data.Length > 0)
                {
                    try
                    {
                        _logger.TraceEvent(TraceEventType.Information, /*id*/ 0, $"Deserializing data into memory");
                        _userTokenCache.DeserializeMsalV3(data);
                    }
                    catch (Exception e)
                    {
                        _logger.TraceEvent(TraceEventType.Warning, /*id*/ 0, $"An exception was encountered while deserializing the data during initialization of {nameof(MsalCacheHelper)} : {e}");

                        Clear();
                    }
                }

                _logger.TraceEvent(TraceEventType.Information, /*id*/ 0, $"Done initializing");
            }
        }
예제 #2
0
        /// <summary>
        /// Registers a token cache to synchronize with on disk storage.
        /// </summary>
        /// <param name="tokenCache">Token Cache</param>
        public void RegisterCache(ITokenCache tokenCache)
        {
            // OK, we have two nested locks here. We need to maintain a clear ordering to avoid deadlocks.
            // 1. Use the CrossPlatLock which is respected by all processes and is used around all cache accesses.
            // 2. Use _lockObject which is used in UnregisterCache, and is needed for all accesses of _registeredCaches.
            //
            // Here specifically, we don't want to set this.CacheLock because we're done with the lock by the end of the method.
            using (var crossPlatLock = CreateCrossPlatLock(_storageCreationProperties))
            {
                lock (_lockObject)
                {
                    _logger.TraceEvent(TraceEventType.Information, /*id*/ 0, $"Registering token cache with on disk storage");
                    if (_registeredCaches.Contains(tokenCache))
                    {
                        _logger.TraceEvent(TraceEventType.Warning, /*id*/ 0, $"Redundant registration of {nameof(tokenCache)} in {nameof(MsalCacheHelper)}, skipping further registration.");
                        return;
                    }

                    _userTokenCache = tokenCache ?? throw new ArgumentNullException(nameof(tokenCache));

                    _userTokenCache.SetBeforeAccess(BeforeAccessNotification);
                    _userTokenCache.SetAfterAccess(AfterAccessNotification);

                    _logger.TraceEvent(TraceEventType.Information, /*id*/ 0, $"Initializing msal cache");

                    if (_store.HasChanged)
                    {
                        _logger.TraceEvent(TraceEventType.Information, /*id*/ 0, $"Before access, the store has changed");
                        byte[] fileData = _store.ReadData();
                        _logger.TraceEvent(TraceEventType.Information, /*id*/ 0, $"Read '{fileData?.Length}' bytes from storage");
                        _cachedStoreData = _store.ReadData();
                        _logger.TraceEvent(TraceEventType.Information, /*id*/ 0, $"Read '{_cachedStoreData?.Length}' bytes from storage");
                    }

                    try
                    {
                        _logger.TraceEvent(TraceEventType.Information, /*id*/ 0, $"Deserializing data into memory");
                        _userTokenCache.DeserializeMsalV3(_cachedStoreData);
                    }
                    catch (Exception e)
                    {
                        _logger.TraceEvent(TraceEventType.Warning, /*id*/ 0, $"An exception was encountered while deserializing the data during initialization of {nameof(MsalCacheHelper)} : {e}");

                        Clear();
                    }
                }

                _registeredCaches.Add(tokenCache); // Ignore return value, since we already bail if _registeredCaches contains tokenCache earlier

                _logger.TraceEvent(TraceEventType.Information, /*id*/ 0, $"Done initializing");
            }
        }
        /// <summary>
        /// Gets the current set of accounts in the cache by creating a new public client, and
        /// deserializing the cache into a temporary object.
        /// </summary>
        private static async Task <HashSet <string> > GetAccountIdentifiersAsync(StorageCreationProperties storageCreationProperties)
        {
            var accountIdentifiers = new HashSet <string>();

            if (File.Exists(storageCreationProperties.CacheFilePath))
            {
                var pca = PublicClientApplicationBuilder.Create(storageCreationProperties.ClientId).Build();

                pca.UserTokenCache.SetBeforeAccess((args) =>
                {
                    var tempCache = new MsalCacheStorage(storageCreationProperties, s_staticLogger.Value);
                    // We're using ReadData here so that decryption is gets handled within the store.
                    args.TokenCache.DeserializeMsalV3(tempCache.ReadData());
                });

                var accounts = await pca.GetAccountsAsync().ConfigureAwait(false);

                foreach (var account in accounts)
                {
                    accountIdentifiers.Add(account.HomeAccountId.Identifier);
                }
            }

            return(accountIdentifiers);
        }
        /// <summary>
        /// Gets the current set of accounts in the cache by creating a new public client, and
        /// deserializing the cache into a temporary object.
        /// </summary>
        private static async Task <HashSet <string> > GetAccountIdentifiersAsync(
            StorageCreationProperties storageCreationProperties,
            TraceSourceLogger logger)
        {
            var accountIdentifiers = new HashSet <string>();

            if (File.Exists(storageCreationProperties.CacheFilePath))
            {
                var pca = PublicClientApplicationBuilder.Create(storageCreationProperties.ClientId).Build();

                pca.UserTokenCache.SetBeforeAccess((args) =>
                {
                    MsalCacheStorage tempCache = null;
                    try
                    {
                        tempCache = MsalCacheStorage.Create(storageCreationProperties, s_staticLogger.Value.Source);
                        // We're using ReadData here so that decryption is handled within the store.
                        var data = tempCache.ReadData();
                        args.TokenCache.DeserializeMsalV3(data);
                    }
                    catch (Exception e)
                    {
                        logger.LogError("An error occured while reading the token cache: " + e);
                        logger.LogError("Deleting the token cache as it might be corrupt.");
                        tempCache.Clear();
                    }
                });

                var accounts = await pca.GetAccountsAsync().ConfigureAwait(false);

                foreach (var account in accounts)
                {
                    accountIdentifiers.Add(account.HomeAccountId.Identifier);
                }
            }

            return(accountIdentifiers);
        }