Skip to content

Commit

Permalink
Support user-based authentication in live tests (Azure#33994)
Browse files Browse the repository at this point in the history
  • Loading branch information
mccoyp authored and sofiar-msft committed Feb 16, 2024
1 parent aeaf1f6 commit ac7a139
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 24 deletions.
40 changes: 28 additions & 12 deletions doc/dev/tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,13 @@ Live Azure resources will be necessary in order to run live tests and produce re
resource management commands, documented in [/eng/common/TestResources][test_resources], that streamline this process.
Both pure ARM templates (`test-resources.json`) and BICEP files (`test-resources.bicep`) are supported.

User-based authentication is preferred when using test resources. To enable this:
- Use the [`-UserAuth` command flag][user_auth_flag] when running the `New-TestResources` script.
- Set the environment variable `AZURE_TEST_USE_PWSH_AUTH` to "true" to authenticate with Azure PowerShell, or
`AZURE_TEST_USE_CLI_AUTH` to "true" to authenticate with Azure CLI.
- Ensure you're logged into the tool you choose -- if
you used `New-TestResources.ps1` to deploy resources, you'll already have logged in with Azure PowerShell.

If you haven't yet set up a `test-resources` file for test resource deployment and/or want to use test resources of
your own, you can just configure credentials to target these resources instead.

Expand Down Expand Up @@ -209,14 +216,20 @@ environment variables necessary to run live tests for the service. After storing
-- formatted as `VARIABLE=value` on separate lines -- your credentials and test configuration variables will be set in
our environment when running tests.

If you used the [`-UserAuth` command flag][user_auth_flag] to deploy test resources, set either
`AZURE_TEST_USE_PWSH_AUTH` or `AZURE_TEST_USE_CLI_AUTH` to "true" to authenticate with Azure PowerShell or Azure CLI,
respectively. If both are set to true, Azure PowerShell will be used.

If your service doesn't have a `test-resources` file for test deployment, you'll need to set environment variables
for `AZURE_SUBSCRIPTION_ID`, `AZURE_TENANT_ID`, `AZURE_CLIENT_ID`, and `AZURE_CLIENT_SECRET` at minimum.
for authentication at minimum. For user-based authentication, use `AZURE_TEST_USE_PWSH_AUTH` or
`AZURE_TEST_USE_CLI_AUTH` as described above.

For service principal authentication:
1. Set the `AZURE_SUBSCRIPTION_ID` variable to your organization's subscription ID. You can find it in the "Overview"
section of the "Subscriptions" blade in the [Azure Portal][azure_portal].
2. Define the `AZURE_TENANT_ID`, `AZURE_CLIENT_ID`, and `AZURE_CLIENT_SECRET` of a test service principal. If you do not
have a service principal, use the Azure CLI's [az ad sp create-for-rbac][azure_cli_service_principal] command (ideally,
using your alias as the service principal's name prefix):
have a service principal, use the Azure CLI's [az ad sp create-for-rbac][azure_cli_service_principal] command
(ideally, using your alias as the service principal's name prefix):

```
az login
Expand Down Expand Up @@ -326,7 +339,9 @@ well. To run tests in playback, either set `AZURE_TEST_RUN_LIVE` to "false" or l

### Run and record tests

With the `AZURE_TEST_RUN_LIVE` environment variable set to "true", use `pytest` to run your test(s) in live mode.
First, refer to the [Configure test variables](#configure-test-variables) section to ensure environment variables are
set for test resources and authentication. With the `AZURE_TEST_RUN_LIVE` environment variable set to "true", use
`pytest` to run your test(s) in live mode.

```
(env) azure-sdk-for-python\sdk\my-service\my-package> pytest tests
Expand All @@ -339,18 +354,18 @@ Playback test errors most frequently indicate a need for additional sanitizers a
[Sanitize secrets](#sanitize-secrets)). If you encounter any unexpected errors, refer to the
[test proxy troubleshooting guide][troubleshooting_guide].

At this point there should folder called `recordings` inside your package's `tests` directory. Each recording in this
folder will be a `.json` file that captures the HTTP traffic that was generated while running the test matching the
file's name.
If tests were recorded for a new library, there should now be a folder called `recordings` inside your package's
`tests` directory. Each recording in this folder will be a `.json` file that captures the HTTP traffic that was
generated while running the test matching the file's name.

The final step in setting up recordings is to move these files out of the `azure-sdk-for-python` and into the
`azure-sdk-assets` repository. The [recording migration guide][recording_move] describes how to do so. This step only
needs to be completed once. Your library will have an `assets.json` file at its root, which stores the `azure-sdk-assets`
tag that contains the current set of recordings.
needs to be completed once. Your library will have an `assets.json` file at its root, which stores the
`azure-sdk-assets` tag that contains the current set of recordings.

From this point on, recordings will automatically be fetched when tests are run in playback mode -- either from
a local cache (described in [Update test recordings](#update-test-recordings)), or from `azure-sdk-assets` if they're
not locally available.
From this point on, recordings will automatically be fetched when tests are run in playback mode -- either from a local
cache (described in [Update test recordings](#update-test-recordings)), or from `azure-sdk-assets` if they're not
locally available.

#### Update test recordings

Expand Down Expand Up @@ -725,3 +740,4 @@ Tests that use the Shared Access Signature (SAS) to authenticate a client should
[test_proxy_startup]: https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/test_proxy_migration_guide.md#start-the-proxy-server
[test_resources]: https://github.com/Azure/azure-sdk-for-python/tree/main/eng/common/TestResources#readme
[troubleshooting_guide]: https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/test_proxy_troubleshooting.md
[user_auth_flag]: https://github.com/Azure/azure-sdk-for-python/blob/main/eng/common/TestResources/New-TestResources.ps1.md#-userauth
58 changes: 46 additions & 12 deletions tools/azure-sdk-tools/devtools_testutils/azure_recorded_testcase.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# license information.
# --------------------------------------------------------------------------
import functools
import logging
import os
import os.path
import six
Expand All @@ -24,6 +25,8 @@
from .sanitizers import add_general_string_sanitizer


_LOGGER = logging.getLogger()

load_dotenv(find_dotenv())


Expand Down Expand Up @@ -87,23 +90,54 @@ def get_credential(self, client_class, **kwargs):
tenant_id = os.environ.get("AZURE_TENANT_ID", getattr(os.environ, "TENANT_ID", None))
client_id = os.environ.get("AZURE_CLIENT_ID", getattr(os.environ, "CLIENT_ID", None))
secret = os.environ.get("AZURE_CLIENT_SECRET", getattr(os.environ, "CLIENT_SECRET", None))

use_pwsh = os.environ.get("AZURE_TEST_USE_PWSH_AUTH", "false")
use_cli = os.environ.get("AZURE_TEST_USE_CLI_AUTH", "false")
is_async = kwargs.pop("is_async", False)

if tenant_id and client_id and secret and self.is_live:
if _is_autorest_v3(client_class):
# Create azure-identity class
from azure.identity import ClientSecretCredential
# Return live credentials only in live mode
if self.is_live:
# User-based authentication through Azure PowerShell, if requested
if use_pwsh.lower() == "true":
_LOGGER.info(
"Environment variable AZURE_TEST_USE_PWSH_AUTH set to 'true'. Using AzurePowerShellCredential."
)
from azure.identity import AzurePowerShellCredential

if is_async:
from azure.identity.aio import ClientSecretCredential
return ClientSecretCredential(tenant_id=tenant_id, client_id=client_id, client_secret=secret)
else:
# Create msrestazure class
from msrestazure.azure_active_directory import (
ServicePrincipalCredentials,
)
from azure.identity.aio import AzurePowerShellCredential
return AzurePowerShellCredential()
# User-based authentication through Azure CLI, if requested
if use_cli.lower() == "true":
_LOGGER.info("Environment variable AZURE_TEST_USE_CLI_AUTH set to 'true'. Using AzureCliCredential.")
from azure.identity import AzureCliCredential

if is_async:
from azure.identity.aio import AzureCliCredential
return AzureCliCredential()

# Service principal authentication
if tenant_id and client_id and secret:
# Check for track 2 client
if _is_autorest_v3(client_class):
_LOGGER.info(
"Service principal client ID, secret, and tenant ID detected. Using ClientSecretCredential.\n"
"For user-based auth, set AZURE_TEST_USE_PWSH_AUTH or AZURE_TEST_USE_CLI_AUTH to 'true'."
)
from azure.identity import ClientSecretCredential

if is_async:
from azure.identity.aio import ClientSecretCredential
return ClientSecretCredential(tenant_id=tenant_id, client_id=client_id, client_secret=secret)
else:
# Create msrestazure class
from msrestazure.azure_active_directory import (
ServicePrincipalCredentials,
)

return ServicePrincipalCredentials(tenant=tenant_id, client_id=client_id, secret=secret)

return ServicePrincipalCredentials(tenant=tenant_id, client_id=client_id, secret=secret)
# For playback tests, return credentials that will accept playback `get_token` calls
else:
if _is_autorest_v3(client_class):
if is_async:
Expand Down

0 comments on commit ac7a139

Please sign in to comment.