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
31 changes: 20 additions & 11 deletions src/azure-cli-core/azure/cli/core/_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,10 @@ def get_msal_token(self, scopes, data):
authority = posixpath.join(self.cli_ctx.cloud.endpoints.active_directory, tenant)
app = ClientApplication(_CLIENT_ID, authority=authority)
result = app.acquire_token_by_refresh_token(refresh_token, scopes, data=data)

if 'error' in result:
Comment thread
houk-ms marked this conversation as resolved.
from azure.cli.core.adal_authentication import aad_error_handler
aad_error_handler(result)
return username, result["access_token"]

def get_refresh_token(self, resource=None,
Expand Down Expand Up @@ -674,17 +678,22 @@ def get_raw_token(self, resource=None, subscription=None, tenant=None):
creds = self._get_token_from_cloud_shell(resource)
else:
tenant_dest = tenant if tenant else account[_TENANT_ID]
if user_type == _USER:
# User
creds = self._creds_cache.retrieve_token_for_user(username_or_sp_id,
tenant_dest, resource)
else:
# Service Principal
use_cert_sn_issuer = bool(account[_USER_ENTITY].get(_SERVICE_PRINCIPAL_CERT_SN_ISSUER_AUTH))
creds = self._creds_cache.retrieve_token_for_service_principal(username_or_sp_id,
resource,
tenant_dest,
use_cert_sn_issuer)
import adal
try:
if user_type == _USER:
# User
creds = self._creds_cache.retrieve_token_for_user(username_or_sp_id,
tenant_dest, resource)
else:
# Service Principal
use_cert_sn_issuer = bool(account[_USER_ENTITY].get(_SERVICE_PRINCIPAL_CERT_SN_ISSUER_AUTH))
creds = self._creds_cache.retrieve_token_for_service_principal(username_or_sp_id,
resource,
tenant_dest,
use_cert_sn_issuer)
except adal.AdalError as ex:
from azure.cli.core.adal_authentication import adal_error_handler
adal_error_handler(ex)
return (creds,
None if tenant else str(account[_SUBSCRIPTION_ID]),
str(tenant if tenant else account[_TENANT_ID]))
Expand Down
43 changes: 27 additions & 16 deletions src/azure-cli-core/azure/cli/core/adal_authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,24 +43,9 @@ def _get_token(self, sdk_resource=None):
AdalAuthentication._log_hostname()
raise err
except adal.AdalError as err:
# pylint: disable=no-member
if in_cloud_console():
AdalAuthentication._log_hostname()

err = (getattr(err, 'error_response', None) or {}).get('error_description') or str(err)
if 'AADSTS70008' in err: # all errors starting with 70008 should be creds expiration related
raise CLIError("Credentials have expired due to inactivity. {}".format(
"Please run 'az login'" if not in_cloud_console() else ''))
if 'AADSTS50079' in err:
raise CLIError("Configuration of your account was changed. {}".format(
"Please run 'az login'" if not in_cloud_console() else ''))
if 'AADSTS50173' in err:
raise CLIError("The credential data used by CLI has been expired because you might have changed or "
"reset the password. {}".format(
"Please clear browser's cookies and run 'az login'"
if not in_cloud_console() else ''))

raise CLIError(err)
adal_error_handler(err)
except requests.exceptions.SSLError as err:
from .util import SSLERROR_TEMPLATE
raise CLIError(SSLERROR_TEMPLATE.format(str(err)))
Expand Down Expand Up @@ -246,3 +231,29 @@ def _timestamp(dt):
# https://docs.python.org/3/library/unittest.mock-examples.html#partial-mocking
# https://williambert.online/2011/07/how-to-unit-testing-in-django-with-mocking-and-patching/
return dt.timestamp()


def aad_error_handler(error: dict):
""" Handle the error from AAD server returned by ADAL or MSAL. """
login_message = ("To re-authenticate, please {}. If the problem persists, "
"please contact your tenant administrator."
.format("refresh Azure Portal" if in_cloud_console() else "run `az login`"))
Comment thread
fengzhou-msft marked this conversation as resolved.

# https://docs.microsoft.com/en-us/azure/active-directory/develop/reference-aadsts-error-codes
# Search for an error code at https://login.microsoftonline.com/error
msg = error.get('error_description')

from azure.cli.core.azclierror import AuthenticationError
raise AuthenticationError(msg, login_message)


def adal_error_handler(err: adal.AdalError):
""" Handle AdalError. """
try:
aad_error_handler(err.error_response)
except AttributeError:
# In case of AdalError created as
# AdalError('More than one token matches the criteria. The result is ambiguous.')
# https://github.com/Azure/azure-cli/issues/15320
from azure.cli.core.azclierror import UnknownError
raise UnknownError(str(err), recommendation="Please run `az account clear`, then `az login`.")
4 changes: 4 additions & 0 deletions src/azure-cli-core/azure/cli/core/azclierror.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,4 +260,8 @@ class RecommendationError(ClientError):
""" The client error raised by `az next`. It is needed in `az next` to skip error records. """
pass


class AuthenticationError(ServiceError):
""" Raised when AAD authentication fails. """

# endregion