diff --git a/msal/__main__.py b/msal/__main__.py index 0c6c59f7..2ee982a6 100644 --- a/msal/__main__.py +++ b/msal/__main__.py @@ -300,6 +300,7 @@ def _main(): instance_discovery=instance_discovery, enable_broker_on_windows=enable_broker, enable_broker_on_mac=enable_broker, + enable_broker_on_linux=enable_broker, enable_pii_log=enable_pii_log, token_cache=global_cache, ) if not is_cca else msal.ConfidentialClientApplication( diff --git a/msal/application.py b/msal/application.py index 7f7615de..58bdd4af 100644 --- a/msal/application.py +++ b/msal/application.py @@ -675,7 +675,7 @@ def _decide_broker(self, allow_broker, enable_pii_log): "allow_broker is deprecated. " "Please use PublicClientApplication(..., " "enable_broker_on_windows=True, " - "enable_broker_on_mac=...)", + "...)", DeprecationWarning) opted_in_for_broker = ( self._enable_broker # True means Opted-in from PCA @@ -704,7 +704,7 @@ def _decide_broker(self, allow_broker, enable_pii_log): def is_pop_supported(self): """Returns True if this client supports Proof-of-Possession Access Token.""" - return self._enable_broker + return self._enable_broker and sys.platform != "linux" def _decorate_scope( self, scopes, @@ -1576,10 +1576,14 @@ def _acquire_token_silent_from_cache_and_possibly_refresh_it( raise ValueError("auth_scheme is not supported in Cloud Shell") return self._acquire_token_by_cloud_shell(scopes, data=data) + is_ssh_cert_or_pop_request = ( + data.get("token_type") == "ssh-cert" or + data.get("token_type") == "pop" or + isinstance(auth_scheme, msal.auth_scheme.PopAuthScheme)) if self._enable_broker and account and account.get("account_source") in ( _GRANT_TYPE_BROKER, # Broker successfully established this account previously. None, # Unknown data from older MSAL. Broker might still work. - ): + ) and (sys.platform != "linux" or not is_ssh_cert_or_pop_request): from .broker import _acquire_token_silently response = _acquire_token_silently( "https://{}/{}".format(self.authority.instance, self.authority.tenant), @@ -1826,7 +1830,7 @@ def acquire_token_by_username_password( """ claims = _merge_claims_challenge_and_capabilities( self._client_capabilities, claims_challenge) - if self._enable_broker: + if self._enable_broker and sys.platform != "linux": from .broker import _signin_silently response = _signin_silently( "https://{}/{}".format(self.authority.instance, self.authority.tenant), @@ -1924,7 +1928,7 @@ def __init__(self, client_id, client_credential=None, **kwargs): .. note:: - You may set enable_broker_on_windows and/or enable_broker_on_mac to True. + You may set enable_broker_on_windows and/or enable_broker_on_mac and/or enable_broker_on_linux to True. **What is a broker, and why use it?** @@ -1952,9 +1956,11 @@ def __init__(self, client_id, client_credential=None, **kwargs): if your app is expected to run on Windows 10+ * ``msauth.com.msauth.unsignedapp://auth`` if your app is expected to run on Mac + * ``ms-appx-web://Microsoft.AAD.BrokerPlugin/your_client_id`` + if your app is expected to run on Linux, especially WSL 2. installed broker dependency, - e.g. ``pip install msal[broker]>=1.31,<2``. + e.g. ``pip install msal[broker]>=1.32,<2``. 3. tested with ``acquire_token_interactive()`` and ``acquire_token_silent()``. @@ -1992,15 +1998,23 @@ def __init__(self, client_id, client_credential=None, **kwargs): This parameter defaults to None, which means MSAL will not utilize a broker. New in MSAL Python 1.31.0. + + :param boolean enable_broker_on_linux: + This setting is only effective if your app is running on Linux. + This parameter defaults to None, which means MSAL will not utilize a broker. + + New in MSAL Python 1.32.0. """ if client_credential is not None: raise ValueError("Public Client should not possess credentials") # Using kwargs notation for now. We will switch to keyword-only arguments. enable_broker_on_windows = kwargs.pop("enable_broker_on_windows", False) enable_broker_on_mac = kwargs.pop("enable_broker_on_mac", False) + enable_broker_on_linux = kwargs.pop("enable_broker_on_linux", False) self._enable_broker = bool( enable_broker_on_windows and sys.platform == "win32" - or enable_broker_on_mac and sys.platform == "darwin") + or enable_broker_on_mac and sys.platform == "darwin" + or enable_broker_on_linux and sys.platform == "linux") super(PublicClientApplication, self).__init__( client_id, client_credential=None, **kwargs) @@ -2129,6 +2143,10 @@ def acquire_token_interactive( False ) and data.get("token_type") != "ssh-cert" # Work around a known issue as of PyMsalRuntime 0.8 self._validate_ssh_cert_input_data(data) + is_ssh_cert_or_pop_request = ( + data.get("token_type") == "ssh-cert" or + data.get("token_type") == "pop" or + isinstance(auth_scheme, msal.auth_scheme.PopAuthScheme)) if not on_before_launching_ui: on_before_launching_ui = lambda **kwargs: None if _is_running_in_cloud_shell() and prompt == "none": @@ -2137,7 +2155,7 @@ def acquire_token_interactive( return self._acquire_token_by_cloud_shell(scopes, data=data) claims = _merge_claims_challenge_and_capabilities( self._client_capabilities, claims_challenge) - if self._enable_broker: + if self._enable_broker and (sys.platform != "linux" or not is_ssh_cert_or_pop_request): if parent_window_handle is None: raise ValueError( "parent_window_handle is required when you opted into using broker. " @@ -2162,7 +2180,9 @@ def acquire_token_interactive( ) return self._process_broker_response(response, scopes, data) - if auth_scheme: + if isinstance(auth_scheme, msal.auth_scheme.PopAuthScheme) and sys.platform == "linux": + raise ValueError("POP is not supported on Linux") + elif auth_scheme: raise ValueError(self._AUTH_SCHEME_UNSUPPORTED) on_before_launching_ui(ui="browser") telemetry_context = self._build_telemetry_context( diff --git a/msal/broker.py b/msal/broker.py index f4d71e11..710234b1 100644 --- a/msal/broker.py +++ b/msal/broker.py @@ -27,6 +27,7 @@ min_ver = { "win32": "1.20", "darwin": "1.31", + "linux": "1.32", }.get(sys.platform) if min_ver: raise ImportError( diff --git a/sample/interactive_sample.py b/sample/interactive_sample.py index 8c3f2df9..e0f463cb 100644 --- a/sample/interactive_sample.py +++ b/sample/interactive_sample.py @@ -47,7 +47,7 @@ oidc_authority=os.getenv('OIDC_AUTHORITY'), # For External ID with custom domain #enable_broker_on_windows=True, # Opted in. You will be guided to meet the prerequisites, if your app hasn't already #enable_broker_on_mac=True, # Opted in. You will be guided to meet the prerequisites, if your app hasn't already - + #enable_broker_on_linux=True, # Opted in. You will be guided to meet the prerequisites, if your app hasn't already token_cache=global_token_cache, # Let this app (re)use an existing token cache. # If absent, ClientApplication will create its own empty token cache ) diff --git a/setup.cfg b/setup.cfg index 6dfcfc7b..16f7cca3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -62,9 +62,11 @@ broker = # most existing MSAL Python apps do not have the redirect_uri needed by broker. # # We need pymsalruntime.CallbackData introduced in PyMsalRuntime 0.14 - pymsalruntime>=0.14,<0.18; python_version>='3.6' and platform_system=='Windows' + pymsalruntime>=0.14,<0.19; python_version>='3.6' and platform_system=='Windows' # On Mac, PyMsalRuntime 0.17+ is expected to support SSH cert and ROPC - pymsalruntime>=0.17,<0.18; python_version>='3.8' and platform_system=='Darwin' + pymsalruntime>=0.17,<0.19; python_version>='3.8' and platform_system=='Darwin' + # PyMsalRuntime 0.18+ is expected to support broker on Linux + pymsalruntime>=0.18,<0.19; python_version>='3.8' and platform_system=='Linux' [options.packages.find] exclude = diff --git a/tests/broker-test.py b/tests/broker-test.py index cdcc4817..4af75abb 100644 --- a/tests/broker-test.py +++ b/tests/broker-test.py @@ -39,7 +39,9 @@ _AZURE_CLI, authority="https://login.microsoftonline.com/organizations", enable_broker_on_mac=True, - enable_broker_on_windows=True) + enable_broker_on_windows=True, + enable_broker_on_linux=True, + ) def interactive_and_silent(scopes, auth_scheme, data, expected_token_type): print("An account picker shall be pop up, possibly behind this console. Continue from there.") diff --git a/tests/test_e2e.py b/tests/test_e2e.py index b2701569..832c3d0e 100644 --- a/tests/test_e2e.py +++ b/tests/test_e2e.py @@ -200,6 +200,7 @@ def _build_app(cls, http_client=http_client or MinimalHttpClient(), enable_broker_on_windows=broker_available, enable_broker_on_mac=broker_available, + enable_broker_on_linux=broker_available, ) def _test_username_password(self,