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,219 @@
1
+ #!/usr/bin/env python
2
+ from __future__ import annotations
3
+
4
+ """This module implements the base class for authenticator classes.
5
+
6
+ Note:
7
+ **kwargs are added to most functions so that child classes can safely ignore extra in
8
+ arguments in case of a caller API change and named arguments are enforced to prevent
9
+ issues with argument being sent in out of order.
10
+ """
11
+
12
+ import logging
13
+ import time
14
+ from abc import ABC, abstractmethod
15
+ from enum import Enum, unique
16
+ from os import getenv
17
+ from typing import TYPE_CHECKING, Any, Iterator
18
+
19
+ from ..errorcode import ER_FAILED_TO_CONNECT_TO_DB
20
+ from ..errors import DatabaseError, Error, OperationalError
21
+ from ..sqlstate import SQLSTATE_CONNECTION_WAS_NOT_ESTABLISHED
22
+ from ..time_util import TimeoutBackoffCtx
23
+
24
+ if TYPE_CHECKING:
25
+ from .. import SnowflakeConnection
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+ """
30
+ Default value for max retry is 1 because
31
+ Python requests module already tries twice
32
+ by default. Unlike JWT where we need to refresh
33
+ token every 10 seconds, general authenticators
34
+ wait for 60 seconds before connection timeout
35
+ per attempt totaling a 240 sec wait time for a non
36
+ JWT based authenticator which is more than enough.
37
+ This can be changed ofcourse using MAX_CNXN_RETRY_ATTEMPTS
38
+ env variable.
39
+ """
40
+ DEFAULT_MAX_CON_RETRY_ATTEMPTS = 1
41
+ DEFAULT_AUTH_CLASS_TIMEOUT = 120
42
+
43
+
44
+ @unique
45
+ class AuthType(Enum):
46
+ DEFAULT = "SNOWFLAKE" # default authenticator name
47
+ EXTERNAL_BROWSER = "EXTERNALBROWSER"
48
+ KEY_PAIR = "SNOWFLAKE_JWT"
49
+ OAUTH = "OAUTH"
50
+ ID_TOKEN = "ID_TOKEN"
51
+ USR_PWD_MFA = "USERNAME_PASSWORD_MFA"
52
+ OKTA = "OKTA"
53
+ PAT = "PROGRAMMATIC_ACCESS_TOKEN'"
54
+ NO_AUTH = "NO_AUTH"
55
+ WORKLOAD_IDENTITY = "WORKLOAD_IDENTITY"
56
+ PAT_WITH_EXTERNAL_SESSION = "PAT_WITH_EXTERNAL_SESSION"
57
+
58
+
59
+ class AuthByPlugin(ABC):
60
+ """External Authenticator interface."""
61
+
62
+ def __init__(
63
+ self,
64
+ timeout: int | None = None,
65
+ backoff_generator: Iterator | None = None,
66
+ **kwargs,
67
+ ) -> None:
68
+ self.consent_cache_id_token = False
69
+
70
+ self._retry_ctx = TimeoutBackoffCtx(
71
+ timeout=timeout if timeout is not None else DEFAULT_AUTH_CLASS_TIMEOUT,
72
+ max_retry_attempts=kwargs.get(
73
+ "max_retry_attempts",
74
+ int(getenv("MAX_CON_RETRY_ATTEMPTS", DEFAULT_MAX_CON_RETRY_ATTEMPTS)),
75
+ ),
76
+ backoff_generator=backoff_generator,
77
+ )
78
+
79
+ # some authenticators may want to override socket level timeout
80
+ # for example, AuthByKeyPair will set this to ensure JWT tokens are refreshed in time
81
+ # if not None, this will override socket_timeout specified in connection
82
+ self._socket_timeout = None
83
+
84
+ @property
85
+ def timeout(self) -> int:
86
+ """The timeout of _retry_ctx is guaranteed not to be None during AuthByPlugin initialization"""
87
+ return self._retry_ctx.timeout
88
+
89
+ @timeout.setter
90
+ def timeout(self) -> None:
91
+ logger.warning(
92
+ "Attempting to mutate timeout of AuthByPlugin. Create a new instance with desired parameters instead."
93
+ )
94
+
95
+ @property
96
+ @abstractmethod
97
+ def type_(self) -> AuthType:
98
+ """Return the Snowflake friendly name of auth class."""
99
+ raise NotImplementedError
100
+
101
+ @property
102
+ @abstractmethod
103
+ def assertion_content(self) -> str:
104
+ """Return a safe version of the information used to authenticate with Snowflake.
105
+
106
+ This is used for logging, useful for printing temporary tokens, but make sure to
107
+ mask secrets.
108
+ """
109
+ raise NotImplementedError
110
+
111
+ @abstractmethod
112
+ def prepare(
113
+ self,
114
+ *,
115
+ conn: SnowflakeConnection,
116
+ authenticator: str,
117
+ service_name: str | None,
118
+ account: str,
119
+ user: str,
120
+ password: str | None,
121
+ **kwargs: Any,
122
+ ) -> str | None:
123
+ """Prepare for authentication.
124
+
125
+ This function is useful for situations where we need to reach out to a 3rd-party
126
+ service before authenticating with Snowflake.
127
+ """
128
+ raise NotImplementedError
129
+
130
+ @abstractmethod
131
+ def update_body(self, body: dict[Any, Any]) -> None:
132
+ """Update the body of the authentication request."""
133
+ raise NotImplementedError
134
+
135
+ @abstractmethod
136
+ def reset_secrets(self) -> None:
137
+ """Reset secret members."""
138
+ raise NotImplementedError
139
+
140
+ @abstractmethod
141
+ def reauthenticate(
142
+ self,
143
+ *,
144
+ conn: SnowflakeConnection,
145
+ **kwargs: Any,
146
+ ) -> dict[str, Any]:
147
+ """Re-perform authentication.
148
+
149
+ The difference between this and authentication is that secrets will be removed
150
+ from memory by the time this gets called.
151
+ """
152
+ raise NotImplementedError
153
+
154
+ def _handle_failure(
155
+ self,
156
+ *,
157
+ conn: SnowflakeConnection,
158
+ ret: dict[Any, Any],
159
+ **kwargs: Any,
160
+ ) -> None:
161
+ """Handles a failure when an issue happens while connecting to Snowflake.
162
+
163
+ If the user returns from this function execution will continue. The argument
164
+ data can be manipulated from within this function and so recovery is possible
165
+ from here.
166
+ """
167
+ Error.errorhandler_wrapper(
168
+ conn,
169
+ None,
170
+ DatabaseError,
171
+ {
172
+ "msg": "Failed to connect to DB: {host}:{port}, {message}".format(
173
+ host=conn._rest._host,
174
+ port=conn._rest._port,
175
+ message=ret["message"],
176
+ ),
177
+ "errno": int(ret.get("code", -1)),
178
+ "sqlstate": SQLSTATE_CONNECTION_WAS_NOT_ESTABLISHED,
179
+ },
180
+ )
181
+
182
+ def handle_timeout(
183
+ self,
184
+ *,
185
+ authenticator: str,
186
+ service_name: str | None,
187
+ account: str,
188
+ user: str,
189
+ password: str,
190
+ **kwargs: Any,
191
+ ) -> None:
192
+ """Default timeout handler.
193
+
194
+ This will trigger if the authenticator
195
+ hasn't implemented one. By default we retry on timeouts and use
196
+ jitter to deduce the time to sleep before retrying. The sleep
197
+ time ranges between 1 and 16 seconds.
198
+ """
199
+
200
+ # Some authenticators may not want to delete the parameters to this function
201
+ # Currently, the only authenticator where this is the case is AuthByKeyPair
202
+ if kwargs.pop("delete_params", True):
203
+ del authenticator, service_name, account, user, password
204
+
205
+ logger.debug("Default timeout handler invoked for authenticator")
206
+ if not self._retry_ctx.should_retry:
207
+ error = OperationalError(
208
+ msg=f"Could not connect to Snowflake backend after {self._retry_ctx.current_retry_count + 1} attempt(s)."
209
+ "Aborting",
210
+ errno=ER_FAILED_TO_CONNECT_TO_DB,
211
+ )
212
+ raise error
213
+ else:
214
+ logger.debug(
215
+ f"Hit connection timeout, attempt number {self._retry_ctx.current_retry_count + 1}."
216
+ " Will retry in a bit..."
217
+ )
218
+ time.sleep(float(self._retry_ctx.current_sleep_time))
219
+ self._retry_ctx.increment()
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env python
2
+ from __future__ import annotations
3
+
4
+ from typing import Any
5
+
6
+ from .by_plugin import AuthByPlugin, AuthType
7
+
8
+
9
+ class AuthByDefault(AuthByPlugin):
10
+ """Default username and password authenticator."""
11
+
12
+ @property
13
+ def type_(self) -> AuthType:
14
+ return AuthType.DEFAULT
15
+
16
+ @property
17
+ def assertion_content(self) -> str:
18
+ return "*********"
19
+
20
+ def __init__(self, password: str, **kwargs) -> None:
21
+ """Initializes an instance with a password."""
22
+ super().__init__(**kwargs)
23
+ self._password: str | None = password
24
+
25
+ def reset_secrets(self) -> None:
26
+ self._password = None
27
+
28
+ def prepare(self, **kwargs: Any) -> None:
29
+ pass
30
+
31
+ def reauthenticate(self, **kwargs: Any) -> dict[str, bool]:
32
+ return {"success": False}
33
+
34
+ def update_body(self, body: dict[Any, Any]) -> None:
35
+ """Sets the password if available."""
36
+ body["data"]["PASSWORD"] = self._password
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env python
2
+ from __future__ import annotations
3
+
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ from ..network import ID_TOKEN_AUTHENTICATOR
7
+ from .by_plugin import AuthByPlugin, AuthType
8
+ from .webbrowser import AuthByWebBrowser
9
+
10
+ if TYPE_CHECKING:
11
+ from ..connection import SnowflakeConnection
12
+
13
+
14
+ class AuthByIdToken(AuthByPlugin):
15
+ """Internal IdToken Based Authentication.
16
+
17
+ Works by accepting an id_toke and use that to authenticate. Only be used when users are using EXTERNAL_BROWSER_AUTHENTICATOR
18
+ """
19
+
20
+ @property
21
+ def type_(self) -> AuthType:
22
+ return AuthType.ID_TOKEN
23
+
24
+ @property
25
+ def assertion_content(self) -> str:
26
+ return self._id_token
27
+
28
+ def __init__(
29
+ self,
30
+ id_token: str,
31
+ application: str,
32
+ protocol: str | None,
33
+ host: str | None,
34
+ port: str | None,
35
+ **kwargs,
36
+ ) -> None:
37
+ """Initialized an instance with an IdToken."""
38
+ super().__init__(**kwargs)
39
+ self._id_token: str | None = id_token
40
+ self._application = application
41
+ self._protocol = protocol
42
+ self._host = host
43
+ self._port = port
44
+
45
+ def reset_secrets(self) -> None:
46
+ self._id_token = None
47
+
48
+ def prepare(self, **kwargs: Any) -> None:
49
+ pass
50
+
51
+ def reauthenticate(
52
+ self,
53
+ *,
54
+ conn: SnowflakeConnection,
55
+ **kwargs: Any,
56
+ ) -> dict[str, bool]:
57
+ conn.auth_class = AuthByWebBrowser(
58
+ application=self._application,
59
+ protocol=self._protocol,
60
+ host=self._host,
61
+ port=self._port,
62
+ timeout=conn.login_timeout,
63
+ backoff_generator=conn._backoff_generator,
64
+ )
65
+ conn._authenticate(conn.auth_class)
66
+ conn._auth_class.reset_secrets()
67
+ return {"success": True}
68
+
69
+ def update_body(self, body: dict[Any, Any]) -> None:
70
+ """Idtoken needs the authenticator and token attributes set."""
71
+ body["data"]["AUTHENTICATOR"] = ID_TOKEN_AUTHENTICATOR
72
+ body["data"]["TOKEN"] = self._id_token
@@ -0,0 +1,222 @@
1
+ #!/usr/bin/env python
2
+ from __future__ import annotations
3
+
4
+ import base64
5
+ import hashlib
6
+ import os
7
+ from datetime import datetime, timedelta, timezone
8
+ from logging import getLogger
9
+ from typing import Any
10
+
11
+ import jwt
12
+ from cryptography.hazmat.backends import default_backend
13
+ from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey
14
+ from cryptography.hazmat.primitives.serialization import (
15
+ Encoding,
16
+ PublicFormat,
17
+ load_der_private_key,
18
+ )
19
+
20
+ from ..errorcode import ER_CONNECTION_TIMEOUT, ER_INVALID_PRIVATE_KEY
21
+ from ..errors import OperationalError, ProgrammingError
22
+ from ..network import KEY_PAIR_AUTHENTICATOR
23
+ from .by_plugin import AuthByPlugin, AuthType
24
+
25
+ logger = getLogger(__name__)
26
+
27
+
28
+ class AuthByKeyPair(AuthByPlugin):
29
+ """Key pair based authentication."""
30
+
31
+ ALGORITHM = "RS256"
32
+ ISSUER = "iss"
33
+ SUBJECT = "sub"
34
+ EXPIRE_TIME = "exp"
35
+ ISSUE_TIME = "iat"
36
+ LIFETIME = 60
37
+ DEFAULT_JWT_RETRY_ATTEMPTS = 10
38
+ DEFAULT_JWT_CNXN_WAIT_TIME = 10
39
+
40
+ def __init__(
41
+ self,
42
+ private_key: bytes | str | RSAPrivateKey,
43
+ lifetime_in_seconds: int = LIFETIME,
44
+ **kwargs,
45
+ ) -> None:
46
+ """Inits AuthByKeyPair class with private key.
47
+
48
+ Args:
49
+ private_key: a byte array of der formats of private key, or an
50
+ object that implements the `RSAPrivateKey` interface.
51
+ lifetime_in_seconds: number of seconds the JWT token will be valid
52
+ """
53
+ super().__init__(
54
+ max_retry_attempts=int(
55
+ os.getenv(
56
+ "JWT_CNXN_RETRY_ATTEMPTS", AuthByKeyPair.DEFAULT_JWT_RETRY_ATTEMPTS
57
+ )
58
+ ),
59
+ **kwargs,
60
+ )
61
+
62
+ # set internal socket timeout override
63
+ self._socket_timeout = int(
64
+ timedelta(
65
+ seconds=int(
66
+ os.getenv(
67
+ "JWT_CNXN_WAIT_TIME",
68
+ AuthByKeyPair.DEFAULT_JWT_CNXN_WAIT_TIME,
69
+ )
70
+ )
71
+ ).total_seconds()
72
+ )
73
+
74
+ self._private_key: bytes | str | RSAPrivateKey | None = private_key
75
+ self._jwt_token = ""
76
+ self._jwt_token_exp = 0
77
+ self._lifetime = timedelta(
78
+ seconds=int(os.getenv("JWT_LIFETIME_IN_SECONDS", lifetime_in_seconds))
79
+ )
80
+
81
+ def reset_secrets(self) -> None:
82
+ self._private_key = None
83
+
84
+ @property
85
+ def type_(self) -> AuthType:
86
+ return AuthType.KEY_PAIR
87
+
88
+ def prepare(
89
+ self,
90
+ *,
91
+ account: str,
92
+ user: str,
93
+ **kwargs: Any,
94
+ ) -> str:
95
+ if ".global" in account:
96
+ account = account.partition("-")[0]
97
+ else:
98
+ account = account.partition(".")[0]
99
+ account = account.upper()
100
+ user = user.upper()
101
+
102
+ now = datetime.now(timezone.utc).replace(tzinfo=None)
103
+
104
+ if isinstance(self._private_key, str):
105
+ try:
106
+ self._private_key = base64.b64decode(self._private_key)
107
+ except Exception as e:
108
+ raise ProgrammingError(
109
+ msg=f"Failed to decode private key: {e}\nPlease provide a valid "
110
+ "unencrypted rsa private key in base64-encoded DER format as a "
111
+ "str object",
112
+ errno=ER_INVALID_PRIVATE_KEY,
113
+ )
114
+
115
+ if isinstance(self._private_key, bytes):
116
+ try:
117
+ private_key = load_der_private_key(
118
+ data=self._private_key,
119
+ password=None,
120
+ backend=default_backend(),
121
+ )
122
+ except Exception as e:
123
+ raise ProgrammingError(
124
+ msg=f"Failed to load private key: {e}\nPlease provide a valid "
125
+ "unencrypted rsa private key in DER format as bytes object",
126
+ errno=ER_INVALID_PRIVATE_KEY,
127
+ )
128
+
129
+ if not isinstance(private_key, RSAPrivateKey):
130
+ raise ProgrammingError(
131
+ msg=f"Private key type ({private_key.__class__.__name__}) not supported."
132
+ "\nPlease provide a valid rsa private key in DER format as bytes "
133
+ "object",
134
+ errno=ER_INVALID_PRIVATE_KEY,
135
+ )
136
+ elif isinstance(self._private_key, RSAPrivateKey):
137
+ private_key = self._private_key
138
+ else:
139
+ raise TypeError(
140
+ f"Expected bytes or RSAPrivateKey, got {type(self._private_key)}"
141
+ )
142
+
143
+ public_key_fp = self.calculate_public_key_fingerprint(private_key)
144
+
145
+ self._jwt_token_exp = now + self._lifetime
146
+ payload = {
147
+ self.ISSUER: f"{account}.{user}.{public_key_fp}",
148
+ self.SUBJECT: f"{account}.{user}",
149
+ self.ISSUE_TIME: now,
150
+ self.EXPIRE_TIME: self._jwt_token_exp,
151
+ }
152
+
153
+ _jwt_token = jwt.encode(payload, private_key, algorithm=self.ALGORITHM)
154
+
155
+ # jwt.encode() returns bytes in pyjwt 1.x and a string
156
+ # in pyjwt 2.x
157
+ if isinstance(_jwt_token, bytes):
158
+ self._jwt_token = _jwt_token.decode("utf-8")
159
+ else:
160
+ self._jwt_token = _jwt_token
161
+
162
+ return self._jwt_token
163
+
164
+ def reauthenticate(self, **kwargs: Any) -> dict[str, bool]:
165
+ return {"success": False}
166
+
167
+ @staticmethod
168
+ def calculate_public_key_fingerprint(private_key):
169
+ # get public key bytes
170
+ public_key_der = private_key.public_key().public_bytes(
171
+ Encoding.DER, PublicFormat.SubjectPublicKeyInfo
172
+ )
173
+
174
+ # take sha256 on raw bytes and then do base64 encode
175
+ sha256hash = hashlib.sha256()
176
+ sha256hash.update(public_key_der)
177
+
178
+ public_key_fp = "SHA256:" + base64.b64encode(sha256hash.digest()).decode(
179
+ "utf-8"
180
+ )
181
+ logger.debug("Public key fingerprint is %s", public_key_fp)
182
+
183
+ return public_key_fp
184
+
185
+ def update_body(self, body: dict[Any, Any]) -> None:
186
+ body["data"]["AUTHENTICATOR"] = KEY_PAIR_AUTHENTICATOR
187
+ body["data"]["TOKEN"] = self._jwt_token
188
+
189
+ def assertion_content(self) -> str:
190
+ return self._jwt_token
191
+
192
+ def should_retry(self, count: int) -> bool:
193
+ return count < self._jwt_retry_attempts
194
+
195
+ def handle_timeout(
196
+ self,
197
+ *,
198
+ authenticator: str,
199
+ service_name: str | None,
200
+ account: str,
201
+ user: str,
202
+ password: str | None,
203
+ **kwargs: Any,
204
+ ) -> None:
205
+ logger.debug("Invoking base timeout handler")
206
+ super().handle_timeout(
207
+ authenticator=authenticator,
208
+ service_name=service_name,
209
+ account=account,
210
+ user=user,
211
+ password=password,
212
+ delete_params=False,
213
+ )
214
+
215
+ logger.debug("Base timeout handler passed, preparing new token before retrying")
216
+ self.prepare(account=account, user=user)
217
+
218
+ @staticmethod
219
+ def can_handle_exception(op: OperationalError) -> bool:
220
+ if op.errno is ER_CONNECTION_TIMEOUT:
221
+ return True
222
+ return False
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env python
2
+ from __future__ import annotations
3
+
4
+ from typing import Any
5
+
6
+ from .by_plugin import AuthByPlugin, AuthType
7
+
8
+
9
+ class AuthNoAuth(AuthByPlugin):
10
+ """No-auth Authentication.
11
+
12
+ It is a dummy auth that requires no extra connection establishment.
13
+ """
14
+
15
+ @property
16
+ def type_(self) -> AuthType:
17
+ return AuthType.NO_AUTH
18
+
19
+ @property
20
+ def assertion_content(self) -> str | None:
21
+ return None
22
+
23
+ def __init__(self) -> None:
24
+ super().__init__()
25
+
26
+ def reset_secrets(self) -> None:
27
+ pass
28
+
29
+ def prepare(
30
+ self,
31
+ **kwargs: Any,
32
+ ) -> None:
33
+ pass
34
+
35
+ def reauthenticate(self, **kwargs: Any) -> dict[str, bool]:
36
+ return {"success": True}
37
+
38
+ def update_body(self, body: dict[Any, Any]) -> None:
39
+ pass
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env python
2
+ from __future__ import annotations
3
+
4
+ from typing import Any
5
+
6
+ from ..network import OAUTH_AUTHENTICATOR
7
+ from .by_plugin import AuthByPlugin, AuthType
8
+
9
+
10
+ class AuthByOAuth(AuthByPlugin):
11
+ """OAuth Based Authentication.
12
+
13
+ Works by accepting an OAuth token and using that to authenticate.
14
+ """
15
+
16
+ @property
17
+ def type_(self) -> AuthType:
18
+ return AuthType.OAUTH
19
+
20
+ @property
21
+ def assertion_content(self) -> str | None:
22
+ """Returns the token."""
23
+ return self._oauth_token
24
+
25
+ def __init__(self, oauth_token: str, **kwargs) -> None:
26
+ """Initializes an instance with an OAuth Token."""
27
+ super().__init__(**kwargs)
28
+ self._oauth_token: str | None = oauth_token
29
+
30
+ def reset_secrets(self) -> None:
31
+ self._oauth_token = None
32
+
33
+ def prepare(
34
+ self,
35
+ **kwargs: Any,
36
+ ) -> None:
37
+ """Nothing to do here, token should be obtained outside the driver."""
38
+ pass
39
+
40
+ def reauthenticate(self, **kwargs: Any) -> dict[str, bool]:
41
+ return {"success": False}
42
+
43
+ def update_body(self, body: dict[Any, Any]) -> None:
44
+ """Update some information required by OAuth.
45
+
46
+ OAuth needs the authenticator and token attributes set, as well as loginname, which is set already in auth.py.
47
+ """
48
+ body["data"]["AUTHENTICATOR"] = OAUTH_AUTHENTICATOR
49
+ body["data"]["TOKEN"] = self._oauth_token