diff --git a/src/azure-cli-core/azure/cli/core/_profile.py b/src/azure-cli-core/azure/cli/core/_profile.py index 58aa33340b4..78449018190 100644 --- a/src/azure-cli-core/azure/cli/core/_profile.py +++ b/src/azure-cli-core/azure/cli/core/_profile.py @@ -347,6 +347,46 @@ def get_login_credentials(self, resource=None, client_id=None, subscription_id=N str(account[_TENANT_ID])) def get_raw_token(self, resource=None, scopes=None, subscription=None, tenant=None): + # Check if AZ_USE_AZD_AUTH environment variable is set + if os.environ.get('AZ_USE_AZD_AUTH'): + try: + from azure.identity import AzureDeveloperCliCredential + + # Convert resource to scopes if needed + if resource and not scopes: + from .auth.util import resource_to_scopes + scopes = resource_to_scopes(resource) + + # Use ARM as the default scopes + if not scopes: + scopes = self._arm_scope + + # Create Azure Developer CLI credential + azd_credential = AzureDeveloperCliCredential() + sdk_token = azd_credential.get_token(*scopes) + + # Convert epoch int 'expires_on' to datetime string 'expiresOn' for backward compatibility + # WARNING: expiresOn is deprecated and will be removed in future release. + import datetime + expiresOn = datetime.datetime.fromtimestamp(sdk_token.expires_on).strftime("%Y-%m-%d %H:%M:%S.%f") + + token_entry = { + 'accessToken': sdk_token.token, + 'expires_on': sdk_token.expires_on, # epoch int, like 1605238724 + 'expiresOn': expiresOn # datetime string, like "2020-11-12 13:50:47.114324" + } + + # (tokenType, accessToken, tokenEntry) + creds = 'Bearer', sdk_token.token, token_entry + + # For AZD authentication, we don't have subscription/tenant info from the current account + # So we return None for these values to let the caller handle them appropriately + return (creds, None, None) + + except Exception as ex: + logger.warning("Failed to use Azure Developer CLI credential: %s. Falling back to standard authentication.", str(ex)) + # Fall through to standard authentication flow + # Convert resource to scopes if resource and not scopes: from .auth.util import resource_to_scopes diff --git a/src/azure-cli-core/setup.py b/src/azure-cli-core/setup.py index 35952b82f14..2b2a6413e9c 100644 --- a/src/azure-cli-core/setup.py +++ b/src/azure-cli-core/setup.py @@ -45,6 +45,7 @@ DEPENDENCIES = [ 'argcomplete~=2.0', 'azure-cli-telemetry==1.0.8.*', + 'azure-identity>=1.12.0', 'azure-mgmt-core>=1.2.0,<2', 'cryptography', # On Linux, the distribution (Ubuntu, Debian, etc) and version are logged in telemetry @@ -53,7 +54,7 @@ 'jmespath', 'knack~=0.10.1', 'msal-extensions~=1.0.0', - 'msal[broker]==1.20.0', + 'msal[broker]>=1.20.0,<2.0.0', 'msrestazure~=0.6.4', 'packaging>=20.9', 'paramiko>=2.0.8,<4.0.0', diff --git a/src/azure-cli/requirements.py3.Darwin.txt b/src/azure-cli/requirements.py3.Darwin.txt index 678da5ed2fc..2d9173b8eb6 100644 --- a/src/azure-cli/requirements.py3.Darwin.txt +++ b/src/azure-cli/requirements.py3.Darwin.txt @@ -9,6 +9,7 @@ azure-cli-telemetry==1.0.8 azure-cli==2.48.1 azure-common==1.1.22 azure-core==1.26.0 +azure-identity==1.15.0 azure-cosmos==3.2.0 azure-data-tables==12.4.0 azure-datalake-store==0.0.49 diff --git a/src/azure-cli/requirements.py3.Linux.txt b/src/azure-cli/requirements.py3.Linux.txt index 0cacffa77b8..e56fd96c146 100644 --- a/src/azure-cli/requirements.py3.Linux.txt +++ b/src/azure-cli/requirements.py3.Linux.txt @@ -9,6 +9,7 @@ azure-cli-telemetry==1.0.8 azure-cli==2.48.1 azure-common==1.1.22 azure-core==1.26.0 +azure-identity==1.15.0 azure-cosmos==3.2.0 azure-data-tables==12.4.0 azure-datalake-store==0.0.49 diff --git a/src/azure-cli/requirements.py3.windows.txt b/src/azure-cli/requirements.py3.windows.txt index 36a05a24605..b560a7b801f 100644 --- a/src/azure-cli/requirements.py3.windows.txt +++ b/src/azure-cli/requirements.py3.windows.txt @@ -9,6 +9,7 @@ azure-cli-telemetry==1.0.8 azure-cli==2.48.1 azure-common==1.1.22 azure-core==1.26.0 +azure-identity==1.15.0 azure-cosmos==3.2.0 azure-data-tables==12.4.0 azure-datalake-store==0.0.49