Added support for opening in a defined Firefox container

This commit is contained in:
Ezri Brimhall 2025-06-24 09:16:25 -06:00
parent 14c38fb756
commit 052a6ff029
Signed by: ezri
GPG Key ID: 058A78E5680C6F24
2 changed files with 37 additions and 10 deletions

View File

@ -13,6 +13,7 @@ from .auth_flows import AuthFlows
from .listener_targets import ListenerTargets from .listener_targets import ListenerTargets
from .agent_tools import parse_prelogin from .agent_tools import parse_prelogin
import webbrowser import webbrowser
import urllib.parse
from asyncio import Future, wait_for, TimeoutError, get_running_loop from asyncio import Future, wait_for, TimeoutError, get_running_loop
@ -20,7 +21,7 @@ class GlobalProtectSamlAuthenticator:
"""Encapsulates SAML authentication flow.""" """Encapsulates SAML authentication flow."""
def __init__(self): def __init__(self):
self._future: Future = None self._future: Future | None = None
async def saml_authenticate_in_browser( async def saml_authenticate_in_browser(
self, auth_flow: str, options: Variant self, auth_flow: str, options: Variant
@ -31,16 +32,21 @@ class GlobalProtectSamlAuthenticator:
f"This auth handler is for {AuthFlows.GLOBALPROTECT_SAML_DEFAULT_BROWSER} and does not support {auth_flow}" f"This auth handler is for {AuthFlows.GLOBALPROTECT_SAML_DEFAULT_BROWSER} and does not support {auth_flow}"
) )
# Options should contain a single string that is the URL to visit. # Options should contain a single string that is the URL to visit, or a struct of two strings.
if options.signature != "s": if options.signature not in {"s", "(ss)"}:
raise InvalidArguments( raise InvalidArguments(
f"Option signature for SAML auth must be string (s), got {options.signature}" f"Option signature for SAML auth must be string ('s') or struct of 2 strings ('(ss)'), got {options.signature}"
) )
if self._future is not None: if self._future is not None:
raise AuthenticationInProgress() raise AuthenticationInProgress()
webbrowser.open(options.value) if options.signature == "(ss)":
target = f"ext+container:name={urllib.parse.quote_plus(options.value[0])}&url={urllib.parse.quote_plus(options.value[1])}"
else:
target = options.value
webbrowser.open(target)
self._future = get_running_loop().create_future() self._future = get_running_loop().create_future()
try: try:
return await wait_for(self._future, timeout=300) return await wait_for(self._future, timeout=300)

View File

@ -14,7 +14,6 @@ from asyncio.subprocess import Process, PIPE, DEVNULL
from dbus_fast import Variant from dbus_fast import Variant
from sys import platform from sys import platform
import requests import requests
from vpn_manager.common import errors
from vpn_manager.utils import unwrap_variant from vpn_manager.utils import unwrap_variant
from .insecure_tls import TLSAdapter from .insecure_tls import TLSAdapter
import logging import logging
@ -43,6 +42,11 @@ class Options(TypedDict, total=False):
spoof_clientos: str spoof_clientos: str
use_default_browser: bool use_default_browser: bool
# If set, will attempt to open the in-browser request using
# a Firefox "Open external links in a container" plugin URI,
# using the container name set here.
firefox_browser_container: str
class Auth(TypedDict): class Auth(TypedDict):
"""Auth type definition for GlobalProtect VPNs.""" """Auth type definition for GlobalProtect VPNs."""
@ -169,10 +173,27 @@ class GlobalProtectConnection(
else AuthFlows.GLOBALPROTECT_SAML_INTEGRATED else AuthFlows.GLOBALPROTECT_SAML_INTEGRATED
) )
auth_result = await self._manager.request_credentials( if (
auth_flow, auth_flow == AuthFlows.GLOBALPROTECT_SAML_DEFAULT_BROWSER
Variant("s", base64.b64decode(preauth.get("saml-request")).decode("utf-8")), and "firefox_browser_container" in options
) ):
auth_result = await self._manager.request_credentials(
auth_flow,
Variant(
"(ss)",
(
base64.b64decode(preauth.get("saml-request")).decode("utf-8"),
options["firefox_browser_container"],
),
),
)
else:
auth_result = await self._manager.request_credentials(
auth_flow,
Variant(
"s", base64.b64decode(preauth.get("saml-request")).decode("utf-8")
),
)
if auth_result.signature != "a{ss}": if auth_result.signature != "a{ss}":
# Make sure the agent is well-behaved and is returning a valid response for this request. # Make sure the agent is well-behaved and is returning a valid response for this request.