config.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. # Copyright (c) "Neo4j"
  2. # Neo4j Sweden AB [https://neo4j.com]
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # https://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. from __future__ import annotations
  16. import typing as t
  17. from .._async_compat.concurrency import AsyncLock
  18. from .._conf import (
  19. _trust_to_trusted_certificates,
  20. Config,
  21. DeprecatedAlternative,
  22. TrustAll,
  23. TrustCustomCAs,
  24. TrustSystemCAs,
  25. )
  26. if t.TYPE_CHECKING:
  27. import ssl
  28. from .._auth_management import ClientCertificate
  29. class AsyncPoolConfig(Config):
  30. """Connection pool configuration."""
  31. #: Max Connection Lifetime
  32. max_connection_lifetime = 3600 # seconds
  33. # The maximum duration the driver will keep a connection for before being
  34. # removed from the pool.
  35. #: Timeout after which idle connections will be checked for liveness
  36. #: before returned from the pool.
  37. liveness_check_timeout = None
  38. #: Max Connection Pool Size
  39. max_connection_pool_size = 100
  40. # The maximum total number of connections allowed, per host
  41. # (i.e. cluster nodes), to be managed by the connection pool.
  42. #: Connection Timeout
  43. connection_timeout = 30.0 # seconds
  44. # The maximum amount of time to wait for a TCP connection to be
  45. # established.
  46. #: Trust
  47. trust = DeprecatedAlternative(
  48. "trusted_certificates", _trust_to_trusted_certificates
  49. )
  50. # Specify how to determine the authenticity of encryption certificates
  51. # provided by the Neo4j instance on connection.
  52. #: Custom Resolver
  53. resolver = None
  54. # Custom resolver function, returning list of resolved addresses.
  55. #: Encrypted
  56. encrypted = False
  57. # Specify whether to use an encrypted connection between the driver and
  58. # server.
  59. #: SSL Certificates to Trust
  60. trusted_certificates = TrustSystemCAs()
  61. # Specify how to determine the authenticity of encryption certificates
  62. # provided by the Neo4j instance on connection.
  63. # * `neo4j.TrustSystemCAs()`: Use system trust store. (default)
  64. # * `neo4j.TrustAll()`: Trust any certificate.
  65. # * `neo4j.TrustCustomCAs("<path>", ...)`:
  66. # Trust the specified certificate(s).
  67. #: Certificate to use for mTLS as 2nd authentication factor.
  68. client_certificate = None
  69. #: Custom SSL context to use for wrapping sockets
  70. ssl_context = None
  71. # Use any custom SSL context to wrap sockets.
  72. # Overwrites `trusted_certificates` and `encrypted`.
  73. # The use of this option is strongly discouraged.
  74. #: User Agent (Python Driver Specific)
  75. user_agent = None
  76. # Specify the client agent name.
  77. #: Socket Keep Alive (Python and .NET Driver Specific)
  78. keep_alive = True
  79. # Specify whether TCP keep-alive should be enabled.
  80. #: Authentication provider
  81. auth = None
  82. #: Lowest notification severity for the server to return
  83. notifications_min_severity = None
  84. #: List of notification classifications/categories for the server to ignore
  85. notifications_disabled_classifications = None
  86. #: Opt-Out of telemetry collection
  87. telemetry_disabled = False
  88. _ssl_context_cache: ssl.SSLContext | None
  89. _ssl_context_cache_lock: AsyncLock
  90. def __init__(self, *args, **kwargs) -> None:
  91. super().__init__(*args, **kwargs)
  92. self._ssl_context_cache = None
  93. self._ssl_context_cache_lock = AsyncLock()
  94. async def get_ssl_context(self) -> ssl.SSLContext | None:
  95. if self.ssl_context is not None:
  96. return self.ssl_context
  97. if not self.encrypted:
  98. return None
  99. client_cert: ClientCertificate | None = None
  100. # try to serve the cached ssl context
  101. async with self._ssl_context_cache_lock:
  102. if self._ssl_context_cache is not None:
  103. if self.client_certificate is None:
  104. return self._ssl_context_cache
  105. client_cert = await self.client_certificate.get_certificate()
  106. if client_cert is None:
  107. return self._ssl_context_cache
  108. elif self.client_certificate is not None:
  109. client_cert = await self.client_certificate.get_certificate()
  110. import ssl
  111. # SSL stands for Secure Sockets Layer and was originally created by
  112. # Netscape.
  113. # SSLv2 and SSLv3 are the 2 versions of this protocol (SSLv1 was
  114. # never publicly released).
  115. # After SSLv3, SSL was renamed to TLS.
  116. # TLS stands for Transport Layer Security and started with TLSv1.0
  117. # which is an upgraded version of SSLv3.
  118. # SSLv2 - (Disabled)
  119. # SSLv3 - (Disabled)
  120. # TLS 1.0 - Released in 1999, published as RFC 2246. (Disabled)
  121. # TLS 1.1 - Released in 2006, published as RFC 4346. (Disabled)
  122. # TLS 1.2 - Released in 2008, published as RFC 5246.
  123. # https://docs.python.org/3.7/library/ssl.html#ssl.PROTOCOL_TLS_CLIENT
  124. ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
  125. # For recommended security options see
  126. # https://docs.python.org/3.10/library/ssl.html#protocol-versions
  127. ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2
  128. if isinstance(self.trusted_certificates, TrustAll):
  129. # trust any certificate
  130. ssl_context.check_hostname = False
  131. # https://docs.python.org/3.7/library/ssl.html#ssl.CERT_NONE
  132. ssl_context.verify_mode = ssl.CERT_NONE
  133. elif isinstance(self.trusted_certificates, TrustCustomCAs):
  134. # trust the specified certificate(s)
  135. ssl_context.check_hostname = True
  136. ssl_context.verify_mode = ssl.CERT_REQUIRED
  137. for cert in self.trusted_certificates.certs:
  138. ssl_context.load_verify_locations(cert)
  139. else:
  140. # default
  141. # trust system CA certificates
  142. ssl_context.check_hostname = True
  143. ssl_context.verify_mode = ssl.CERT_REQUIRED
  144. # Must be load_default_certs, not set_default_verify_paths to
  145. # work on Windows with system CAs.
  146. ssl_context.load_default_certs()
  147. if client_cert is not None:
  148. ssl_context.load_cert_chain(
  149. client_cert.certfile,
  150. keyfile=client_cert.keyfile,
  151. password=client_cert.password,
  152. )
  153. self._ssl_context_cache = ssl_context
  154. return ssl_context