snowflake-connector-python icon indicating copy to clipboard operation
snowflake-connector-python copied to clipboard

SNOW-974917: How can we use SF_AUTH_SOCKET_ADDR ?

Open RobbertDM opened this issue 2 years ago • 7 comments

What is the current behavior?

The bigger context is that I am using gitpod, a cloud IDE, and I want to use externalbrowser authentication with Snowflake. This opens a SAML flow that always redirects to localhost, but I want it to redirect to my gitpod instance's URL, where the server is actually listening.

For the port, I can use this SF_AUTH_SOCKET_PORT variable and that works brilliantly:

  • I set export SF_AUTH_SOCKET_PORT=50000
  • It spins up a server at localhost:50000
  • The eventual redirect happens to localhost:50000.

However, for the hostname, if I try to set something like export SF_AUTH_SOCKET_ADDR='myworkspace.gitpod.io', then it complains that it cannot assign the requested address: [Errno 99] Cannot assign requested address

I guess socket.bind doesn't like us passing actual domain names.

https://github.com/snowflakedb/snowflake-connector-python/blob/9b6b0a63887e472e7c05365e5db896bf4d818db1/src/snowflake/connector/auth/webbrowser.py#L119-L123

So I wonder, how should we use this environment variable then? Is there any way to change the redirect URL to some public URL like myworkspace.gitpod.io?

What is the desired behavior?

  • SF_AUTH_SOCKET_ADDR also modifies the redirect URL instead of leaving it on localhost
  • We create a new SF_AUTH_REDIRECT_URL env variable that controls only the redirect URL for the SAML request

How would this improve snowflake-connector-python?

Cloud IDE users would be able to use externalbrowser authentication.

References and other background

https://github.com/snowflakedb/snowflake-connector-python/blob/9b6b0a63887e472e7c05365e5db896bf4d818db1/src/snowflake/connector/auth/webbrowser.py#L119-L123

https://github.com/snowflakedb/snowflake-connector-python/blob/9b6b0a63887e472e7c05365e5db896bf4d818db1/src/snowflake/connector/auth/webbrowser.py#L401

RobbertDM avatar Nov 20 '23 19:11 RobbertDM

Thanks for reporting. Creating a new env var sounds like a good solution. I'm not sure if we have the bandwidth to prioritize this but we would be open to review PRs. Just in case I miss something, @sfc-gh-mkeller : WDYT? Are there some something that I might be missing?

sfc-gh-sfan avatar Nov 22 '23 18:11 sfc-gh-sfan

I would gladly open a PR, but I'm afraid this requires a change at snowflake side too: In the lines below, a POST request is made: https://github.com/snowflakedb/snowflake-connector-python/blob/9b6b0a63887e472e7c05365e5db896bf4d818db1/src/snowflake/connector/auth/webbrowser.py#L388-L411

Where body["data"]["BROWSER_MODE_REDIRECT_PORT"] = str(callback_port) is specified. If at Snowflake side, the server does not accept a BROWSER_MODE_REDIRECT_HOST or something similar, then I don't think any PR could enable setting the redirect URL.

RobbertDM avatar Nov 22 '23 21:11 RobbertDM

hey @RobbertDM, trying to provide a potential workaround here, is it possible to get the IP of the domain and then pass it to SF_AUTH_SOCKET_ADDR to get your case work?

the IP could be retrieved via Python socket module:

import socket
ip_address = socket.gethostbyname('<domain_name>')

sfc-gh-aling avatar Mar 14 '24 17:03 sfc-gh-aling

Hey @sfc-gh-aling ,

No, I'm really convinced there is no simple workaround except for modifying the server at Snowflake side to accept a parameter like BROWSER_MODE_REDIRECT_HOST.

Even if we could make socket bind to whatever IP or host, the server would anyways return a redirect URL to localhost, because it does not know what else to redirect to. This SF_AUTH_SOCKET_ADDR is never propagated to Snowflake.


With 2 extra lines we can replicate what the snowflake connector will try to do:

import socket
ip_address = socket.gethostbyname('redacted-customersal-tnzk49f3eqt.ws.redacted.gitpod.cloud')
socket_connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_connection.bind((ip_address, 0))

which will give you OSError: [Errno 99] Cannot assign requested address Because that public IP address returned by gethostbyname is not available on any of my interfaces.

What we could do instead is

import socket
socket_connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_connection.bind((socket.gethostname(), 0))

where socket.gethostname() returns redacted-customersal-tnzk49f3eqt, which is known locally and resolves to 127.0.0.1.

Setting SF_AUTH_SOCKET_ADDR=redacted-customersal-tnzk49f3eqt therefore also does not give any errors, but, as expected, the redirect URL still redirect to localhost.

RobbertDM avatar Mar 21 '24 09:03 RobbertDM