Skip to content

Commit 7cadf60

Browse files
authored
Add more logging to GetAccounts by id (#4929)
Add more verbose logging to cache op
1 parent 5dacb5f commit 7cadf60

File tree

3 files changed

+86
-30
lines changed

3 files changed

+86
-30
lines changed

src/client/Microsoft.Identity.Client/ClientApplicationBase.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ public abstract partial class ClientApplicationBase : ApplicationBase, IClientAp
3838

3939
internal ClientApplicationBase(ApplicationConfiguration config) : base(config)
4040
{
41-
UserTokenCacheInternal =
42-
config.UserTokenCacheInternalForTest ??
41+
UserTokenCacheInternal =
42+
config.UserTokenCacheInternalForTest ??
4343
new TokenCache(
4444
ServiceBundle,
4545
false,
@@ -171,6 +171,15 @@ private async Task<IEnumerable<IAccount>> GetAccountsInternalAsync(ApiIds apiId,
171171
{
172172
Guid correlationId = Guid.NewGuid();
173173
RequestContext requestContext = CreateRequestContext(correlationId, cancellationToken);
174+
175+
if (requestContext.Logger.IsLoggingEnabled(LogLevel.Info))
176+
{
177+
requestContext.Logger.Info($"==== GetAccounts started - {apiId} ====");
178+
requestContext.Logger.InfoPii(
179+
$"Account id filter: {homeAccountIdFilter}",
180+
$"Account id filter: {!string.IsNullOrEmpty(homeAccountIdFilter)}");
181+
}
182+
174183
requestContext.ApiEvent = new ApiEvent(correlationId);
175184
requestContext.ApiEvent.ApiId = apiId;
176185

src/client/Microsoft.Identity.Client/PlatformsCommon/Shared/InMemoryPartitionedUserTokenCacheAccessor.cs

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -223,17 +223,36 @@ public virtual List<MsalAccessTokenCacheItem> GetAllAccessTokens(string partitio
223223
/// It should only support external token caching, in the hope that the external token cache is partitioned.
224224
public virtual List<MsalRefreshTokenCacheItem> GetAllRefreshTokens(string partitionKey = null, ILoggerAdapter requestlogger = null)
225225
{
226+
List<MsalRefreshTokenCacheItem> result;
226227
var logger = requestlogger ?? _logger;
227-
logger.Always($"[Internal cache] Total number of cache partitions found while getting refresh tokens: {RefreshTokenCacheDictionary.Count}");
228+
logger.AlwaysPii(
229+
$"[Internal cache] Total number of cache partitions found while getting refresh tokens: {RefreshTokenCacheDictionary.Count}. PartitionKey {partitionKey}",
230+
$"[Internal cache] Total number of cache partitions found while getting refresh tokens: {RefreshTokenCacheDictionary.Count}. PartitionKey {!string.IsNullOrEmpty(partitionKey)}");
231+
228232
if (string.IsNullOrEmpty(partitionKey))
229233
{
230-
return RefreshTokenCacheDictionary.SelectMany(dict => dict.Value).Select(kv => kv.Value).ToList();
234+
result = RefreshTokenCacheDictionary.SelectMany(dict => dict.Value).Select(kv => kv.Value).ToList();
235+
logger.Verbose(() => $"[Internal cache] GetAllRefreshTokens (no partition) found {result.Count} refresh tokens:");
236+
231237
}
232238
else
233239
{
234240
RefreshTokenCacheDictionary.TryGetValue(partitionKey, out ConcurrentDictionary<string, MsalRefreshTokenCacheItem> partition);
235-
return partition?.Select(kv => kv.Value)?.ToList() ?? CollectionHelpers.GetEmptyList<MsalRefreshTokenCacheItem>();
241+
242+
result = partition?.Select(kv => kv.Value)?.ToList() ?? CollectionHelpers.GetEmptyList<MsalRefreshTokenCacheItem>();
243+
if (logger.IsLoggingEnabled(LogLevel.Verbose))
244+
{
245+
logger.Verbose(() => $"[Internal cache] GetAllRefreshTokens (with partition - exists? {partition != null})) found {result.Count} refresh tokens:");
246+
if (RefreshTokenCacheDictionary.Count == 1 && result.Count == 0)
247+
{
248+
logger.VerbosePii(
249+
() => $"[Internal cache] 0 RTs and 1 partition. Partition in cache is {RefreshTokenCacheDictionary.Keys.First()}",
250+
() => "[Internal cache] 0 RTs and 1 partition] 0 RTs and 1 partition.");
251+
}
252+
}
236253
}
254+
255+
return result;
237256
}
238257

239258
/// WARNING: if partitionKey is null, this API is slow as it loads all tokens, not just from 1 partition.
@@ -255,15 +274,37 @@ public virtual List<MsalIdTokenCacheItem> GetAllIdTokens(string partitionKey = n
255274
/// It should only support external token caching, in the hope that the external token cache is partitioned.
256275
public virtual List<MsalAccountCacheItem> GetAllAccounts(string partitionKey = null, ILoggerAdapter requestlogger = null)
257276
{
277+
var logger = requestlogger ?? _logger;
278+
List<MsalAccountCacheItem> result;
279+
280+
logger.AlwaysPii(
281+
$"[Internal cache] Total number of cache partitions found while getting accounts: {AccountCacheDictionary.Count}. PartitionKey {partitionKey}",
282+
$"[Internal cache] Total number of cache partitions found while getting accounts: {AccountCacheDictionary.Count}. PartitionKey {!string.IsNullOrEmpty(partitionKey)}");
283+
258284
if (string.IsNullOrEmpty(partitionKey))
259285
{
260-
return AccountCacheDictionary.SelectMany(dict => dict.Value).Select(kv => kv.Value).ToList();
286+
result = AccountCacheDictionary.SelectMany(dict => dict.Value).Select(kv => kv.Value).ToList();
287+
logger.Verbose(() => $"[Internal cache] GetAllAccounts (no partition) found {result.Count} accounts.");
261288
}
262289
else
263290
{
264291
AccountCacheDictionary.TryGetValue(partitionKey, out ConcurrentDictionary<string, MsalAccountCacheItem> partition);
265-
return partition?.Select(kv => kv.Value)?.ToList() ?? CollectionHelpers.GetEmptyList<MsalAccountCacheItem>();
292+
result = partition?.Select(kv => kv.Value)?.ToList() ?? CollectionHelpers.GetEmptyList<MsalAccountCacheItem>();
293+
294+
if (logger.IsLoggingEnabled(LogLevel.Verbose))
295+
{
296+
logger.Verbose(() => $"[Internal cache] GetAllAccounts (with partition - exists? {partition != null}) found {result.Count} accounts.");
297+
if (AccountCacheDictionary.Count == 1 && result.Count == 0)
298+
{
299+
// get dictionary first key
300+
logger.VerbosePii(
301+
() => $"[Internal cache] 0 RTs and 1 partition. Partition in cache is {AccountCacheDictionary.Keys.First()}",
302+
() => "[Internal cache] 0 RTs and 1 partition] 0 RTs and 1 partition.");
303+
}
304+
}
266305
}
306+
307+
return result;
267308
}
268309

269310
public virtual List<MsalAppMetadataCacheItem> GetAllAppMetadata()

src/client/Microsoft.Identity.Client/TokenCache.ITokenCacheInternal.cs

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ async Task<Tuple<MsalAccessTokenCacheItem, MsalIdTokenCacheItem, Account>> IToke
9090
"client_credentials flow should not receive a refresh token");
9191

9292
Debug.Assert(
93-
(requestParams.ApiId != ApiEvent.ApiIds.AcquireTokenForSystemAssignedManagedIdentity ||
93+
(requestParams.ApiId != ApiEvent.ApiIds.AcquireTokenForSystemAssignedManagedIdentity ||
9494
requestParams.ApiId != ApiEvent.ApiIds.AcquireTokenForUserAssignedManagedIdentity),
9595
"Managed identity flow should not receive a refresh token");
9696

@@ -152,7 +152,7 @@ async Task<Tuple<MsalAccessTokenCacheItem, MsalIdTokenCacheItem, Account>> IToke
152152
}
153153
}
154154

155-
155+
156156
account = new Account(
157157
homeAccountId,
158158
username,
@@ -195,7 +195,7 @@ async Task<Tuple<MsalAccessTokenCacheItem, MsalIdTokenCacheItem, Account>> IToke
195195
identityLogger: requestParams.RequestContext.Logger.IdentityLogger,
196196
piiLoggingEnabled: requestParams.RequestContext.Logger.PiiLoggingEnabled);
197197

198-
var measuredResultDuration = await StopwatchService.MeasureCodeBlockAsync( async () =>
198+
var measuredResultDuration = await StopwatchService.MeasureCodeBlockAsync(async () =>
199199
{
200200
await tokenCacheInternal.OnBeforeAccessAsync(args).ConfigureAwait(false);
201201
await tokenCacheInternal.OnBeforeWriteAsync(args).ConfigureAwait(false);
@@ -930,18 +930,21 @@ async Task<IEnumerable<IAccount>> ITokenCacheInternal.GetAccountsAsync(Authentic
930930
// this will either be the home account ID or null, it can never be OBO assertion or tenant ID
931931
string partitionKey = CacheKeyFactory.GetKeyFromRequest(requestParameters);
932932

933+
logger.VerbosePii(() => $"[GetAccounts] PartitionKey: {partitionKey}. request.HomeAccountId {requestParameters.HomeAccountId}", () => "");
934+
933935
var refreshTokenCacheItems = Accessor.GetAllRefreshTokens(partitionKey);
934936
var accountCacheItems = Accessor.GetAllAccounts(partitionKey);
935937

936938
if (filterByClientId)
937939
{
938-
FilterTokensByClientId(refreshTokenCacheItems);
940+
refreshTokenCacheItems.FilterWithLogging(item =>
941+
string.Equals(item.ClientId, ClientId, StringComparison.OrdinalIgnoreCase),
942+
logger,
943+
"[GetAccounts] Filtering RTs by clientID",
944+
true);
939945
}
940946

941-
if (logger.IsLoggingEnabled(LogLevel.Verbose))
942-
{
943-
logger.Verbose(() => $"[GetAccounts] Found {refreshTokenCacheItems.Count} RTs and {accountCacheItems.Count} accounts in MSAL cache. ");
944-
}
947+
logger.Verbose(() => $"[GetAccounts] Found {refreshTokenCacheItems.Count} RTs and {accountCacheItems.Count} accounts in MSAL cache before env filtering.");
945948

946949
// Multi-cloud support - must filter by environment.
947950
ISet<string> allEnvironmentsInCache = new HashSet<string>(
@@ -969,15 +972,21 @@ async Task<IEnumerable<IAccount>> ITokenCacheInternal.GetAccountsAsync(Authentic
969972
// since the authority in request is different from the authority used to get the token
970973
if (!requestParameters.AppConfig.MultiCloudSupportEnabled)
971974
{
972-
refreshTokenCacheItems.RemoveAll(rt => !instanceMetadata.Aliases.ContainsOrdinalIgnoreCase(rt.Environment));
973-
accountCacheItems.RemoveAll(acc => !instanceMetadata.Aliases.ContainsOrdinalIgnoreCase(acc.Environment));
974-
}
975+
refreshTokenCacheItems.FilterWithLogging(
976+
rt => instanceMetadata.Aliases.ContainsOrdinalIgnoreCase(rt.Environment),
977+
logger,
978+
"[GetAccounts] Filtering RTs by environment",
979+
true);
975980

976-
if (logger.IsLoggingEnabled(LogLevel.Verbose))
977-
{
978-
logger.Verbose(() => $"[GetAccounts] Found {refreshTokenCacheItems.Count} RTs and {accountCacheItems.Count} accounts in MSAL cache after environment filtering. ");
981+
accountCacheItems.FilterWithLogging(
982+
a => instanceMetadata.Aliases.ContainsOrdinalIgnoreCase(a.Environment),
983+
logger,
984+
"[GetAccounts] Filtering accounts by environment",
985+
true);
979986
}
980987

988+
logger.Verbose(() => $"[GetAccounts] Found {refreshTokenCacheItems.Count} RTs and {accountCacheItems.Count} accounts in MSAL cache after environment filtering. ");
989+
981990
IDictionary<string, Account> clientInfoToAccountMap = new Dictionary<string, Account>();
982991
foreach (MsalRefreshTokenCacheItem rtItem in refreshTokenCacheItems)
983992
{
@@ -1047,14 +1056,11 @@ async Task<IEnumerable<IAccount>> ITokenCacheInternal.GetAccountsAsync(Authentic
10471056

10481057
if (!string.IsNullOrEmpty(requestParameters.HomeAccountId))
10491058
{
1050-
accounts = accounts.Where(acc => acc.HomeAccountId.Identifier.Equals(
1051-
requestParameters.HomeAccountId,
1052-
StringComparison.OrdinalIgnoreCase)).ToList();
1053-
1054-
if (logger.IsLoggingEnabled(LogLevel.Verbose))
1055-
{
1056-
logger.Verbose(() => $"Filtered by home account id. Remaining accounts {accounts.Count} ");
1057-
}
1059+
accounts.FilterWithLogging(
1060+
acc => acc.HomeAccountId.Identifier.Equals(requestParameters.HomeAccountId, StringComparison.OrdinalIgnoreCase),
1061+
logger,
1062+
"[GetAccounts] Filtering by accountID",
1063+
true);
10581064
}
10591065

10601066
return accounts;
@@ -1287,7 +1293,7 @@ async Task ITokenCacheInternal.RemoveAccountAsync(IAccount account, Authenticati
12871293
}
12881294

12891295
RemoveAccountInternal(account, requestParameters.RequestContext);
1290-
1296+
12911297
if (IsLegacyAdalCacheEnabled(requestParameters))
12921298
{
12931299
CacheFallbackOperations.RemoveAdalUser(

0 commit comments

Comments
 (0)