private static void AssertThrottlingCacheEntryCount( SingletonThrottlingManager throttlingManager, int retryAfterEntryCount = 0, int httpStatusEntryCount = 0, int uiRequiredEntryCount = 0) { var(retryAfterProvider, httpStatusProvider, uiRequiredProvider) = throttlingManager.GetTypedThrottlingProviders(); Assert.AreEqual(retryAfterEntryCount, retryAfterProvider.ThrottlingCache.CacheForTest.Count); Assert.AreEqual(httpStatusEntryCount, httpStatusProvider.ThrottlingCache.CacheForTest.Count); Assert.AreEqual(uiRequiredEntryCount, uiRequiredProvider.ThrottlingCache.CacheForTest.Count); }
public async Task ATS_NonExpired_NeedsRefresh_AADUnavailableResponse_Async() { // Arrange using (MockHttpAndServiceBundle harness = base.CreateTestHarness()) { Trace.WriteLine("1. Setup an app with a token cache with one AT"); PublicClientApplication app = SetupPca(harness); Trace.WriteLine("2. Configure AT so that it shows it needs to be refreshed"); UpdateATWithRefreshOn(app.UserTokenCacheInternal.Accessor, DateTime.UtcNow - TimeSpan.FromMinutes(1)); TokenCacheAccessRecorder cacheAccess = app.UserTokenCache.RecordAccess(); Trace.WriteLine("3. Configure AAD to respond with a 500 error"); harness.HttpManager.AddAllMocks(TokenResponseType.Invalid_AADUnavailable503); harness.HttpManager.AddTokenResponse(TokenResponseType.Invalid_AADUnavailable503); // Act var account = new Account(TestConstants.s_userIdentifier, TestConstants.DisplayableId, null); AuthenticationResult result = await app .AcquireTokenSilent( TestConstants.s_scope.ToArray(), account) .ExecuteAsync(CancellationToken.None) .ConfigureAwait(false); // Assert Assert.IsNotNull(result, "ATS still succeeds even though AAD is unavaible"); Assert.AreEqual(0, harness.HttpManager.QueueSize); cacheAccess.AssertAccessCounts(1, 0); // the refresh failed, no new data is written to the cache // reset throttling, otherwise MSAL would block similar requests for 2 minutes // and we would still get a cached response SingletonThrottlingManager.GetInstance().ResetCache(); // Now let AAD respond with tokens harness.HttpManager.AddTokenResponse(TokenResponseType.Valid); result = await app .AcquireTokenSilent( TestConstants.s_scope.ToArray(), account) .ExecuteAsync(CancellationToken.None) .ConfigureAwait(false); Assert.IsNotNull(result); cacheAccess.AssertAccessCounts(2, 1); // new tokens written to cache } }
internal ServiceBundle( ApplicationConfiguration config, bool shouldClearCaches = false) { Config = config; ApplicationLogger = new MsalLogger( Guid.Empty, config.ClientName, config.ClientVersion, config.LogLevel, config.EnablePiiLogging, config.IsDefaultPlatformLoggingEnabled, config.LoggingCallback); PlatformProxy = config.PlatformProxy ?? PlatformProxyFactory.CreatePlatformProxy(ApplicationLogger); HttpManager = config.HttpManager ?? new HttpManager( config.HttpClientFactory ?? PlatformProxy.CreateDefaultHttpClientFactory()); HttpTelemetryManager = new HttpTelemetryManager(); if (config.TelemetryConfig != null) { // This can return null if the device isn't sampled in. There's no need for processing MATS events if we're not going to send them. Mats = TelemetryClient.CreateMats(config, PlatformProxy, config.TelemetryConfig); MatsTelemetryManager = Mats?.TelemetryManager ?? new TelemetryManager(config, PlatformProxy, config.TelemetryCallback); } else { MatsTelemetryManager = new TelemetryManager(config, PlatformProxy, config.TelemetryCallback); } InstanceDiscoveryManager = new InstanceDiscoveryManager( HttpManager, shouldClearCaches, config.CustomInstanceDiscoveryMetadata, config.CustomInstanceDiscoveryMetadataUri); WsTrustWebRequestManager = new WsTrustWebRequestManager(HttpManager); ThrottlingManager = SingletonThrottlingManager.GetInstance(); DeviceAuthManager = config.DeviceAuthManagerForTest ?? PlatformProxy.CreateDeviceAuthManager(); if (shouldClearCaches) { AuthorityManager.ClearValidationCache(); } }
internal ServiceBundle( ApplicationConfiguration config, bool shouldClearCaches = false) { Config = config; ApplicationLogger = new MsalLogger( Guid.Empty, config.ClientName, config.ClientVersion, config.LogLevel, config.EnablePiiLogging, config.IsDefaultPlatformLoggingEnabled, config.LoggingCallback); PlatformProxy = config.PlatformProxy ?? PlatformProxyFactory.CreatePlatformProxy(ApplicationLogger); HttpManager = config.HttpManager ?? new HttpManager( config.HttpClientFactory ?? PlatformProxy.CreateDefaultHttpClientFactory()); HttpTelemetryManager = new HttpTelemetryManager(); InstanceDiscoveryManager = new InstanceDiscoveryManager( HttpManager, shouldClearCaches, config.CustomInstanceDiscoveryMetadata, config.CustomInstanceDiscoveryMetadataUri); WsTrustWebRequestManager = new WsTrustWebRequestManager(HttpManager); ThrottlingManager = SingletonThrottlingManager.GetInstance(); DeviceAuthManager = config.DeviceAuthManagerForTest ?? PlatformProxy.CreateDeviceAuthManager(); if (shouldClearCaches) // for test { AuthorityManager.ClearValidationCache(); PoPProviderFactory.Reset(); } }
public async Task ATS_NonExpired_NeedsRefresh_AADUnavailableResponse_Async() { // Arrange using (MockHttpAndServiceBundle harness = base.CreateTestHarness()) { Trace.WriteLine("1. Setup an app with a token cache with one AT"); PublicClientApplication app = SetupPca(harness); Trace.WriteLine("2. Configure AT so that it shows it needs to be refreshed"); UpdateATWithRefreshOn(app.UserTokenCacheInternal.Accessor); TokenCacheAccessRecorder cacheAccess = app.UserTokenCache.RecordAccess(); Trace.WriteLine("3. Configure AAD to respond with a 500 error"); harness.HttpManager.AddAllMocks(TokenResponseType.Invalid_AADUnavailable503); harness.HttpManager.AddTokenResponse(TokenResponseType.Invalid_AADUnavailable503); // Act var account = new Account(TestConstants.s_userIdentifier, TestConstants.DisplayableId, null); AuthenticationResult result = await app .AcquireTokenSilent( TestConstants.s_scope.ToArray(), account) .ExecuteAsync(CancellationToken.None) .ConfigureAwait(false); // The following can be indeterministic due to background threading nature // So it is verified on check and wait basis Assert.IsTrue(YieldTillSatisfied(() => harness.HttpManager.QueueSize == 0), "Background refresh 1 did not execute."); // Assert Assert.AreEqual(0, harness.HttpManager.QueueSize); Assert.AreEqual(CacheRefreshReason.ProactivelyRefreshed, result.AuthenticationResultMetadata.CacheRefreshReason); cacheAccess.WaitTo_AssertAcessCounts(1, 0); // the refresh failed, no new data is written to the cache // reset throttling, otherwise MSAL would block similar requests for 2 minutes // and we would still get a cached response SingletonThrottlingManager.GetInstance().ResetCache(); // Now let AAD respond with tokens harness.HttpManager.AddTokenResponse(TokenResponseType.Valid_UserFlows); result = await app .AcquireTokenSilent( TestConstants.s_scope.ToArray(), account) .ExecuteAsync(CancellationToken.None) .ConfigureAwait(false); Assert.AreEqual(CacheRefreshReason.ProactivelyRefreshed, result.AuthenticationResultMetadata.CacheRefreshReason); Assert.IsTrue(YieldTillSatisfied( () => harness.HttpManager.QueueSize == 0), "Background refresh 2 did not execute."); Assert.IsTrue( YieldTillSatisfied(() => cacheAccess.AfterAccessTotalCount == 3), "The background refresh executed, but the cache was not updated"); cacheAccess.WaitTo_AssertAcessCounts(2, 1); // new tokens written to cache } }