public async Task ClientCreds_Expired_NeedsRefresh_AADInvalidResponse_Async() { // Arrange using (MockHttpAndServiceBundle harness = base.CreateTestHarness()) { Trace.WriteLine("1. Setup an app with a token cache with one AT = expired and needs refersh"); ConfidentialClientApplication app = SetupCca(harness); var atItem = TokenCacheHelper.CreateAccessTokenItem(); UpdateATWithRefreshOn(atItem, DateTime.UtcNow - TimeSpan.FromMinutes(1), true); TokenCacheHelper.PopulateDefaultAppTokenCache(app, atItem); TokenCacheAccessRecorder cacheAccess = app.AppTokenCache.RecordAccess(); Trace.WriteLine("2. Configure AAD to be unavaiable"); harness.HttpManager.AddAllMocks(TokenResponseType.Invalid_AADUnavailable503); harness.HttpManager.AddTokenResponse(TokenResponseType.Invalid_AADUnavailable503); // Act MsalServiceException ex = await AssertException.TaskThrowsAsync <MsalServiceException>(() => app .AcquireTokenForClient(TestConstants.s_scope) .ExecuteAsync()) .ConfigureAwait(false); Assert.IsFalse(ex is MsalUiRequiredException, "5xx exceptions do not translate to MsalUIRequired"); Assert.AreEqual(503, ex.StatusCode); cacheAccess.AssertAccessCounts(1, 0); } }
public async Task ClientCreds_NonExpired_NeedsRefresh_AADInvalidResponse_Async() { // Arrange using (MockHttpAndServiceBundle harness = base.CreateTestHarness()) { Trace.WriteLine("1. Setup an app"); ConfidentialClientApplication app = SetupCca(harness); Trace.WriteLine("2. Configure AT so that it shows it needs to be refreshed"); MsalAccessTokenCacheItem atItem = TokenCacheHelper.CreateAccessTokenItem(); UpdateATWithRefreshOn(atItem, DateTime.UtcNow - TimeSpan.FromMinutes(1)); TokenCacheHelper.PopulateDefaultAppTokenCache(app, atItem); TokenCacheAccessRecorder cacheAccess = app.AppTokenCache.RecordAccess(); Trace.WriteLine("3. Configure AAD to respond with the typical Invalid Grant error"); harness.HttpManager.AddAllMocks(TokenResponseType.InvalidGrant); // Act await AssertException.TaskThrowsAsync <MsalUiRequiredException>(() => app.AcquireTokenForClient(TestConstants.s_scope) .ExecuteAsync()) .ConfigureAwait(false); cacheAccess.AssertAccessCounts(1, 0); } }
public async Task ClientCreds_NonExpired_NeedsRefresh_ValidResponse_Async() { // Arrange using (MockHttpAndServiceBundle harness = base.CreateTestHarness()) { Trace.WriteLine("1. Setup an app"); ConfidentialClientApplication app = SetupCca(harness); Trace.WriteLine("2. Configure AT so that it shows it needs to be refreshed"); MsalAccessTokenCacheItem atItem = TokenCacheHelper.CreateAccessTokenItem(); UpdateATWithRefreshOn(atItem, DateTime.UtcNow - TimeSpan.FromMinutes(1)); TokenCacheHelper.PopulateDefaultAppTokenCache(app, atItem); TokenCacheAccessRecorder cacheAccess = app.AppTokenCache.RecordAccess(); Trace.WriteLine("3. Configure AAD to respond with valid token to the refresh RT flow"); harness.HttpManager.AddAllMocks(TokenResponseType.Valid); // Act Trace.WriteLine("4. ATS - should perform an RT refresh"); AuthenticationResult result = await app.AcquireTokenForClient(TestConstants.s_scope) .ExecuteAsync() .ConfigureAwait(false); // Assert Assert.IsNotNull(result); Assert.AreEqual(0, harness.HttpManager.QueueSize, "MSAL should have refreshed the token because the original AT was marked for refresh"); cacheAccess.AssertAccessCounts(1, 1); } }
public async Task ClientCreds_NonExpired_NeedsRefresh_AADUnavailableResponse_Async() { // Arrange using (MockHttpAndServiceBundle harness = base.CreateTestHarness()) { Trace.WriteLine("1. Setup an app "); ConfidentialClientApplication app = SetupCca(harness); Trace.WriteLine("2. Configure AT so that it shows it needs to be refreshed"); MsalAccessTokenCacheItem atItem = TokenCacheHelper.CreateAccessTokenItem(); UpdateATWithRefreshOn(atItem, DateTime.UtcNow - TimeSpan.FromMinutes(1)); TokenCacheHelper.PopulateDefaultAppTokenCache(app, atItem); TokenCacheAccessRecorder cacheAccess = app.AppTokenCache.RecordAccess(); //UpdateATWithRefreshOn(app.AppTokenCacheInternal.Accessor, DateTime.UtcNow - TimeSpan.FromMinutes(1)); Trace.WriteLine("3. Configure AAD to respond with an error"); harness.HttpManager.AddAllMocks(TokenResponseType.Invalid_AADUnavailable503); harness.HttpManager.AddTokenResponse(TokenResponseType.Invalid_AADUnavailable503); // Act AuthenticationResult result = await app.AcquireTokenForClient(TestConstants.s_scope) .ExecuteAsync() .ConfigureAwait(false); // Assert Assert.IsNotNull(result, "ClientCreds should 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 // Now let AAD respond with tokens harness.HttpManager.AddTokenResponse(TokenResponseType.Valid); result = await app.AcquireTokenForClient(TestConstants.s_scope) .ExecuteAsync() .ConfigureAwait(false); Assert.IsNotNull(result); cacheAccess.AssertAccessCounts(2, 1); // new tokens written to cache } }
public async Task AcquireTokenForClient_BypassesCacheForAccessTokens_IfClaimsUsed_Async() { // Arrange using (MockHttpAndServiceBundle harness = base.CreateTestHarness()) { Trace.WriteLine("1. Setup an app with a token cache with one AT"); ConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(TestConstants.ClientId) .WithAuthority(AzureCloudInstance.AzurePublic, TestConstants.Utid) .WithClientSecret(TestConstants.ClientSecret) .WithHttpManager(harness.HttpManager) .BuildConcrete(); TokenCacheHelper.PopulateDefaultAppTokenCache(app); Trace.WriteLine("2. AcquireTokenForClient returns from the cache "); AuthenticationResult result = await app.AcquireTokenForClient(TestConstants.s_scope) .ExecuteAsync() .ConfigureAwait(false); Assert.IsNotNull(result, "A result is obtained from the cache, i.e. without HTTP calls"); harness.HttpManager.AddInstanceDiscoveryMockHandler(); var refreshHandler = new MockHttpMessageHandler() { ExpectedMethod = HttpMethod.Post, ResponseMessage = MockHelpers.CreateSuccessTokenResponseMessage( TestConstants.UniqueId, TestConstants.DisplayableId, TestConstants.s_scope.ToArray()) }; harness.HttpManager.AddMockHandler(refreshHandler); // Act Trace.WriteLine("3. AcquireTokenForClient + Claims does not return AT from cache"); await app.AcquireTokenForClient(TestConstants.s_scope) .WithClaims(TestConstants.Claims) .ExecuteAsync() .ConfigureAwait(false); Assert.IsNotNull(result, "An access token is no longer obtained from the cache. The RT is used to get one from the STS."); } }