sensu-plugins-mongodb-mrtrotl 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (181) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1 -0
  3. data/LICENSE +22 -0
  4. data/README.md +27 -0
  5. data/bin/check-mongodb-metric.rb +144 -0
  6. data/bin/check-mongodb-query-count.rb +267 -0
  7. data/bin/check-mongodb.py +1644 -0
  8. data/bin/check-mongodb.rb +5 -0
  9. data/bin/metrics-mongodb-replication.rb +254 -0
  10. data/bin/metrics-mongodb.rb +133 -0
  11. data/lib/bson/__init__.py +1347 -0
  12. data/lib/bson/__pycache__/__init__.cpython-310.pyc +0 -0
  13. data/lib/bson/__pycache__/_helpers.cpython-310.pyc +0 -0
  14. data/lib/bson/__pycache__/binary.cpython-310.pyc +0 -0
  15. data/lib/bson/__pycache__/code.cpython-310.pyc +0 -0
  16. data/lib/bson/__pycache__/codec_options.cpython-310.pyc +0 -0
  17. data/lib/bson/__pycache__/dbref.cpython-310.pyc +0 -0
  18. data/lib/bson/__pycache__/decimal128.cpython-310.pyc +0 -0
  19. data/lib/bson/__pycache__/errors.cpython-310.pyc +0 -0
  20. data/lib/bson/__pycache__/int64.cpython-310.pyc +0 -0
  21. data/lib/bson/__pycache__/json_util.cpython-310.pyc +0 -0
  22. data/lib/bson/__pycache__/max_key.cpython-310.pyc +0 -0
  23. data/lib/bson/__pycache__/min_key.cpython-310.pyc +0 -0
  24. data/lib/bson/__pycache__/objectid.cpython-310.pyc +0 -0
  25. data/lib/bson/__pycache__/raw_bson.cpython-310.pyc +0 -0
  26. data/lib/bson/__pycache__/regex.cpython-310.pyc +0 -0
  27. data/lib/bson/__pycache__/son.cpython-310.pyc +0 -0
  28. data/lib/bson/__pycache__/timestamp.cpython-310.pyc +0 -0
  29. data/lib/bson/__pycache__/tz_util.cpython-310.pyc +0 -0
  30. data/lib/bson/_cbson.cpython-310-x86_64-linux-gnu.so +0 -0
  31. data/lib/bson/_helpers.py +41 -0
  32. data/lib/bson/binary.py +364 -0
  33. data/lib/bson/code.py +101 -0
  34. data/lib/bson/codec_options.py +414 -0
  35. data/lib/bson/codec_options.pyi +100 -0
  36. data/lib/bson/dbref.py +133 -0
  37. data/lib/bson/decimal128.py +314 -0
  38. data/lib/bson/errors.py +35 -0
  39. data/lib/bson/int64.py +39 -0
  40. data/lib/bson/json_util.py +874 -0
  41. data/lib/bson/max_key.py +55 -0
  42. data/lib/bson/min_key.py +55 -0
  43. data/lib/bson/objectid.py +286 -0
  44. data/lib/bson/py.typed +2 -0
  45. data/lib/bson/raw_bson.py +175 -0
  46. data/lib/bson/regex.py +135 -0
  47. data/lib/bson/son.py +208 -0
  48. data/lib/bson/timestamp.py +124 -0
  49. data/lib/bson/tz_util.py +52 -0
  50. data/lib/gridfs/__init__.py +1015 -0
  51. data/lib/gridfs/__pycache__/__init__.cpython-310.pyc +0 -0
  52. data/lib/gridfs/__pycache__/errors.cpython-310.pyc +0 -0
  53. data/lib/gridfs/__pycache__/grid_file.cpython-310.pyc +0 -0
  54. data/lib/gridfs/errors.py +33 -0
  55. data/lib/gridfs/grid_file.py +907 -0
  56. data/lib/gridfs/py.typed +2 -0
  57. data/lib/pymongo/__init__.py +185 -0
  58. data/lib/pymongo/__pycache__/__init__.cpython-310.pyc +0 -0
  59. data/lib/pymongo/__pycache__/_csot.cpython-310.pyc +0 -0
  60. data/lib/pymongo/__pycache__/aggregation.cpython-310.pyc +0 -0
  61. data/lib/pymongo/__pycache__/auth.cpython-310.pyc +0 -0
  62. data/lib/pymongo/__pycache__/auth_aws.cpython-310.pyc +0 -0
  63. data/lib/pymongo/__pycache__/bulk.cpython-310.pyc +0 -0
  64. data/lib/pymongo/__pycache__/change_stream.cpython-310.pyc +0 -0
  65. data/lib/pymongo/__pycache__/client_options.cpython-310.pyc +0 -0
  66. data/lib/pymongo/__pycache__/client_session.cpython-310.pyc +0 -0
  67. data/lib/pymongo/__pycache__/collation.cpython-310.pyc +0 -0
  68. data/lib/pymongo/__pycache__/collection.cpython-310.pyc +0 -0
  69. data/lib/pymongo/__pycache__/command_cursor.cpython-310.pyc +0 -0
  70. data/lib/pymongo/__pycache__/common.cpython-310.pyc +0 -0
  71. data/lib/pymongo/__pycache__/compression_support.cpython-310.pyc +0 -0
  72. data/lib/pymongo/__pycache__/cursor.cpython-310.pyc +0 -0
  73. data/lib/pymongo/__pycache__/daemon.cpython-310.pyc +0 -0
  74. data/lib/pymongo/__pycache__/database.cpython-310.pyc +0 -0
  75. data/lib/pymongo/__pycache__/driver_info.cpython-310.pyc +0 -0
  76. data/lib/pymongo/__pycache__/encryption.cpython-310.pyc +0 -0
  77. data/lib/pymongo/__pycache__/encryption_options.cpython-310.pyc +0 -0
  78. data/lib/pymongo/__pycache__/errors.cpython-310.pyc +0 -0
  79. data/lib/pymongo/__pycache__/event_loggers.cpython-310.pyc +0 -0
  80. data/lib/pymongo/__pycache__/hello.cpython-310.pyc +0 -0
  81. data/lib/pymongo/__pycache__/helpers.cpython-310.pyc +0 -0
  82. data/lib/pymongo/__pycache__/max_staleness_selectors.cpython-310.pyc +0 -0
  83. data/lib/pymongo/__pycache__/message.cpython-310.pyc +0 -0
  84. data/lib/pymongo/__pycache__/mongo_client.cpython-310.pyc +0 -0
  85. data/lib/pymongo/__pycache__/monitor.cpython-310.pyc +0 -0
  86. data/lib/pymongo/__pycache__/monitoring.cpython-310.pyc +0 -0
  87. data/lib/pymongo/__pycache__/network.cpython-310.pyc +0 -0
  88. data/lib/pymongo/__pycache__/ocsp_cache.cpython-310.pyc +0 -0
  89. data/lib/pymongo/__pycache__/ocsp_support.cpython-310.pyc +0 -0
  90. data/lib/pymongo/__pycache__/operations.cpython-310.pyc +0 -0
  91. data/lib/pymongo/__pycache__/periodic_executor.cpython-310.pyc +0 -0
  92. data/lib/pymongo/__pycache__/pool.cpython-310.pyc +0 -0
  93. data/lib/pymongo/__pycache__/pyopenssl_context.cpython-310.pyc +0 -0
  94. data/lib/pymongo/__pycache__/read_concern.cpython-310.pyc +0 -0
  95. data/lib/pymongo/__pycache__/read_preferences.cpython-310.pyc +0 -0
  96. data/lib/pymongo/__pycache__/response.cpython-310.pyc +0 -0
  97. data/lib/pymongo/__pycache__/results.cpython-310.pyc +0 -0
  98. data/lib/pymongo/__pycache__/saslprep.cpython-310.pyc +0 -0
  99. data/lib/pymongo/__pycache__/server.cpython-310.pyc +0 -0
  100. data/lib/pymongo/__pycache__/server_api.cpython-310.pyc +0 -0
  101. data/lib/pymongo/__pycache__/server_description.cpython-310.pyc +0 -0
  102. data/lib/pymongo/__pycache__/server_selectors.cpython-310.pyc +0 -0
  103. data/lib/pymongo/__pycache__/server_type.cpython-310.pyc +0 -0
  104. data/lib/pymongo/__pycache__/settings.cpython-310.pyc +0 -0
  105. data/lib/pymongo/__pycache__/socket_checker.cpython-310.pyc +0 -0
  106. data/lib/pymongo/__pycache__/srv_resolver.cpython-310.pyc +0 -0
  107. data/lib/pymongo/__pycache__/ssl_context.cpython-310.pyc +0 -0
  108. data/lib/pymongo/__pycache__/ssl_support.cpython-310.pyc +0 -0
  109. data/lib/pymongo/__pycache__/topology.cpython-310.pyc +0 -0
  110. data/lib/pymongo/__pycache__/topology_description.cpython-310.pyc +0 -0
  111. data/lib/pymongo/__pycache__/typings.cpython-310.pyc +0 -0
  112. data/lib/pymongo/__pycache__/uri_parser.cpython-310.pyc +0 -0
  113. data/lib/pymongo/__pycache__/write_concern.cpython-310.pyc +0 -0
  114. data/lib/pymongo/_cmessage.cpython-310-x86_64-linux-gnu.so +0 -0
  115. data/lib/pymongo/_csot.py +118 -0
  116. data/lib/pymongo/aggregation.py +229 -0
  117. data/lib/pymongo/auth.py +549 -0
  118. data/lib/pymongo/auth_aws.py +94 -0
  119. data/lib/pymongo/bulk.py +513 -0
  120. data/lib/pymongo/change_stream.py +457 -0
  121. data/lib/pymongo/client_options.py +302 -0
  122. data/lib/pymongo/client_session.py +1112 -0
  123. data/lib/pymongo/collation.py +224 -0
  124. data/lib/pymongo/collection.py +3204 -0
  125. data/lib/pymongo/command_cursor.py +353 -0
  126. data/lib/pymongo/common.py +984 -0
  127. data/lib/pymongo/compression_support.py +149 -0
  128. data/lib/pymongo/cursor.py +1345 -0
  129. data/lib/pymongo/daemon.py +141 -0
  130. data/lib/pymongo/database.py +1202 -0
  131. data/lib/pymongo/driver_info.py +42 -0
  132. data/lib/pymongo/encryption.py +884 -0
  133. data/lib/pymongo/encryption_options.py +221 -0
  134. data/lib/pymongo/errors.py +365 -0
  135. data/lib/pymongo/event_loggers.py +221 -0
  136. data/lib/pymongo/hello.py +219 -0
  137. data/lib/pymongo/helpers.py +259 -0
  138. data/lib/pymongo/max_staleness_selectors.py +114 -0
  139. data/lib/pymongo/message.py +1440 -0
  140. data/lib/pymongo/mongo_client.py +2144 -0
  141. data/lib/pymongo/monitor.py +440 -0
  142. data/lib/pymongo/monitoring.py +1801 -0
  143. data/lib/pymongo/network.py +311 -0
  144. data/lib/pymongo/ocsp_cache.py +87 -0
  145. data/lib/pymongo/ocsp_support.py +372 -0
  146. data/lib/pymongo/operations.py +507 -0
  147. data/lib/pymongo/periodic_executor.py +183 -0
  148. data/lib/pymongo/pool.py +1660 -0
  149. data/lib/pymongo/py.typed +2 -0
  150. data/lib/pymongo/pyopenssl_context.py +383 -0
  151. data/lib/pymongo/read_concern.py +75 -0
  152. data/lib/pymongo/read_preferences.py +609 -0
  153. data/lib/pymongo/response.py +109 -0
  154. data/lib/pymongo/results.py +217 -0
  155. data/lib/pymongo/saslprep.py +113 -0
  156. data/lib/pymongo/server.py +247 -0
  157. data/lib/pymongo/server_api.py +170 -0
  158. data/lib/pymongo/server_description.py +285 -0
  159. data/lib/pymongo/server_selectors.py +153 -0
  160. data/lib/pymongo/server_type.py +32 -0
  161. data/lib/pymongo/settings.py +159 -0
  162. data/lib/pymongo/socket_checker.py +104 -0
  163. data/lib/pymongo/srv_resolver.py +126 -0
  164. data/lib/pymongo/ssl_context.py +39 -0
  165. data/lib/pymongo/ssl_support.py +99 -0
  166. data/lib/pymongo/topology.py +890 -0
  167. data/lib/pymongo/topology_description.py +639 -0
  168. data/lib/pymongo/typings.py +39 -0
  169. data/lib/pymongo/uri_parser.py +624 -0
  170. data/lib/pymongo/write_concern.py +129 -0
  171. data/lib/pymongo-4.2.0.dist-info/INSTALLER +1 -0
  172. data/lib/pymongo-4.2.0.dist-info/LICENSE +201 -0
  173. data/lib/pymongo-4.2.0.dist-info/METADATA +250 -0
  174. data/lib/pymongo-4.2.0.dist-info/RECORD +167 -0
  175. data/lib/pymongo-4.2.0.dist-info/REQUESTED +0 -0
  176. data/lib/pymongo-4.2.0.dist-info/WHEEL +6 -0
  177. data/lib/pymongo-4.2.0.dist-info/top_level.txt +3 -0
  178. data/lib/sensu-plugins-mongodb/metrics.rb +391 -0
  179. data/lib/sensu-plugins-mongodb/version.rb +9 -0
  180. data/lib/sensu-plugins-mongodb.rb +1 -0
  181. metadata +407 -0
@@ -0,0 +1,2 @@
1
+ # PEP-561 Support File.
2
+ # "Package maintainers who wish to support type checking of their code MUST add a marker file named py.typed to their package supporting typing".
@@ -0,0 +1,383 @@
1
+ # Copyright 2019-present MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"); you
4
+ # may not use this file except in compliance with the License. You
5
+ # may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12
+ # implied. See the License for the specific language governing
13
+ # permissions and limitations under the License.
14
+
15
+ """A CPython compatible SSLContext implementation wrapping PyOpenSSL's
16
+ context.
17
+ """
18
+
19
+ import socket as _socket
20
+ import ssl as _stdlibssl
21
+ import sys as _sys
22
+ import time as _time
23
+ from errno import EINTR as _EINTR
24
+ from ipaddress import ip_address as _ip_address
25
+
26
+ from cryptography.x509 import load_der_x509_certificate as _load_der_x509_certificate
27
+ from OpenSSL import SSL as _SSL
28
+ from OpenSSL import crypto as _crypto
29
+ from service_identity import CertificateError as _SICertificateError
30
+ from service_identity import VerificationError as _SIVerificationError
31
+ from service_identity.pyopenssl import verify_hostname as _verify_hostname
32
+ from service_identity.pyopenssl import verify_ip_address as _verify_ip_address
33
+
34
+ from pymongo.errors import ConfigurationError as _ConfigurationError
35
+ from pymongo.errors import _CertificateError
36
+ from pymongo.ocsp_cache import _OCSPCache
37
+ from pymongo.ocsp_support import _load_trusted_ca_certs, _ocsp_callback
38
+ from pymongo.socket_checker import SocketChecker as _SocketChecker
39
+ from pymongo.socket_checker import _errno_from_exception
40
+
41
+ try:
42
+ import certifi
43
+
44
+ _HAVE_CERTIFI = True
45
+ except ImportError:
46
+ _HAVE_CERTIFI = False
47
+
48
+ PROTOCOL_SSLv23 = _SSL.SSLv23_METHOD
49
+ # Always available
50
+ OP_NO_SSLv2 = _SSL.OP_NO_SSLv2
51
+ OP_NO_SSLv3 = _SSL.OP_NO_SSLv3
52
+ OP_NO_COMPRESSION = _SSL.OP_NO_COMPRESSION
53
+ # This isn't currently documented for PyOpenSSL
54
+ OP_NO_RENEGOTIATION = getattr(_SSL, "OP_NO_RENEGOTIATION", 0)
55
+
56
+ # Always available
57
+ HAS_SNI = True
58
+ IS_PYOPENSSL = True
59
+
60
+ # Base Exception class
61
+ SSLError = _SSL.Error
62
+
63
+ # https://github.com/python/cpython/blob/v3.8.0/Modules/_ssl.c#L2995-L3002
64
+ _VERIFY_MAP = {
65
+ _stdlibssl.CERT_NONE: _SSL.VERIFY_NONE,
66
+ _stdlibssl.CERT_OPTIONAL: _SSL.VERIFY_PEER,
67
+ _stdlibssl.CERT_REQUIRED: _SSL.VERIFY_PEER | _SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
68
+ }
69
+
70
+ _REVERSE_VERIFY_MAP = dict((value, key) for key, value in _VERIFY_MAP.items())
71
+
72
+
73
+ # For SNI support. According to RFC6066, section 3, IPv4 and IPv6 literals are
74
+ # not permitted for SNI hostname.
75
+ def _is_ip_address(address):
76
+ try:
77
+ _ip_address(address)
78
+ return True
79
+ except (ValueError, UnicodeError): # noqa: B014
80
+ return False
81
+
82
+
83
+ # According to the docs for Connection.send it can raise
84
+ # WantX509LookupError and should be retried.
85
+ BLOCKING_IO_ERRORS = (_SSL.WantReadError, _SSL.WantWriteError, _SSL.WantX509LookupError)
86
+
87
+
88
+ def _ragged_eof(exc):
89
+ """Return True if the OpenSSL.SSL.SysCallError is a ragged EOF."""
90
+ return exc.args == (-1, "Unexpected EOF")
91
+
92
+
93
+ # https://github.com/pyca/pyopenssl/issues/168
94
+ # https://github.com/pyca/pyopenssl/issues/176
95
+ # https://docs.python.org/3/library/ssl.html#notes-on-non-blocking-sockets
96
+ class _sslConn(_SSL.Connection):
97
+ def __init__(self, ctx, sock, suppress_ragged_eofs):
98
+ self.socket_checker = _SocketChecker()
99
+ self.suppress_ragged_eofs = suppress_ragged_eofs
100
+ super(_sslConn, self).__init__(ctx, sock)
101
+
102
+ def _call(self, call, *args, **kwargs):
103
+ timeout = self.gettimeout()
104
+ if timeout:
105
+ start = _time.monotonic()
106
+ while True:
107
+ try:
108
+ return call(*args, **kwargs)
109
+ except BLOCKING_IO_ERRORS as exc:
110
+ if isinstance(exc, _SSL.WantReadError):
111
+ want_read = True
112
+ want_write = False
113
+ elif isinstance(exc, _SSL.WantWriteError):
114
+ want_read = False
115
+ want_write = True
116
+ else:
117
+ want_read = True
118
+ want_write = True
119
+ self.socket_checker.select(self, want_read, want_write, timeout)
120
+ if timeout and _time.monotonic() - start > timeout:
121
+ raise _socket.timeout("timed out")
122
+ continue
123
+
124
+ def do_handshake(self, *args, **kwargs):
125
+ return self._call(super(_sslConn, self).do_handshake, *args, **kwargs)
126
+
127
+ def recv(self, *args, **kwargs):
128
+ try:
129
+ return self._call(super(_sslConn, self).recv, *args, **kwargs)
130
+ except _SSL.SysCallError as exc:
131
+ # Suppress ragged EOFs to match the stdlib.
132
+ if self.suppress_ragged_eofs and _ragged_eof(exc):
133
+ return b""
134
+ raise
135
+
136
+ def recv_into(self, *args, **kwargs):
137
+ try:
138
+ return self._call(super(_sslConn, self).recv_into, *args, **kwargs) # type: ignore
139
+ except _SSL.SysCallError as exc:
140
+ # Suppress ragged EOFs to match the stdlib.
141
+ if self.suppress_ragged_eofs and _ragged_eof(exc):
142
+ return 0
143
+ raise
144
+
145
+ def sendall(self, buf, flags=0):
146
+ view = memoryview(buf)
147
+ total_length = len(buf)
148
+ total_sent = 0
149
+ sent = 0
150
+ while total_sent < total_length:
151
+ try:
152
+ sent = self._call(
153
+ super(_sslConn, self).send, view[total_sent:], flags # type: ignore
154
+ )
155
+ # XXX: It's not clear if this can actually happen. PyOpenSSL
156
+ # doesn't appear to have any interrupt handling, nor any interrupt
157
+ # errors for OpenSSL connections.
158
+ except (IOError, OSError) as exc: # noqa: B014
159
+ if _errno_from_exception(exc) == _EINTR:
160
+ continue
161
+ raise
162
+ # https://github.com/pyca/pyopenssl/blob/19.1.0/src/OpenSSL/SSL.py#L1756
163
+ # https://www.openssl.org/docs/man1.0.2/man3/SSL_write.html
164
+ if sent <= 0:
165
+ raise Exception("Connection closed")
166
+ total_sent += sent
167
+
168
+
169
+ class _CallbackData(object):
170
+ """Data class which is passed to the OCSP callback."""
171
+
172
+ def __init__(self):
173
+ self.trusted_ca_certs = None
174
+ self.check_ocsp_endpoint = None
175
+ self.ocsp_response_cache = _OCSPCache()
176
+
177
+
178
+ class SSLContext(object):
179
+ """A CPython compatible SSLContext implementation wrapping PyOpenSSL's
180
+ context.
181
+ """
182
+
183
+ __slots__ = ("_protocol", "_ctx", "_callback_data", "_check_hostname")
184
+
185
+ def __init__(self, protocol):
186
+ self._protocol = protocol
187
+ self._ctx = _SSL.Context(self._protocol)
188
+ self._callback_data = _CallbackData()
189
+ self._check_hostname = True
190
+ # OCSP
191
+ # XXX: Find a better place to do this someday, since this is client
192
+ # side configuration and wrap_socket tries to support both client and
193
+ # server side sockets.
194
+ self._callback_data.check_ocsp_endpoint = True
195
+ self._ctx.set_ocsp_client_callback(callback=_ocsp_callback, data=self._callback_data)
196
+
197
+ @property
198
+ def protocol(self):
199
+ """The protocol version chosen when constructing the context.
200
+ This attribute is read-only.
201
+ """
202
+ return self._protocol
203
+
204
+ def __get_verify_mode(self):
205
+ """Whether to try to verify other peers' certificates and how to
206
+ behave if verification fails. This attribute must be one of
207
+ ssl.CERT_NONE, ssl.CERT_OPTIONAL or ssl.CERT_REQUIRED.
208
+ """
209
+ return _REVERSE_VERIFY_MAP[self._ctx.get_verify_mode()]
210
+
211
+ def __set_verify_mode(self, value):
212
+ """Setter for verify_mode."""
213
+
214
+ def _cb(connobj, x509obj, errnum, errdepth, retcode):
215
+ # It seems we don't need to do anything here. Twisted doesn't,
216
+ # and OpenSSL's SSL_CTX_set_verify let's you pass NULL
217
+ # for the callback option. It's weird that PyOpenSSL requires
218
+ # this.
219
+ return retcode
220
+
221
+ self._ctx.set_verify(_VERIFY_MAP[value], _cb)
222
+
223
+ verify_mode = property(__get_verify_mode, __set_verify_mode)
224
+
225
+ def __get_check_hostname(self):
226
+ return self._check_hostname
227
+
228
+ def __set_check_hostname(self, value):
229
+ if not isinstance(value, bool):
230
+ raise TypeError("check_hostname must be True or False")
231
+ self._check_hostname = value
232
+
233
+ check_hostname = property(__get_check_hostname, __set_check_hostname)
234
+
235
+ def __get_check_ocsp_endpoint(self):
236
+ return self._callback_data.check_ocsp_endpoint
237
+
238
+ def __set_check_ocsp_endpoint(self, value):
239
+ if not isinstance(value, bool):
240
+ raise TypeError("check_ocsp must be True or False")
241
+ self._callback_data.check_ocsp_endpoint = value
242
+
243
+ check_ocsp_endpoint = property(__get_check_ocsp_endpoint, __set_check_ocsp_endpoint)
244
+
245
+ def __get_options(self):
246
+ # Calling set_options adds the option to the existing bitmask and
247
+ # returns the new bitmask.
248
+ # https://www.pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Context.set_options
249
+ return self._ctx.set_options(0)
250
+
251
+ def __set_options(self, value):
252
+ # Explcitly convert to int, since newer CPython versions
253
+ # use enum.IntFlag for options. The values are the same
254
+ # regardless of implementation.
255
+ self._ctx.set_options(int(value))
256
+
257
+ options = property(__get_options, __set_options)
258
+
259
+ def load_cert_chain(self, certfile, keyfile=None, password=None):
260
+ """Load a private key and the corresponding certificate. The certfile
261
+ string must be the path to a single file in PEM format containing the
262
+ certificate as well as any number of CA certificates needed to
263
+ establish the certificate's authenticity. The keyfile string, if
264
+ present, must point to a file containing the private key. Otherwise
265
+ the private key will be taken from certfile as well.
266
+ """
267
+ # Match CPython behavior
268
+ # https://github.com/python/cpython/blob/v3.8.0/Modules/_ssl.c#L3930-L3971
269
+ # Password callback MUST be set first or it will be ignored.
270
+ if password:
271
+
272
+ def _pwcb(max_length, prompt_twice, user_data):
273
+ # XXX:We could check the password length against what OpenSSL
274
+ # tells us is the max, but we can't raise an exception, so...
275
+ # warn?
276
+ return password.encode("utf-8")
277
+
278
+ self._ctx.set_passwd_cb(_pwcb)
279
+ self._ctx.use_certificate_chain_file(certfile)
280
+ self._ctx.use_privatekey_file(keyfile or certfile)
281
+ self._ctx.check_privatekey()
282
+
283
+ def load_verify_locations(self, cafile=None, capath=None):
284
+ """Load a set of "certification authority"(CA) certificates used to
285
+ validate other peers' certificates when `~verify_mode` is other than
286
+ ssl.CERT_NONE.
287
+ """
288
+ self._ctx.load_verify_locations(cafile, capath)
289
+ # Manually load the CA certs when get_verified_chain is not available (pyopenssl<20).
290
+ if not hasattr(_SSL.Connection, "get_verified_chain"):
291
+ self._callback_data.trusted_ca_certs = _load_trusted_ca_certs(cafile)
292
+
293
+ def _load_certifi(self):
294
+ """Attempt to load CA certs from certifi."""
295
+ if _HAVE_CERTIFI:
296
+ self.load_verify_locations(certifi.where())
297
+ else:
298
+ raise _ConfigurationError(
299
+ "tlsAllowInvalidCertificates is False but no system "
300
+ "CA certificates could be loaded. Please install the "
301
+ "certifi package, or provide a path to a CA file using "
302
+ "the tlsCAFile option"
303
+ )
304
+
305
+ def _load_wincerts(self, store):
306
+ """Attempt to load CA certs from Windows trust store."""
307
+ cert_store = self._ctx.get_cert_store()
308
+ oid = _stdlibssl.Purpose.SERVER_AUTH.oid
309
+ for cert, encoding, trust in _stdlibssl.enum_certificates(store): # type: ignore
310
+ if encoding == "x509_asn":
311
+ if trust is True or oid in trust:
312
+ cert_store.add_cert(
313
+ _crypto.X509.from_cryptography(_load_der_x509_certificate(cert))
314
+ )
315
+
316
+ def load_default_certs(self):
317
+ """A PyOpenSSL version of load_default_certs from CPython."""
318
+ # PyOpenSSL is incapable of loading CA certs from Windows, and mostly
319
+ # incapable on macOS.
320
+ # https://www.pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Context.set_default_verify_paths
321
+ if _sys.platform == "win32":
322
+ try:
323
+ for storename in ("CA", "ROOT"):
324
+ self._load_wincerts(storename)
325
+ except PermissionError:
326
+ # Fall back to certifi
327
+ self._load_certifi()
328
+ elif _sys.platform == "darwin":
329
+ self._load_certifi()
330
+ self._ctx.set_default_verify_paths()
331
+
332
+ def set_default_verify_paths(self):
333
+ """Specify that the platform provided CA certificates are to be used
334
+ for verification purposes."""
335
+ # Note: See PyOpenSSL's docs for limitations, which are similar
336
+ # but not that same as CPython's.
337
+ self._ctx.set_default_verify_paths()
338
+
339
+ def wrap_socket(
340
+ self,
341
+ sock,
342
+ server_side=False,
343
+ do_handshake_on_connect=True,
344
+ suppress_ragged_eofs=True,
345
+ server_hostname=None,
346
+ session=None,
347
+ ):
348
+ """Wrap an existing Python socket sock and return a TLS socket
349
+ object.
350
+ """
351
+ ssl_conn = _sslConn(self._ctx, sock, suppress_ragged_eofs)
352
+ if session:
353
+ ssl_conn.set_session(session)
354
+ if server_side is True:
355
+ ssl_conn.set_accept_state()
356
+ else:
357
+ # SNI
358
+ if server_hostname and not _is_ip_address(server_hostname):
359
+ # XXX: Do this in a callback registered with
360
+ # SSLContext.set_info_callback? See Twisted for an example.
361
+ ssl_conn.set_tlsext_host_name(server_hostname.encode("idna"))
362
+ if self.verify_mode != _stdlibssl.CERT_NONE:
363
+ # Request a stapled OCSP response.
364
+ ssl_conn.request_ocsp()
365
+ ssl_conn.set_connect_state()
366
+ # If this wasn't true the caller of wrap_socket would call
367
+ # do_handshake()
368
+ if do_handshake_on_connect:
369
+ # XXX: If we do hostname checking in a callback we can get rid
370
+ # of this call to do_handshake() since the handshake
371
+ # will happen automatically later.
372
+ ssl_conn.do_handshake()
373
+ # XXX: Do this in a callback registered with
374
+ # SSLContext.set_info_callback? See Twisted for an example.
375
+ if self.check_hostname and server_hostname is not None:
376
+ try:
377
+ if _is_ip_address(server_hostname):
378
+ _verify_ip_address(ssl_conn, server_hostname)
379
+ else:
380
+ _verify_hostname(ssl_conn, server_hostname)
381
+ except (_SICertificateError, _SIVerificationError) as exc:
382
+ raise _CertificateError(str(exc))
383
+ return ssl_conn
@@ -0,0 +1,75 @@
1
+ # Copyright 2015 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License",
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Tools for working with read concerns."""
16
+
17
+ from typing import Any, Dict, Optional
18
+
19
+
20
+ class ReadConcern(object):
21
+ """ReadConcern
22
+
23
+ :Parameters:
24
+ - `level`: (string) The read concern level specifies the level of
25
+ isolation for read operations. For example, a read operation using a
26
+ read concern level of ``majority`` will only return data that has been
27
+ written to a majority of nodes. If the level is left unspecified, the
28
+ server default will be used.
29
+
30
+ .. versionadded:: 3.2
31
+
32
+ """
33
+
34
+ def __init__(self, level: Optional[str] = None) -> None:
35
+ if level is None or isinstance(level, str):
36
+ self.__level = level
37
+ else:
38
+ raise TypeError("level must be a string or None.")
39
+
40
+ @property
41
+ def level(self) -> Optional[str]:
42
+ """The read concern level."""
43
+ return self.__level
44
+
45
+ @property
46
+ def ok_for_legacy(self) -> bool:
47
+ """Return ``True`` if this read concern is compatible with
48
+ old wire protocol versions."""
49
+ return self.level is None or self.level == "local"
50
+
51
+ @property
52
+ def document(self) -> Dict[str, Any]:
53
+ """The document representation of this read concern.
54
+
55
+ .. note::
56
+ :class:`ReadConcern` is immutable. Mutating the value of
57
+ :attr:`document` does not mutate this :class:`ReadConcern`.
58
+ """
59
+ doc = {}
60
+ if self.__level:
61
+ doc["level"] = self.level
62
+ return doc
63
+
64
+ def __eq__(self, other: Any) -> bool:
65
+ if isinstance(other, ReadConcern):
66
+ return self.document == other.document
67
+ return NotImplemented
68
+
69
+ def __repr__(self):
70
+ if self.level:
71
+ return "ReadConcern(%s)" % self.level
72
+ return "ReadConcern()"
73
+
74
+
75
+ DEFAULT_READ_CONCERN = ReadConcern()