snowflake-connector-python 3.16.0__cp313-cp313-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. snowflake/connector/__init__.py +96 -0
  2. snowflake/connector/_query_context_cache.py +276 -0
  3. snowflake/connector/_sql_util.py +48 -0
  4. snowflake/connector/_utils.py +70 -0
  5. snowflake/connector/arrow_context.py +203 -0
  6. snowflake/connector/auth/__init__.py +53 -0
  7. snowflake/connector/auth/_auth.py +586 -0
  8. snowflake/connector/auth/_http_server.py +220 -0
  9. snowflake/connector/auth/_oauth_base.py +400 -0
  10. snowflake/connector/auth/by_plugin.py +219 -0
  11. snowflake/connector/auth/default.py +36 -0
  12. snowflake/connector/auth/idtoken.py +72 -0
  13. snowflake/connector/auth/keypair.py +222 -0
  14. snowflake/connector/auth/no_auth.py +39 -0
  15. snowflake/connector/auth/oauth.py +49 -0
  16. snowflake/connector/auth/oauth_code.py +479 -0
  17. snowflake/connector/auth/oauth_credentials.py +66 -0
  18. snowflake/connector/auth/okta.py +335 -0
  19. snowflake/connector/auth/pat.py +39 -0
  20. snowflake/connector/auth/usrpwdmfa.py +69 -0
  21. snowflake/connector/auth/webbrowser.py +502 -0
  22. snowflake/connector/auth/workload_identity.py +94 -0
  23. snowflake/connector/azure_storage_client.py +276 -0
  24. snowflake/connector/backoff_policies.py +141 -0
  25. snowflake/connector/bind_upload_agent.py +89 -0
  26. snowflake/connector/cache.py +696 -0
  27. snowflake/connector/compat.py +127 -0
  28. snowflake/connector/config_manager.py +496 -0
  29. snowflake/connector/connection.py +2273 -0
  30. snowflake/connector/connection_diagnostic.py +776 -0
  31. snowflake/connector/constants.py +442 -0
  32. snowflake/connector/converter.py +785 -0
  33. snowflake/connector/converter_issue23517.py +87 -0
  34. snowflake/connector/converter_null.py +14 -0
  35. snowflake/connector/converter_snowsql.py +205 -0
  36. snowflake/connector/cursor.py +1951 -0
  37. snowflake/connector/dbapi.py +53 -0
  38. snowflake/connector/description.py +19 -0
  39. snowflake/connector/direct_file_operation_utils.py +88 -0
  40. snowflake/connector/encryption_util.py +220 -0
  41. snowflake/connector/errorcode.py +91 -0
  42. snowflake/connector/errors.py +615 -0
  43. snowflake/connector/externals_utils/__init__.py +0 -0
  44. snowflake/connector/externals_utils/externals_setup.py +27 -0
  45. snowflake/connector/feature.py +4 -0
  46. snowflake/connector/file_compression_type.py +118 -0
  47. snowflake/connector/file_lock.py +72 -0
  48. snowflake/connector/file_transfer_agent.py +1215 -0
  49. snowflake/connector/file_util.py +153 -0
  50. snowflake/connector/gcs_storage_client.py +474 -0
  51. snowflake/connector/gzip_decoder.py +85 -0
  52. snowflake/connector/local_storage_client.py +90 -0
  53. snowflake/connector/log_configuration.py +60 -0
  54. snowflake/connector/logging_utils/__init__.py +0 -0
  55. snowflake/connector/logging_utils/filters.py +72 -0
  56. snowflake/connector/nanoarrow_arrow_iterator.cp313-win_amd64.pyd +0 -0
  57. snowflake/connector/nanoarrow_cpp/ArrowIterator/ArrayConverter.cpp +60 -0
  58. snowflake/connector/nanoarrow_cpp/ArrowIterator/ArrayConverter.hpp +29 -0
  59. snowflake/connector/nanoarrow_cpp/ArrowIterator/BinaryConverter.cpp +19 -0
  60. snowflake/connector/nanoarrow_cpp/ArrowIterator/BinaryConverter.hpp +26 -0
  61. snowflake/connector/nanoarrow_cpp/ArrowIterator/BooleanConverter.cpp +21 -0
  62. snowflake/connector/nanoarrow_cpp/ArrowIterator/BooleanConverter.hpp +23 -0
  63. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowChunkIterator.cpp +557 -0
  64. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowChunkIterator.hpp +98 -0
  65. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowIterator.cpp +125 -0
  66. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowIterator.hpp +115 -0
  67. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowTableIterator.cpp +1005 -0
  68. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowTableIterator.hpp +127 -0
  69. snowflake/connector/nanoarrow_cpp/ArrowIterator/DateConverter.cpp +47 -0
  70. snowflake/connector/nanoarrow_cpp/ArrowIterator/DateConverter.hpp +46 -0
  71. snowflake/connector/nanoarrow_cpp/ArrowIterator/DecFloatConverter.cpp +83 -0
  72. snowflake/connector/nanoarrow_cpp/ArrowIterator/DecFloatConverter.hpp +35 -0
  73. snowflake/connector/nanoarrow_cpp/ArrowIterator/DecimalConverter.cpp +97 -0
  74. snowflake/connector/nanoarrow_cpp/ArrowIterator/DecimalConverter.hpp +72 -0
  75. snowflake/connector/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.cpp +73 -0
  76. snowflake/connector/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.hpp +28 -0
  77. snowflake/connector/nanoarrow_cpp/ArrowIterator/FloatConverter.cpp +30 -0
  78. snowflake/connector/nanoarrow_cpp/ArrowIterator/FloatConverter.hpp +35 -0
  79. snowflake/connector/nanoarrow_cpp/ArrowIterator/IColumnConverter.hpp +17 -0
  80. snowflake/connector/nanoarrow_cpp/ArrowIterator/IntConverter.cpp +23 -0
  81. snowflake/connector/nanoarrow_cpp/ArrowIterator/IntConverter.hpp +45 -0
  82. snowflake/connector/nanoarrow_cpp/ArrowIterator/IntervalConverter.cpp +71 -0
  83. snowflake/connector/nanoarrow_cpp/ArrowIterator/IntervalConverter.hpp +56 -0
  84. snowflake/connector/nanoarrow_cpp/ArrowIterator/LICENSE.txt +209 -0
  85. snowflake/connector/nanoarrow_cpp/ArrowIterator/MapConverter.cpp +75 -0
  86. snowflake/connector/nanoarrow_cpp/ArrowIterator/MapConverter.hpp +30 -0
  87. snowflake/connector/nanoarrow_cpp/ArrowIterator/ObjectConverter.cpp +46 -0
  88. snowflake/connector/nanoarrow_cpp/ArrowIterator/ObjectConverter.hpp +29 -0
  89. snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Common.cpp +8 -0
  90. snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Common.hpp +95 -0
  91. snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Helpers.cpp +57 -0
  92. snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Helpers.hpp +36 -0
  93. snowflake/connector/nanoarrow_cpp/ArrowIterator/SnowflakeType.cpp +34 -0
  94. snowflake/connector/nanoarrow_cpp/ArrowIterator/SnowflakeType.hpp +48 -0
  95. snowflake/connector/nanoarrow_cpp/ArrowIterator/StringConverter.cpp +19 -0
  96. snowflake/connector/nanoarrow_cpp/ArrowIterator/StringConverter.hpp +26 -0
  97. snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeConverter.cpp +36 -0
  98. snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeConverter.hpp +31 -0
  99. snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeStampConverter.cpp +346 -0
  100. snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeStampConverter.hpp +145 -0
  101. snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/macros.hpp +14 -0
  102. snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/time.cpp +65 -0
  103. snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/time.hpp +68 -0
  104. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_accessors.h +101 -0
  105. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_alloc.h +127 -0
  106. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_assert.h +45 -0
  107. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_builder.h +1908 -0
  108. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_emitter.h +215 -0
  109. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_endian.h +125 -0
  110. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_epilogue.h +7 -0
  111. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_flatbuffers.h +55 -0
  112. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_identifier.h +148 -0
  113. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_iov.h +31 -0
  114. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_prologue.h +8 -0
  115. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_refmap.h +144 -0
  116. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_rtconfig.h +162 -0
  117. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_types.h +97 -0
  118. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_verifier.h +239 -0
  119. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/flatcc_portable.h +14 -0
  120. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/paligned_alloc.h +210 -0
  121. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pattributes.h +84 -0
  122. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic.h +84 -0
  123. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_pop.h +20 -0
  124. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_push.h +51 -0
  125. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian.h +206 -0
  126. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian_detect.h +118 -0
  127. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinline.h +19 -0
  128. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinttypes.h +52 -0
  129. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable.h +2 -0
  130. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable_basic.h +25 -0
  131. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstatic_assert.h +67 -0
  132. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdalign.h +162 -0
  133. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdint.h +898 -0
  134. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/punaligned.h +190 -0
  135. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pversion.h +6 -0
  136. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pwarnings.h +52 -0
  137. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc.c +3204 -0
  138. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.c +3217 -0
  139. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.h +3618 -0
  140. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.hpp +379 -0
  141. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_arrow_iterator.pyx +256 -0
  142. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_device.c +512 -0
  143. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_device.h +350 -0
  144. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.c +33273 -0
  145. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.h +397 -0
  146. snowflake/connector/nanoarrow_cpp/Logging/logging.cpp +100 -0
  147. snowflake/connector/nanoarrow_cpp/Logging/logging.hpp +49 -0
  148. snowflake/connector/network.py +1297 -0
  149. snowflake/connector/ocsp_asn1crypto.py +447 -0
  150. snowflake/connector/ocsp_snowflake.py +1883 -0
  151. snowflake/connector/options.py +131 -0
  152. snowflake/connector/pandas_tools.py +732 -0
  153. snowflake/connector/proxy.py +43 -0
  154. snowflake/connector/py.typed +0 -0
  155. snowflake/connector/result_batch.py +786 -0
  156. snowflake/connector/result_set.py +319 -0
  157. snowflake/connector/s3_storage_client.py +605 -0
  158. snowflake/connector/secret_detector.py +181 -0
  159. snowflake/connector/sf_dirs.py +64 -0
  160. snowflake/connector/sfbinaryformat.py +35 -0
  161. snowflake/connector/sfdatetime.py +345 -0
  162. snowflake/connector/snow_logging.py +144 -0
  163. snowflake/connector/sqlstate.py +9 -0
  164. snowflake/connector/ssd_internal_keys.py +30 -0
  165. snowflake/connector/ssl_wrap_socket.py +134 -0
  166. snowflake/connector/storage_client.py +478 -0
  167. snowflake/connector/telemetry.py +249 -0
  168. snowflake/connector/telemetry_oob.py +543 -0
  169. snowflake/connector/test_util.py +30 -0
  170. snowflake/connector/time_util.py +159 -0
  171. snowflake/connector/token_cache.py +402 -0
  172. snowflake/connector/tool/__init__.py +0 -0
  173. snowflake/connector/tool/dump_certs.py +57 -0
  174. snowflake/connector/tool/dump_ocsp_response.py +139 -0
  175. snowflake/connector/tool/dump_ocsp_response_cache.py +194 -0
  176. snowflake/connector/tool/probe_connection.py +69 -0
  177. snowflake/connector/url_util.py +49 -0
  178. snowflake/connector/util_text.py +301 -0
  179. snowflake/connector/vendored/__init__.py +3 -0
  180. snowflake/connector/vendored/requests/LICENSE +175 -0
  181. snowflake/connector/vendored/requests/__init__.py +169 -0
  182. snowflake/connector/vendored/requests/__version__.py +14 -0
  183. snowflake/connector/vendored/requests/_internal_utils.py +50 -0
  184. snowflake/connector/vendored/requests/adapters.py +537 -0
  185. snowflake/connector/vendored/requests/api.py +157 -0
  186. snowflake/connector/vendored/requests/auth.py +315 -0
  187. snowflake/connector/vendored/requests/certs.py +17 -0
  188. snowflake/connector/vendored/requests/compat.py +79 -0
  189. snowflake/connector/vendored/requests/cookies.py +561 -0
  190. snowflake/connector/vendored/requests/exceptions.py +140 -0
  191. snowflake/connector/vendored/requests/help.py +134 -0
  192. snowflake/connector/vendored/requests/hooks.py +33 -0
  193. snowflake/connector/vendored/requests/models.py +1033 -0
  194. snowflake/connector/vendored/requests/sessions.py +833 -0
  195. snowflake/connector/vendored/requests/status_codes.py +128 -0
  196. snowflake/connector/vendored/requests/structures.py +99 -0
  197. snowflake/connector/vendored/requests/utils.py +1093 -0
  198. snowflake/connector/vendored/urllib3/LICENSE.txt +21 -0
  199. snowflake/connector/vendored/urllib3/__init__.py +85 -0
  200. snowflake/connector/vendored/urllib3/_collections.py +355 -0
  201. snowflake/connector/vendored/urllib3/_version.py +2 -0
  202. snowflake/connector/vendored/urllib3/connection.py +572 -0
  203. snowflake/connector/vendored/urllib3/connectionpool.py +1137 -0
  204. snowflake/connector/vendored/urllib3/contrib/__init__.py +0 -0
  205. snowflake/connector/vendored/urllib3/contrib/_appengine_environ.py +36 -0
  206. snowflake/connector/vendored/urllib3/contrib/_securetransport/__init__.py +0 -0
  207. snowflake/connector/vendored/urllib3/contrib/_securetransport/bindings.py +519 -0
  208. snowflake/connector/vendored/urllib3/contrib/_securetransport/low_level.py +397 -0
  209. snowflake/connector/vendored/urllib3/contrib/appengine.py +314 -0
  210. snowflake/connector/vendored/urllib3/contrib/ntlmpool.py +130 -0
  211. snowflake/connector/vendored/urllib3/contrib/pyopenssl.py +509 -0
  212. snowflake/connector/vendored/urllib3/contrib/securetransport.py +920 -0
  213. snowflake/connector/vendored/urllib3/contrib/socks.py +216 -0
  214. snowflake/connector/vendored/urllib3/exceptions.py +323 -0
  215. snowflake/connector/vendored/urllib3/fields.py +274 -0
  216. snowflake/connector/vendored/urllib3/filepost.py +98 -0
  217. snowflake/connector/vendored/urllib3/packages/__init__.py +0 -0
  218. snowflake/connector/vendored/urllib3/packages/backports/__init__.py +0 -0
  219. snowflake/connector/vendored/urllib3/packages/backports/makefile.py +51 -0
  220. snowflake/connector/vendored/urllib3/packages/backports/weakref_finalize.py +155 -0
  221. snowflake/connector/vendored/urllib3/packages/six.py +1076 -0
  222. snowflake/connector/vendored/urllib3/poolmanager.py +540 -0
  223. snowflake/connector/vendored/urllib3/request.py +191 -0
  224. snowflake/connector/vendored/urllib3/response.py +885 -0
  225. snowflake/connector/vendored/urllib3/util/__init__.py +49 -0
  226. snowflake/connector/vendored/urllib3/util/connection.py +156 -0
  227. snowflake/connector/vendored/urllib3/util/proxy.py +57 -0
  228. snowflake/connector/vendored/urllib3/util/queue.py +22 -0
  229. snowflake/connector/vendored/urllib3/util/request.py +146 -0
  230. snowflake/connector/vendored/urllib3/util/response.py +107 -0
  231. snowflake/connector/vendored/urllib3/util/retry.py +620 -0
  232. snowflake/connector/vendored/urllib3/util/ssl_.py +495 -0
  233. snowflake/connector/vendored/urllib3/util/ssl_match_hostname.py +159 -0
  234. snowflake/connector/vendored/urllib3/util/ssltransport.py +221 -0
  235. snowflake/connector/vendored/urllib3/util/timeout.py +271 -0
  236. snowflake/connector/vendored/urllib3/util/url.py +435 -0
  237. snowflake/connector/vendored/urllib3/util/wait.py +152 -0
  238. snowflake/connector/version.py +3 -0
  239. snowflake/connector/wif_util.py +407 -0
  240. snowflake_connector_python-3.16.0.dist-info/METADATA +1475 -0
  241. snowflake_connector_python-3.16.0.dist-info/RECORD +246 -0
  242. snowflake_connector_python-3.16.0.dist-info/WHEEL +5 -0
  243. snowflake_connector_python-3.16.0.dist-info/entry_points.txt +4 -0
  244. snowflake_connector_python-3.16.0.dist-info/licenses/LICENSE.txt +202 -0
  245. snowflake_connector_python-3.16.0.dist-info/licenses/NOTICE +8 -0
  246. snowflake_connector_python-3.16.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,335 @@
1
+ #!/usr/bin/env python
2
+ from __future__ import annotations
3
+
4
+ import json
5
+ import logging
6
+ import time
7
+ from functools import partial
8
+ from typing import TYPE_CHECKING, Any, Callable
9
+
10
+ from ..compat import unescape, urlencode, urlsplit
11
+ from ..constants import (
12
+ HTTP_HEADER_ACCEPT,
13
+ HTTP_HEADER_CONTENT_TYPE,
14
+ HTTP_HEADER_SERVICE_NAME,
15
+ HTTP_HEADER_USER_AGENT,
16
+ )
17
+ from ..errorcode import ER_IDP_CONNECTION_ERROR, ER_INCORRECT_DESTINATION
18
+ from ..errors import DatabaseError, Error, RefreshTokenError
19
+ from ..network import CONTENT_TYPE_APPLICATION_JSON, PYTHON_CONNECTOR_USER_AGENT
20
+ from ..sqlstate import SQLSTATE_CONNECTION_WAS_NOT_ESTABLISHED
21
+ from . import Auth
22
+ from .by_plugin import AuthByPlugin, AuthType
23
+
24
+ if TYPE_CHECKING:
25
+ from .. import SnowflakeConnection
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+
30
+ def _is_prefix_equal(url1, url2):
31
+ """Checks if URL prefixes are identical.
32
+
33
+ The scheme, hostname and port number are compared. If the port number is not specified and the scheme is https,
34
+ the port number is assumed to be 443.
35
+ """
36
+ parsed_url1 = urlsplit(url1)
37
+ parsed_url2 = urlsplit(url2)
38
+
39
+ port1 = parsed_url1.port
40
+ if not port1 and parsed_url1.scheme == "https":
41
+ port1 = "443"
42
+ port2 = parsed_url1.port
43
+ if not port2 and parsed_url2.scheme == "https":
44
+ port2 = "443"
45
+
46
+ return (
47
+ parsed_url1.hostname == parsed_url2.hostname
48
+ and port1 == port2
49
+ and parsed_url1.scheme == parsed_url2.scheme
50
+ )
51
+
52
+
53
+ def _get_post_back_url_from_html(html):
54
+ """Gets the post back URL.
55
+
56
+ Since the HTML is not well-formed, minidom cannot be used to convert to
57
+ DOM. The first discovered form is assumed to be the form to post back
58
+ and the URL is taken from action attributes.
59
+ """
60
+ logger.debug(html)
61
+
62
+ idx = html.find("<form")
63
+ start_idx = html.find('action="', idx)
64
+ end_idx = html.find('"', start_idx + 8)
65
+ return unescape(html[start_idx + 8 : end_idx])
66
+
67
+
68
+ class AuthByOkta(AuthByPlugin):
69
+ """Authenticate user by OKTA."""
70
+
71
+ def __init__(self, application: str, **kwargs) -> None:
72
+ super().__init__(**kwargs)
73
+ self._saml_response = None
74
+ self._application = application
75
+
76
+ def reset_secrets(self) -> None:
77
+ pass
78
+
79
+ @property
80
+ def type_(self) -> AuthType:
81
+ return AuthType.OKTA
82
+
83
+ @property
84
+ def assertion_content(self) -> str:
85
+ return self._saml_response
86
+
87
+ def update_body(self, body: dict[Any, Any]) -> None:
88
+ body["data"]["RAW_SAML_RESPONSE"] = self._saml_response
89
+
90
+ def prepare(
91
+ self,
92
+ *,
93
+ conn: SnowflakeConnection,
94
+ authenticator: str,
95
+ service_name: str | None,
96
+ account: str,
97
+ user: str,
98
+ password: str,
99
+ **kwargs: Any,
100
+ ) -> None:
101
+ """SAML Authentication.
102
+
103
+ Steps are:
104
+ 1. query GS to obtain IDP token and SSO url
105
+ 2. IMPORTANT Client side validation:
106
+ validate both token url and sso url contains same prefix
107
+ (protocol + host + port) as the given authenticator url.
108
+ Explanation:
109
+ This provides a way for the user to 'authenticate' the IDP it is
110
+ sending his/her credentials to. Without such a check, the user could
111
+ be coerced to provide credentials to an IDP impersonator.
112
+ 3. query IDP token url to authenticate and retrieve access token
113
+ 4. given access token, query IDP URL snowflake app to get SAML response
114
+ 5. IMPORTANT Client side validation:
115
+ validate the post back url come back with the SAML response
116
+ contains the same prefix as the Snowflake's server url, which is the
117
+ intended destination url to Snowflake.
118
+ Explanation:
119
+ This emulates the behavior of IDP initiated login flow in the user
120
+ browser where the IDP instructs the browser to POST the SAML
121
+ assertion to the specific SP endpoint. This is critical in
122
+ preventing a SAML assertion issued to one SP from being sent to
123
+ another SP.
124
+ """
125
+ logger.debug("authenticating by SAML")
126
+ headers, sso_url, token_url = self._step1(
127
+ conn,
128
+ authenticator,
129
+ service_name,
130
+ account,
131
+ user,
132
+ )
133
+ self._step2(conn, authenticator, sso_url, token_url)
134
+ response_html = self._step4(
135
+ conn,
136
+ partial(self._step3, conn, headers, token_url, user, password),
137
+ sso_url,
138
+ )
139
+ self._step5(conn, response_html)
140
+
141
+ def reauthenticate(self, **kwargs: Any) -> dict[str, bool]:
142
+ return {"success": False}
143
+
144
+ def _step1(
145
+ self,
146
+ conn: SnowflakeConnection,
147
+ authenticator: str,
148
+ service_name: str | None,
149
+ account: str,
150
+ user: str,
151
+ ) -> tuple[dict[str, str], str, str]:
152
+ logger.debug("step 1: query GS to obtain IDP token and SSO url")
153
+
154
+ headers = {
155
+ HTTP_HEADER_CONTENT_TYPE: CONTENT_TYPE_APPLICATION_JSON,
156
+ HTTP_HEADER_ACCEPT: CONTENT_TYPE_APPLICATION_JSON,
157
+ HTTP_HEADER_USER_AGENT: PYTHON_CONNECTOR_USER_AGENT,
158
+ }
159
+ if service_name:
160
+ headers[HTTP_HEADER_SERVICE_NAME] = service_name
161
+ url = "/session/authenticator-request"
162
+ body = Auth.base_auth_data(
163
+ user,
164
+ account,
165
+ conn.application,
166
+ conn._internal_application_name,
167
+ conn._internal_application_version,
168
+ conn._ocsp_mode(),
169
+ conn.login_timeout,
170
+ conn._network_timeout,
171
+ )
172
+
173
+ body["data"]["AUTHENTICATOR"] = authenticator
174
+ logger.debug(
175
+ "account=%s, authenticator=%s",
176
+ account,
177
+ authenticator,
178
+ )
179
+ ret = conn._rest._post_request(
180
+ url,
181
+ headers,
182
+ json.dumps(body),
183
+ timeout=conn._rest._connection.login_timeout,
184
+ socket_timeout=conn._rest._connection.login_timeout,
185
+ )
186
+
187
+ if not ret["success"]:
188
+ self._handle_failure(conn=conn, ret=ret)
189
+
190
+ data = ret["data"]
191
+ token_url = data["tokenUrl"]
192
+ sso_url = data["ssoUrl"]
193
+ return headers, sso_url, token_url
194
+
195
+ def _step2(
196
+ self,
197
+ conn: SnowflakeConnection,
198
+ authenticator: str,
199
+ sso_url: str,
200
+ token_url: str,
201
+ ) -> None:
202
+ logger.debug(
203
+ "step 2: validate Token and SSO URL has the same prefix as authenticator"
204
+ )
205
+ if not _is_prefix_equal(authenticator, token_url) or not _is_prefix_equal(
206
+ authenticator, sso_url
207
+ ):
208
+ Error.errorhandler_wrapper(
209
+ conn._rest._connection,
210
+ None,
211
+ DatabaseError,
212
+ {
213
+ "msg": (
214
+ "The specified authenticator is not supported: "
215
+ f"{authenticator}, token_url: {token_url}, "
216
+ f"sso_url: {sso_url}"
217
+ ),
218
+ "errno": ER_IDP_CONNECTION_ERROR,
219
+ "sqlstate": SQLSTATE_CONNECTION_WAS_NOT_ESTABLISHED,
220
+ },
221
+ )
222
+
223
+ @staticmethod
224
+ def _step3(
225
+ conn: SnowflakeConnection,
226
+ headers: dict[str, str],
227
+ token_url: str,
228
+ user: str,
229
+ password: str,
230
+ ) -> str:
231
+ logger.debug(
232
+ "step 3: query IDP token url to authenticate and " "retrieve access token"
233
+ )
234
+ data = {
235
+ "username": user,
236
+ "password": password,
237
+ }
238
+ ret = conn._rest.fetch(
239
+ "post",
240
+ token_url,
241
+ headers,
242
+ data=json.dumps(data),
243
+ timeout=conn._rest._connection.login_timeout,
244
+ socket_timeout=conn._rest._connection.login_timeout,
245
+ catch_okta_unauthorized_error=True,
246
+ )
247
+ one_time_token = ret.get("sessionToken", ret.get("cookieToken"))
248
+ if not one_time_token:
249
+ Error.errorhandler_wrapper(
250
+ conn._rest._connection,
251
+ None,
252
+ DatabaseError,
253
+ {
254
+ "msg": (
255
+ "The authentication failed for {user} "
256
+ "by {token_url}.".format(
257
+ token_url=token_url,
258
+ user=user,
259
+ )
260
+ ),
261
+ "errno": ER_IDP_CONNECTION_ERROR,
262
+ "sqlstate": SQLSTATE_CONNECTION_WAS_NOT_ESTABLISHED,
263
+ },
264
+ )
265
+ return one_time_token
266
+
267
+ @staticmethod
268
+ def _step4(
269
+ conn: SnowflakeConnection,
270
+ generate_one_time_token: Callable,
271
+ sso_url: str,
272
+ ) -> dict[Any, Any]:
273
+ logger.debug("step 4: query IDP URL snowflake app to get SAML " "response")
274
+ timeout_time = time.time() + conn.login_timeout if conn.login_timeout else None
275
+ response_html = {}
276
+ origin_sso_url = sso_url
277
+ while timeout_time is None or time.time() < timeout_time:
278
+ try:
279
+ url_parameters = {
280
+ "RelayState": "/some/deep/link",
281
+ "onetimetoken": generate_one_time_token(),
282
+ }
283
+ sso_url = origin_sso_url + "?" + urlencode(url_parameters)
284
+ headers = {
285
+ HTTP_HEADER_ACCEPT: "*/*",
286
+ }
287
+ remaining_timeout = timeout_time - time.time() if timeout_time else None
288
+ response_html = conn._rest.fetch(
289
+ "get",
290
+ sso_url,
291
+ headers,
292
+ timeout=remaining_timeout,
293
+ socket_timeout=remaining_timeout,
294
+ is_raw_text=True,
295
+ is_okta_authentication=True,
296
+ )
297
+ break
298
+ except RefreshTokenError:
299
+ logger.debug("step4: refresh token for re-authentication")
300
+ return response_html
301
+
302
+ def _step5(
303
+ self,
304
+ conn: SnowflakeConnection,
305
+ response_html: str,
306
+ ) -> None:
307
+ logger.debug("step 5: validate post_back_url matches Snowflake URL")
308
+ post_back_url = _get_post_back_url_from_html(response_html)
309
+ full_url = "{protocol}://{host}:{port}".format(
310
+ protocol=conn._rest._protocol,
311
+ host=conn._rest._host,
312
+ port=conn._rest._port,
313
+ )
314
+ if not getattr(conn, "_disable_saml_url_check", False) and not _is_prefix_equal(
315
+ post_back_url, full_url
316
+ ):
317
+ Error.errorhandler_wrapper(
318
+ conn._rest._connection,
319
+ None,
320
+ DatabaseError,
321
+ {
322
+ "msg": (
323
+ "The specified authenticator and destination "
324
+ "URL in the SAML assertion do not match: "
325
+ "expected: {url}, "
326
+ "post back: {post_back_url}".format(
327
+ url=full_url,
328
+ post_back_url=post_back_url,
329
+ )
330
+ ),
331
+ "errno": ER_INCORRECT_DESTINATION,
332
+ "sqlstate": SQLSTATE_CONNECTION_WAS_NOT_ESTABLISHED,
333
+ },
334
+ )
335
+ self._saml_response = response_html
@@ -0,0 +1,39 @@
1
+ from __future__ import annotations
2
+
3
+ import typing
4
+
5
+ from snowflake.connector.network import PROGRAMMATIC_ACCESS_TOKEN
6
+
7
+ from .by_plugin import AuthByPlugin, AuthType
8
+
9
+
10
+ class AuthByPAT(AuthByPlugin):
11
+
12
+ def __init__(self, pat_token: str, **kwargs) -> None:
13
+ super().__init__(**kwargs)
14
+ self._pat_token: str | None = pat_token
15
+
16
+ def type_(self) -> AuthType:
17
+ return AuthType.PAT
18
+
19
+ def reset_secrets(self) -> None:
20
+ self._pat_token = None
21
+
22
+ def update_body(self, body: dict[typing.Any, typing.Any]) -> None:
23
+ body["data"]["AUTHENTICATOR"] = PROGRAMMATIC_ACCESS_TOKEN
24
+ body["data"]["TOKEN"] = self._pat_token
25
+
26
+ def prepare(
27
+ self,
28
+ **kwargs: typing.Any,
29
+ ) -> None:
30
+ """Nothing to do here, token should be obtained outside the driver."""
31
+ pass
32
+
33
+ def reauthenticate(self, **kwargs: typing.Any) -> dict[str, bool]:
34
+ return {"success": False}
35
+
36
+ @property
37
+ def assertion_content(self) -> str | None:
38
+ """Returns the token."""
39
+ return self._pat_token
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env python
2
+ from __future__ import annotations
3
+
4
+ import logging
5
+ from typing import TYPE_CHECKING, Any
6
+
7
+ from ..errorcode import ER_NO_PASSWORD
8
+ from ..errors import ProgrammingError
9
+ from .by_plugin import AuthByPlugin, AuthType
10
+
11
+ if TYPE_CHECKING:
12
+ from .. import SnowflakeConnection
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+ MFA_TOKEN = "MFATOKEN"
17
+
18
+
19
+ class AuthByUsrPwdMfa(AuthByPlugin):
20
+ """Username & password & mfa authenticator."""
21
+
22
+ @property
23
+ def assertion_content(self) -> str:
24
+ return "*********"
25
+
26
+ def __init__(
27
+ self,
28
+ password: str,
29
+ mfa_token: str | None = None,
30
+ **kwargs,
31
+ ) -> None:
32
+ """Initializes and instance with a password and a mfa token."""
33
+ super().__init__(**kwargs)
34
+ self._password: str | None = password
35
+ self._mfa_token: str | None = mfa_token
36
+
37
+ def reset_secrets(self) -> None:
38
+ self._password = None
39
+ self._mfa_token = None
40
+
41
+ @property
42
+ def type_(self) -> AuthType:
43
+ return AuthType.USR_PWD_MFA
44
+
45
+ def prepare(
46
+ self,
47
+ *,
48
+ conn: SnowflakeConnection,
49
+ **kwargs: Any,
50
+ ) -> None:
51
+ if conn._rest and conn._rest.mfa_token:
52
+ self._mfa_token = conn._rest.mfa_token
53
+
54
+ def reauthenticate(self, **kwargs) -> dict[str, bool]:
55
+ return {"success": False}
56
+
57
+ def update_body(self, body: dict[Any, Any]) -> None:
58
+ """Sets the password and mfa_token if available.
59
+
60
+ Don't set body['data']['AUTHENTICATOR'], since this is still snowflake default authenticator.
61
+ """
62
+ if not self._password:
63
+ raise ProgrammingError(
64
+ msg="Password for username password authenticator is empty.",
65
+ errno=ER_NO_PASSWORD,
66
+ )
67
+ body["data"]["PASSWORD"] = self._password
68
+ if self._mfa_token:
69
+ body["data"]["TOKEN"] = self._mfa_token