Skip to content

Commit 8a817f7

Browse files
committed
RDBC-788 Secured Changes API
1 parent 6e7b87e commit 8a817f7

File tree

6 files changed

+83
-18
lines changed

6 files changed

+83
-18
lines changed

ravendb/changes/database_changes.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
import ssl
12
from threading import Lock
23
from typing import TYPE_CHECKING, Dict
34

5+
from websocket import WebSocket
6+
47
from ravendb.changes.observers import Observable
58
from ravendb.changes.types import (
69
DocumentChange,
@@ -66,16 +69,16 @@ def do_work(self):
6669
while not self._closed:
6770
try:
6871
if not self.client_websocket.connected:
69-
# todo: certificates
70-
# if self._request_executor.certificate:
71-
# if isinstance(self._request_executor.certificate, tuple):
72-
# (crt, key) = self._request_executor.certificate
73-
# self.client_websocket.sock_opt.sslopt.update({"certfile": crt, "keyfile": key})
74-
# else:
75-
# self.client_websocket.sock_opt.sslopt.update(
76-
# {"ca_certs": self._request_executor.certificate}
77-
# )
78-
self.client_websocket.connect(url)
72+
# Get certificate and wrap socket into secured socket
73+
if self._request_executor.certificate_path:
74+
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
75+
ssl_context.load_cert_chain(self._request_executor.certificate_path)
76+
self.client_websocket = WebSocket(sslopt={"context": ssl_context})
77+
78+
self.client_websocket.connect(url, suppress_origin=True)
79+
else:
80+
self.client_websocket.connect(url)
81+
7982
for observables in self._observables.values():
8083
for observer in observables.values():
8184
observer.set(self._executor.submit(observer.on_connect))

ravendb/serverwide/operations/common.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,8 @@ def __init__(
143143

144144
def create_request(self, node: ServerNode) -> requests.Request:
145145
url = (
146-
f"{node.url}/admin/databases?name={self.__database_name}&replicationFactor={self.__replication_factor}"
146+
f"{node.url}/admin/databases?name={self.__database_name}"
147+
f"&replicationFactor={self.__replication_factor}&?raft-request-id={self.get_raft_unique_request_id}"
147148
)
148149

149150
request = requests.Request("PUT")

ravendb/tests/jvm_migrated_tests/client_tests/indexing_tests/test_indexes_from_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ def test_can_stop_and_start(self):
173173

174174
self.assertEqual(IndexRunningStatus.RUNNING, status.status)
175175

176-
self.assertEquals(1, len(status.indexes))
176+
self.assertEqual(1, len(status.indexes))
177177

178178
self.assertEqual(IndexRunningStatus.RUNNING, status.indexes[0].status)
179179

ravendb/tests/jvm_migrated_tests/issues_tests/test_ravenDB_6967.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def test_can_delete_index_errors(self):
7878
index_errors3 = self.store.maintenance.send(GetIndexErrorsOperation("Index3"))
7979

8080
self.assertGreater(sum([len(x.errors) for x in index_errors1]), 0)
81-
self.assertEquals(sum([len(x.errors) for x in index_errors2]), 0)
81+
self.assertEqual(sum([len(x.errors) for x in index_errors2]), 0)
8282
self.assertGreater(sum([len(x.errors) for x in index_errors3]), 0)
8383

8484
self.store.maintenance.send(DeleteIndexErrorsOperation())
@@ -87,8 +87,8 @@ def test_can_delete_index_errors(self):
8787
index_errors2 = self.store.maintenance.send(GetIndexErrorsOperation("Index2"))
8888
index_errors3 = self.store.maintenance.send(GetIndexErrorsOperation("Index3"))
8989

90-
self.assertEquals(sum([len(x.errors) for x in index_errors1]), 0)
91-
self.assertEquals(sum([len(x.errors) for x in index_errors2]), 0)
92-
self.assertEquals(sum([len(x.errors) for x in index_errors3]), 0)
90+
self.assertEqual(sum([len(x.errors) for x in index_errors1]), 0)
91+
self.assertEqual(sum([len(x.errors) for x in index_errors2]), 0)
92+
self.assertEqual(sum([len(x.errors) for x in index_errors3]), 0)
9393

9494
RavenTestHelper.assert_no_index_errors(self.store)

ravendb/tests/jvm_migrated_tests/server_tests/documents/notifications/test_changes.py

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from ravendb import AbstractIndexCreationTask, SetIndexesPriorityOperation
55
from ravendb.changes.observers import ActionObserver
6-
from ravendb.changes.types import DocumentChange, IndexChange
6+
from ravendb.changes.types import DocumentChange, IndexChange, DocumentChangeType
77
from ravendb.documents.indexes.definitions import IndexPriority
88
from ravendb.infrastructure.entities import User
99
from ravendb.infrastructure.orders import Order
@@ -235,3 +235,62 @@ def __ev(value: DocumentChange):
235235
self.assertEqual("users/2", document_changes[1].key)
236236

237237
close_action()
238+
239+
def test_changes_with_https(self):
240+
event = Event()
241+
changes_list = []
242+
exception = None
243+
244+
def _on_error(e):
245+
nonlocal exception
246+
exception = e
247+
248+
changes = self.secured_document_store.changes(on_error=_on_error)
249+
observable = changes.for_document("users/1")
250+
251+
def __ev(value: DocumentChange):
252+
changes_list.append(value)
253+
event.set()
254+
255+
observer = ActionObserver(__ev)
256+
close_action = observable.subscribe_with_observer(observer)
257+
try:
258+
observable.ensure_subscribe_now()
259+
except Exception:
260+
raise exception
261+
262+
with self.secured_document_store.open_session() as session:
263+
user = User()
264+
session.store(user, "users/1")
265+
session.save_changes()
266+
267+
event.wait(2)
268+
document_change = changes_list[0]
269+
self.assertIsNotNone(document_change)
270+
self.assertEqual("users/1", document_change.key)
271+
self.assertEqual(DocumentChangeType.PUT, document_change.type_of_change)
272+
273+
changes_list.clear()
274+
275+
try:
276+
event.wait(1)
277+
except Exception:
278+
pass
279+
280+
self.assertEqual(0, len(changes_list))
281+
close_action()
282+
# at this point we should be unsubscribed from changes on 'users/1'
283+
284+
with self.secured_document_store.open_session() as session:
285+
user = User()
286+
user.name = "another name"
287+
session.store(user, "users/1")
288+
session.save_changes()
289+
290+
# it should be empty
291+
try:
292+
event.wait(1)
293+
except Exception:
294+
pass
295+
296+
self.assertEqual(0, len(changes_list))

ravendb/util/tcp_utils.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ def connect(
1717
) -> socket.socket:
1818
hostname, port = url_string.replace("tcp://", "").split(":")
1919
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
20+
2021
is_ssl_socket = server_certificate_base64 and client_certificate_pem_path
21-
if server_certificate_base64 and client_certificate_pem_path:
22+
if is_ssl_socket:
2223
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
2324
context.load_cert_chain(client_certificate_pem_path, password=certificate_private_key_password)
2425
s = context.wrap_socket(s)
26+
2527
s.connect((hostname, int(port)))
2628
if is_ssl_socket and base64.b64decode(server_certificate_base64) != s.getpeercert(True):
2729
raise ConnectionError("Failed to validate public server certificate.")

0 commit comments

Comments
 (0)