/// <summary>
        /// Returns an access token depending on the type requested for testing.
        /// </summary>
        /// <returns></returns>
        private Task <AppAuthenticationResult> AcquireTokenAsync()
        {
            AppAuthenticationResult authResult;

            switch (_mockAuthenticationContextTestType)
            {
            case MockAuthenticationContextTestType.AcquireTokenSilentAsyncFail:
            case MockAuthenticationContextTestType.AcquireTokenAsyncClientCertificateFail:
            case MockAuthenticationContextTestType.AcquireTokenAsyncClientCredentialFail:
            case MockAuthenticationContextTestType.AcquireTokenAsyncUserCredentialFail:
                return(Task.FromResult <AppAuthenticationResult>(null));

            case MockAuthenticationContextTestType.AcquireInvalidTokenAsyncFail:
                authResult = AppAuthenticationResult.Create(TokenHelper.GetInvalidAppToken());
                return(Task.FromResult(authResult));

            case MockAuthenticationContextTestType.AcquireTokenAsyncException:
                throw new Exception(Constants.AdalException);

            case MockAuthenticationContextTestType.AcquireTokenSilentAsyncSuccess:
            case MockAuthenticationContextTestType.AcquireTokenAsyncUserCredentialSuccess:
                authResult = AppAuthenticationResult.Create(TokenHelper.GetUserToken());
                return(Task.FromResult(authResult));

            case MockAuthenticationContextTestType.AcquireTokenAsyncClientCertificateSuccess:
            case MockAuthenticationContextTestType.AcquireTokenAsyncClientCredentialSuccess:
                authResult = AppAuthenticationResult.Create(TokenHelper.GetAppToken());
                return(Task.FromResult(authResult));
            }

            return(null);
        }
Пример #2
0
        public void CanGetJwtTokenWithForceRefresh(bool forceRefreshInput)
        {
            var authResult    = new AppAuthenticationResult();
            var tokenProvider = new Mock <AzureServiceTokenProvider>(TestConnectionString, TestAzureAdInstance);

            tokenProvider
            .Setup(p => p.GetAuthenticationResultAsync(
                       It.IsAny <string>(), It.IsAny <bool>(), It.IsAny <CancellationToken>()))
            .Returns <string, bool, CancellationToken>((resource, forceRefresh, cancellationToken) =>
            {
                Assert.Equal(forceRefreshInput, forceRefresh);
                return(Task.FromResult(authResult));
            });

            var tokenProviderFactory = new Mock <IJwtTokenProviderFactory>();

            tokenProviderFactory
            .Setup(f => f.CreateAzureServiceTokenProvider(It.IsAny <string>(), It.IsAny <HttpClient>()))
            .Returns <string, HttpClient>((appId, customHttpClient) => tokenProvider.Object);

            var sut   = new ManagedIdentityAuthenticator(TestAppId, TestAudience, tokenProviderFactory.Object);
            var token = sut.GetTokenAsync(forceRefreshInput).GetAwaiter().GetResult();

            Assert.Equal(authResult.AccessToken, token.AccessToken);
            Assert.Equal(authResult.ExpiresOn, token.ExpiresOn);
        }
        public override async ValueTask <AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
        {
            var authProvider = new AzureServiceTokenProvider();
            AppAuthenticationResult result = await authProvider.GetAuthenticationResultAsync(Resource, _managedIdentityTenantId);

            return(new AccessToken(result.AccessToken, result.ExpiresOn));
        }
        private async Task <NewTokenAndFrequency> TokenRenewerAsync(
            object state,
            CancellationToken cancellationToken)
        {
            string StorageResource             = BlobServiceURI;
            AppAuthenticationResult authResult = await((AzureServiceTokenProvider)state).GetAuthenticationResultAsync(StorageResource, (string)null, new CancellationToken());
            TimeSpan next = authResult.ExpiresOn - DateTimeOffset.UtcNow - TimeSpan.FromMinutes(5.0);

            if (next.Ticks < 0L)
            {
                next = new TimeSpan();
            }
            return(new NewTokenAndFrequency(authResult.AccessToken, new TimeSpan?(next)));
        }
Пример #5
0
        public override async ValueTask <AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
        {
            var    authProvider = new AzureServiceTokenProvider();
            string tenantId     = _managedIdentityTenantId;

            if (tenantId != null && tenantId.Length == 0)
            {
                tenantId = null; //We want to clearly indicate to the provider if we do not specify a tenant, so no empty strings
            }

            AppAuthenticationResult result = await authProvider.GetAuthenticationResultAsync(Resource, tenantId);

            return(new AccessToken(result.AccessToken, result.ExpiresOn));
        }
Пример #6
0
        private static async Task <NewTokenAndFrequency> TokenRenewerAsync(object state, CancellationToken cancellationToken)
        {
            // Specify the resource ID for requesting Azure AD tokens for Azure Storage.
            const string StorageResource = "https://storage.azure.com/";

            // Use the same token provider to request a new token.
            AppAuthenticationResult authResult = await((AzureServiceTokenProvider)state).GetAuthenticationResultAsync(StorageResource, cancellationToken: cancellationToken);

            // Renew the token 5 minutes before it expires.
            var next = (authResult.ExpiresOn - DateTimeOffset.UtcNow) - TimeSpan.FromMinutes(5);

            if (next.Ticks < 0)
            {
                next = default(TimeSpan);
                Debug.WriteLine("Renewing token...");
            }

            // Return the new token and the next refresh time.
            return(new NewTokenAndFrequency(authResult.AccessToken, next));
        }
        public async Task GetTokenUsingServicePrincipalWithClientSecretTest()
        {
            GraphHelper graphHelper = new GraphHelper(_tenantId);
            string      secret      = Convert.ToBase64String(Encoding.ASCII.GetBytes(Guid.NewGuid().ToString()));
            Application app         = await graphHelper.CreateApplicationAsync(secret);

            // Get token using service principal
            AppAuthenticationResult authResult = null;
            int count = 5;

            Environment.SetEnvironmentVariable(Constants.ConnectionStringEnvironmentVariableName, $"RunAs=App;TenantId={_tenantId};AppId={app.AppId};AppKey={secret}");
            AzureServiceTokenProvider astp = new AzureServiceTokenProvider();

            while (authResult == null && count > 0)
            {
                try
                {
                    authResult = await astp.GetAuthenticationResultAsync(Constants.SqlAzureResourceId, _tenantId);

                    await astp.GetAccessTokenAsync(Constants.KeyVaultResourceId);
                }
                catch
                {
                    // It takes time for Azure AD to realize a new application has been added.
                    await Task.Delay(15000);

                    count--;
                }
            }

            // Delete the application
            await graphHelper.DeleteApplicationAsync(app);

            Environment.SetEnvironmentVariable(Constants.ConnectionStringEnvironmentVariableName, null);

            Validator.ValidateToken(authResult.AccessToken, astp.PrincipalUsed, Constants.AppType, _tenantId, app.AppId, expiresOn: authResult.ExpiresOn);
        }
Пример #8
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);
        }
        /// <summary>
        /// One must be logged in using Azure CLI and set AppAuthenticationTestCertUrl to a secret URL for a certificate in Key Vault before running this test.
        /// The test creates a new Azure AD application and service principal, uses the cert as the credential, and then uses the library to authenticate to it, using the cert.
        /// After the cert, the Azure AD application is deleted. Cert is removed from current user store on the machine.
        /// </summary>
        /// <param name="certIdentifierType"></param>
        /// <returns></returns>
        private async Task GetTokenUsingServicePrincipalWithCertTestImpl(CertIdentifierType certIdentifierType)
        {
            string testCertUrl = Environment.GetEnvironmentVariable(Constants.TestCertUrlEnv);

            // Get a certificate from key vault.
            // For security, this certificate is not hard coded in the test case, since it gets added as app credential in Azure AD, and may not get removed.
            AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider(Constants.AzureCliConnectionString);
            KeyVaultHelper            keyVaultHelper            = new KeyVaultHelper(new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback)));
            string certAsString = await keyVaultHelper.ExportCertificateAsBlob(testCertUrl).ConfigureAwait(false);

            X509Certificate2 cert = new X509Certificate2(Convert.FromBase64String(certAsString), string.Empty);

            // Create an application
            GraphHelper graphHelper = new GraphHelper(_tenantId);
            Application app         = await graphHelper.CreateApplicationAsync(cert).ConfigureAwait(false);

            // Get token using service principal, this will cache the cert
            AppAuthenticationResult authResult = null;
            int count = 5;

            string thumbprint = cert.Thumbprint?.ToLower();

            // Construct connection string using client id and cert info
            string connectionString = null;

            switch (certIdentifierType)
            {
            case CertIdentifierType.SubjectName:
            case CertIdentifierType.Thumbprint:
                string thumbprintOrSubjectName = (certIdentifierType == CertIdentifierType.Thumbprint) ? $"CertificateThumbprint={thumbprint}" : $"CertificateSubjectName={cert.Subject}";
                connectionString = $"RunAs=App;AppId={app.AppId};TenantId={_tenantId};{thumbprintOrSubjectName};CertificateStoreLocation={Constants.CurrentUserStore};";
                break;

            case CertIdentifierType.KeyVaultCertificateSecretIdentifier:
                connectionString = $"RunAs=App;AppId={app.AppId};TenantId={_tenantId};CertificateKeyVaultCertificateSecretIdentifier={testCertUrl};";
                break;
            }

            AzureServiceTokenProvider astp =
                new AzureServiceTokenProvider(connectionString);

            if (certIdentifierType == CertIdentifierType.SubjectName ||
                certIdentifierType == CertIdentifierType.Thumbprint)
            {
                // Import the certificate
                CertUtil.ImportCertificate(cert);
            }

            while (authResult == null && count > 0)
            {
                try
                {
                    await astp.GetAccessTokenAsync(Constants.KeyVaultResourceId);

                    authResult = await astp.GetAuthenticationResultAsync(Constants.SqlAzureResourceId, _tenantId);
                }
                catch
                {
                    // It takes time for Azure AD to realize a new application has been added.
                    await Task.Delay(15000);

                    count--;
                }
            }

            if (certIdentifierType == CertIdentifierType.SubjectName ||
                certIdentifierType == CertIdentifierType.Thumbprint)
            {
                // Delete the cert
                CertUtil.DeleteCertificate(cert.Thumbprint);

                var deletedCert = CertUtil.GetCertificate(cert.Thumbprint);
                Assert.Null(deletedCert);
            }

            // Get token again using a cert which is deleted, but in the cache
            await astp.GetAccessTokenAsync(Constants.SqlAzureResourceId, _tenantId);

            // Delete the application and service principal
            await graphHelper.DeleteApplicationAsync(app);

            Validator.ValidateToken(authResult.AccessToken, astp.PrincipalUsed, Constants.AppType, _tenantId,
                                    app.AppId, cert.Thumbprint, expiresOn: authResult.ExpiresOn);
        }