Skip to content

SNOW-3295149: AuthByWebBrowser._receive_saml_token does not properly handle socket tcp stream #2831

@nataziel

Description

@nataziel

Python version

3.12.12 (but the issues is version agnostic)

Operating system and processor architecture

Linux-6.6.87.1-microsoft-standard-WSL2-x86_64-with-glibc2.41 (but the issue is platform agnostic)

Installed packages

Using Python 3.12.12 environment at: /root/.cache/uv-venv/my_project
annotated-types==0.7.0
anyio==4.13.0
asn1crypto==1.5.1
boto3==1.42.76
boto3-stubs==1.42.76
botocore==1.42.76
botocore-stubs==1.42.41
certifi==2026.2.25
cffi==2.0.0
charset-normalizer==3.4.6
-e file:///workspaces/my_project
cryptography==46.0.6
filelock==3.25.2
genai-prices==0.0.56
griffelib==2.0.1
h11==0.16.0
httpcore==1.0.9
httpx==0.28.1
idna==3.11
importlib-metadata==8.7.1
jmespath==1.1.0
logfire-api==4.30.0
loguru==0.7.3
mypy-boto3-bedrock-runtime==1.42.42
mypy-boto3-sts==1.42.3
nodeenv==1.10.0
numpy==2.4.3
opentelemetry-api==1.40.0
packaging==26.0
pandas==2.3.3
platformdirs==4.9.4
polars==1.39.3
polars-runtime-32==1.39.3
prek==0.3.8
pyarrow==23.0.1
pycparser==3.0
pydantic==2.12.5
pydantic-ai-slim==1.72.0
pydantic-core==2.41.5
pydantic-graph==1.72.0
pyjwt==2.12.1
pyopenssl==26.0.0
pyright==1.1.408
python-dateutil==2.9.0.post0
pytz==2026.1.post1
requests==2.33.0
ruff==0.15.7
s3transfer==0.16.0
six==1.17.0
snowflake-connector-python==4.4.0
sortedcontainers==2.4.0
tomlkit==0.14.0
types-awscrt==0.31.3
types-s3transfer==0.16.0
typing-extensions==4.15.0
typing-inspection==0.4.2
tzdata==2025.3
urllib3==2.6.3
zipp==3.23.0

What did you do?

Attempt to connect to snowflake via external web browser

What did you expect to see?

Sometimes, when attempting to connect to snowflake with SSO via external browser authentication, running the code in a linux devcontainer on wsl2, I experience an error at


where it fails to split the string into 3 pieces.

The reason this occurs is because _receive_saml_token at

raw_data = socket_client.recv(BUF_SIZE)

does not correctly parse the incoming tcp byte stream to completion. Once it receives any amount of bytes through the socket it moves on to decode and then process the received data. There is no guarantee that the entire message is received in a single call to socket.recv(), so it may or may not have everything it needs to properly process the token.

There is special handling for receiving 0 bytes in containerised environments to begin with and using socket.MSG_DONTWAIT etc., but that is tangential to the fact that there is no guarantee that a single call to socket.recv() will receive all the data that is being transmitted, even when you specify an arbitarily large BUF_SIZE. This error could occur on any platform, whether in a containerised application or not, because the basic assumption that a single call to socket.recv() will get all the data that is being transmitted is incorrect. You have to repeatedly call recv until you've received everything or do some fancy parsing after receiving some amount of bytes to check if you have what you need before closing the socket.

I see a todo at the top of the file that you want to convert it over to the new AuthHttpServer class, but that also has the same problem.

I have done a little tinkering with a minimal fix, but it's pretty tricky at the socket level, it might be easier/safer/less bug prone to instantiate a proper httpserver but it's a much larger amount of code to change

Can you set logging to DEBUG and collect the logs?

Note I actually caught this while running via the vscode debugger so there's a bunch of extra frames in the traceback. It does occur outside the debugger as well


2026-03-27 01:22:55,000 - my-package-runner config_manager.py:359 - read_config() - DEBUG - Fail to read configuration file from /root/.config/snowflake/config.toml due to no permission on its parent directory
2026-03-27 01:22:55,001 - my-package-runner config_manager.py:359 - read_config() - DEBUG - Fail to read configuration file from /root/.config/snowflake/connections.toml due to no permission on its parent directory
2026-03-27 01:22:55,001 - my-package-runner connection.py:620 - __init__() - INFO - Snowflake Connector for Python Version: 4.4.0, Python Version: 3.12.12, Platform: Linux-6.6.87.1-microsoft-standard-WSL2-x86_64-with-glibc2.41
2026-03-27 01:22:55,002 - my-package-runner connection.py:1120 - connect() - DEBUG - connect
2026-03-27 01:22:55,002 - my-package-runner connection.py:1638 - __config() - DEBUG - __config
2026-03-27 01:22:55,002 - my-package-runner connection.py:1716 - __config() - INFO - Connecting to GLOBAL Snowflake domain
2026-03-27 01:22:55,002 - my-package-runner connection.py:1852 - __config() - DEBUG - This connection is in OCSP Fail Open Mode. TLS Certificates would be checked for validity and revocation status. Any other Certificate Revocation related exceptions or OCSP Responder failures would be disregarded in favor of connectivity.
2026-03-27 01:22:55,003 - my-package-runner converter.py:156 - __init__() - DEBUG - use_numpy: False
2026-03-27 01:22:55,003 - my-package-runner connection.py:1366 - __open_connection() - DEBUG - REST API object was created: REDACTED_URL
2026-03-27 01:22:55,004 - my-package-runner webbrowser.py:113 - prepare() - DEBUG - authenticating by Web Browser
2026-03-27 01:22:55,004 - my-package-runner webbrowser.py:148 - prepare() - DEBUG - step 1: query GS to obtain SSO url
2026-03-27 01:23:10,510 - my-package-runner platform_detection.py:549 - detect_platforms() - DEBUG - Platform detection completed. Detected platforms: ['has_aws_identity_timeout', 'is_gce_vm_timeout', 'has_gcp_identity_timeout']
2026-03-27 01:23:10,511 - my-package-runner webbrowser.py:481 - _get_sso_url() - DEBUG - account=REDACTED, authenticator=EXTERNALBROWSER, user=REDACTED
2026-03-27 01:23:10,515 - my-package-runner retry.py:298 - from_int() - DEBUG - Converted retries value: 1 -> Retry(total=1, connect=None, read=None, redirect=None, status=None)
2026-03-27 01:23:10,516 - my-package-runner network.py:906 - _request_exec_wrapper() - DEBUG - remaining request timeout: N/A ms, retry cnt: 1
2026-03-27 01:23:10,517 - my-package-runner network.py:887 - add_request_guid() - DEBUG - Request guid: REDACTED
2026-03-27 01:23:10,517 - my-package-runner network.py:1091 - _request_exec() - DEBUG - socket timeout: 60
2026-03-27 01:23:10,520 - my-package-runner connectionpool.py:1049 - _new_conn() - DEBUG - Starting new HTTPS connection (1): REDACTED_URL
2026-03-27 01:23:10,625 - my-package-runner ssl_wrap_socket.py:196 - ssl_wrap_socket_with_cert_revocation_checks() - DEBUG - CRL Check Mode: DISABLED
2026-03-27 01:23:10,625 - my-package-runner ssl_wrap_socket.py:224 - ssl_wrap_socket_with_cert_revocation_checks() - DEBUG - OCSP Mode: FAIL_OPEN, OCSP response cache file name: None
2026-03-27 01:23:10,643 - my-package-runner ocsp_snowflake.py:679 - reset_cache_dir() - DEBUG - cache directory: /root/.cache/snowflake
2026-03-27 01:23:10,646 - my-package-runner ocsp_snowflake.py:717 - reset_ocsp_response_cache_uri() - DEBUG - ocsp_response_cache_uri: file:///root/.cache/snowflake/ocsp_response_cache.json
2026-03-27 01:23:10,646 - my-package-runner ocsp_snowflake.py:720 - reset_ocsp_response_cache_uri() - DEBUG - OCSP_VALIDATION_CACHE size: 303
2026-03-27 01:23:10,646 - my-package-runner ocsp_snowflake.py:512 - reset_ocsp_dynamic_cache_server_url() - DEBUG - OCSP response cache server is enabled: http://ocsp.snowflakecomputing.com/ocsp_response_cache.json
2026-03-27 01:23:10,646 - my-package-runner ocsp_snowflake.py:525 - reset_ocsp_dynamic_cache_server_url() - DEBUG - OCSP dynamic cache server RETRY URL: None
2026-03-27 01:23:10,647 - my-package-runner ocsp_snowflake.py:1160 - validate() - DEBUG - validating certificate: REDACTED_URL
2026-03-27 01:23:10,647 - my-package-runner ocsp_asn1crypto.py:398 - extract_certificate_chain() - DEBUG - # of certificates: 3
2026-03-27 01:23:10,672 - my-package-runner ocsp_asn1crypto.py:87 - read_cert_bundle() - DEBUG - reading certificate bundle: /root/.cache/uv-venv/my-package/lib/python3.12/site-packages/certifi/cacert.pem
2026-03-27 01:23:10,681 - my-package-runner ocsp_asn1crypto.py:403 - extract_certificate_chain() - DEBUG - subject: OrderedDict({'country_name': 'US', 'state_or_province_name': 'Montana', 'locality_name': 'Bozeman', 'organization_name': 'Snowflake Inc.', 'common_name': '*.aws_region.aws.snowflakecomputing.com'}), issuer: OrderedDict({'country_name': 'US', 'organization_name': 'DigiCert Inc', 'common_name': 'DigiCert Global G2 TLS RSA SHA256 2020 CA1'})
2026-03-27 01:23:10,681 - my-package-runner ocsp_asn1crypto.py:403 - extract_certificate_chain() - DEBUG - subject: OrderedDict({'country_name': 'US', 'organization_name': 'DigiCert Inc', 'common_name': 'DigiCert Global G2 TLS RSA SHA256 2020 CA1'}), issuer: OrderedDict({'country_name': 'US', 'organization_name': 'DigiCert Inc', 'organizational_unit_name': 'www.digicert.com', 'common_name': 'DigiCert Global Root G2'})
2026-03-27 01:23:10,681 - my-package-runner ocsp_asn1crypto.py:408 - extract_certificate_chain() - DEBUG - A trusted root certificate found: OrderedDict({'country_name': 'US', 'organization_name': 'DigiCert Inc', 'common_name': 'DigiCert Global G2 TLS RSA SHA256 2020 CA1'}), stopping chain traversal here
2026-03-27 01:23:10,683 - my-package-runner ocsp_asn1crypto.py:432 - create_pair_issuer_subject() - DEBUG - not found issuer_der: OrderedDict({'country_name': 'US', 'organization_name': 'DigiCert Inc', 'organizational_unit_name': 'www.digicert.com', 'common_name': 'DigiCert Global Root G2'})
2026-03-27 01:23:10,684 - my-package-runner ocsp_snowflake.py:917 - find_cache() - DEBUG - hit cache for subject: OrderedDict({'country_name': 'US', 'state_or_province_name': 'Montana', 'locality_name': 'Bozeman', 'organization_name': 'Snowflake Inc.', 'common_name': '*.aws_region.aws.snowflakecomputing.com'})
2026-03-27 01:23:10,685 - my-package-runner ocsp_snowflake.py:917 - find_cache() - DEBUG - hit cache for subject: OrderedDict({'country_name': 'US', 'organization_name': 'DigiCert Inc', 'common_name': 'DigiCert Global G2 TLS RSA SHA256 2020 CA1'})
2026-03-27 01:23:10,686 - my-package-runner ocsp_snowflake.py:1217 - _validate() - DEBUG - ok
2026-03-27 01:23:10,725 - my-package-runner connectionpool.py:544 - _make_request() - DEBUG - REDACTED_URL "POST /session/authenticator-request?request_guid=REDACTED HTTP/1.1" 200 None
2026-03-27 01:23:10,727 - my-package-runner network.py:1123 - _request_exec() - DEBUG - SUCCESS
2026-03-27 01:23:10,727 - my-package-runner network.py:766 - _post_request() - DEBUG - ret[code] = None, after post request
2026-03-27 01:23:10,727 - my-package-runner webbrowser.py:156 - prepare() - DEBUG - Validate SSO URL
Initiating login request with your identity provider. Press CTRL+C to abort and try again...
2026-03-27 01:23:10,727 - my-package-runner webbrowser.py:171 - prepare() - DEBUG - step 2: open a browser
Going to open: REDACTED_URL to authenticate...
A browser window should have opened for you to complete the login. If you can't see it, check existing browser windows, or your OS settings.
2026-03-27 01:23:10,814 - my-package-runner webbrowser.py:185 - prepare() - DEBUG - step 3: accept SAML token
2026-03-27 01:23:13,347 - my-package-runner webbrowser.py:258 - _receive_saml_token() - DEBUG - Calling socket_client.recv with MSG_DONTWAIT flag due to SNOWFLAKE_AUTH_SOCKET_MSG_DONTWAIT env var
2026-03-27 01:30:13,282 - analyse-transcripts-runner webbrowser.py:443 - _get_user_agent() - DEBUG - No User-Agent
Traceback (most recent call last):
  File "/usr/local/lib/python3.12/runpy.py", line 198, in _run_module_as_main
    return _run_code(code, main_globals, None,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/runpy.py", line 88, in _run_code
    exec(code, run_globals)
  File "/root/.vscode-server/extensions/ms-python.debugpy-2025.18.0-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/__main__.py", line 71, in <module>
    cli.main()
  File "/root/.vscode-server/extensions/ms-python.debugpy-2025.18.0-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/../debugpy/server/cli.py", line 508, in main
    run()
  File "/root/.vscode-server/extensions/ms-python.debugpy-2025.18.0-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/../debugpy/server/cli.py", line 358, in run_file
    runpy.run_path(target, run_name="__main__")
  File "/root/.vscode-server/extensions/ms-python.debugpy-2025.18.0-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 310, in run_path
    return _run_module_code(code, init_globals, run_name, pkg_name=pkg_name, script_name=fname)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/root/.vscode-server/extensions/ms-python.debugpy-2025.18.0-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 127, in _run_module_code
    _run_code(code, mod_globals, init_globals, mod_name, mod_spec, pkg_name, script_name)
  File "/root/.vscode-server/extensions/ms-python.debugpy-2025.18.0-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 118, in _run_code
    exec(code, run_globals)
  File "/workspaces/my-package/debug/debug.py", line 18, in <module>
    run()
  File "/workspaces/my-package/src/my_package/__init__.py", line 30, in run
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/concurrent/futures/_base.py", line 449, in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/concurrent/futures/_base.py", line 401, in __get_result
    raise self._exception
  File "/workspaces/my-package/src/my_package/__init__.py", line 20, in _run_in_worker
    asyncio.run(analyse_transcripts())
  File "/usr/local/lib/python3.12/asyncio/runners.py", line 195, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/asyncio/base_events.py", line 691, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/workspaces/my-package/src/my_package/main.py", line 22, in analyse_transcripts
    conn = SnowflakeHelper()
           ^^^^^^^^^^^^^^^^^
  File "/workspaces/my-package/src/my_package/utils/snowflake.py", line 19, in __init__
    self._conn = self._connect()
                 ^^^^^^^^^^^^^^^
  File "/workspaces/my-package/src/my_package/utils/snowflake.py", line 49, in _connect
    return snowflake.connector.connect(**self.connection_args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/root/.cache/uv-venv/my-package/lib/python3.12/site-packages/snowflake/connector/__init__.py", line 64, in Connect
    return SnowflakeConnection(**kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/root/.cache/uv-venv/my-package/lib/python3.12/site-packages/snowflake/connector/connection.py", line 688, in __init__
    self.connect(**kwargs)
  File "/root/.cache/uv-venv/my-package/lib/python3.12/site-packages/snowflake/connector/connection.py", line 1184, in connect
    self.__open_connection()
  File "/root/.cache/uv-venv/my-package/lib/python3.12/site-packages/snowflake/connector/connection.py", line 1623, in __open_connection
    self.authenticate_with_retry(self.auth_class)
  File "/root/.cache/uv-venv/my-package/lib/python3.12/site-packages/snowflake/connector/connection.py", line 1959, in authenticate_with_retry
    self._authenticate(auth_instance)
  File "/root/.cache/uv-venv/my-package/lib/python3.12/site-packages/snowflake/connector/connection.py", line 1975, in _authenticate
    auth_instance.prepare(
  File "/root/.cache/uv-venv/my-package/lib/python3.12/site-packages/snowflake/connector/auth/webbrowser.py", line 186, in prepare
    self._receive_saml_token(conn, socket_connection)
  File "/root/.cache/uv-venv/my-package/lib/python3.12/site-packages/snowflake/connector/auth/webbrowser.py", line 283, in _receive_saml_token
    self._process_receive_saml_token(conn, data, socket_client)
  File "/root/.cache/uv-venv/my-package/lib/python3.12/site-packages/snowflake/connector/auth/webbrowser.py", line 340, in _process_receive_saml_token
    if not self._process_get(data) and not self._process_post(conn, data):
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/root/.cache/uv-venv/my-package/lib/python3.12/site-packages/snowflake/connector/auth/webbrowser.py", line 407, in _process_get
    _, url, _ = target_line.split()
    ^^^^^^^^^
ValueError: not enough values to unpack (expected 3, got 2)

Metadata

Metadata

Labels

bugstatus-triage_doneInitial triage done, will be further handled by the driver team

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions