55import sys
66import warnings
77from threading import Lock
8+ from typing import Optional # Needed in Python 3.7 & 3.8
89import os
910
1011from .oauth2cli import Client , JwtAssertionCreator
2122
2223
2324# The __init__.py will import this. Not the other way around.
24- __version__ = "1.30 .0" # When releasing, also check and bump our dependencies's versions if needed
25+ __version__ = "1.31 .0" # When releasing, also check and bump our dependencies's versions if needed
2526
2627logger = logging .getLogger (__name__ )
2728_AUTHORITY_TYPE_CLOUDSHELL = "CLOUDSHELL"
2829
30+ def _init_broker (enable_pii_log ): # Make it a function to allow mocking
31+ from . import broker # Trigger Broker's initialization, lazily
32+ if enable_pii_log :
33+ broker ._enable_pii_log ()
34+
2935def extract_certs (public_cert_content ):
3036 # Parses raw public certificate file contents and returns a list of strings
3137 # Usage: headers = {"x5c": extract_certs(open("my_cert.pem").read())}
@@ -189,6 +195,21 @@ def obtain_token_by_username_password(self, username, password, **kwargs):
189195 username , password , headers = headers , ** kwargs )
190196
191197
198+ def _msal_extension_check ():
199+ # Can't run this in module or class level otherwise you'll get circular import error
200+ try :
201+ from msal_extensions import __version__ as v
202+ major , minor , _ = v .split ("." , maxsplit = 3 )
203+ if not (int (major ) >= 1 and int (minor ) >= 2 ):
204+ warnings .warn (
205+ "Please upgrade msal-extensions. "
206+ "Only msal-extensions 1.2+ can work with msal 1.30+" )
207+ except ImportError :
208+ pass # The optional msal_extensions is not installed. Business as usual.
209+ except ValueError :
210+ logger .exception (f"msal_extensions version { v } not in major.minor.patch format" )
211+
212+
192213class ClientApplication (object ):
193214 """You do not usually directly use this class. Use its subclasses instead:
194215 :class:`PublicClientApplication` and :class:`ConfidentialClientApplication`.
@@ -205,6 +226,7 @@ class ClientApplication(object):
205226 REMOVE_ACCOUNT_ID = "903"
206227
207228 ATTEMPT_REGION_DISCOVERY = True # "TryAutoDetect"
229+ DISABLE_MSAL_FORCE_REGION = False # Used in azure_region to disable MSAL_FORCE_REGION behavior
208230 _TOKEN_SOURCE = "token_source"
209231 _TOKEN_SOURCE_IDP = "identity_provider"
210232 _TOKEN_SOURCE_CACHE = "cache"
@@ -411,9 +433,11 @@ def __init__(
411433 (STS) what this client is capable for,
412434 so STS can decide to turn on certain features.
413435 For example, if client is capable to handle *claims challenge*,
414- STS can then issue CAE access tokens to resources
415- knowing when the resource emits *claims challenge*
416- the client will be capable to handle.
436+ STS may issue
437+ `Continuous Access Evaluation (CAE) <https://learn.microsoft.com/entra/identity/conditional-access/concept-continuous-access-evaluation>`_
438+ access tokens to resources,
439+ knowing that when the resource emits a *claims challenge*
440+ the client will be able to handle those challenges.
417441
418442 Implementation details:
419443 Client capability is implemented using "claims" parameter on the wire,
@@ -426,11 +450,14 @@ def __init__(
426450 Instructs MSAL to use the Entra regional token service. This legacy feature is only available to
427451 first-party applications. Only ``acquire_token_for_client()`` is supported.
428452
429- Supports 3 values:
453+ Supports 4 values:
430454
431- ``azure_region=None`` - meaning no region is used. This is the default value.
432- ``azure_region="some_region"`` - meaning the specified region is used.
433- ``azure_region=True`` - meaning MSAL will try to auto-detect the region. This is not recommended.
455+ 1. ``azure_region=None`` - This default value means no region is configured.
456+ MSAL will use the region defined in env var ``MSAL_FORCE_REGION``.
457+ 2. ``azure_region="some_region"`` - meaning the specified region is used.
458+ 3. ``azure_region=True`` - meaning
459+ MSAL will try to auto-detect the region. This is not recommended.
460+ 4. ``azure_region=False`` - meaning MSAL will use no region.
434461
435462 .. note::
436463 Region auto-discovery has been tested on VMs and on Azure Functions. It is unreliable.
@@ -608,7 +635,10 @@ def __init__(
608635 except ValueError : # Those are explicit authority validation errors
609636 raise
610637 except Exception : # The rest are typically connection errors
611- if validate_authority and azure_region and not oidc_authority :
638+ if validate_authority and not oidc_authority and (
639+ azure_region # Opted in to use region
640+ or (azure_region is None and os .getenv ("MSAL_FORCE_REGION" )) # Will use region
641+ ):
612642 # Since caller opts in to use region, here we tolerate connection
613643 # errors happened during authority validation at non-region endpoint
614644 self .authority = Authority (
@@ -628,6 +658,8 @@ def __init__(
628658 self .authority_groups = None
629659 self ._telemetry_buffer = {}
630660 self ._telemetry_lock = Lock ()
661+ _msal_extension_check ()
662+
631663
632664 def _decide_broker (self , allow_broker , enable_pii_log ):
633665 is_confidential_app = self .client_credential or isinstance (
@@ -638,20 +670,28 @@ def _decide_broker(self, allow_broker, enable_pii_log):
638670 if allow_broker :
639671 warnings .warn (
640672 "allow_broker is deprecated. "
641- "Please use PublicClientApplication(..., enable_broker_on_windows=True)" ,
673+ "Please use PublicClientApplication(..., "
674+ "enable_broker_on_windows=True, "
675+ "enable_broker_on_mac=...)" ,
642676 DeprecationWarning )
643- self ._enable_broker = self ._enable_broker or (
677+ opted_in_for_broker = (
678+ self ._enable_broker # True means Opted-in from PCA
679+ or (
644680 # When we started the broker project on Windows platform,
645681 # the allow_broker was meant to be cross-platform. Now we realize
646682 # that other platforms have different redirect_uri requirements,
647683 # so the old allow_broker is deprecated and will only for Windows.
648684 allow_broker and sys .platform == "win32" )
649- if (self ._enable_broker and not is_confidential_app
650- and not self .authority .is_adfs and not self .authority ._is_b2c ):
685+ )
686+ self ._enable_broker = ( # This same variable will also store the state
687+ opted_in_for_broker
688+ and not is_confidential_app
689+ and not self .authority .is_adfs
690+ and not self .authority ._is_b2c
691+ )
692+ if self ._enable_broker :
651693 try :
652- from . import broker # Trigger Broker's initialization
653- if enable_pii_log :
654- broker ._enable_pii_log ()
694+ _init_broker (enable_pii_log )
655695 except RuntimeError :
656696 self ._enable_broker = False
657697 logger .exception (
@@ -692,9 +732,11 @@ def _build_telemetry_context(
692732 self ._telemetry_buffer , self ._telemetry_lock , api_id ,
693733 correlation_id = correlation_id , refresh_reason = refresh_reason )
694734
695- def _get_regional_authority (self , central_authority ):
696- if not self ._region_configured : # User did not opt-in to ESTS-R
735+ def _get_regional_authority (self , central_authority ) -> Optional [ Authority ] :
736+ if self ._region_configured is False : # User opts out of ESTS-R
697737 return None # Short circuit to completely bypass region detection
738+ if self ._region_configured is None : # User did not make an ESTS-R choice
739+ self ._region_configured = os .getenv ("MSAL_FORCE_REGION" ) or None
698740 self ._region_detected = self ._region_detected or _detect_region (
699741 self .http_client if self ._region_configured is not None else None )
700742 if (self ._region_configured != self .ATTEMPT_REGION_DISCOVERY
@@ -1879,7 +1921,7 @@ def __init__(self, client_id, client_credential=None, **kwargs):
18791921
18801922 .. note::
18811923
1882- You may set enable_broker_on_windows to True.
1924+ You may set enable_broker_on_windows and/or enable_broker_on_mac to True.
18831925
18841926 **What is a broker, and why use it?**
18851927
@@ -1905,9 +1947,11 @@ def __init__(self, client_id, client_credential=None, **kwargs):
19051947
19061948 * ``ms-appx-web://Microsoft.AAD.BrokerPlugin/your_client_id``
19071949 if your app is expected to run on Windows 10+
1950+ * ``msauth.com.msauth.unsignedapp://auth``
1951+ if your app is expected to run on Mac
19081952
19091953 2. installed broker dependency,
1910- e.g. ``pip install msal[broker]>=1.25 ,<2``.
1954+ e.g. ``pip install msal[broker]>=1.31 ,<2``.
19111955
19121956 3. tested with ``acquire_token_interactive()`` and ``acquire_token_silent()``.
19131957
@@ -1939,12 +1983,21 @@ def __init__(self, client_id, client_credential=None, **kwargs):
19391983 This parameter defaults to None, which means MSAL will not utilize a broker.
19401984
19411985 New in MSAL Python 1.25.0.
1986+
1987+ :param boolean enable_broker_on_mac:
1988+ This setting is only effective if your app is running on Mac.
1989+ This parameter defaults to None, which means MSAL will not utilize a broker.
1990+
1991+ New in MSAL Python 1.31.0.
19421992 """
19431993 if client_credential is not None :
19441994 raise ValueError ("Public Client should not possess credentials" )
19451995 # Using kwargs notation for now. We will switch to keyword-only arguments.
19461996 enable_broker_on_windows = kwargs .pop ("enable_broker_on_windows" , False )
1947- self ._enable_broker = enable_broker_on_windows and sys .platform == "win32"
1997+ enable_broker_on_mac = kwargs .pop ("enable_broker_on_mac" , False )
1998+ self ._enable_broker = bool (
1999+ enable_broker_on_windows and sys .platform == "win32"
2000+ or enable_broker_on_mac and sys .platform == "darwin" )
19482001 super (PublicClientApplication , self ).__init__ (
19492002 client_id , client_credential = None , ** kwargs )
19502003
@@ -2022,14 +2075,22 @@ def acquire_token_interactive(
20222075 New in version 1.15.
20232076
20242077 :param int parent_window_handle:
2025- Required if your app is running on Windows and opted in to use broker.
2078+ OPTIONAL.
2079+
2080+ * If your app does not opt in to use broker,
2081+ you do not need to provide a ``parent_window_handle`` here.
2082+
2083+ * If your app opts in to use broker,
2084+ ``parent_window_handle`` is required.
20262085
2027- If your app is a GUI app,
2028- you are recommended to also provide its window handle,
2029- so that the sign in UI window will properly pop up on top of your window.
2086+ - If your app is a GUI app running on Windows or Mac system,
2087+ you are required to also provide its window handle,
2088+ so that the sign-in window will pop up on top of your window.
2089+ - If your app is a console app running on Windows or Mac system,
2090+ you can use a placeholder
2091+ ``PublicClientApplication.CONSOLE_WINDOW_HANDLE``.
20302092
2031- If your app is a console app (most Python scripts are console apps),
2032- you can use a placeholder value ``msal.PublicClientApplication.CONSOLE_WINDOW_HANDLE``.
2093+ Most Python scripts are console apps.
20332094
20342095 New in version 1.20.0.
20352096
0 commit comments