Пример #1
0
        private static List <IAccount> UpdateWithAdalAccounts(
            string envFromRequest,
            IEnumerable <string> envAliases,
            AdalUsersForMsal adalUsers,
            IDictionary <string, Account> clientInfoToAccountMap)
        {
            var accounts = new List <IAccount>();

            foreach (KeyValuePair <string, AdalUserInfo> pair in adalUsers.GetUsersWithClientInfo(envAliases))
            {
                var    clientInfo        = ClientInfo.CreateFromJson(pair.Key);
                string accountIdentifier = clientInfo.ToAccountIdentifier();

                if (!clientInfoToAccountMap.ContainsKey(accountIdentifier))
                {
                    clientInfoToAccountMap[accountIdentifier] = new Account(
                        accountIdentifier, pair.Value.DisplayableId, envFromRequest);
                }
            }

            accounts.AddRange(clientInfoToAccountMap.Values);
            var uniqueUserNames = clientInfoToAccountMap.Values.Select(o => o.Username).Distinct().ToList();

            foreach (AdalUserInfo user in adalUsers.GetUsersWithoutClientInfo(envAliases))
            {
                if (!string.IsNullOrEmpty(user.DisplayableId) && !uniqueUserNames.Contains(user.DisplayableId))
                {
                    accounts.Add(new Account(null, user.DisplayableId, envFromRequest));
                    uniqueUserNames.Add(user.DisplayableId);
                }
            }

            return(accounts);
        }
Пример #2
0
        private List <IAccount> UpdateWithAdalAccountsWithoutClientInfo(
            string envFromRequest,
            IEnumerable <string> envAliases,
            AdalUsersForMsal adalUsers,
            IDictionary <string, Account> clientInfoToAccountMap)
        {
            var accounts = new List <IAccount>();

            accounts.AddRange(clientInfoToAccountMap.Values);

            if (ServiceBundle.Config.LegacyCacheCompatibilityEnabled)
            {
                var uniqueUserNames = clientInfoToAccountMap.Values.Select(o => o.Username).Distinct().ToList();

                foreach (AdalUserInfo user in adalUsers.GetUsersWithoutClientInfo(envAliases))
                {
                    if (!string.IsNullOrEmpty(user.DisplayableId) && !uniqueUserNames.Contains(user.DisplayableId))
                    {
                        accounts.Add(new Account(null, user.DisplayableId, envFromRequest));
                        uniqueUserNames.Add(user.DisplayableId);
                    }
                }
            }

            return(accounts);
        }
        /// <remarks>
        /// Get accounts should not make a network call, if possible. This can be achieved if
        /// all the environments in the token cache are known to MSAL, as MSAL keeps a list of
        /// known environments in <see cref="KnownMetadataProvider"/>
        /// </remarks>
        async Task <IEnumerable <IAccount> > ITokenCacheInternal.GetAccountsAsync(string authority, RequestContext requestContext)
        {
            var  environment      = Authority.GetEnviroment(authority);
            bool filterByClientId = !_featureFlags.IsFociEnabled;

            IEnumerable <MsalRefreshTokenCacheItem> rtCacheItems      = GetAllRefreshTokensWithNoLocks(filterByClientId);
            IEnumerable <MsalAccountCacheItem>      accountCacheItems = _accessor.GetAllAccounts();

            AdalUsersForMsal adalUsersResult = CacheFallbackOperations.GetAllAdalUsersForMsal(
                Logger,
                LegacyCachePersistence,
                ClientId);

            // Multi-cloud support - must filter by env.
            ISet <string> allEnvironmentsInCache = new HashSet <string>(
                accountCacheItems.Select(aci => aci.Environment),
                StringComparer.OrdinalIgnoreCase);

            allEnvironmentsInCache.UnionWith(rtCacheItems.Select(rt => rt.Environment));
            allEnvironmentsInCache.UnionWith(adalUsersResult.GetAdalUserEnviroments());

            var instanceMetadata = await ServiceBundle.InstanceDiscoveryManager.GetMetadataEntryTryAvoidNetworkAsync(
                authority,
                allEnvironmentsInCache,
                requestContext).ConfigureAwait(false);

            rtCacheItems      = rtCacheItems.Where(rt => instanceMetadata.Aliases.ContainsOrdinalIgnoreCase(rt.Environment));
            accountCacheItems = accountCacheItems.Where(acc => instanceMetadata.Aliases.ContainsOrdinalIgnoreCase(acc.Environment));

            IDictionary <string, Account> clientInfoToAccountMap = new Dictionary <string, Account>();

            foreach (MsalRefreshTokenCacheItem rtItem in rtCacheItems)
            {
                foreach (MsalAccountCacheItem account in accountCacheItems)
                {
                    if (RtMatchesAccount(rtItem, account))
                    {
                        clientInfoToAccountMap[rtItem.HomeAccountId] = new Account(
                            account.HomeAccountId,
                            account.PreferredUsername,
                            environment);  // Preserve the env passed in by the user

                        break;
                    }
                }
            }

            IEnumerable <IAccount> accounts = UpdateWithAdalAccounts(
                environment,
                instanceMetadata.Aliases,
                adalUsersResult,
                clientInfoToAccountMap);

            return(accounts);
        }
Пример #4
0
        private static void AssertByUsername(
            AdalUsersForMsal adalUsers,
            IEnumerable <string> enviroments,
            IEnumerable <string> expectedUsersWithClientInfo,
            IEnumerable <string> expectedUsersWithoutClientInfo)
        {
            // Assert
            var usersWithClientInfo = adalUsers.GetUsersWithClientInfo(enviroments).Select(x => x.Value);
            IEnumerable <AdalUserInfo> usersWithoutClientInfo = adalUsers.GetUsersWithoutClientInfo(enviroments);

            AssertUsersByDisplayName(
                expectedUsersWithClientInfo,
                usersWithClientInfo,
                "Expecting only user1 and user2 because the other users either have no ClientInfo or have a different env or clientid");
            AssertUsersByDisplayName(expectedUsersWithoutClientInfo, usersWithoutClientInfo);
        }
Пример #5
0
        private static void UpdateMapWithAdalAccountsWithClientInfo(
            string envFromRequest,
            IEnumerable <string> envAliases,
            AdalUsersForMsal adalUsers,
            IDictionary <string, Account> clientInfoToAccountMap)
        {
            foreach (KeyValuePair <string, AdalUserInfo> pair in adalUsers.GetUsersWithClientInfo(envAliases))
            {
                var    clientInfo        = ClientInfo.CreateFromJson(pair.Key);
                string accountIdentifier = clientInfo.ToAccountIdentifier();

                if (!clientInfoToAccountMap.ContainsKey(accountIdentifier))
                {
                    clientInfoToAccountMap[accountIdentifier] = new Account(
                        accountIdentifier, pair.Value.DisplayableId, envFromRequest);
                }
            }
        }
        [TestCategory(TestCategories.Regression)] // https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/1815

        public async Task UnifiedCache_ProcessAdalDictionaryForDuplicateKey_Async()
        {
            using (var harness = CreateTestHarness())
            {
                var app = PublicClientApplicationBuilder
                          .Create(TestConstants.ClientId)
                          .WithAuthority(new Uri(ClientApplicationBase.DefaultAuthority), true)
                          .WithUserTokenLegacyCachePersistenceForTest(new TestLegacyCachePersistance())
                          .WithHttpManager(harness.HttpManager)
                          .BuildConcrete();

                CreateAdalCache(harness.ServiceBundle.ApplicationLogger, app.UserTokenCacheInternal.LegacyPersistence, TestConstants.s_scope.ToString());

                var adalUsers =
                    CacheFallbackOperations.GetAllAdalUsersForMsal(
                        harness.ServiceBundle.ApplicationLogger,
                        app.UserTokenCacheInternal.LegacyPersistence,
                        TestConstants.ClientId);

                CreateAdalCache(harness.ServiceBundle.ApplicationLogger, app.UserTokenCacheInternal.LegacyPersistence, "user.read");

                AdalUsersForMsal adalUsers2 =
                    CacheFallbackOperations.GetAllAdalUsersForMsal(
                        harness.ServiceBundle.ApplicationLogger,
                        app.UserTokenCacheInternal.LegacyPersistence,
                        TestConstants.ClientId);

                Assert.AreEqual(
                    adalUsers.GetUsersWithClientInfo(null).Single().Key,
                    adalUsers2.GetUsersWithClientInfo(null).Single().Key);

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

                Assert.AreEqual(1, accounts.Count(), "The 2 RTs belong to the same user");

                // The ADAL cache contains access tokens, but these are NOT usable by MSAL / v2 endpoint.
                // MSAL will however use the RT from ADAL to fetch new access tokens...
                harness.HttpManager.AddAllMocks(TokenResponseType.Valid);
                var res = await app.AcquireTokenSilent(TestConstants.s_scope, accounts.First()).ExecuteAsync().ConfigureAwait(false);

                Assert.IsNotNull(res);
            }
        }
Пример #7
0
        /// <remarks>
        /// Get accounts should not make a network call, if possible. This can be achieved if
        /// all the environments in the token cache are known to MSAL, as MSAL keeps a list of
        /// known environments in <see cref="KnownMetadataProvider"/>
        /// </remarks>
        async Task <IEnumerable <IAccount> > ITokenCacheInternal.GetAccountsAsync(AuthenticationRequestParameters requestParameters)
        {
            var  logger           = requestParameters.RequestContext.Logger;
            var  environment      = requestParameters.AuthorityInfo.Host;
            bool filterByClientId = !_featureFlags.IsFociEnabled;

            IEnumerable <MsalRefreshTokenCacheItem> rtCacheItems      = GetAllRefreshTokensWithNoLocks(filterByClientId);
            IEnumerable <MsalAccountCacheItem>      accountCacheItems = _accessor.GetAllAccounts();

            if (logger.IsLoggingEnabled(LogLevel.Verbose))
            {
                logger.Verbose($"GetAccounts found {rtCacheItems.Count()} RTs and {accountCacheItems.Count()} accounts in MSAL cache. ");
            }

            // Multi-cloud support - must filter by env.
            ISet <string> allEnvironmentsInCache = new HashSet <string>(
                accountCacheItems.Select(aci => aci.Environment),
                StringComparer.OrdinalIgnoreCase);

            allEnvironmentsInCache.UnionWith(rtCacheItems.Select(rt => rt.Environment));

            AdalUsersForMsal adalUsersResult = null;

            if (ServiceBundle.Config.LegacyCacheCompatibilityEnabled)
            {
                adalUsersResult = CacheFallbackOperations.GetAllAdalUsersForMsal(
                    Logger,
                    LegacyCachePersistence,
                    ClientId);
                allEnvironmentsInCache.UnionWith(adalUsersResult.GetAdalUserEnviroments());
            }

            var instanceMetadata = await ServiceBundle.InstanceDiscoveryManager.GetMetadataEntryTryAvoidNetworkAsync(
                requestParameters.AuthorityInfo,
                allEnvironmentsInCache,
                requestParameters.RequestContext).ConfigureAwait(false);

            rtCacheItems      = rtCacheItems.Where(rt => instanceMetadata.Aliases.ContainsOrdinalIgnoreCase(rt.Environment));
            accountCacheItems = accountCacheItems.Where(acc => instanceMetadata.Aliases.ContainsOrdinalIgnoreCase(acc.Environment));

            if (logger.IsLoggingEnabled(LogLevel.Verbose))
            {
                logger.Verbose($"GetAccounts found {rtCacheItems.Count()} RTs and {accountCacheItems.Count()} accounts in MSAL cache after environment filtering. ");
            }

            IDictionary <string, Account> clientInfoToAccountMap = new Dictionary <string, Account>();

            foreach (MsalRefreshTokenCacheItem rtItem in rtCacheItems)
            {
                foreach (MsalAccountCacheItem account in accountCacheItems)
                {
                    if (RtMatchesAccount(rtItem, account))
                    {
                        clientInfoToAccountMap[rtItem.HomeAccountId] = new Account(
                            account.HomeAccountId,
                            account.PreferredUsername,
                            environment, // Preserve the env passed in by the user
                            account.WamAccountIds);

                        break;
                    }
                }
            }

            if (ServiceBundle.Config.LegacyCacheCompatibilityEnabled)
            {
                UpdateMapWithAdalAccountsWithClientInfo(
                    environment,
                    instanceMetadata.Aliases,
                    adalUsersResult,
                    clientInfoToAccountMap);
            }

            // Add WAM accounts stored in MSAL's cache - for which we do not have an RT
            if (requestParameters.AppConfig.IsBrokerEnabled && ServiceBundle.PlatformProxy.BrokerSupportsWamAccounts)
            {
                foreach (MsalAccountCacheItem wamAccountCache in accountCacheItems.Where(
                             acc => acc.WamAccountIds != null &&
                             acc.WamAccountIds.ContainsKey(requestParameters.AppConfig.ClientId)))
                {
                    var wamAccount = new Account(
                        wamAccountCache.HomeAccountId,
                        wamAccountCache.PreferredUsername,
                        environment,
                        wamAccountCache.WamAccountIds);

                    clientInfoToAccountMap[wamAccountCache.HomeAccountId] = wamAccount;
                }
            }

            IEnumerable <IAccount> accounts = UpdateWithAdalAccountsWithoutClientInfo(environment,
                                                                                      instanceMetadata.Aliases,
                                                                                      adalUsersResult,
                                                                                      clientInfoToAccountMap);

            if (!string.IsNullOrEmpty(requestParameters.HomeAccountId))
            {
                accounts = accounts.Where(acc => acc.HomeAccountId.Identifier.Equals(
                                              requestParameters.HomeAccountId,
                                              StringComparison.OrdinalIgnoreCase));

                if (logger.IsLoggingEnabled(LogLevel.Verbose))
                {
                    logger.Verbose($"Filtered by home account id. Remaining accounts {accounts.Count()} ");
                }
            }

            return(accounts);
        }