Example #1
0
        public async Task DiscoveryTestFirstSuccess()
        {
            // Mock process manager is being asked to act like Azure CLI was able to get the token.
            MockProcessManager          mockProcessManager          = new MockProcessManager(MockProcessManager.MockProcessManagerRequestType.Success);
            AzureCliAccessTokenProvider azureCliAccessTokenProvider = new AzureCliAccessTokenProvider(mockProcessManager);

            // Mock MSI is being asked to act like MSI was able to get token.
            MockMsi                mockMsi                = new MockMsi(MockMsi.MsiTestType.MsiAppServicesSuccess);
            HttpClient             httpClient             = new HttpClient(mockMsi);
            MsiAccessTokenProvider msiAccessTokenProvider = new MsiAccessTokenProvider(httpClient);

            // AzureServiceTokenProvider is being asked to use two providers, and return token from the first that succeeds.
            var providers = new List <NonInteractiveAzureServiceTokenProviderBase> {
                azureCliAccessTokenProvider, msiAccessTokenProvider
            };
            AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider(providers);

            var token = await azureServiceTokenProvider.GetAccessTokenAsync(Constants.GraphResourceId, Constants.TenantId);

            // Mock process manager will be hit first, and so the hit count should be 1.
            Assert.Equal(1, mockProcessManager.HitCount);

            // Msi handler will not be hit, since AzureCliAccessTokenProvider was able to return token. So this hit count should be 0.
            Assert.Equal(0, mockMsi.HitCount);

            Validator.ValidateToken(token, azureServiceTokenProvider.PrincipalUsed, Constants.UserType, Constants.TenantId);
        }
Example #2
0
        public async Task DiscoveryTestFirstFail()
        {
            // Mock process manager is being asked to act like Azure CLI was NOT able to get the token.
            MockProcessManager          mockProcessManager          = new MockProcessManager(MockProcessManager.MockProcessManagerRequestType.ProcessNotFound);
            AzureCliAccessTokenProvider azureCliAccessTokenProvider = new AzureCliAccessTokenProvider(mockProcessManager);

            // Mock MSI is being asked to act like MSI was able to get token.
            MockMsi                mockMsi                = new MockMsi(MockMsi.MsiTestType.MsiAzureVmSuccess);
            HttpClient             httpClient             = new HttpClient(mockMsi);
            MsiAccessTokenProvider msiAccessTokenProvider = new MsiAccessTokenProvider(httpClient);

            // AzureServiceTokenProvider is being asked to use two providers, and return token from the first that succeeds.
            var providers = new List <NonInteractiveAzureServiceTokenProviderBase> {
                azureCliAccessTokenProvider, msiAccessTokenProvider
            };
            AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider(providers);

            var token = await azureServiceTokenProvider.GetAccessTokenAsync(Constants.GraphResourceId, Constants.TenantId);

            // Mock process manager will be hit first, and so hit count will be 1.
            Assert.Equal(1, mockProcessManager.HitCount);

            // AzureCliAccessTokenProvider will fail, and so Msi handler will be hit next. So hit count is 2 here (1 for probe request, 1 for token request).
            Assert.Equal(2, mockMsi.HitCount);

            // MsiAccessTokenProvider should succeed, and we should get a valid token.
            Validator.ValidateToken(token, azureServiceTokenProvider.PrincipalUsed, Constants.AppType, Constants.TenantId, Constants.TestAppId);
        }
Example #3
0
        public void DiscoveryTestBothFail()
        {
            // Mock process manager is being asked to act like Azure CLI was NOT able to get the token.
            MockProcessManager          mockProcessManager          = new MockProcessManager(MockProcessManager.MockProcessManagerRequestType.ProcessNotFound);
            AzureCliAccessTokenProvider azureCliAccessTokenProvider = new AzureCliAccessTokenProvider(mockProcessManager);

            // Mock MSI is being asked to act like MSI was able to get token.
            MockMsi                mockMsi                = new MockMsi(MockMsi.MsiTestType.MsiAppServicesFailure);
            HttpClient             httpClient             = new HttpClient(mockMsi);
            MsiAccessTokenProvider msiAccessTokenProvider = new MsiAccessTokenProvider(httpClient);

            // AzureServiceTokenProvider is being asked to use two providers, and and both should fail to get token.
            var providers = new List <NonInteractiveAzureServiceTokenProviderBase> {
                azureCliAccessTokenProvider, msiAccessTokenProvider
            };
            AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider(providers);

            var exception = Assert.ThrowsAsync <AzureServiceTokenProviderException>(() => azureServiceTokenProvider.GetAccessTokenAsync(Constants.GraphResourceId, Constants.TenantId));

            Assert.Contains(Constants.NoMethodWorkedToGetTokenError, exception.Result.Message);

            // Mock process manager will fail, and so hit count will be 1.
            Assert.Equal(1, mockProcessManager.HitCount);

            // AzureCliAccessTokenProvider will fail, and so Msi handler will be hit next. So hit count is 1 here.
            Assert.Equal(1, mockMsi.HitCount);
        }
Example #4
0
        public async Task GetAppAuthResultForceRefreshTest()
        {
            // Create two instances of AzureServiceTokenProvider based on AzureCliAccessTokenProvider.
            MockProcessManager          mockProcessManager          = new MockProcessManager(MockProcessManager.MockProcessManagerRequestType.Success);
            AzureCliAccessTokenProvider azureCliAccessTokenProvider = new AzureCliAccessTokenProvider(mockProcessManager);
            AzureServiceTokenProvider   azureServiceTokenProvider   = new AzureServiceTokenProvider(azureCliAccessTokenProvider);
            AzureServiceTokenProvider   azureServiceTokenProvider1  = new AzureServiceTokenProvider(azureCliAccessTokenProvider);

            // Part 1: Verify force refresh of sequential requests will request new tokens.
            await azureServiceTokenProvider.GetAccessTokenAsync(Constants.KeyVaultResourceId);

            Assert.Equal(1, mockProcessManager.HitCount);

            await azureServiceTokenProvider.GetAccessTokenAsync(Constants.KeyVaultResourceId);

            Assert.Equal(1, mockProcessManager.HitCount); // cache hit.

            await azureServiceTokenProvider.GetAccessTokenAsync(Constants.KeyVaultResourceId, forceRefresh : true);

            Assert.Equal(2, mockProcessManager.HitCount); // force refresh hit.

            await azureServiceTokenProvider1.GetAccessTokenAsync(Constants.KeyVaultResourceId);

            Assert.Equal(2, mockProcessManager.HitCount); // cache hit.

            await azureServiceTokenProvider1.GetAccessTokenAsync(Constants.KeyVaultResourceId, forceRefresh : true);

            Assert.Equal(3, mockProcessManager.HitCount); // force refresh hit.

            // Part 2: Verify parallel force-refreshes re-use the same fetched token.
            // TODO: current system does not allow for controlling this flow, test would be non-deterministic and intermitently fail.
        }
Example #5
0
        public async Task DiscoveryTestFirstFail()
        {
            // Mock process manager is being asked to act like Azure CLI was NOT able to get the token.
            MockProcessManager          mockProcessManager          = new MockProcessManager(MockProcessManager.MockProcessManagerRequestType.ProcessNotFound);
            AzureCliAccessTokenProvider azureCliAccessTokenProvider = new AzureCliAccessTokenProvider(mockProcessManager);

            // Mock MSI is being asked to act like MSI was able to get token.
            MockMsi mockMsi = new MockMsi(MockMsi.MsiTestType.MsiAppServicesSuccess);
            MsiAccessTokenProvider msiAccessTokenProvider = new MsiAccessTokenProvider(mockMsi);

            // set env vars so MsiAccessTokenProvider assumes App Service environment and not VM environment
            Environment.SetEnvironmentVariable(Constants.MsiAppServiceEndpointEnv, Constants.MsiEndpoint);
            Environment.SetEnvironmentVariable(Constants.MsiAppServiceHeaderEnv, Constants.ClientSecret);

            // AzureServiceTokenProvider is being asked to use two providers, and return token from the first that succeeds.
            var providers = new List <NonInteractiveAzureServiceTokenProviderBase> {
                azureCliAccessTokenProvider, msiAccessTokenProvider
            };
            AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider(providers);

            var token = await azureServiceTokenProvider.GetAccessTokenAsync(Constants.GraphResourceId, Constants.TenantId);

            // Mock process manager will be hit first, and so hit count will be 1.
            Assert.Equal(1, mockProcessManager.HitCount);

            // AzureCliAccessTokenProvider will fail, and so Msi handler will be hit next. So hit count is 1 here.
            Assert.Equal(1, mockMsi.HitCount);

            // MsiAccessTokenProvider should succeed, and we should get a valid token.
            Validator.ValidateToken(token, azureServiceTokenProvider.PrincipalUsed, Constants.AppType, Constants.TenantId, Constants.TestAppId);
        }
        public async Task KeyVaultCertificateSecretIdentifierSuccessTest(bool includeTenantId)
        {
            X509Certificate2 cert = new X509Certificate2(Convert.FromBase64String(Constants.TestCert), string.Empty);

            MockProcessManager          mockProcessManager          = new MockProcessManager(MockProcessManager.MockProcessManagerRequestType.Success);
            AzureCliAccessTokenProvider azureCliAccessTokenProvider = new AzureCliAccessTokenProvider(mockProcessManager);

            // Create KeyVaultClient with MockKeyVault to mock successful calls to KeyVault
            MockKeyVault   mockKeyVault   = new MockKeyVault(MockKeyVault.KeyVaultClientTestType.CertificateSecretIdentifierSuccess);
            HttpClient     httpClient     = new HttpClient(mockKeyVault);
            KeyVaultClient keyVaultClient = new KeyVaultClient(httpClient, azureCliAccessTokenProvider);

            // MockAuthenticationContext is being asked to act like client cert auth suceeded.
            MockAuthenticationContext mockAuthenticationContext = new MockAuthenticationContext(MockAuthenticationContext.MockAuthenticationContextTestType.AcquireTokenAsyncClientCertificateSuccess);

            string tenantIdParam = includeTenantId ? Constants.TenantId : null;

            // Create ClientCertificateAzureServiceTokenProvider instance with a subject name
            ClientCertificateAzureServiceTokenProvider provider = new ClientCertificateAzureServiceTokenProvider(Constants.TestAppId,
                                                                                                                 Constants.TestKeyVaultCertificateSecretIdentifier, CertificateIdentifierType.KeyVaultCertificateSecretIdentifier, null, Constants.AzureAdInstance, tenantIdParam, 0, mockAuthenticationContext, keyVaultClient);

            // Get the token. This will test that ClientCertificateAzureServiceTokenProvider could fetch the cert from CurrentUser store based on subject name in the connection string.
            var authResult = await provider.GetAuthResultAsync(Constants.ArmResourceId, string.Empty).ConfigureAwait(false);

            Validator.ValidateToken(authResult.AccessToken, provider.PrincipalUsed, Constants.AppType, Constants.TenantId, Constants.TestAppId, cert.Thumbprint, expiresOn: authResult.ExpiresOn);
        }
        public async Task ResourceInvalidCharsTest()
        {
            MockProcessManager mockProcessManager = new MockProcessManager(MockProcessManager.MockProcessManagerRequestType.Success);

            AzureCliAccessTokenProvider azureCliAccessTokenProvider = new AzureCliAccessTokenProvider(mockProcessManager);

            var exception = await Assert.ThrowsAsync <AzureServiceTokenProviderException>(() => Task.Run(() => azureCliAccessTokenProvider.GetAuthResultAsync("https://test^", Constants.TenantId)));

            Assert.Contains(Constants.NotInExpectedFormatError, exception.Message);
        }
        public async Task CliNotFoundTest()
        {
            MockProcessManager mockProcessManager = new MockProcessManager(MockProcessManager.MockProcessManagerRequestType.ProcessNotFound);

            AzureCliAccessTokenProvider azureCliAccessTokenProvider = new AzureCliAccessTokenProvider(mockProcessManager);

            var exception = await Assert.ThrowsAsync <AzureServiceTokenProviderException>(() => Task.Run(() => azureCliAccessTokenProvider.GetAuthResultAsync(Constants.KeyVaultResourceId, Constants.TenantId)));

            Assert.Contains(Constants.ProgramNotFoundError, exception.Message);
        }
        public async Task FailedToGetTokenUsingAzureCliTest()
        {
            MockProcessManager mockProcessManager = new MockProcessManager(MockProcessManager.MockProcessManagerRequestType.Failure);

            AzureCliAccessTokenProvider azureCliAccessTokenProvider = new AzureCliAccessTokenProvider(mockProcessManager);

            var exception = await Assert.ThrowsAsync <AzureServiceTokenProviderException>(() => Task.Run(() => azureCliAccessTokenProvider.GetAuthResultAsync(Constants.KeyVaultResourceId, Constants.TenantId)));

            Assert.Contains(Constants.FailedToGetTokenError, exception.Message);
            Assert.Contains(Constants.DeveloperToolError, exception.Message);
        }
        public async Task GetTokenUsingAzureCliTest()
        {
            // Mock the progress manager. This emulates running an actual process e.g. az account get-access-token
            MockProcessManager mockProcessManager = new MockProcessManager(MockProcessManager.MockProcessManagerRequestType.Success);

            // AzureCliAccessTokenProvider has in internal only constructor to allow for unit testing.
            AzureCliAccessTokenProvider azureCliAccessTokenProvider = new AzureCliAccessTokenProvider(mockProcessManager);

            // Get token and validate it
            var authResult = await azureCliAccessTokenProvider.GetAuthResultAsync(Constants.KeyVaultResourceId, Constants.TenantId).ConfigureAwait(false);

            Validator.ValidateToken(authResult.AccessToken, azureCliAccessTokenProvider.PrincipalUsed, Constants.UserType, Constants.TenantId);
        }
        public async Task InvalidKeyVaultSecretType()
        {
            MockProcessManager          mockProcessManager          = new MockProcessManager(MockProcessManager.MockProcessManagerRequestType.Success);
            AzureCliAccessTokenProvider azureCliAccessTokenProvider = new AzureCliAccessTokenProvider(mockProcessManager);

            // use a secret identifier, but return secret bundle for password/secret and not certificate
            MockKeyVault   mockKeyVault   = new MockKeyVault(TestType.PasswordSecretIdentifierSuccess);
            HttpClient     httpClient     = new HttpClient(mockKeyVault);
            KeyVaultClient keyVaultClient = new KeyVaultClient(httpClient, azureCliAccessTokenProvider);

            var exception = await Assert.ThrowsAnyAsync <Exception>(() => Task.Run(() => keyVaultClient.GetCertificateAsync(Constants.TestKeyVaultCertificateSecretIdentifier)));

            Assert.Contains(KeyVaultClient.SecretBundleInvalidContentTypeError, exception.Message);
        }
        public async Task SecretNotFoundTest()
        {
            MockProcessManager          mockProcessManager          = new MockProcessManager(MockProcessManager.MockProcessManagerRequestType.Success);
            AzureCliAccessTokenProvider azureCliAccessTokenProvider = new AzureCliAccessTokenProvider(mockProcessManager);

            MockKeyVault   mockKeyVault   = new MockKeyVault(TestType.SecretNotFound);
            HttpClient     httpClient     = new HttpClient(mockKeyVault);
            KeyVaultClient keyVaultClient = new KeyVaultClient(httpClient, azureCliAccessTokenProvider);

            var exception = await Assert.ThrowsAnyAsync <Exception>(() => Task.Run(() => keyVaultClient.GetCertificateAsync(Constants.TestKeyVaultCertificateSecretIdentifier)));

            Assert.Contains(KeyVaultClient.KeyVaultResponseError, exception.Message);
            Assert.Contains(MockKeyVault.SecretNotFoundErrorMessage, exception.Message);
        }
Example #13
0
        public async Task ResourceNullOrEmptyWhenGettingTokenTest()
        {
            // Mock ProcessManager is being asked to act like Azure CLI is not installed.
            MockProcessManager          mockProcessManager          = new MockProcessManager(MockProcessManager.MockProcessManagerRequestType.ProcessNotFound);
            AzureCliAccessTokenProvider azureCliAccessTokenProvider = new AzureCliAccessTokenProvider(mockProcessManager);
            AzureServiceTokenProvider   azureServiceTokenProvider   = new AzureServiceTokenProvider(azureCliAccessTokenProvider);

            var exception = await Assert.ThrowsAsync <ArgumentNullException>(() => Task.Run(() => azureServiceTokenProvider.GetAccessTokenAsync(null, Constants.TenantId)));

            Assert.Contains(Constants.CannotBeNullError, exception.ToString());

            exception = await Assert.ThrowsAsync <ArgumentNullException>(() => Task.Run(() => azureServiceTokenProvider.GetAccessTokenAsync(string.Empty, Constants.TenantId)));

            Assert.Contains(Constants.CannotBeNullError, exception.ToString());
        }
        public async Task KeyVaultTokenProviderErrorTest()
        {
            MockProcessManager          mockProcessManager          = new MockProcessManager(MockProcessManager.MockProcessManagerRequestType.Failure);
            AzureCliAccessTokenProvider azureCliAccessTokenProvider = new AzureCliAccessTokenProvider(mockProcessManager);

            MockKeyVault   mockKeyVault   = new MockKeyVault(TestType.CertificateSecretIdentifierSuccess);
            HttpClient     httpClient     = new HttpClient(mockKeyVault);
            KeyVaultClient keyVaultClient = new KeyVaultClient(httpClient, azureCliAccessTokenProvider);

            var exception = await Assert.ThrowsAnyAsync <Exception>(() => Task.Run(() => keyVaultClient.GetCertificateAsync(Constants.TestKeyVaultCertificateSecretIdentifier)));

            Assert.Contains(AzureServiceTokenProviderException.GenericErrorMessage, exception.Message);
            Assert.Contains(KeyVaultClient.KeyVaultAccessTokenRetrievalError, exception.Message);
            Assert.Contains(string.Format(KeyVaultClient.TokenProviderErrorsFormat, 1), exception.Message);
            Assert.Contains(Constants.DeveloperToolError, exception.Message);
        }
Example #15
0
        public async Task GetTokenExceptionTest()
        {
            // Mock ProcessManager is being asked to act like Azure CLI is not installed.
            MockProcessManager          mockProcessManager          = new MockProcessManager(MockProcessManager.MockProcessManagerRequestType.ProcessNotFound);
            AzureCliAccessTokenProvider azureCliAccessTokenProvider = new AzureCliAccessTokenProvider(mockProcessManager);
            AzureServiceTokenProvider   azureServiceTokenProvider   = new AzureServiceTokenProvider(azureCliAccessTokenProvider);

            await Assert.ThrowsAsync <AzureServiceTokenProviderException>(() => Task.Run(() => azureServiceTokenProvider.GetAccessTokenAsync(Constants.GraphResourceId, Constants.TenantId)));

            // Hit count should be 1, since we called Get Token once.
            Assert.Equal(1, mockProcessManager.HitCount);

            var exception = await Assert.ThrowsAsync <AzureServiceTokenProviderException>(() => Task.Run(() => azureServiceTokenProvider.GetAccessTokenAsync(Constants.GraphResourceId, Constants.TenantId)));

            // Hit count is 2, since token could not be fetched, and so was not in cache.
            // This tells us that tokens are only cached if they are aquired.
            Assert.Equal(2, mockProcessManager.HitCount);

            // Exception should contain the resource and tenant
            Assert.Contains(Constants.GraphResourceId, exception.ToString());
            Assert.Contains(Constants.TenantId, exception.ToString());
        }
Example #16
0
        public void DiscoveryTestBothFail()
        {
            // Mock process manager is being asked to act like Azure CLI was NOT able to get the token.
            MockProcessManager          mockProcessManager          = new MockProcessManager(MockProcessManager.MockProcessManagerRequestType.ProcessNotFound);
            AzureCliAccessTokenProvider azureCliAccessTokenProvider = new AzureCliAccessTokenProvider(mockProcessManager);

            // Mock MSI is being asked to act like MSI was NOT able to get token.
            MockMsi                mockMsi                = new MockMsi(MockMsi.MsiTestType.MsiAppServicesFailure);
            HttpClient             httpClient             = new HttpClient(mockMsi);
            MsiAccessTokenProvider msiAccessTokenProvider = new MsiAccessTokenProvider(httpClient);

            // set env vars so MsiAccessTokenProvider assumes App Service environment and not VM environment
            Environment.SetEnvironmentVariable(Constants.MsiAppServiceEndpointEnv, Constants.MsiEndpoint);
            Environment.SetEnvironmentVariable(Constants.MsiAppServiceSecretEnv, Constants.ClientSecret);

            // use test hook to expedite test
            MsiRetryHelper.WaitBeforeRetry = false;

            // AzureServiceTokenProvider is being asked to use two providers, and and both should fail to get token.
            var providers = new List <NonInteractiveAzureServiceTokenProviderBase> {
                azureCliAccessTokenProvider, msiAccessTokenProvider
            };
            AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider(providers);

            var exception = Assert.ThrowsAsync <AzureServiceTokenProviderException>(() => azureServiceTokenProvider.GetAccessTokenAsync(Constants.GraphResourceId, Constants.TenantId));

            Assert.Contains(Constants.NoMethodWorkedToGetTokenError, exception.Result.Message);

            // Mock process manager will fail, and so hit count will be 1.
            Assert.Equal(1, mockProcessManager.HitCount);

            // AzureCliAccessTokenProvider will fail, and so MSI handler will be hit next. MSI retry count is 5 so hit count is 5 here.
            Assert.Equal(5, mockMsi.HitCount);

            // Clean up environment variables
            Environment.SetEnvironmentVariable(Constants.MsiAppServiceEndpointEnv, null);
            Environment.SetEnvironmentVariable(Constants.MsiAppServiceSecretEnv, null);
        }
Example #17
0
        public async Task KeyVaultCertificateNotFoundTest()
        {
            MockAuthenticationContext mockAuthenticationContext = new MockAuthenticationContext(MockAuthenticationContext.MockAuthenticationContextTestType.AcquireTokenAsyncClientCertificateSuccess);

            MockProcessManager          mockProcessManager          = new MockProcessManager(MockProcessManager.MockProcessManagerRequestType.Success);
            AzureCliAccessTokenProvider azureCliAccessTokenProvider = new AzureCliAccessTokenProvider(mockProcessManager);

            MockKeyVault   mockKeyVault   = new MockKeyVault(MockKeyVault.KeyVaultClientTestType.SecretNotFound);
            HttpClient     httpClient     = new HttpClient(mockKeyVault);
            KeyVaultClient keyVaultClient = new KeyVaultClient(httpClient, azureCliAccessTokenProvider);

            string SecretIdentifier = "https://testbedkeyvault.vault.azure.net/secrets/secret/";
            ClientCertificateAzureServiceTokenProvider provider = new ClientCertificateAzureServiceTokenProvider(Constants.TestAppId,
                                                                                                                 SecretIdentifier, CertificateIdentifierType.KeyVaultSecretIdentifier, Constants.CurrentUserStore, Constants.TenantId, Constants.AzureAdInstance, mockAuthenticationContext, keyVaultClient);

            var exception = await Assert.ThrowsAsync <AzureServiceTokenProviderException>(() => Task.Run(() => provider.GetAuthResultAsync(Constants.ArmResourceId, Constants.TenantId)));

            Assert.Contains(Constants.ArmResourceId, exception.Message);
            Assert.Contains(Constants.TenantId, exception.Message);
            Assert.Contains(AzureServiceTokenProviderException.KeyVaultCertificateRetrievalError, exception.Message);
            Assert.Contains(KeyVaultClient.KeyVaultResponseError, exception.Message);
            Assert.Contains(MockKeyVault.SecretNotFoundErrorMessage, exception.Message);
        }
Example #18
0
        public async Task GetAppAuthResultCacheTest()
        {
            // Create two instances of AzureServiceTokenProvider based on AzureCliAccessTokenProvider.
            MockProcessManager          mockProcessManager          = new MockProcessManager(MockProcessManager.MockProcessManagerRequestType.Success);
            AzureCliAccessTokenProvider azureCliAccessTokenProvider = new AzureCliAccessTokenProvider(mockProcessManager);
            AzureServiceTokenProvider   azureServiceTokenProvider   = new AzureServiceTokenProvider(azureCliAccessTokenProvider);
            AzureServiceTokenProvider   azureServiceTokenProvider1  = new AzureServiceTokenProvider(azureCliAccessTokenProvider);

            List <Task> tasks = new List <Task>();

            // ManualResetEvent will enable testing of SemaphoreSlim used in AzureServiceTokenProvider.
            ManualResetEvent manualResetEvent = new ManualResetEvent(false);

            // Use AzureServiceTokenProviders to get tokens in parallel.
            for (int i = 0; i < 5; i++)
            {
                Task task = Task.Run(async delegate
                {
                    // This will prevent the next line from running, until manualResetEvent.Set() is called.
                    // This will ensure all GetAccessTokenAsync calls are made at once.
                    manualResetEvent.WaitOne();

                    await azureServiceTokenProvider.GetAccessTokenAsync(Constants.KeyVaultResourceId);
                });

                tasks.Add(task);

                Task task1 = Task.Run(async delegate
                {
                    manualResetEvent.WaitOne();

                    // This is using the other instance of AzureServiceTokenProvider.
                    await azureServiceTokenProvider1.GetAccessTokenAsync(Constants.KeyVaultResourceId);
                });

                tasks.Add(task1);
            }

            // This will cause GetAccessTokenAsync calls to be made concurrently.
            manualResetEvent.Set();
            await Task.WhenAll(tasks);

            // Even though multiple calls are made to get token concurrently, using two different instances, the process manager should only be called once.
            // This test tells us that the cache is working as intended.
            Assert.Equal(1, mockProcessManager.HitCount);

            // Get the token again. This will test if the cache call before semaphore use is working as intended.
            for (int i = 0; i < 5; i++)
            {
                tasks.Add(azureServiceTokenProvider.GetAccessTokenAsync(Constants.KeyVaultResourceId));
            }

            await Task.WhenAll(tasks);

            // The hit count should still be 1, since the token should be fetched from cache.
            Assert.Equal(1, mockProcessManager.HitCount);

            // Update the cache entry, to simulate token expiration. This updated token will expire in just less than 5 minutes.
            // In a real scenario, the token will expire after some time.
            // AppAuthResultCache should not return this, since it is about to expire.
            var tokenResponse = TokenResponse.Parse(TokenHelper.GetUserTokenResponse(5 * 60 - 2));
            var authResult    = AppAuthenticationResult.Create(tokenResponse, TokenResponse.DateFormat.DateTimeString);

            AppAuthResultCache.AddOrUpdate("ConnectionString:;Authority:;Resource:https://vault.azure.net/",
                                           new Tuple <AppAuthenticationResult, Principal>(authResult, null));

            // Get the token again.
            for (int i = 0; i < 5; i++)
            {
                tasks.Add(azureServiceTokenProvider.GetAccessTokenAsync(Constants.KeyVaultResourceId));
            }

            await Task.WhenAll(tasks);

            // Hit count should be 2 now, since new token should have been aquired.
            Assert.Equal(2, mockProcessManager.HitCount);
        }