Skip to content

Commit c8291ac

Browse files
authored
Add login_hint argument to InteractiveBrowserCredential (Azure#19229)
1 parent b37aa44 commit c8291ac

File tree

3 files changed

+48
-11
lines changed

3 files changed

+48
-11
lines changed

sdk/identity/azure-identity/CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
# Release History
22

33
## 1.7.0b2 (Unreleased)
4-
4+
### Added
5+
- `InteractiveBrowserCredential` keyword argument `login_hint` enables
6+
pre-filling the username/email address field on the login page
7+
([#19225](https://github.com/Azure/azure-sdk-for-python/issues/19225))
58

69
## 1.7.0b1 (2021-06-08)
710
Beginning with this release, this library requires Python 2.7 or 3.6+.

sdk/identity/azure-identity/azure/identity/_credentials/browser.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,23 @@ class InteractiveBrowserCredential(InteractiveCredential):
3232
there with the authorization code flow, using PKCE (Proof Key for Code Exchange) internally to protect the code.
3333
3434
:keyword str authority: Authority of an Azure Active Directory endpoint, for example 'login.microsoftonline.com',
35-
the authority for Azure Public Cloud (which is the default). :class:`~azure.identity.AzureAuthorityHosts`
36-
defines authorities for other clouds.
35+
the authority for Azure Public Cloud (which is the default). :class:`~azure.identity.AzureAuthorityHosts`
36+
defines authorities for other clouds.
3737
:keyword str tenant_id: an Azure Active Directory tenant ID. Defaults to the 'organizations' tenant, which can
38-
authenticate work or school accounts.
38+
authenticate work or school accounts.
3939
:keyword str client_id: Client ID of the Azure Active Directory application users will sign in to. If
40-
unspecified, users will authenticate to an Azure development application.
40+
unspecified, users will authenticate to an Azure development application.
41+
:keyword str login_hint: a username suggestion to pre-fill the login page's username/email address field. A user
42+
may still log in with a different username.
4143
:keyword str redirect_uri: a redirect URI for the application identified by `client_id` as configured in Azure
42-
Active Directory, for example "http://localhost:8400". This is only required when passing a value for
43-
`client_id`, and must match a redirect URI in the application's registration. The credential must be able to
44-
bind a socket to this URI.
44+
Active Directory, for example "http://localhost:8400". This is only required when passing a value for
45+
`client_id`, and must match a redirect URI in the application's registration. The credential must be able to
46+
bind a socket to this URI.
4547
:keyword AuthenticationRecord authentication_record: :class:`AuthenticationRecord` returned by :func:`authenticate`
4648
:keyword bool disable_automatic_authentication: if True, :func:`get_token` will raise
47-
:class:`AuthenticationRequiredError` when user interaction is required to acquire a token. Defaults to False.
49+
:class:`AuthenticationRequiredError` when user interaction is required to acquire a token. Defaults to False.
4850
:keyword cache_persistence_options: configuration for persistent token caching. If unspecified, the credential
49-
will cache tokens in memory.
51+
will cache tokens in memory.
5052
:paramtype cache_persistence_options: ~azure.identity.TokenCachePersistenceOptions
5153
:keyword int timeout: seconds to wait for the user to complete authentication. Defaults to 300 (5 minutes).
5254
:raises ValueError: invalid `redirect_uri`
@@ -62,6 +64,7 @@ def __init__(self, **kwargs):
6264
else:
6365
self._parsed_url = None
6466

67+
self._login_hint = kwargs.pop("login_hint", None)
6568
self._timeout = kwargs.pop("timeout", 300)
6669
self._server_class = kwargs.pop("_server_class", AuthCodeRedirectServer)
6770
client_id = kwargs.pop("client_id", DEVELOPER_SIGN_ON_CLIENT_ID)
@@ -96,7 +99,11 @@ def _request_token(self, *scopes, **kwargs):
9699
claims = kwargs.get("claims")
97100
app = self._get_app()
98101
flow = app.initiate_auth_code_flow(
99-
scopes, redirect_uri=redirect_uri, prompt="select_account", claims_challenge=claims
102+
scopes,
103+
redirect_uri=redirect_uri,
104+
prompt="select_account",
105+
claims_challenge=claims,
106+
login_hint=self._login_hint,
100107
)
101108
if "auth_uri" not in flow:
102109
raise CredentialUnavailableError("Failed to begin authentication flow")

sdk/identity/azure-identity/tests/test_browser_credential.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,33 @@ def test_claims_challenge():
266266
assert kwargs["claims_challenge"] == expected_claims
267267

268268

269+
def test_login_hint():
270+
expected_username = "user@foo.com"
271+
auth_code_response = {"code": "authorization-code", "state": ["..."]}
272+
server_class = Mock(return_value=Mock(wait_for_redirect=lambda: auth_code_response))
273+
transport = Mock(send=Mock(side_effect=Exception("this test mocks MSAL, so no request should be sent")))
274+
275+
msal_acquire_token_result = dict(
276+
build_aad_response(access_token="**", id_token=build_id_token()),
277+
id_token_claims=id_token_claims("issuer", "subject", "audience", upn="upn"),
278+
)
279+
mock_msal_app = Mock(
280+
acquire_token_by_auth_code_flow=Mock(return_value=msal_acquire_token_result),
281+
initiate_auth_code_flow=Mock(return_value={"auth_uri": "http://localhost"}),
282+
)
283+
284+
credential = InteractiveBrowserCredential(
285+
_server_class=server_class, transport=transport, login_hint=expected_username
286+
)
287+
with patch("msal.PublicClientApplication", Mock(return_value=mock_msal_app)):
288+
with patch(WEBBROWSER_OPEN, lambda _: True):
289+
credential.authenticate(scopes=["scope"])
290+
291+
assert mock_msal_app.initiate_auth_code_flow.call_count == 1
292+
_, kwargs = mock_msal_app.initiate_auth_code_flow.call_args
293+
assert kwargs["login_hint"] == expected_username
294+
295+
269296
@pytest.mark.parametrize(
270297
"uname,is_wsl",
271298
(

0 commit comments

Comments
 (0)