From 61dde5eacfb80bf0398ecd8cd596b2cd8221afc0 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Fri, 11 Jun 2021 17:05:01 -0700 Subject: [PATCH 1/5] Add login_hint argument to InteractiveBrowserCredential --- .../azure/identity/_credentials/browser.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/browser.py b/sdk/identity/azure-identity/azure/identity/_credentials/browser.py index 0f773df22602..373f354843e8 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/browser.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/browser.py @@ -38,6 +38,8 @@ class InteractiveBrowserCredential(InteractiveCredential): authenticate work or school accounts. :keyword str client_id: Client ID of the Azure Active Directory application users will sign in to. If unspecified, users will authenticate to an Azure development application. + :keyword str login_hint: a username suggestion to pre-fill the login page's username/email address field. A user + may still log in with a different username. :keyword str redirect_uri: a redirect URI for the application identified by `client_id` as configured in Azure Active Directory, for example "http://localhost:8400". This is only required when passing a value for `client_id`, and must match a redirect URI in the application's registration. The credential must be able to @@ -62,6 +64,7 @@ def __init__(self, **kwargs): else: self._parsed_url = None + self._login_hint = kwargs.pop("login_hint", None) self._timeout = kwargs.pop("timeout", 300) self._server_class = kwargs.pop("_server_class", AuthCodeRedirectServer) client_id = kwargs.pop("client_id", DEVELOPER_SIGN_ON_CLIENT_ID) @@ -96,7 +99,11 @@ def _request_token(self, *scopes, **kwargs): claims = kwargs.get("claims") app = self._get_app() flow = app.initiate_auth_code_flow( - scopes, redirect_uri=redirect_uri, prompt="select_account", claims_challenge=claims + scopes, + redirect_uri=redirect_uri, + prompt="select_account", + claims_challenge=claims, + login_hint=self._login_hint, ) if "auth_uri" not in flow: raise CredentialUnavailableError("Failed to begin authentication flow") From dec691f872ff40f2ecf0847add6967099c14ce50 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Fri, 11 Jun 2021 17:05:34 -0700 Subject: [PATCH 2/5] dedent docstring --- .../azure/identity/_credentials/browser.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/browser.py b/sdk/identity/azure-identity/azure/identity/_credentials/browser.py index 373f354843e8..a8e025fb2f3e 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/browser.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/browser.py @@ -32,23 +32,23 @@ class InteractiveBrowserCredential(InteractiveCredential): there with the authorization code flow, using PKCE (Proof Key for Code Exchange) internally to protect the code. :keyword str authority: Authority of an Azure Active Directory endpoint, for example 'login.microsoftonline.com', - the authority for Azure Public Cloud (which is the default). :class:`~azure.identity.AzureAuthorityHosts` - defines authorities for other clouds. + the authority for Azure Public Cloud (which is the default). :class:`~azure.identity.AzureAuthorityHosts` + defines authorities for other clouds. :keyword str tenant_id: an Azure Active Directory tenant ID. Defaults to the 'organizations' tenant, which can - authenticate work or school accounts. + authenticate work or school accounts. :keyword str client_id: Client ID of the Azure Active Directory application users will sign in to. If - unspecified, users will authenticate to an Azure development application. + unspecified, users will authenticate to an Azure development application. :keyword str login_hint: a username suggestion to pre-fill the login page's username/email address field. A user may still log in with a different username. :keyword str redirect_uri: a redirect URI for the application identified by `client_id` as configured in Azure - Active Directory, for example "http://localhost:8400". This is only required when passing a value for - `client_id`, and must match a redirect URI in the application's registration. The credential must be able to - bind a socket to this URI. + Active Directory, for example "http://localhost:8400". This is only required when passing a value for + `client_id`, and must match a redirect URI in the application's registration. The credential must be able to + bind a socket to this URI. :keyword AuthenticationRecord authentication_record: :class:`AuthenticationRecord` returned by :func:`authenticate` :keyword bool disable_automatic_authentication: if True, :func:`get_token` will raise - :class:`AuthenticationRequiredError` when user interaction is required to acquire a token. Defaults to False. + :class:`AuthenticationRequiredError` when user interaction is required to acquire a token. Defaults to False. :keyword cache_persistence_options: configuration for persistent token caching. If unspecified, the credential - will cache tokens in memory. + will cache tokens in memory. :paramtype cache_persistence_options: ~azure.identity.TokenCachePersistenceOptions :keyword int timeout: seconds to wait for the user to complete authentication. Defaults to 300 (5 minutes). :raises ValueError: invalid `redirect_uri` From 90f02da7e814be4548a7b1557aed30c3345ca480 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Fri, 11 Jun 2021 17:05:54 -0700 Subject: [PATCH 3/5] add a test --- .../tests/test_browser_credential.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/sdk/identity/azure-identity/tests/test_browser_credential.py b/sdk/identity/azure-identity/tests/test_browser_credential.py index 967a988e44c2..af2eae903220 100644 --- a/sdk/identity/azure-identity/tests/test_browser_credential.py +++ b/sdk/identity/azure-identity/tests/test_browser_credential.py @@ -266,6 +266,32 @@ def test_claims_challenge(): assert kwargs["claims_challenge"] == expected_claims +def test_login_hint(): + expected_username = "user@foo.com" + auth_code_response = {"code": "authorization-code", "state": ["..."]} + server_class = Mock(return_value=Mock(wait_for_redirect=lambda: auth_code_response)) + transport = Mock(send=Mock(side_effect=Exception("this test mocks MSAL, so no request should be sent"))) + + msal_acquire_token_result = dict( + build_aad_response(access_token="**", id_token=build_id_token()), + id_token_claims=id_token_claims("issuer", "subject", "audience", upn="upn"), + ) + mock_msal_app = Mock( + acquire_token_by_auth_code_flow=Mock(return_value=msal_acquire_token_result), + initiate_auth_code_flow=Mock(return_value={"auth_uri": "http://localhost"}), + ) + + credential = InteractiveBrowserCredential( + _server_class=server_class, transport=transport, login_hint=expected_username + ) + with patch("msal.PublicClientApplication", Mock(return_value=mock_msal_app)): + with patch(WEBBROWSER_OPEN, lambda _: True): + credential.authenticate(scopes=["scope"]) + assert mock_msal_app.initiate_auth_code_flow.call_count == 1 + _, kwargs = mock_msal_app.initiate_auth_code_flow.call_args + assert kwargs["login_hint"] == expected_username + + @pytest.mark.parametrize( "uname,is_wsl", ( From 08ff0668f9b8e50f62686cdead1c0592d1287168 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Fri, 11 Jun 2021 17:05:57 -0700 Subject: [PATCH 4/5] update changelog --- sdk/identity/azure-identity/CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sdk/identity/azure-identity/CHANGELOG.md b/sdk/identity/azure-identity/CHANGELOG.md index 3e35534ea3ac..981f17b360d0 100644 --- a/sdk/identity/azure-identity/CHANGELOG.md +++ b/sdk/identity/azure-identity/CHANGELOG.md @@ -1,7 +1,10 @@ # Release History ## 1.7.0b2 (Unreleased) - +### Added +- `InteractiveBrowserCredential` keyword argument `login_hint` enables + pre-filling the username/email address field on the login page + ([#19225](https://github.com/Azure/azure-sdk-for-python/issues/19225)) ## 1.7.0b1 (2021-06-08) Beginning with this release, this library requires Python 2.7 or 3.6+. From d3f5f34eb9be462b491e4f508b98972645c77c3d Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Fri, 18 Jun 2021 08:42:16 -0700 Subject: [PATCH 5/5] dedent --- .../azure-identity/tests/test_browser_credential.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sdk/identity/azure-identity/tests/test_browser_credential.py b/sdk/identity/azure-identity/tests/test_browser_credential.py index af2eae903220..47fe2dc4e9ab 100644 --- a/sdk/identity/azure-identity/tests/test_browser_credential.py +++ b/sdk/identity/azure-identity/tests/test_browser_credential.py @@ -287,9 +287,10 @@ def test_login_hint(): with patch("msal.PublicClientApplication", Mock(return_value=mock_msal_app)): with patch(WEBBROWSER_OPEN, lambda _: True): credential.authenticate(scopes=["scope"]) - assert mock_msal_app.initiate_auth_code_flow.call_count == 1 - _, kwargs = mock_msal_app.initiate_auth_code_flow.call_args - assert kwargs["login_hint"] == expected_username + + assert mock_msal_app.initiate_auth_code_flow.call_count == 1 + _, kwargs = mock_msal_app.initiate_auth_code_flow.call_args + assert kwargs["login_hint"] == expected_username @pytest.mark.parametrize(