Skip to content

Commit fa46664

Browse files
xiangyan99l0lawrence
authored andcommitted
Broker on mac support (Azure#38274)
* Broker on mac support * update * update * update * update * update * update readme * update
1 parent 8e04cf5 commit fa46664

File tree

5 files changed

+114
-44
lines changed

5 files changed

+114
-44
lines changed

.vscode/cspell.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@
316316
"mktime",
317317
"mlindex",
318318
"msal",
319+
"msauth",
319320
"msrest",
320321
"msrestazure",
321322
"MSSQL",

sdk/identity/azure-identity-broker/CHANGELOG.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
# Release History
22

3-
## 1.2.1 (Unreleased)
3+
## 1.3.0b1 (2024-11-05)
44

55
### Features Added
66

7-
### Breaking Changes
8-
9-
### Bugs Fixed
10-
11-
### Other Changes
7+
- Added broker on macOS support.
128

139
## 1.2.0 (2024-10-08)
1410

sdk/identity/azure-identity-broker/README.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
This package extends the [Azure Identity][azure_identity] library by providing supplemental credentials for authenticating via an authentication broker.
66

7-
An authentication broker is an application that runs on a user’s machine that manages the authentication handshakes and token maintenance for connected accounts. Currently, only the Windows authentication broker, Web Account Manager (WAM), is supported.
7+
An authentication broker is an application that runs on a user’s machine that manages the authentication handshakes and token maintenance for connected accounts. Currently, only the following brokers are supported:
8+
- Web Account Manager (WAM) on Windows
9+
- Company Portal on macOS
810

911
[Source code][source_code] | [Package (PyPI)][azure_identity_broker] | [API reference documentation][ref_docs] | [Microsoft Entra ID documentation][entra_id]
1012

@@ -28,15 +30,16 @@ When authenticating interactively via `InteractiveBrowserBrokerCredential`, a pa
2830

2931
## Microsoft account (MSA) passthrough
3032

31-
Microsoft accounts (MSA) are personal accounts created by users to access Microsoft services. MSA passthrough is a legacy configuration which enables users to get tokens to resources which normally don't accept MSA logins. This feature is only available to first-party applications. Users authenticating with an application that is configured to use MSA passthrough can set `enable_msa_passthrough` to `True` inside `InteractiveBrowserBrokerCredential` to allow these personal accounts to be listed by WAM.
33+
Microsoft accounts (MSA) are personal accounts created by users to access Microsoft services. MSA passthrough is a legacy configuration which enables users to get tokens to resources which normally don't accept MSA logins. This feature is only available to first-party applications. Users authenticating with an application that is configured to use MSA passthrough can set `enable_msa_passthrough` to `True` inside `InteractiveBrowserBrokerCredential` to allow these personal accounts to be listed by broker.
3234

3335
## Redirect URIs
3436

35-
Microsoft Entra applications rely on redirect URIs to determine where to send the authentication response after a user has logged in. To enable brokered authentication through WAM, a redirect URI matching the following pattern should be registered to the application:
37+
Microsoft Entra applications rely on redirect URIs to determine where to send the authentication response after a user has logged in. To enable brokered authentication through broker, a redirect URI matching the following pattern should be registered to the application:
3638

37-
```
38-
ms-appx-web://Microsoft.AAD.BrokerPlugin/{client_id}
39-
```
39+
* ``ms-appx-web://Microsoft.AAD.BrokerPlugin/your_client_id``
40+
if your app is expected to run on Windows 10+
41+
* ``msauth.com.msauth.unsignedapp://auth``
42+
if your app is expected to run on Mac
4043

4144
## Examples
4245

sdk/identity/azure-identity-broker/azure/identity/broker/_browser.py

Lines changed: 101 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# Licensed under the MIT License.
44
# ------------------------------------
55
import socket
6+
import sys
67
from typing import Dict, Any, Mapping, Union
78
import msal
89

@@ -32,8 +33,10 @@ class PopTokenRequestOptions(TokenRequestOptions):
3233
class InteractiveBrowserBrokerCredential(_InteractiveBrowserCredential):
3334
"""Uses an authentication broker to interactively sign in a user.
3435
35-
Currently, only the Windows authentication broker, Web Account Manager (WAM), is supported. Users on macOS and Linux
36-
will be authenticated through a browser.
36+
Currently, only the following brokers are supported:
37+
- Web Account Manager (WAM) on Windows
38+
- Company Portal on macOS
39+
Users on Linux will be authenticated through the browser.
3740
3841
:func:`~get_token` opens a browser to a login URL provided by Microsoft Entra ID and authenticates a user
3942
there with the authorization code flow, using PKCE (Proof Key for Code Exchange) internally to protect the code.
@@ -86,48 +89,79 @@ def _request_token(self, *scopes: str, **kwargs: Any) -> Dict:
8689
auth_scheme = msal.PopAuthScheme(
8790
http_method=pop["resource_request_method"], url=pop["resource_request_url"], nonce=pop["nonce"]
8891
)
89-
90-
if self._use_default_broker_account:
92+
if sys.platform.startswith("win"):
93+
if self._use_default_broker_account:
94+
try:
95+
result = app.acquire_token_interactive(
96+
scopes=scopes,
97+
login_hint=self._login_hint,
98+
claims_challenge=claims,
99+
timeout=self._timeout,
100+
prompt=msal.Prompt.NONE,
101+
port=port,
102+
parent_window_handle=self._parent_window_handle,
103+
enable_msa_passthrough=self._enable_msa_passthrough,
104+
auth_scheme=auth_scheme,
105+
)
106+
if "access_token" in result:
107+
return result
108+
except socket.error:
109+
pass
110+
try:
111+
result = app.acquire_token_interactive(
112+
scopes=scopes,
113+
login_hint=self._login_hint,
114+
claims_challenge=claims,
115+
timeout=self._timeout,
116+
prompt="select_account",
117+
port=port,
118+
parent_window_handle=self._parent_window_handle,
119+
enable_msa_passthrough=self._enable_msa_passthrough,
120+
auth_scheme=auth_scheme,
121+
)
122+
except socket.error as ex:
123+
raise CredentialUnavailableError(message="Couldn't start an HTTP server.") from ex
124+
if "access_token" not in result and "error_description" in result:
125+
if within_dac.get():
126+
raise CredentialUnavailableError(message=result["error_description"])
127+
raise ClientAuthenticationError(message=result.get("error_description"))
128+
if "access_token" not in result:
129+
if within_dac.get():
130+
raise CredentialUnavailableError(message="Failed to authenticate user")
131+
raise ClientAuthenticationError(message="Failed to authenticate user")
132+
else:
91133
try:
92134
result = app.acquire_token_interactive(
93135
scopes=scopes,
94136
login_hint=self._login_hint,
95137
claims_challenge=claims,
96138
timeout=self._timeout,
97-
prompt=msal.Prompt.NONE,
139+
prompt="select_account",
98140
port=port,
99141
parent_window_handle=self._parent_window_handle,
100142
enable_msa_passthrough=self._enable_msa_passthrough,
101143
auth_scheme=auth_scheme,
102144
)
145+
except Exception: # pylint: disable=broad-except
146+
app = self._disable_broker_on_app(**kwargs)
147+
result = app.acquire_token_interactive(
148+
scopes=scopes,
149+
login_hint=self._login_hint,
150+
claims_challenge=claims,
151+
timeout=self._timeout,
152+
prompt="select_account",
153+
port=port,
154+
parent_window_handle=self._parent_window_handle,
155+
enable_msa_passthrough=self._enable_msa_passthrough,
156+
)
103157
if "access_token" in result:
104158
return result
105-
except socket.error:
106-
pass
107-
try:
108-
result = app.acquire_token_interactive(
109-
scopes=scopes,
110-
login_hint=self._login_hint,
111-
claims_challenge=claims,
112-
timeout=self._timeout,
113-
prompt="select_account",
114-
port=port,
115-
parent_window_handle=self._parent_window_handle,
116-
enable_msa_passthrough=self._enable_msa_passthrough,
117-
auth_scheme=auth_scheme,
118-
)
119-
except socket.error as ex:
120-
raise CredentialUnavailableError(message="Couldn't start an HTTP server.") from ex
121-
if "access_token" not in result and "error_description" in result:
122-
if within_dac.get():
123-
raise CredentialUnavailableError(message=result["error_description"])
124-
raise ClientAuthenticationError(message=result.get("error_description"))
125-
if "access_token" not in result:
126-
if within_dac.get():
127-
raise CredentialUnavailableError(message="Failed to authenticate user")
128-
raise ClientAuthenticationError(message="Failed to authenticate user")
129-
130-
# base class will raise for other errors
159+
if "error_description" in result:
160+
if within_dac.get():
161+
# pylint: disable=raise-missing-from
162+
raise CredentialUnavailableError(message=result["error_description"])
163+
# pylint: disable=raise-missing-from
164+
raise ClientAuthenticationError(message=result.get("error_description"))
131165
return result
132166

133167
def _get_app(self, **kwargs: Any) -> msal.ClientApplication:
@@ -160,7 +194,43 @@ def _get_app(self, **kwargs: Any) -> msal.ClientApplication:
160194
http_client=self._client,
161195
instance_discovery=self._instance_discovery,
162196
enable_broker_on_windows=True,
197+
enable_broker_on_mac=True,
163198
enable_pii_log=self._enable_support_logging,
164199
)
165200

166201
return client_applications_map[tenant_id]
202+
203+
def _disable_broker_on_app(self, **kwargs: Any) -> msal.ClientApplication:
204+
tenant_id = resolve_tenant(
205+
self._tenant_id, additionally_allowed_tenants=self._additionally_allowed_tenants, **kwargs
206+
)
207+
208+
client_applications_map = self._client_applications
209+
capabilities = None
210+
token_cache = self._cache
211+
212+
app_class = msal.PublicClientApplication
213+
214+
if kwargs.get("enable_cae"):
215+
client_applications_map = self._cae_client_applications
216+
capabilities = ["CP1"]
217+
token_cache = self._cae_cache
218+
219+
if not token_cache:
220+
token_cache = self._initialize_cache(is_cae=bool(kwargs.get("enable_cae")))
221+
222+
client_applications_map[tenant_id] = app_class(
223+
client_id=self._client_id,
224+
client_credential=self._client_credential,
225+
client_capabilities=capabilities,
226+
authority="{}/{}".format(self._authority, tenant_id),
227+
azure_region=self._regional_authority,
228+
token_cache=token_cache,
229+
http_client=self._client,
230+
instance_discovery=self._instance_discovery,
231+
enable_broker_on_windows=False,
232+
enable_broker_on_mac=False,
233+
enable_pii_log=self._enable_support_logging,
234+
)
235+
236+
return client_applications_map[tenant_id]

sdk/identity/azure-identity-broker/azure/identity/broker/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
# Copyright (c) Microsoft Corporation.
33
# Licensed under the MIT License.
44
# ------------------------------------
5-
VERSION = "1.2.1"
5+
VERSION = "1.3.0b1"

0 commit comments

Comments
 (0)