Skip to content

Commit

Permalink
[Core] PREVIEW: Support Web Account Manager (WAM) login on Windows (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
jiasli authored Sep 15, 2022
1 parent 30a8fc7 commit 8474a10
Show file tree
Hide file tree
Showing 8 changed files with 36 additions and 12 deletions.
8 changes: 6 additions & 2 deletions src/azure-cli-core/azure/cli/core/_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,7 @@ def find_using_common_tenant(self, username, credential=None):
# The tenant requires MFA and can't be accessed with home tenant's refresh token
mfa_tenants.append(t)
else:
logger.warning("Failed to authenticate '%s' due to error '%s'", t, ex)
logger.warning("Failed to authenticate %s due to error '%s'", t.tenant_id_name, ex)
continue

if not subscriptions:
Expand Down Expand Up @@ -856,4 +856,8 @@ def _create_identity_instance(cli_ctx, *args, **kwargs):
# EXPERIMENTAL: Use core.use_msal_http_cache=False to turn off MSAL HTTP cache.
use_msal_http_cache = cli_ctx.config.getboolean('core', 'use_msal_http_cache', fallback=True)

return Identity(*args, encrypt=encrypt, use_msal_http_cache=use_msal_http_cache, **kwargs)
# PREVIEW: On Windows, use core.allow_broker=true to use broker (WAM) for authentication.
allow_broker = cli_ctx.config.getboolean('core', 'allow_broker', fallback=False)

return Identity(*args, encrypt=encrypt, use_msal_http_cache=use_msal_http_cache, allow_broker=allow_broker,
**kwargs)
27 changes: 22 additions & 5 deletions src/azure-cli-core/azure/cli/core/auth/identity.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ class Identity: # pylint: disable=too-many-instance-attributes
# It follows singleton pattern so that _secret_file is read only once.
_service_principal_store_instance = None

def __init__(self, authority, tenant_id=None, client_id=None, encrypt=False, use_msal_http_cache=True):
def __init__(self, authority, tenant_id=None, client_id=None, encrypt=False, use_msal_http_cache=True,
allow_broker=None):
"""
:param authority: Authentication authority endpoint. For example,
- AAD: https://login.microsoftonline.com
Expand All @@ -68,6 +69,7 @@ def __init__(self, authority, tenant_id=None, client_id=None, encrypt=False, use
self.client_id = client_id or AZURE_CLI_CLIENT_ID
self._encrypt = encrypt
self._use_msal_http_cache = use_msal_http_cache
self._allow_broker = allow_broker

# Build the authority in MSAL style
self._msal_authority, self._is_adfs = _get_authority_url(authority, tenant_id)
Expand Down Expand Up @@ -96,6 +98,7 @@ def _msal_app_kwargs(self):
"authority": self._msal_authority,
"token_cache": Identity._msal_token_cache,
"http_cache": Identity._msal_http_cache,
"allow_broker": self._allow_broker,
# CP1 means we can handle claims challenges (CAE)
"client_capabilities": None if "AZURE_IDENTITY_DISABLE_CP1" in os.environ else ["CP1"]
}
Expand Down Expand Up @@ -132,9 +135,15 @@ def _service_principal_store(self):
def login_with_auth_code(self, scopes, **kwargs):
# Emit a warning to inform that a browser is opened.
# Only show the path part of the URL and hide the query string.
logger.warning("A web browser has been opened at %s. Please continue the login in the web browser. "
"If no web browser is available or if the web browser fails to open, use device code flow "
"with `az login --use-device-code`.", self._msal_app.authority.authorization_endpoint)

def _prompt_launching_ui(ui=None, **_):
if ui == 'browser':
logger.warning("A web browser has been opened at %s. Please continue the login in the web browser. "
"If no web browser is available or if the web browser fails to open, use device code "
"flow with `az login --use-device-code`.",
self._msal_app.authority.authorization_endpoint)
elif ui == 'broker':
logger.warning("Please select the account you want to log in with.")

from .util import read_response_templates
success_template, error_template = read_response_templates()
Expand All @@ -143,7 +152,9 @@ def login_with_auth_code(self, scopes, **kwargs):
# on port 8400 from the old design. However, ADFS only allows port 8400.
result = self._msal_app.acquire_token_interactive(
scopes, prompt='select_account', port=8400 if self._is_adfs else None,
success_template=success_template, error_template=error_template, **kwargs)
success_template=success_template, error_template=error_template,
parent_window_handle=self._msal_app.CONSOLE_WINDOW_HANDLE, on_before_launching_ui=_prompt_launching_ui,
**kwargs)
return check_result(result)

def login_with_device_code(self, scopes, **kwargs):
Expand Down Expand Up @@ -187,6 +198,12 @@ def logout_user(self, user):
self._msal_app.remove_account(account)

def logout_all_users(self):
# Remove users from MSAL
accounts = self._msal_app.get_accounts()
for account in accounts:
self._msal_app.remove_account(account)

# Also remove token cache file
for e in file_extensions.values():
_try_remove(self._token_cache_file + e)

Expand Down
2 changes: 1 addition & 1 deletion src/azure-cli-core/azure/cli/core/auth/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def aad_error_handler(error, **kwargs):
else "Interactive authentication is needed. Please run:\n{}").format(login_command)

from azure.cli.core.azclierror import AuthenticationError
raise AuthenticationError(error_description, recommendation=login_message)
raise AuthenticationError(error_description, msal_error=error, recommendation=login_message)


def _generate_login_command(scopes=None, claims=None):
Expand Down
3 changes: 3 additions & 0 deletions src/azure-cli-core/azure/cli/core/azclierror.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,9 @@ class RecommendationError(ClientError):

class AuthenticationError(ServiceError):
""" Raised when AAD authentication fails. """
def __init__(self, error_msg, msal_error=None, **kwargs):
super().__init__(error_msg, **kwargs)
self.msal_error = msal_error


class HTTPError(CLIError):
Expand Down
2 changes: 1 addition & 1 deletion src/azure-cli-core/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
'jmespath',
'knack~=0.10.0',
'msal-extensions~=1.0.0',
'msal==1.18.0b1',
'msal[broker]==1.20.0b1',
'msrestazure~=0.6.4',
'packaging>=20.9,<22.0',
'paramiko>=2.0.8,<3.0.0',
Expand Down
2 changes: 1 addition & 1 deletion src/azure-cli/requirements.py3.Darwin.txt
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ jsondiff==2.0.0
knack==0.10.0
MarkupSafe==2.0.1
msal-extensions==1.0.0
msal==1.18.0b1
msal[broker]==1.20.0b1
msrest==0.7.1
msrestazure==0.6.4
oauthlib==3.0.1
Expand Down
2 changes: 1 addition & 1 deletion src/azure-cli/requirements.py3.Linux.txt
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ jsondiff==2.0.0
knack==0.10.0
MarkupSafe==2.0.1
msal-extensions==1.0.0
msal==1.18.0b1
msal[broker]==1.20.0b1
msrest==0.7.1
msrestazure==0.6.4
oauthlib==3.0.1
Expand Down
2 changes: 1 addition & 1 deletion src/azure-cli/requirements.py3.windows.txt
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ jsondiff==2.0.0
knack==0.10.0
MarkupSafe==2.0.1
msal-extensions==1.0.0
msal==1.18.0b1
msal[broker]==1.20.0b1
msrest==0.7.1
msrestazure==0.6.4
oauthlib==3.0.1
Expand Down

0 comments on commit 8474a10

Please sign in to comment.