Beispiel #1
0
        public async Task WAM_AccountIds_GetMerged_Async()
        {
            // Arrange
            using (var httpManager = new MockHttpManager())
            {
                var cache = new InMemoryTokenCache();
                httpManager.AddInstanceDiscoveryMockHandler();

                var mockBroker = Substitute.For <IBroker>();
                mockBroker.IsBrokerInstalledAndInvokable().Returns(true);

                var msalTokenResponse1 = CreateMsalTokenResponseFromWam("wam1");
                var msalTokenResponse2 = CreateMsalTokenResponseFromWam("wam2");
                var msalTokenResponse3 = CreateMsalTokenResponseFromWam("wam3");

                // 2 apps must share the token cache, like FOCI apps, for this test to be interesting
                var pca1 = PublicClientApplicationBuilder.Create(TestConstants.ClientId)
                           .WithExperimentalFeatures(true)
                           .WithBroker(true)
                           .WithHttpManager(httpManager)
                           .BuildConcrete();

                var pca2 = PublicClientApplicationBuilder.Create(TestConstants.ClientId2)
                           .WithExperimentalFeatures(true)
                           .WithBroker(true)
                           .WithHttpManager(httpManager)
                           .BuildConcrete();

                cache.Bind(pca1.UserTokenCache);
                cache.Bind(pca2.UserTokenCache);

                pca1.ServiceBundle.PlatformProxy.SetBrokerForTest(mockBroker);
                pca2.ServiceBundle.PlatformProxy.SetBrokerForTest(mockBroker);

                // Act
                mockBroker.AcquireTokenInteractiveAsync(null, null).ReturnsForAnyArgs(Task.FromResult(msalTokenResponse1));
                await pca1.AcquireTokenInteractive(TestConstants.s_scope).ExecuteAsync().ConfigureAwait(false);

                // this should override wam1 id
                mockBroker.AcquireTokenInteractiveAsync(null, null).ReturnsForAnyArgs(Task.FromResult(msalTokenResponse2));
                await pca1.AcquireTokenInteractive(TestConstants.s_scope).ExecuteAsync().ConfigureAwait(false);

                mockBroker.AcquireTokenInteractiveAsync(null, null).ReturnsForAnyArgs(Task.FromResult(msalTokenResponse3));
                await pca2.AcquireTokenInteractive(TestConstants.s_scope).ExecuteAsync().ConfigureAwait(false);

                var accounts1 = await pca1.GetAccountsAsync().ConfigureAwait(false);

                var accounts2 = await pca2.GetAccountsAsync().ConfigureAwait(false);

                // Assert
                var wamAccountIds = (accounts1.Single() as IAccountInternal).WamAccountIds;
                Assert.AreEqual(2, wamAccountIds.Count);
                Assert.AreEqual("wam2", wamAccountIds[TestConstants.ClientId]);
                Assert.AreEqual("wam3", wamAccountIds[TestConstants.ClientId2]);
                CoreAssert.AssertDictionariesAreEqual(wamAccountIds, (accounts2.Single() as IAccountInternal).WamAccountIds, StringComparer.Ordinal);
            }
        }
Beispiel #2
0
        public async Task TokensAreInterchangable_Regional_To_NonRegional_Async()
        {
            using (var httpManager = new MockHttpManager())
            {
                httpManager.AddRegionDiscoveryMockHandler(TestConstants.Region);
                httpManager.AddMockHandler(CreateTokenResponseHttpHandler(true));

                IConfidentialClientApplication appWithRegion = CreateCca(
                    httpManager,
                    ConfidentialClientApplication.AttemptRegionDiscovery);
                InMemoryTokenCache memoryTokenCache = new InMemoryTokenCache();
                memoryTokenCache.Bind(appWithRegion.AppTokenCache);

                IConfidentialClientApplication appWithoutRegion = CreateCca(
                    httpManager,
                    null);
                memoryTokenCache.Bind(appWithoutRegion.AppTokenCache);

                AuthenticationResult result = await appWithRegion
                                              .AcquireTokenForClient(TestConstants.s_scope)
                                              .ExecuteAsync(CancellationToken.None)
                                              .ConfigureAwait(false);

                Assert.AreEqual(TestConstants.Region, result.ApiEvent.RegionUsed);
                Assert.AreEqual(TestConstants.Region, result.ApiEvent.AutoDetectedRegion);
                Assert.AreEqual(RegionAutodetectionSource.Imds, result.ApiEvent.RegionAutodetectionSource);
                Assert.AreEqual(RegionOutcome.AutodetectSuccess, result.ApiEvent.RegionOutcome);
                Assert.AreEqual(TestConstants.Region, result.AuthenticationResultMetadata.RegionDetails.RegionUsed);
                Assert.AreEqual(RegionOutcome.AutodetectSuccess, result.AuthenticationResultMetadata.RegionDetails.RegionOutcome);
                Assert.IsNull(result.AuthenticationResultMetadata.RegionDetails.AutoDetectionError);

                // when switching to non-region, token is found in the cache
                result = await appWithoutRegion
                         .AcquireTokenForClient(TestConstants.s_scope)
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

                Assert.AreEqual(null, result.ApiEvent.RegionUsed);
                Assert.IsNull(result.ApiEvent.AutoDetectedRegion);
                Assert.AreEqual(RegionAutodetectionSource.None, result.ApiEvent.RegionAutodetectionSource);
                Assert.AreEqual(RegionOutcome.None, result.ApiEvent.RegionOutcome);
                Assert.IsTrue(result.AuthenticationResultMetadata.TokenSource == TokenSource.Cache);
                Assert.IsNull(result.AuthenticationResultMetadata.RegionDetails.RegionUsed);
                Assert.AreEqual(RegionOutcome.None, result.AuthenticationResultMetadata.RegionDetails.RegionOutcome);
                Assert.IsNull(result.AuthenticationResultMetadata.RegionDetails.AutoDetectionError);
            }
        }
Beispiel #3
0
        private PublicClientApplication CreatePca(MockHttpManager httpManager, bool populateUserCache = false)
        {
            PublicClientApplication pca = PublicClientApplicationBuilder.Create(TestConstants.ClientId)
                                          .WithAuthority(new Uri(ClientApplicationBase.DefaultAuthority), false)
                                          .WithHttpManager(httpManager)
                                          .BuildConcrete();

            if (populateUserCache)
            {
                TokenCacheHelper.PopulateCache(pca.UserTokenCacheInternal.Accessor);
            }
            InMemoryTokenCache memoryTokenCache = new InMemoryTokenCache(withOperationDelay: true, shouldClearExistingCache: false);

            memoryTokenCache.Bind(pca.UserTokenCache);

            return(pca);
        }
        public async Task TelemetrySerializedTokenCacheTestAsync()
        {
            Environment.SetEnvironmentVariable(TestConstants.RegionName, TestConstants.Region);

            var inMemoryTokenCache = new InMemoryTokenCache();

            inMemoryTokenCache.Bind(_app.AppTokenCache);

            Trace.WriteLine("Acquire token for client with token serialization.");
            var result = await RunAcquireTokenForClientAsync(AcquireTokenForClientOutcome.Success).ConfigureAwait(false);

            AssertCurrentTelemetry(result.HttpRequest,
                                   ApiIds.AcquireTokenForClient,
                                   "1",
                                   isCacheSerialized: true);
            AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 0);
        }
Beispiel #5
0
        public async Task MetricsUpdatedSucessfully_AcquireTokenForClient_Async()
        {
            using (var harness = CreateTestHarness())
            {
                harness.HttpManager.AddInstanceDiscoveryMockHandler();
                harness.HttpManager.AddMockHandlerSuccessfulClientCredentialTokenResponseMessage();

                ConfidentialClientApplication cca = ConfidentialClientApplicationBuilder.Create(TestConstants.ClientId)
                                                    .WithAuthority(new Uri(ClientApplicationBase.DefaultAuthority), false)
                                                    .WithRedirectUri(TestConstants.RedirectUri)
                                                    .WithClientSecret(TestConstants.ClientSecret)
                                                    .WithHttpManager(harness.HttpManager)
                                                    .BuildConcrete();

                InMemoryTokenCache memoryTokenCache = new InMemoryTokenCache(withOperationDelay: true, shouldClearExistingCache: false);
                memoryTokenCache.Bind(cca.AppTokenCache);

                // Act - AcquireTokenForClient
                AuthenticationResult result = await cca.AcquireTokenForClient(TestConstants.s_scope.ToArray()).ExecuteAsync(CancellationToken.None).ConfigureAwait(false);

                Assert.IsNotNull(result);
                Assert.AreEqual(TokenSource.IdentityProvider, result.AuthenticationResultMetadata.TokenSource);
                Assert.IsTrue(result.AuthenticationResultMetadata.DurationInCacheInMs > 0);
                Assert.IsTrue(result.AuthenticationResultMetadata.DurationTotalInMs > 0);
                Assert.AreEqual(
                    "https://login.microsoftonline.com/common/oauth2/v2.0/token",
                    result.AuthenticationResultMetadata.TokenEndpoint);
                Assert.AreEqual(1, Metrics.TotalAccessTokensFromIdP);
                Assert.AreEqual(0, Metrics.TotalAccessTokensFromCache);
                Assert.AreEqual(0, Metrics.TotalAccessTokensFromBroker);

                // Act - AcquireTokenForClient returns result from cache
                result = await cca.AcquireTokenForClient(TestConstants.s_scope.ToArray()).ExecuteAsync(CancellationToken.None).ConfigureAwait(false);

                Assert.IsNotNull(result);
                Assert.AreEqual(TokenSource.Cache, result.AuthenticationResultMetadata.TokenSource);
                Assert.IsTrue(result.AuthenticationResultMetadata.DurationInCacheInMs > 0);
                Assert.IsTrue(result.AuthenticationResultMetadata.DurationInHttpInMs == 0);
                Assert.IsTrue(result.AuthenticationResultMetadata.DurationTotalInMs > 0);
                Assert.AreEqual(1, Metrics.TotalAccessTokensFromIdP);
                Assert.AreEqual(1, Metrics.TotalAccessTokensFromCache);
                Assert.AreEqual(0, Metrics.TotalAccessTokensFromBroker);
                Assert.IsTrue(Metrics.TotalDurationInMs > 0);
                Assert.IsNull(result.AuthenticationResultMetadata.TokenEndpoint);
            }
        }
        public void GlobalSetup()
        {
            var cca = ConfidentialClientApplicationBuilder
                      .Create(TestConstants.ClientId)
                      .WithAuthority(new Uri(TestConstants.AuthorityTestTenant))
                      .WithRedirectUri(TestConstants.RedirectUri)
                      .WithClientSecret(TestConstants.ClientSecret)
                      .BuildConcrete();

            var inMemoryTokenCache = new InMemoryTokenCache();

            inMemoryTokenCache.Bind(cca.AppTokenCache);

            TokenCacheHelper tokenCacheHelper = new TokenCacheHelper();

            tokenCacheHelper.PopulateCacheForClientCredential(cca.AppTokenCacheInternal.Accessor, TokenCacheSize);

            _acquireTokenForClientBuilder = cca
                                            .AcquireTokenForClient(TestConstants.s_scope)
                                            .WithForceRefresh(false);
        }
        public async Task TelemetryTestSerializedTokenCacheAsync()
        {
            using (_harness = CreateTestHarness())
            {
                _harness.HttpManager.AddInstanceDiscoveryMockHandler();

                _app = PublicClientApplicationBuilder.Create(TestConstants.ClientId)
                       .WithHttpManager(_harness.HttpManager)
                       .WithDefaultRedirectUri()
                       .WithLogging((lvl, msg, pii) => Trace.WriteLine($"[MSAL_LOG][{lvl}] {msg}"))
                       .BuildConcrete();

                var inMemoryTokenCache = new InMemoryTokenCache();
                inMemoryTokenCache.Bind(_app.UserTokenCache);

                Trace.WriteLine("Step 1. Acquire Token Interactive successful");
                var result = await RunAcquireTokenInteractiveAsync(AcquireTokenInteractiveOutcome.Success).ConfigureAwait(false);

                AssertCurrentTelemetry(result.HttpRequest, ApiIds.AcquireTokenInteractive, CacheInfoTelemetry.None, isCacheSerialized: true);
                AssertPreviousTelemetry(result.HttpRequest, expectedSilentCount: 0);
            }
        }
        public async Task TokensAreInterchangable_NonRegional_To_Regional_Async()
        {
            using (var httpManager = new MockHttpManager())
            {
                httpManager.AddInstanceDiscoveryMockHandler();
                httpManager.AddMockHandler(CreateTokenResponseHttpHandler(false));

                IConfidentialClientApplication appWithRegion = CreateCca(
                    httpManager,
                    ConfidentialClientApplication.AttemptRegionDiscovery);
                InMemoryTokenCache memoryTokenCache = new InMemoryTokenCache();
                memoryTokenCache.Bind(appWithRegion.AppTokenCache);

                IConfidentialClientApplication appWithoutRegion = CreateCca(
                    httpManager,
                    null);
                memoryTokenCache.Bind(appWithoutRegion.AppTokenCache);

                AuthenticationResult result = await appWithoutRegion
                                              .AcquireTokenForClient(TestConstants.s_scope)
                                              .ExecuteAsync(CancellationToken.None)
                                              .ConfigureAwait(false);

                Assert.IsTrue(result.AuthenticationResultMetadata.TokenSource == TokenSource.IdentityProvider);

                httpManager.AddRegionDiscoveryMockHandler("uscentral");

                // when switching to non-region, token is found in the cache
                result = await appWithRegion
                         .AcquireTokenForClient(TestConstants.s_scope)
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

                Assert.IsTrue(result.AuthenticationResultMetadata.TokenSource == TokenSource.Cache);
            }
        }
Beispiel #9
0
        private async Task <(HttpRequestMessage HttpRequest, Guid Correlationid)> RunAcquireTokenForClientAsync(
            AcquireTokenForClientOutcome outcome, bool forceRefresh = false, bool serializeCache = false)
        {
            MockHttpMessageHandler tokenRequestHandler = null;
            Guid correlationId = default;

            switch (outcome)
            {
            case AcquireTokenForClientOutcome.Success:

                var app = ConfidentialClientApplicationBuilder.Create(TestConstants.ClientId)
                          .WithAuthority(AzureCloudInstance.AzurePublic, TestConstants.TenantId, false)
                          .WithClientSecret(TestConstants.ClientSecret)
                          .WithHttpManager(_harness.HttpManager)
                          .WithAzureRegion()
                          .WithExperimentalFeatures(true)
                          .BuildConcrete();

                if (serializeCache)
                {
                    InMemoryTokenCache mem = new InMemoryTokenCache();
                    mem.Bind(app.AppTokenCache);
                }

                tokenRequestHandler = _harness.HttpManager.AddSuccessTokenResponseMockHandlerForPost(authority: TestConstants.AuthorityRegional);
                var authResult = await app
                                 .AcquireTokenForClient(TestConstants.s_scope)
                                 .WithForceRefresh(forceRefresh)
                                 .ExecuteAsync()
                                 .ConfigureAwait(false);

                correlationId = authResult.CorrelationId;
                break;

            case AcquireTokenForClientOutcome.FallbackToGlobal:
                _harness.HttpManager.AddInstanceDiscoveryMockHandler();
                tokenRequestHandler = _harness.HttpManager.AddSuccessTokenResponseMockHandlerForPost(authority: TestConstants.AuthorityTenant);

                var app2 = ConfidentialClientApplicationBuilder.Create(TestConstants.ClientId)
                           .WithAuthority(AzureCloudInstance.AzurePublic, TestConstants.TenantId, false)
                           .WithClientSecret(TestConstants.ClientSecret)
                           .WithHttpManager(_harness.HttpManager)
                           .WithAzureRegion()
                           .WithExperimentalFeatures(true)
                           .BuildConcrete();

                authResult = await app2
                             .AcquireTokenForClient(TestConstants.s_scope)
                             .WithForceRefresh(forceRefresh)
                             .ExecuteAsync()
                             .ConfigureAwait(false);

                correlationId = authResult.CorrelationId;
                break;

            case AcquireTokenForClientOutcome.UserProvidedRegion:

                tokenRequestHandler = _harness.HttpManager.AddSuccessTokenResponseMockHandlerForPost(authority: TestConstants.AuthorityRegional);


                var app3 = ConfidentialClientApplicationBuilder.Create(TestConstants.ClientId)
                           .WithAuthority(AzureCloudInstance.AzurePublic, TestConstants.TenantId, false)
                           .WithClientSecret(TestConstants.ClientSecret)
                           .WithHttpManager(_harness.HttpManager)
                           .WithAzureRegion(TestConstants.Region)
                           .WithExperimentalFeatures(true)
                           .BuildConcrete();
                authResult = await app3
                             .AcquireTokenForClient(TestConstants.s_scope)
                             .WithForceRefresh(forceRefresh)
                             .ExecuteAsync()
                             .ConfigureAwait(false);

                correlationId = authResult.CorrelationId;
                break;

            case AcquireTokenForClientOutcome.AADUnavailableError:
                correlationId = Guid.NewGuid();

                var app5 = ConfidentialClientApplicationBuilder.Create(TestConstants.ClientId)
                           .WithAuthority(AzureCloudInstance.AzurePublic, TestConstants.TenantId, false)
                           .WithClientSecret(TestConstants.ClientSecret)
                           .WithHttpManager(_harness.HttpManager)
                           .WithAzureRegion()
                           .WithExperimentalFeatures(true)
                           .BuildConcrete();

                tokenRequestHandler = new MockHttpMessageHandler()
                {
                    ExpectedMethod  = HttpMethod.Post,
                    ResponseMessage = MockHelpers.CreateFailureMessage(
                        System.Net.HttpStatusCode.GatewayTimeout, "gateway timeout")
                };
                var tokenRequestHandler2 = new MockHttpMessageHandler()
                {
                    ExpectedMethod  = HttpMethod.Post,
                    ResponseMessage = MockHelpers.CreateFailureMessage(
                        System.Net.HttpStatusCode.GatewayTimeout, "gateway timeout")
                };

                // 2 of these are needed because MSAL has a "retry once" policy for 5xx errors
                _harness.HttpManager.AddMockHandler(tokenRequestHandler2);
                _harness.HttpManager.AddMockHandler(tokenRequestHandler);

                var serviceEx = await AssertException.TaskThrowsAsync <MsalServiceException>(() =>
                                                                                             app5
                                                                                             .AcquireTokenForClient(TestConstants.s_scope)
                                                                                             .WithForceRefresh(true)
                                                                                             .WithCorrelationId(correlationId)
                                                                                             .ExecuteAsync())
                                .ConfigureAwait(false);

                break;

            default:
                throw new NotImplementedException();
            }

            Assert.AreEqual(0, _harness.HttpManager.QueueSize);

            return(tokenRequestHandler?.ActualRequestMessage, correlationId);
        }
Beispiel #10
0
        public async Task OboAndSilent_Async(bool serializeCache, bool usePartitionedSerializationCache)
        {
            // Setup: Get lab users, create PCA and get user tokens
            var user1 = (await LabUserHelper.GetSpecificUserAsync("*****@*****.**").ConfigureAwait(false)).User;
            var user2 = (await LabUserHelper.GetSpecificUserAsync("*****@*****.**").ConfigureAwait(false)).User;
            var partitionedInMemoryTokenCache    = new InMemoryPartitionedTokenCache();
            var nonPartitionedInMemoryTokenCache = new InMemoryTokenCache();
            var oboTokens = new HashSet <string>();

            var pca = PublicClientApplicationBuilder
                      .Create(PublicClientID)
                      .WithAuthority(AadAuthorityAudience.AzureAdMultipleOrgs)
                      .Build();

            var user1AuthResult = await pca
                                  .AcquireTokenByUsernamePassword(s_oboServiceScope, user1.Upn, new NetworkCredential("", user1.GetOrFetchPassword()).SecurePassword)
                                  .ExecuteAsync(CancellationToken.None)
                                  .ConfigureAwait(false);

            var user2AuthResult = await pca
                                  .AcquireTokenByUsernamePassword(s_oboServiceScope, user2.Upn, new NetworkCredential("", user2.GetOrFetchPassword()).SecurePassword)
                                  .ExecuteAsync(CancellationToken.None)
                                  .ConfigureAwait(false);

            Assert.AreEqual(user1AuthResult.TenantId, user2AuthResult.TenantId);

            var cca = CreateCCA();

            // Asserts
            // Silent calls should throw
            await AssertException.TaskThrowsAsync <MsalUiRequiredException>(() =>
                                                                            cca.AcquireTokenSilent(s_scopes, user1.Upn)
                                                                            .ExecuteAsync(CancellationToken.None)
                                                                            ).ConfigureAwait(false);

            await AssertException.TaskThrowsAsync <MsalUiRequiredException>(() =>
                                                                            cca.AcquireTokenSilent(s_scopes, user2.Upn)
                                                                            .ExecuteAsync(CancellationToken.None)
                                                                            ).ConfigureAwait(false);

            // User1 - no AT, RT in cache - retrieves from IdP
            var authResult = await cca.AcquireTokenOnBehalfOf(s_scopes, new UserAssertion(user1AuthResult.AccessToken))
                             .ExecuteAsync(CancellationToken.None)
                             .ConfigureAwait(false);

            Assert.AreEqual(TokenSource.IdentityProvider, authResult.AuthenticationResultMetadata.TokenSource);
            Assert.AreEqual(CacheRefreshReason.NoCachedAccessToken, authResult.AuthenticationResultMetadata.CacheRefreshReason);
            oboTokens.Add(authResult.AccessToken);

            // User1 - finds AT in cache
            authResult = await cca.AcquireTokenOnBehalfOf(s_scopes, new UserAssertion(user1AuthResult.AccessToken))
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

            Assert.AreEqual(TokenSource.Cache, authResult.AuthenticationResultMetadata.TokenSource);
            Assert.AreEqual(CacheRefreshReason.NotApplicable, authResult.AuthenticationResultMetadata.CacheRefreshReason);
            oboTokens.Add(authResult.AccessToken);

            // User2 - no AT, RT - retrieves from IdP
            authResult = await cca.AcquireTokenOnBehalfOf(s_scopes, new UserAssertion(user2AuthResult.AccessToken))
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

            Assert.AreEqual(TokenSource.IdentityProvider, authResult.AuthenticationResultMetadata.TokenSource);
            Assert.AreEqual(CacheRefreshReason.NoCachedAccessToken, authResult.AuthenticationResultMetadata.CacheRefreshReason);
            oboTokens.Add(authResult.AccessToken);

            // User2 - finds AT in cache
            authResult = await cca.AcquireTokenOnBehalfOf(s_scopes, new UserAssertion(user2AuthResult.AccessToken))
                         .ExecuteAsync(CancellationToken.None)
                         .ConfigureAwait(false);

            Assert.AreEqual(TokenSource.Cache, authResult.AuthenticationResultMetadata.TokenSource);
            Assert.AreEqual(CacheRefreshReason.NotApplicable, authResult.AuthenticationResultMetadata.CacheRefreshReason);
            oboTokens.Add(authResult.AccessToken);

            Assert.AreEqual(2, oboTokens.Count);

            // Silent calls should throw
            await AssertException.TaskThrowsAsync <MsalUiRequiredException>(() =>
                                                                            cca.AcquireTokenSilent(s_scopes, user1.Upn)
                                                                            .ExecuteAsync(CancellationToken.None)
                                                                            ).ConfigureAwait(false);

            await AssertException.TaskThrowsAsync <MsalUiRequiredException>(() =>
                                                                            cca.AcquireTokenSilent(s_scopes, user2.Upn)
                                                                            .ExecuteAsync(CancellationToken.None)
                                                                            ).ConfigureAwait(false);

            IConfidentialClientApplication CreateCCA()
            {
                var app = ConfidentialClientApplicationBuilder
                          .Create(OboConfidentialClientID)
                          .WithAuthority(new Uri($"https://login.microsoftonline.com/{user1AuthResult.TenantId}"), true)
                          .WithClientSecret(_confidentialClientSecret)
                          .WithLegacyCacheCompatibility(false)
                          .Build();

                if (serializeCache)
                {
                    if (usePartitionedSerializationCache)
                    {
                        partitionedInMemoryTokenCache.Bind(app.UserTokenCache);
                    }
                    else
                    {
                        nonPartitionedInMemoryTokenCache.Bind(app.UserTokenCache);
                    }
                }

                return(app);
            }
        }
        public async Task AuthorityMigrationTestAsync()
        {
            // make sure that for all network calls "preferred_cache" environment is used
            // (it is taken from metadata in instance discovery response),
            // except very first network call - instance discovery

            using (var harness = base.CreateTestHarness())
            {
                var httpManager  = harness.HttpManager;
                var authorityUri = new Uri(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "https://{0}/common",
                        TestConstants.ProductionNotPrefEnvironmentAlias));

                httpManager.AddInstanceDiscoveryMockHandler(authorityUri.AbsoluteUri);

                PublicClientApplication app = PublicClientApplicationBuilder
                                              .Create(TestConstants.ClientId)
                                              .WithAuthority(authorityUri, true)
                                              .WithHttpManager(httpManager)
                                              //.WithUserTokenLegacyCachePersistenceForTest(new TestLegacyCachePersistance())
                                              .WithTelemetry(new TraceTelemetryConfig())
                                              .WithDebugLoggingCallback()
                                              .BuildConcrete();

                InMemoryTokenCache cache = new InMemoryTokenCache();
                cache.Bind(app.UserTokenCache);

                app.ServiceBundle.ConfigureMockWebUI(
                    AuthorizationResult.FromUri(app.AppConfig.RedirectUri + "?code=some-code"),
                    null,
                    TestConstants.ProductionPrefNetworkEnvironment);

                // mock token request
                httpManager.AddMockHandler(new MockHttpMessageHandler
                {
                    ExpectedUrl = string.Format(CultureInfo.InvariantCulture, "https://{0}/common/oauth2/v2.0/token",
                                                TestConstants.ProductionPrefNetworkEnvironment),
                    ExpectedMethod  = HttpMethod.Post,
                    ResponseMessage = MockHelpers.CreateSuccessTokenResponseMessage()
                });

                AuthenticationResult result = await app.AcquireTokenInteractive(TestConstants.s_scope).ExecuteAsync().ConfigureAwait(false);

                // make sure that all cache entities are stored with "preferred_cache" environment
                // (it is taken from metadata in instance discovery response)
                await ValidateCacheEntitiesEnvironmentAsync(app.UserTokenCacheInternal, TestConstants.ProductionPrefCacheEnvironment).ConfigureAwait(false);

                // silent request targeting at, should return at from cache for any environment alias
                foreach (var envAlias in TestConstants.s_prodEnvAliases)
                {
                    var app2 = PublicClientApplicationBuilder
                               .Create(TestConstants.ClientId)
                               .WithAuthority($"https://{envAlias}/common", true)
                               .WithHttpManager(httpManager)
                               .WithTelemetry(new TraceTelemetryConfig())
                               .WithDebugLoggingCallback()
                               .BuildConcrete();

                    cache.Bind(app2.UserTokenCache);

                    result = await app2
                             .AcquireTokenSilent(
                        TestConstants.s_scope,
                        app.GetAccountsAsync().Result.First())
                             .WithAuthority(string.Format(CultureInfo.InvariantCulture, "https://{0}/{1}/", envAlias, TestConstants.Utid))
                             .WithForceRefresh(false)
                             .ExecuteAsync(CancellationToken.None)
                             .ConfigureAwait(false);

                    Assert.IsNotNull(result);
                }

                // silent request targeting rt should find rt in cache for authority with any environment alias
                foreach (var envAlias in TestConstants.s_prodEnvAliases)
                {
                    result = null;

                    httpManager.AddMockHandler(new MockHttpMessageHandler()
                    {
                        ExpectedUrl = string.Format(CultureInfo.InvariantCulture, "https://{0}/{1}/oauth2/v2.0/token",
                                                    TestConstants.ProductionPrefNetworkEnvironment, TestConstants.Utid),
                        ExpectedMethod   = HttpMethod.Post,
                        ExpectedPostData = new Dictionary <string, string>()
                        {
                            { "grant_type", "refresh_token" }
                        },
                        // return not retriable status code
                        ResponseMessage = MockHelpers.CreateInvalidGrantTokenResponseMessage()
                    });

                    try
                    {
                        var app3 = PublicClientApplicationBuilder
                                   .Create(TestConstants.ClientId)
                                   .WithAuthority($"https://{envAlias}/common", true)
                                   .WithHttpManager(httpManager)
                                   .WithTelemetry(new TraceTelemetryConfig())
                                   .WithDebugLoggingCallback()
                                   .BuildConcrete();

                        cache.Bind(app3.UserTokenCache);

                        result = await app3
                                 .AcquireTokenSilent(
                            TestConstants.s_scopeForAnotherResource,
                            (await app.GetAccountsAsync().ConfigureAwait(false)).First())
                                 .WithAuthority(string.Format(CultureInfo.InvariantCulture, "https://{0}/{1}/", envAlias, TestConstants.Utid))
                                 .WithForceRefresh(false)
                                 .ExecuteAsync(CancellationToken.None).ConfigureAwait(false);
                    }
                    catch (MsalUiRequiredException)
                    {
                    }


                    Assert.IsNull(result);
                }
            }
        }