Ejemplo n.º 1
0
        public void CannotAcquireTokenThroughCertTest()
        {
            // Import the test certificate.
            X509Certificate2 cert = new X509Certificate2(Convert.FromBase64String(Constants.TestCert), string.Empty);

            CertUtil.ImportCertificate(cert);

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

            // Create ClientCertificateAzureServiceTokenProvider instance with a subject name
            ClientCertificateAzureServiceTokenProvider provider = new ClientCertificateAzureServiceTokenProvider(Constants.TestAppId,
                                                                                                                 cert.Subject, CertificateIdentifierType.SubjectName, Constants.CurrentUserStore, Constants.TenantId, Constants.AzureAdInstance, mockAuthenticationContext);

            // Get the token. This will test that ClientCertificateAzureServiceTokenProvider could fetch the cert from CurrentUser store based on subject name in the connection string.
            var exception = Assert.ThrowsAsync <AzureServiceTokenProviderException>(() => provider.GetAuthResultAsync(Constants.KeyVaultResourceId, string.Empty));

            // Delete the cert, since testing is done.
            CertUtil.DeleteCertificate(cert.Thumbprint);

            Assert.Contains(Constants.TokenFormatExceptionMessage, exception.Result.Message);
            Assert.Contains(Constants.TokenNotInExpectedFormatError, exception.Result.Message);
        }
        /// <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);
        }