Skip to content

Commit f7b3f4e

Browse files
Ray Luorayluo
Ray Luo
authored andcommitted
Integrate with PyMsalRuntime on mac
Use new enable_broker Use 2 flags, one per supported platform Documents the requirement on parent_window_handle
1 parent e6ebc37 commit f7b3f4e

File tree

6 files changed

+66
-31
lines changed

6 files changed

+66
-31
lines changed

msal/__main__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ def _main():
255255
accept_nonempty_string=True,
256256
),
257257
enable_broker_on_windows=enable_broker,
258+
enable_broker_on_mac=enable_broker,
258259
enable_pii_log=enable_pii_log,
259260
token_cache=global_cache,
260261
)

msal/application.py

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,8 @@ class ClientApplication(object):
187187
"You can enable broker by following these instructions. "
188188
"https://msal-python.readthedocs.io/en/latest/#publicclientapplication")
189189

190+
_enable_broker = False
191+
190192
def __init__(
191193
self, client_id,
192194
client_credential=None, authority=None, validate_authority=True,
@@ -540,7 +542,9 @@ def _decide_broker(self, allow_broker, enable_pii_log):
540542
if allow_broker:
541543
warnings.warn(
542544
"allow_broker is deprecated. "
543-
"Please use PublicClientApplication(..., enable_broker_on_windows=True)",
545+
"Please use PublicClientApplication(..., "
546+
"enable_broker_on_windows=True, "
547+
"enable_broker_on_mac=...)",
544548
DeprecationWarning)
545549
self._enable_broker = self._enable_broker or (
546550
# When we started the broker project on Windows platform,
@@ -1646,7 +1650,8 @@ def acquire_token_by_username_password(
16461650
"""
16471651
claims = _merge_claims_challenge_and_capabilities(
16481652
self._client_capabilities, claims_challenge)
1649-
if False: # Disabled, for now. It was if self._enable_broker:
1653+
if False: # Disabled, for now. It was if self._enable_broker and sys.platform != "darwin":
1654+
# _signin_silently() won't work on Mac. We may revisit on whether it shall work on Windows.
16501655
from .broker import _signin_silently
16511656
response = _signin_silently(
16521657
"https://{}/{}".format(self.authority.instance, self.authority.tenant),
@@ -1744,7 +1749,7 @@ def __init__(self, client_id, client_credential=None, **kwargs):
17441749
17451750
.. note::
17461751
1747-
You may set enable_broker_on_windows to True.
1752+
You may set enable_broker_on_windows and/or enable_broker_on_mac to True.
17481753
17491754
What is a broker, and why use it?
17501755
@@ -1773,9 +1778,11 @@ def __init__(self, client_id, client_credential=None, **kwargs):
17731778
17741779
* ``ms-appx-web://Microsoft.AAD.BrokerPlugin/your_client_id``
17751780
if your app is expected to run on Windows 10+
1781+
* ``msauth.com.msauth.unsignedapp://auth``
1782+
if your app is expected to run on Mac
17761783
17771784
2. installed broker dependency,
1778-
e.g. ``pip install msal[broker]>=1.25,<2``.
1785+
e.g. ``pip install msal[broker]>=1.27.0b1,<2``.
17791786
17801787
3. tested with ``acquire_token_interactive()`` and ``acquire_token_silent()``.
17811788
@@ -1784,12 +1791,21 @@ def __init__(self, client_id, client_credential=None, **kwargs):
17841791
This parameter defaults to None, which means MSAL will not utilize a broker.
17851792
17861793
New in MSAL Python 1.25.0.
1794+
1795+
:param boolean enable_broker_on_mac:
1796+
This setting is only effective if your app is running on Mac.
1797+
This parameter defaults to None, which means MSAL will not utilize a broker.
1798+
1799+
New in MSAL Python 1.27.0.
17871800
"""
17881801
if client_credential is not None:
17891802
raise ValueError("Public Client should not possess credentials")
17901803
# Using kwargs notation for now. We will switch to keyword-only arguments.
17911804
enable_broker_on_windows = kwargs.pop("enable_broker_on_windows", False)
1792-
self._enable_broker = enable_broker_on_windows and sys.platform == "win32"
1805+
enable_broker_on_mac = kwargs.pop("enable_broker_on_mac", False)
1806+
self._enable_broker = bool(
1807+
enable_broker_on_windows and sys.platform == "win32"
1808+
or enable_broker_on_mac and sys.platform == "darwin")
17931809
super(PublicClientApplication, self).__init__(
17941810
client_id, client_credential=None, **kwargs)
17951811

@@ -1867,10 +1883,23 @@ def acquire_token_interactive(
18671883
New in version 1.15.
18681884
18691885
:param int parent_window_handle:
1870-
OPTIONAL. If your app is a GUI app running on modern Windows system,
1871-
and your app opts in to use broker,
1872-
you are recommended to also provide its window handle,
1873-
so that the sign in UI window will properly pop up on top of your window.
1886+
OPTIONAL.
1887+
1888+
* If your app does not opt in to use broker,
1889+
you do not need to provide a ``parent_window_handle`` here.
1890+
1891+
* If your app opts in to use broker,
1892+
``parent_window_handle`` is required.
1893+
1894+
- If your app is a GUI app running on modern Windows system,
1895+
you are required to also provide its window handle,
1896+
so that the sign-in window will pop up on top of your window.
1897+
- If your app is a console app runnong on Windows system,
1898+
you can use a placeholder
1899+
``PublicClientApplication.CONSOLE_WINDOW_HANDLE``.
1900+
- If your app is running on Mac,
1901+
you can use a placeholder
1902+
``PublicClientApplication.CONSOLE_WINDOW_HANDLE``.
18741903
18751904
New in version 1.20.0.
18761905

msal/broker.py

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""This module is an adaptor to the underlying broker.
22
It relies on PyMsalRuntime which is the package providing broker's functionality.
33
"""
4-
from threading import Event
54
import json
65
import logging
76
import time
@@ -35,14 +34,12 @@ class TokenTypeError(ValueError):
3534
pass
3635

3736

38-
class _CallbackData:
39-
def __init__(self):
40-
self.signal = Event()
41-
self.result = None
42-
43-
def complete(self, result):
44-
self.signal.set()
45-
self.result = result
37+
_redirect_uri_on_mac = "msauth.com.msauth.unsignedapp://auth" # Note:
38+
# On Mac, the native Python has a team_id which links to bundle id
39+
# com.apple.python3 however it won't give Python scripts better security.
40+
# Besides, the homebrew-installed Pythons have no team_id
41+
# so they have to use a generic placeholder anyway.
42+
# The v-team chose to combine two situations into using same placeholder.
4643

4744

4845
def _convert_error(error, client_id):
@@ -52,8 +49,9 @@ def _convert_error(error, client_id):
5249
or "AADSTS7000218" in context # This "request body must contain ... client_secret" is just a symptom of current app has no WAM redirect_uri
5350
):
5451
raise RedirectUriError( # This would be seen by either the app developer or end user
55-
"MsalRuntime won't work unless this one more redirect_uri is registered to current app: "
56-
"ms-appx-web://Microsoft.AAD.BrokerPlugin/{}".format(client_id))
52+
"MsalRuntime needs the current app to register these redirect_uri "
53+
"(1) ms-appx-web://Microsoft.AAD.BrokerPlugin/{} (2) {}".format(
54+
client_id, _redirect_uri_on_mac))
5755
# OTOH, AAD would emit other errors when other error handling branch was hit first,
5856
# so, the AADSTS50011/RedirectUriError is not guaranteed to happen.
5957
return {
@@ -70,8 +68,8 @@ def _convert_error(error, client_id):
7068

7169

7270
def _read_account_by_id(account_id, correlation_id):
73-
"""Return an instance of MSALRuntimeAccount, or log error and return None"""
74-
callback_data = _CallbackData()
71+
"""Return an instance of MSALRuntimeError or MSALRuntimeAccount, or None"""
72+
callback_data = pymsalruntime.CallbackData()
7573
pymsalruntime.read_account_by_id(
7674
account_id,
7775
correlation_id,
@@ -142,7 +140,7 @@ def _signin_silently(
142140
params.set_pop_params(
143141
auth_scheme._http_method, auth_scheme._url.netloc, auth_scheme._url.path,
144142
auth_scheme._nonce)
145-
callback_data = _CallbackData()
143+
callback_data = pymsalruntime.CallbackData()
146144
for k, v in kwargs.items(): # This can be used to support domain_hint, max_age, etc.
147145
if v is not None:
148146
params.set_additional_parameter(k, str(v))
@@ -169,8 +167,11 @@ def _signin_interactively(
169167
**kwargs):
170168
params = pymsalruntime.MSALRuntimeAuthParameters(client_id, authority)
171169
params.set_requested_scopes(scopes)
172-
params.set_redirect_uri("placeholder") # pymsalruntime 0.1 requires non-empty str,
170+
params.set_redirect_uri(
171+
# pymsalruntime on Windows requires non-empty str,
173172
# the actual redirect_uri will be overridden by a value hardcoded by the broker
173+
_redirect_uri_on_mac,
174+
)
174175
if prompt:
175176
if prompt == "select_account":
176177
if login_hint:
@@ -197,7 +198,7 @@ def _signin_interactively(
197198
params.set_additional_parameter(k, str(v))
198199
if claims:
199200
params.set_decoded_claims(claims)
200-
callback_data = _CallbackData()
201+
callback_data = pymsalruntime.CallbackData(is_interactive=True)
201202
pymsalruntime.signin_interactively(
202203
parent_window_handle or pymsalruntime.get_console_window() or pymsalruntime.get_desktop_window(), # Since pymsalruntime 0.2+
203204
params,
@@ -230,7 +231,7 @@ def _acquire_token_silently(
230231
for k, v in kwargs.items(): # This can be used to support domain_hint, max_age, etc.
231232
if v is not None:
232233
params.set_additional_parameter(k, str(v))
233-
callback_data = _CallbackData()
234+
callback_data = pymsalruntime.CallbackData()
234235
pymsalruntime.acquire_token_silently(
235236
params,
236237
correlation_id,
@@ -246,7 +247,7 @@ def _signout_silently(client_id, account_id, correlation_id=None):
246247
account = _read_account_by_id(account_id, correlation_id)
247248
if account is None:
248249
return
249-
callback_data = _CallbackData()
250+
callback_data = pymsalruntime.CallbackData()
250251
pymsalruntime.signout_silently( # New in PyMsalRuntime 0.7
251252
client_id,
252253
correlation_id,

sample/interactive_sample.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,11 @@
3737
# Create a preferably long-lived app instance, to avoid the overhead of app creation
3838
global_app = msal.PublicClientApplication(
3939
config["client_id"], authority=config["authority"],
40+
41+
# You may opt in to use broker. See also: https://docs.microsoft.com/en-us/azure/active-directory/develop/scenario-desktop-acquire-token-wam#wam-value-proposition
4042
#enable_broker_on_windows=True, # Opted in. You will be guided to meet the prerequisites, if your app hasn't already
41-
# See also: https://docs.microsoft.com/en-us/azure/active-directory/develop/scenario-desktop-acquire-token-wam#wam-value-proposition
43+
#enable_broker_on_mac=True, # Opted in. You will be guided to meet the prerequisites, if your app hasn't already
44+
4245
token_cache=global_token_cache, # Let this app (re)use an existing token cache.
4346
# If absent, ClientApplication will create its own empty token cache
4447
)

setup.cfg

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@ broker =
6363
# The broker is defined as optional dependency,
6464
# so that downstream apps can opt in. The opt-in is needed, partially because
6565
# most existing MSAL Python apps do not have the redirect_uri needed by broker.
66-
# MSAL Python uses a subset of API from PyMsalRuntime 0.13.0+,
67-
# but we still bump the lower bound to 0.13.2+ for its important bugfix (https://github.com/AzureAD/microsoft-authentication-library-for-cpp/pull/3244)
68-
pymsalruntime>=0.13.2,<0.14; python_version>='3.6' and platform_system=='Windows'
66+
# We need pymsalruntime.CallbackData introduced in PyMsalRuntime 0.14
67+
pymsalruntime>=0.14,<0.15; python_version>='3.6' and platform_system=='Windows'
68+
pymsalruntime>=0.14,<0.15; python_version>='3.8' and platform_system=='Darwin'
6969

7070
[options.packages.find]
7171
exclude =

tests/test_e2e.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ def _build_app(cls,
195195
authority=authority,
196196
http_client=http_client or MinimalHttpClient(),
197197
enable_broker_on_windows=broker_available,
198+
enable_broker_on_mac=broker_available,
198199
)
199200

200201
def _test_username_password(self,

0 commit comments

Comments
 (0)