diff --git a/msal/application.py b/msal/application.py index fa76f941..4f68fc20 100644 --- a/msal/application.py +++ b/msal/application.py @@ -9,6 +9,7 @@ import sys import warnings from threading import Lock +import os import requests @@ -69,6 +70,46 @@ def _clean_up(result): return result +def _preferred_browser(): + """Register Edge and return a name suitable for subsequent webbrowser.get(...) + when appropriate. Otherwise return None. + """ + # On Linux, only Edge will provide device-based Conditional Access support + if sys.platform != "linux": # On other platforms, we have no browser preference + return None + browser_path = "/usr/bin/microsoft-edge" # Use a full path owned by sys admin + user_has_no_preference = "BROWSER" not in os.environ + user_wont_mind_edge = "microsoft-edge" in os.environ.get("BROWSER", "") # Note: + # BROWSER could contain "microsoft-edge" or "/path/to/microsoft-edge". + # Python documentation (https://docs.python.org/3/library/webbrowser.html) + # does not document the name being implicitly register, + # so there is no public API to know whether the ENV VAR browser would work. + # Therefore, we would not bother examine the env var browser's type. + # We would just register our own Edge instance. + if (user_has_no_preference or user_wont_mind_edge) and os.path.exists(browser_path): + try: + import webbrowser # Lazy import. Some distro may not have this. + browser_name = "msal-edge" # Avoid popular name "microsoft-edge" + # otherwise `BROWSER="microsoft-edge"; webbrowser.get("microsoft-edge")` + # would return a GenericBrowser instance which won't work. + try: + registration_available = isinstance( + webbrowser.get(browser_name), webbrowser.BackgroundBrowser) + except webbrowser.Error: + registration_available = False + if not registration_available: + logger.debug("Register %s with %s", browser_name, browser_path) + # By registering our own browser instance with our own name, + # rather than populating a process-wide BROWSER enn var, + # this approach does not have side effect on non-MSAL code path. + webbrowser.register( # Even double-register happens to work fine + browser_name, None, webbrowser.BackgroundBrowser(browser_path)) + return browser_name + except ImportError: + pass # We may still proceed + return None + + class ClientApplication(object): ACQUIRE_TOKEN_SILENT_ID = "84" @@ -1393,6 +1434,7 @@ def acquire_token_interactive( }, data=dict(kwargs.pop("data", {}), claims=claims), headers=telemetry_context.generate_headers(), + browser_name=_preferred_browser(), **kwargs)) telemetry_context.update_telemetry(response) return response