private static void AssertCurrentTelemetry( HttpRequestMessage requestMessage, ApiIds apiId, CacheInfoTelemetry cacheInfo, bool isCacheSerialized = false, bool isLegacyCacheEnabled = true) { string[] telemetryCategories = requestMessage.Headers.GetValues( TelemetryConstants.XClientCurrentTelemetry).Single().Split('|'); Assert.AreEqual(3, telemetryCategories.Length); Assert.AreEqual(1, telemetryCategories[0].Split(',').Length); // version Assert.AreEqual(5, telemetryCategories[1].Split(',').Length); // api_id, cache_info, region_used, region_source, region_outcome Assert.AreEqual(2, telemetryCategories[2].Split(',').Length); // platform_fields Assert.AreEqual(TelemetryConstants.HttpTelemetrySchemaVersion, telemetryCategories[0]); // version Assert.AreEqual( apiId.ToString("D"), telemetryCategories[1].Split(',')[0]); // current_api_id Assert.AreEqual(cacheInfo.ToString("D"), telemetryCategories[1].Split(',')[1]); // cache_info Assert.AreEqual(isCacheSerialized ? "1" : "0", telemetryCategories[2].Split(',')[0]); // is_cache_serialized Assert.AreEqual(isLegacyCacheEnabled ? "1" : "0", telemetryCategories[2].Split(',')[1]); // is_legacy_cache_enabled }
protected override async Task <AuthenticationResult> ExecuteAsync(CancellationToken cancellationToken) { if (AuthenticationRequestParameters.Scope == null || AuthenticationRequestParameters.Scope.Count == 0) { throw new MsalClientException( MsalError.ScopesRequired, MsalErrorMessage.ScopesRequired); } MsalAccessTokenCacheItem cachedAccessTokenItem = null; var logger = AuthenticationRequestParameters.RequestContext.Logger; CacheInfoTelemetry cacheInfoTelemetry = CacheInfoTelemetry.None; if (!_clientParameters.ForceRefresh && string.IsNullOrEmpty(AuthenticationRequestParameters.Claims)) { cachedAccessTokenItem = await CacheManager.FindAccessTokenAsync().ConfigureAwait(false); if (cachedAccessTokenItem != null && !cachedAccessTokenItem.NeedsRefresh()) { AuthenticationRequestParameters.RequestContext.ApiEvent.IsAccessTokenCacheHit = true; Metrics.IncrementTotalAccessTokensFromCache(); return(new AuthenticationResult( cachedAccessTokenItem, null, null, AuthenticationRequestParameters.AuthenticationScheme, AuthenticationRequestParameters.RequestContext.CorrelationId, TokenSource.Cache, AuthenticationRequestParameters.RequestContext.ApiEvent)); } cacheInfoTelemetry = (cachedAccessTokenItem == null) ? CacheInfoTelemetry.NoCachedAT : CacheInfoTelemetry.RefreshIn; } else { logger.Info("Skipped looking for an Access Token in the cache because ForceRefresh or Claims were set. "); if (_clientParameters.ForceRefresh) { cacheInfoTelemetry = CacheInfoTelemetry.ForceRefresh; } } if (AuthenticationRequestParameters.RequestContext.ApiEvent.CacheInfo == (int)CacheInfoTelemetry.None) { AuthenticationRequestParameters.RequestContext.ApiEvent.CacheInfo = (int)cacheInfoTelemetry; } // No AT in the cache or AT needs to be refreshed try { return(await FetchNewAccessTokenAsync(cancellationToken).ConfigureAwait(false)); } catch (MsalServiceException e) { return(await HandleTokenRefreshErrorAsync(e, cachedAccessTokenItem).ConfigureAwait(false)); } }
/// <summary> /// IMPORTANT: this class is perf critical; any changes must be benchmarked using Microsoft.Identity.Test.Performace. /// More information about how to test and what data to look for is in https://aka.ms/msal-net-performance-testing. /// /// Scenario: client_creds with default in-memory cache can get to ~500k tokens /// </summary> async Task <MsalAccessTokenCacheItem> ITokenCacheInternal.FindAccessTokenAsync( AuthenticationRequestParameters requestParams) { var logger = requestParams.RequestContext.Logger; // no authority passed if (requestParams.AuthorityInfo?.CanonicalAuthority == null) { logger.Warning("FindAccessToken: No authority provided. Skipping cache lookup "); return(null); } // take a snapshot of the access tokens to avoid problems where the underlying collection is changed, // as this method is NOT locked by the semaphore IEnumerable <MsalAccessTokenCacheItem> tokenCacheItems = GetAllAccessTokensWithNoLocks(true).ToList(); tokenCacheItems = FilterByHomeAccountTenantOrAssertion(requestParams, tokenCacheItems); tokenCacheItems = FilterByTokenType(requestParams, tokenCacheItems); tokenCacheItems = FilterByScopes(requestParams, tokenCacheItems); tokenCacheItems = await FilterByEnvironmentAsync(requestParams, tokenCacheItems).ConfigureAwait(false); // perf: take a snapshot as calling Count(), Any() etc. on the IEnumerable evaluates it each time IReadOnlyList <MsalAccessTokenCacheItem> finalList = tokenCacheItems.ToList(); CacheInfoTelemetry cacheInfoTelemetry = CacheInfoTelemetry.None; // no match if (finalList.Count == 0) { logger.Verbose("No tokens found for matching authority, client_id, user and scopes."); cacheInfoTelemetry = CacheInfoTelemetry.NoCachedAT; return(null); } MsalAccessTokenCacheItem msalAccessTokenCacheItem = GetSingleResult(requestParams, finalList); msalAccessTokenCacheItem = FilterByKeyId(msalAccessTokenCacheItem, requestParams); msalAccessTokenCacheItem = FilterByExpiry(msalAccessTokenCacheItem, requestParams); if (msalAccessTokenCacheItem == null) { cacheInfoTelemetry = CacheInfoTelemetry.Expired; } requestParams.RequestContext.ApiEvent.CacheInfo = (int)cacheInfoTelemetry; return(msalAccessTokenCacheItem); }
protected override async Task <AuthenticationResult> ExecuteAsync(CancellationToken cancellationToken) { if (AuthenticationRequestParameters.Scope == null || AuthenticationRequestParameters.Scope.Count == 0) { throw new MsalClientException( MsalError.ScopesRequired, MsalErrorMessage.ScopesRequired); } await ResolveAuthorityEndpointsAsync().ConfigureAwait(false); CacheInfoTelemetry cacheInfoTelemetry = CacheInfoTelemetry.None; MsalAccessTokenCacheItem msalAccessTokenItem = null; var logger = AuthenticationRequestParameters.RequestContext.Logger; if (!_onBehalfOfParameters.ForceRefresh) { // look for access token in the cache first. // no access token is found, then it means token does not exist // or new assertion has been passed. We should not use Refresh Token // for the user because the new incoming token may have updated claims // like MFA etc. msalAccessTokenItem = await CacheManager.FindAccessTokenAsync().ConfigureAwait(false); if (msalAccessTokenItem != null && !msalAccessTokenItem.NeedsRefresh()) { var msalIdTokenItem = await CacheManager.GetIdTokenCacheItemAsync(msalAccessTokenItem.GetIdTokenItemKey()).ConfigureAwait(false); AuthenticationRequestParameters.RequestContext.Logger.Info( "OBO found a valid access token in the cache. ID token also found? " + (msalIdTokenItem != null)); AuthenticationRequestParameters.RequestContext.ApiEvent.IsAccessTokenCacheHit = true; return(new AuthenticationResult( msalAccessTokenItem, msalIdTokenItem, AuthenticationRequestParameters.AuthenticationScheme, AuthenticationRequestParameters.RequestContext.CorrelationId, TokenSource.Cache, AuthenticationRequestParameters.RequestContext.ApiEvent)); } cacheInfoTelemetry = (msalAccessTokenItem == null) ? CacheInfoTelemetry.NoCachedAT : CacheInfoTelemetry.RefreshIn; } else { logger.Info("Skipped looking for an Access Token in the cache because ForceRefresh or Claims were set. "); cacheInfoTelemetry = CacheInfoTelemetry.ForceRefresh; } if (AuthenticationRequestParameters.RequestContext.ApiEvent.CacheInfo == (int)CacheInfoTelemetry.None) { AuthenticationRequestParameters.RequestContext.ApiEvent.CacheInfo = (int)cacheInfoTelemetry; } // No AT in the cache or AT needs to be refreshed try { return(await FetchNewAccessTokenAsync(cancellationToken).ConfigureAwait(false)); } catch (MsalServiceException e) { return(HandleTokenRefreshError(e, msalAccessTokenItem)); } }
public async Task <AuthenticationResult> ExecuteAsync(CancellationToken cancellationToken) { var logger = AuthenticationRequestParameters.RequestContext.Logger; MsalAccessTokenCacheItem cachedAccessTokenItem = null; CacheInfoTelemetry cacheInfoTelemetry = CacheInfoTelemetry.None; ThrowIfNoScopesOnB2C(); ThrowIfCurrentBrokerAccount(); if (!_silentParameters.ForceRefresh && string.IsNullOrEmpty(AuthenticationRequestParameters.Claims)) { cachedAccessTokenItem = await CacheManager.FindAccessTokenAsync().ConfigureAwait(false); if (cachedAccessTokenItem != null && !cachedAccessTokenItem.NeedsRefresh()) { logger.Info("Returning access token found in cache. RefreshOn exists ? " + cachedAccessTokenItem.RefreshOn.HasValue); AuthenticationRequestParameters.RequestContext.ApiEvent.IsAccessTokenCacheHit = true; return(await CreateAuthenticationResultAsync(cachedAccessTokenItem).ConfigureAwait(false)); } else if (cachedAccessTokenItem == null) { cacheInfoTelemetry = CacheInfoTelemetry.NoCachedAT; } else { cacheInfoTelemetry = CacheInfoTelemetry.RefreshIn; } } else { cacheInfoTelemetry = CacheInfoTelemetry.ForceRefresh; logger.Info("Skipped looking for an Access Token because ForceRefresh or Claims were set. "); } if (AuthenticationRequestParameters.RequestContext.ApiEvent.CacheInfo == (int)CacheInfoTelemetry.None) { AuthenticationRequestParameters.RequestContext.ApiEvent.CacheInfo = (int)cacheInfoTelemetry; } // No AT or AT.RefreshOn > Now --> refresh the RT try { return(await RefreshRtOrFailAsync(cancellationToken).ConfigureAwait(false)); } catch (MsalServiceException e) { bool isAadUnavailable = e.IsAadUnavailable(); logger.Warning($"Refreshing the RT failed. Is AAD down? {isAadUnavailable}. Is there an AT in the cache that is usable? {cachedAccessTokenItem != null} "); if (cachedAccessTokenItem != null && isAadUnavailable) { logger.Info("Returning existing access token. It is not expired, but should be refreshed. "); return(await CreateAuthenticationResultAsync(cachedAccessTokenItem).ConfigureAwait(false)); } logger.Warning("Failed to refresh the RT and cannot use existing AT (expired or missing). "); throw; } }