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); CacheRefresh cacheRefresh = CacheRefresh.None; 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. MsalAccessTokenCacheItem msalAccessTokenItem = await CacheManager.FindAccessTokenAsync().ConfigureAwait(false); if (msalAccessTokenItem != null) { 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)); } else { cacheRefresh = CacheRefresh.NoCachedAT; } } else { cacheRefresh = CacheRefresh.ForceRefresh; } if (AuthenticationRequestParameters.RequestContext.ApiEvent.CacheRefresh == null) { AuthenticationRequestParameters.RequestContext.ApiEvent.CacheRefresh = (int)cacheRefresh; } var msalTokenResponse = await SendTokenRequestAsync(GetBodyParameters(), cancellationToken).ConfigureAwait(false); return(await CacheTokenResponseAndCreateAuthenticationResultAsync(msalTokenResponse).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(); CacheRefresh cacheRefresh = CacheRefresh.None; // no match if (finalList.Count == 0) { logger.Verbose("No tokens found for matching authority, client_id, user and scopes."); cacheRefresh = CacheRefresh.NoCachedAT; return(null); } MsalAccessTokenCacheItem msalAccessTokenCacheItem = GetSingleResult(requestParams, finalList); msalAccessTokenCacheItem = FilterByKeyId(msalAccessTokenCacheItem, requestParams); msalAccessTokenCacheItem = FilterByExpiry(msalAccessTokenCacheItem, requestParams); if (msalAccessTokenCacheItem == null) { cacheRefresh = CacheRefresh.Expired; } requestParams.RequestContext.ApiEvent.CacheRefresh = (int)cacheRefresh; return(msalAccessTokenCacheItem); }
public async Task <AuthenticationResult> ExecuteAsync(CancellationToken cancellationToken) { var logger = AuthenticationRequestParameters.RequestContext.Logger; MsalAccessTokenCacheItem cachedAccessTokenItem = null; CacheRefresh cacheRefresh = CacheRefresh.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) { cacheRefresh = CacheRefresh.NoCachedAT; } else { cacheRefresh = CacheRefresh.RefreshIn; } } else { cacheRefresh = CacheRefresh.ForceRefresh; logger.Info("Skipped looking for an Access Token because ForceRefresh or Claims were set. "); } if (AuthenticationRequestParameters.RequestContext.ApiEvent.CacheRefresh == null) { AuthenticationRequestParameters.RequestContext.ApiEvent.CacheRefresh = (int)cacheRefresh; } // 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; } }
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; CacheRefresh cacheRefresh = CacheRefresh.None; if (!_clientParameters.ForceRefresh && string.IsNullOrEmpty(AuthenticationRequestParameters.Claims)) { cachedAccessTokenItem = await CacheManager.FindAccessTokenAsync().ConfigureAwait(false); if (cachedAccessTokenItem != null && !cachedAccessTokenItem.NeedsRefresh()) { AuthenticationRequestParameters.RequestContext.ApiEvent.IsAccessTokenCacheHit = true; return(new AuthenticationResult( cachedAccessTokenItem, null, AuthenticationRequestParameters.AuthenticationScheme, AuthenticationRequestParameters.RequestContext.CorrelationId, TokenSource.Cache)); } else if (cachedAccessTokenItem == null) { cacheRefresh = CacheRefresh.NoCachedAT; } else { cacheRefresh = CacheRefresh.RefreshIn; } } else { logger.Info("Skipped looking for an Access Token in the cache because ForceRefresh or Claims were set. "); if (_clientParameters.ForceRefresh) { cacheRefresh = CacheRefresh.ForceRefresh; } } if (AuthenticationRequestParameters.RequestContext.ApiEvent.CacheRefresh == null) { AuthenticationRequestParameters.RequestContext.ApiEvent.CacheRefresh = (int)cacheRefresh; } // No AT in the cache or AT needs to be refreshed try { return(await FetchNewAccessTokenAsync(cancellationToken).ConfigureAwait(false)); } catch (MsalServiceException e) { bool isAadUnavailable = e.IsAadUnavailable(); logger.Warning($"Fetching a new AT 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(new AuthenticationResult( cachedAccessTokenItem, null, AuthenticationRequestParameters.AuthenticationScheme, AuthenticationRequestParameters.RequestContext.CorrelationId, TokenSource.Cache)); } logger.Warning("Either the exception does not indicate a problem with AAD or the token cache does not have an AT that is usable. "); throw; } }