Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ def acquire_token(self, scopes, claims_challenge=None, **kwargs):
scopes, claims_challenge, kwargs)

if claims_challenge:
logger.warning('Acquiring new access token silently for tenant %s with claims challenge: %s',
self._msal_app.authority.tenant, claims_challenge)
logger.info('Acquiring new access token silently with claims challenge: %s', claims_challenge)
result = self._msal_app.acquire_token_silent_with_error(
scopes, self._account, claims_challenge=claims_challenge, **kwargs)

Expand Down
9 changes: 9 additions & 0 deletions src/azure-cli-core/azure/cli/core/auth/tests/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ def test_generate_login_command(self):
assert actual == ('az login --tenant "21987a97-4e85-47c5-9a13-9dc3e11b2a9a" '
'--scope "https://management.core.windows.net//.default"')

# tenant, scopes and claims_challenge
actual = _generate_login_command(
tenant='21987a97-4e85-47c5-9a13-9dc3e11b2a9a',
scopes=["https://management.core.windows.net//.default"],
claims_challenge='{"access_token":{"acrs":{"essential":true,"values":["p1"]}}}')
assert actual == ('az logout\n'
'az login --tenant "21987a97-4e85-47c5-9a13-9dc3e11b2a9a" '
'--scope "https://management.core.windows.net//.default" '
'--claims-challenge "eyJhY2Nlc3NfdG9rZW4iOnsiYWNycyI6eyJlc3NlbnRpYWwiOnRydWUsInZhbHVlcyI6WyJwMSJdfX19"')


if __name__ == '__main__':
Expand Down
30 changes: 22 additions & 8 deletions src/azure-cli-core/azure/cli/core/auth/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"To pass a service principal certificate, use --certificate instead.")


def aad_error_handler(error, **kwargs):
def aad_error_handler(error, tenant=None, scopes=None, claims_challenge=None):
""" Handle the error from AAD server returned by ADAL or MSAL. """

# https://learn.microsoft.com/en-us/azure/active-directory/develop/reference-aadsts-error-codes
Expand All @@ -41,11 +41,21 @@ def aad_error_handler(error, **kwargs):
error_codes = error.get('error_codes')

# Build recommendation message
recommendation = None
if error_codes and 7000215 in error_codes:
recommendation = PASSWORD_CERTIFICATE_WARNING
else:
login_command = _generate_login_command(**kwargs)
recommendation = "Interactive authentication is needed. Please run:\n{}".format(login_command)
login_command = _generate_login_command(tenant=tenant, scopes=scopes, claims_challenge=claims_challenge)
login_message = ('Run the command below to authenticate interactively; '
'additional arguments may be added as needed:\n'
f'{login_command}')

# During a challenge, the exception will caught by azure-mgmt-core, so we show a warning now
if claims_challenge:
logger.info('Failed to acquire token silently. Error detail: %s', error_description)
logger.warning(login_message)
else:
recommendation = login_message

from azure.cli.core.azclierror import AuthenticationError
raise AuthenticationError(error_description, msal_error=error, recommendation=recommendation)
Expand All @@ -69,10 +79,14 @@ def _generate_login_command(tenant=None, scopes=None, claims_challenge=None):

# Rejected by CAE
if claims_challenge:
# Explicit logout is needed: https://github.com/AzureAD/microsoft-authentication-library-for-python/issues/335
return 'az logout\n' + ' '.join(login_command)
from azure.cli.core.util import b64encode
# Base64 encode the claims_challenge to avoid shell interpretation
claims_challenge_encoded = b64encode(claims_challenge)
login_command.extend(['--claims-challenge', f'"{claims_challenge_encoded}"'])

return ' '.join(login_command)
# Explicit logout is preferred, making sure MSAL cache is purged:
# https://github.com/AzureAD/microsoft-authentication-library-for-python/issues/335
return 'az logout\n' + ' '.join(login_command)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We always ask the user to explicitly log out, in case some commands (such as az ad) don't support handling 401 challenge. See AzureAD/microsoft-authentication-library-for-python#335.



def resource_to_scopes(resource):
Expand Down Expand Up @@ -113,7 +127,7 @@ def scopes_to_resource(scopes):
return scope


def check_result(result, **kwargs):
def check_result(result, tenant=None, scopes=None, claims_challenge=None):
"""Parse the result returned by MSAL:

1. Check if the MSAL result contains a valid access token.
Expand All @@ -132,7 +146,7 @@ def check_result(result, **kwargs):
set_msal_telemetry(result['msal_telemetry'])

if 'error' in result:
aad_error_handler(result, **kwargs)
aad_error_handler(result, tenant=tenant, scopes=scopes, claims_challenge=claims_challenge)

# For user authentication
if 'id_token_claims' in result:
Expand Down
Loading