internal async Task <AuthenticationResultEx> LoadFromCacheAsync(CacheQueryData cacheQueryData, CallState callState) { AuthenticationResultEx resultEx = null; var aliasedHosts = await GetOrderedAliasesAsync(cacheQueryData.Authority, false, callState).ConfigureAwait(false); foreach (var aliasedHost in aliasedHosts) { cacheQueryData.Authority = ReplaceHost(cacheQueryData.Authority, aliasedHost); resultEx = LoadFromCacheCommon(cacheQueryData, callState); if (resultEx?.Result != null) { break; } } return(resultEx); }
protected AcquireTokenHandlerBase(Authenticator authenticator, TokenCache tokenCache, string resource, ClientKey clientKey, TokenSubjectType subjectType) { this.Authenticator = authenticator; this.CallState = CreateCallState(this.Authenticator.CorrelationId); PlatformPlugin.Logger.Information(this.CallState, string.Format(CultureInfo.CurrentCulture, "=== Token Acquisition started:\n\tAuthority: {0}\n\tResource: {1}\n\tClientId: {2}\n\tCacheType: {3}\n\tAuthentication Target: {4}\n\t", authenticator.Authority, resource, clientKey.ClientId, (tokenCache != null) ? tokenCache.GetType().FullName + string.Format(CultureInfo.CurrentCulture, " ({0} items)", tokenCache.Count) : "null", subjectType)); this.tokenCache = tokenCache; if (string.IsNullOrWhiteSpace(resource)) { throw new ArgumentNullException("resource"); } this.Resource = (resource != NullResource) ? resource : null; this.ClientKey = clientKey; this.TokenSubjectType = subjectType; this.LoadFromCache = (tokenCache != null); this.StoreToCache = (tokenCache != null); this.SupportADFS = false; this.brokerParameters = new Dictionary <string, string>(); brokerParameters["authority"] = authenticator.Authority; brokerParameters["resource"] = resource; brokerParameters["client_id"] = clientKey.ClientId; brokerParameters["correlation_id"] = this.CallState.CorrelationId.ToString(); brokerParameters["client_version"] = AdalIdHelper.GetAdalVersion(); this.ResultEx = null; CacheQueryData = new CacheQueryData(); CacheQueryData.Authority = Authenticator.Authority; CacheQueryData.Resource = this.Resource; CacheQueryData.ClientId = this.ClientKey.ClientId; CacheQueryData.SubjectType = this.TokenSubjectType; CacheQueryData.UniqueId = this.UniqueId; CacheQueryData.DisplayableId = this.DisplayableId; }
private KeyValuePair <TokenCacheKey, AuthenticationResultEx>?LoadSingleItemFromCache(CacheQueryData cacheQueryData, CallState callState) { lock (cacheLock) { // First identify all potential tokens. List <KeyValuePair <TokenCacheKey, AuthenticationResultEx> > items = this.QueryCache(cacheQueryData.Authority, cacheQueryData.ClientId, cacheQueryData.SubjectType, cacheQueryData.UniqueId, cacheQueryData.DisplayableId, cacheQueryData.AssertionHash); List <KeyValuePair <TokenCacheKey, AuthenticationResultEx> > resourceSpecificItems = items.Where(p => p.Key.ResourceEquals(cacheQueryData.Resource)).ToList(); int resourceValuesCount = resourceSpecificItems.Count(); KeyValuePair <TokenCacheKey, AuthenticationResultEx>?returnValue = null; switch (resourceValuesCount) { case 1: PlatformPlugin.Logger.Information(callState, "An item matching the requested resource was found in the cache"); returnValue = resourceSpecificItems.First(); break; case 0: { // There are no resource specific tokens. Choose any of the MRRT tokens if there are any. List <KeyValuePair <TokenCacheKey, AuthenticationResultEx> > mrrtItems = items.Where(p => p.Value.IsMultipleResourceRefreshToken).ToList(); if (mrrtItems.Any()) { returnValue = mrrtItems.First(); PlatformPlugin.Logger.Information(callState, "A Multi Resource Refresh Token for a different resource was found which can be used"); } } break; default: throw new AdalException(AdalError.MultipleTokensMatched); } // check for tokens issued to same client_id/user_id combination, but any tenant. // this check only applies to user tokens. client tokens should be ignored. if (returnValue == null && cacheQueryData.SubjectType != TokenSubjectType.Client) { List <KeyValuePair <TokenCacheKey, AuthenticationResultEx> > itemsForAllTenants = this.QueryCache( null, cacheQueryData.ClientId, cacheQueryData.SubjectType, cacheQueryData.UniqueId, cacheQueryData.DisplayableId, cacheQueryData.AssertionHash); if (itemsForAllTenants.Count != 0) { returnValue = itemsForAllTenants.First(); } // check if the token was issued by AAD if (returnValue != null && Authenticator.DetectAuthorityType(returnValue.Value.Key.Authority) == AuthorityType.ADFS) { returnValue = null; } } return(returnValue); } }
internal AuthenticationResultEx LoadFromCache(CacheQueryData cacheQueryData, CallState callState) { lock (cacheLock) { PlatformPlugin.Logger.Verbose(callState, "Looking up cache for a token..."); AuthenticationResultEx resultEx = null; KeyValuePair <TokenCacheKey, AuthenticationResultEx>?kvp = this.LoadSingleItemFromCache(cacheQueryData, callState); if (kvp.HasValue) { TokenCacheKey cacheKey = kvp.Value.Key; resultEx = kvp.Value.Value.Clone(); bool tokenNearExpiry = (resultEx.Result.ExpiresOn <= DateTime.UtcNow + TimeSpan.FromMinutes(ExpirationMarginInMinutes)); bool tokenExtendedLifeTimeExpired = (resultEx.Result.ExtendedExpiresOn <= DateTime.UtcNow); //check for cross-tenant authority if (!cacheKey.Authority.Equals(cacheQueryData.Authority)) { // this is a cross-tenant result. use RT only resultEx.Result.AccessToken = null; PlatformPlugin.Logger.Information(callState, "Cross Tenant refresh token was found in the cache"); } else if (tokenNearExpiry && !cacheQueryData.ExtendedLifeTimeEnabled) { resultEx.Result.AccessToken = null; PlatformPlugin.Logger.Information(callState, "An expired or near expiry token was found in the cache"); } else if (!cacheKey.ResourceEquals(cacheQueryData.Resource)) { PlatformPlugin.Logger.Information(callState, string.Format(CultureInfo.CurrentCulture, "Multi resource refresh token for resource '{0}' will be used to acquire token for '{1}'", cacheKey.Resource, cacheQueryData.Resource)); var newResultEx = new AuthenticationResultEx { Result = new AuthenticationResult(null, null, DateTimeOffset.MinValue), RefreshToken = resultEx.RefreshToken, ResourceInResponse = resultEx.ResourceInResponse }; newResultEx.Result.UpdateTenantAndUserInfo(resultEx.Result.TenantId, resultEx.Result.IdToken, resultEx.Result.UserInfo); resultEx = newResultEx; } else if (!tokenExtendedLifeTimeExpired && cacheQueryData.ExtendedLifeTimeEnabled && tokenNearExpiry) { resultEx.Result.ExtendedLifeTimeToken = true; resultEx.Result.ExpiresOn = resultEx.Result.ExtendedExpiresOn; PlatformPlugin.Logger.Information(callState, "The extendedLifeTime is enabled and a stale AT with extendedLifeTimeEnabled is returned."); } else if (tokenExtendedLifeTimeExpired) { resultEx.Result.AccessToken = null; PlatformPlugin.Logger.Information(callState, "The AT has expired its ExtendedLifeTime"); } else { PlatformPlugin.Logger.Information(callState, string.Format(CultureInfo.CurrentCulture, "{0} minutes left until token in cache expires", (resultEx.Result.ExpiresOn - DateTime.UtcNow).TotalMinutes)); } if (resultEx.Result.AccessToken == null && resultEx.RefreshToken == null) { this.tokenCacheDictionary.Remove(cacheKey); PlatformPlugin.Logger.Information(callState, "An old item was removed from the cache"); this.HasStateChanged = true; resultEx = null; } if (resultEx != null) { PlatformPlugin.Logger.Information(callState, "A matching item (access token or refresh token or both) was found in the cache"); } } else { PlatformPlugin.Logger.Information(callState, "No matching token was found in the cache"); } return(resultEx); } }