From a0bd6e5eb034a736546c8198ad21f742c167addc Mon Sep 17 00:00:00 2001 From: Stuckinaboot Date: Tue, 30 Apr 2019 03:27:06 -0400 Subject: [PATCH] Add simple security with communication test --- tests/security/insecure_security.py | 44 --------------- tests/security/simple_security.py | 61 +++++++++++++++++++++ tests/security/test_security_multistream.py | 33 +++++------ 3 files changed, 78 insertions(+), 60 deletions(-) delete mode 100644 tests/security/insecure_security.py create mode 100644 tests/security/simple_security.py diff --git a/tests/security/insecure_security.py b/tests/security/insecure_security.py deleted file mode 100644 index c7a53afd..00000000 --- a/tests/security/insecure_security.py +++ /dev/null @@ -1,44 +0,0 @@ -from libp2p.security.security_transport_interface import ISecureTransport -from libp2p.security.security_conn_interface import ISecureConn - -class InsecureTransport(ISecureTransport): - - def __init__(self, transport_id): - self.transport_id = transport_id - - async def secure_inbound(self, conn): - """ - Secure the connection, either locally or by communicating with opposing node via conn, - for an inbound connection (i.e. we are not the initiator) - :return: secure connection object (that implements secure_conn_interface) - """ - insecure_conn = InsecureConn(conn, self.transport_id) - return insecure_conn - - async def secure_outbound(self, conn, peer_id): - """ - Secure the connection, either locally or by communicating with opposing node via conn, - for an inbound connection (i.e. we are the initiator) - :return: secure connection object (that implements secure_conn_interface) - """ - insecure_conn = InsecureConn(conn, self.transport_id) - return insecure_conn - -class InsecureConn(ISecureConn): - - def __init__(self, conn, conn_id): - self.conn = conn - self.details = {} - self.details["conn_id"] = conn_id - - def get_conn(self): - """ - :return: connection object that has been made secure - """ - return self.conn - - def get_security_details(self): - """ - :return: map containing details about the connections security - """ - return self.details diff --git a/tests/security/simple_security.py b/tests/security/simple_security.py new file mode 100644 index 00000000..5df58113 --- /dev/null +++ b/tests/security/simple_security.py @@ -0,0 +1,61 @@ +import asyncio +from libp2p.security.secure_transport_interface import ISecureTransport +from libp2p.security.secure_conn_interface import ISecureConn + +class SimpleSecurityTransport(ISecureTransport): + + def __init__(self, key_phrase): + self.key_phrase = key_phrase + + async def secure_inbound(self, conn): + """ + Secure the connection, either locally or by communicating with opposing node via conn, + for an inbound connection (i.e. we are not the initiator) + :return: secure connection object (that implements secure_conn_interface) + """ + await conn.write(self.key_phrase.encode()) + incoming = (await conn.read()).decode() + + if incoming != self.key_phrase: + raise Exception("Key phrase differed between nodes. Expected " + self.key_phrase) + + secure_conn = SimpleSecureConn(conn, self.key_phrase) + return secure_conn + + async def secure_outbound(self, conn, peer_id): + """ + Secure the connection, either locally or by communicating with opposing node via conn, + for an inbound connection (i.e. we are the initiator) + :return: secure connection object (that implements secure_conn_interface) + """ + await conn.write(self.key_phrase.encode()) + incoming = (await conn.read()).decode() + + # Force context switch, as this security transport is built for testing locally + # in a single event loop + await asyncio.sleep(0) + + if incoming != self.key_phrase: + raise Exception("Key phrase differed between nodes. Expected " + self.key_phrase) + + secure_conn = SimpleSecureConn(conn, self.key_phrase) + return secure_conn + +class SimpleSecureConn(ISecureConn): + + def __init__(self, conn, key_phrase): + self.conn = conn + self.details = {} + self.details["key_phrase"] = key_phrase + + def get_conn(self): + """ + :return: connection object that has been made secure + """ + return self.conn + + def get_security_details(self): + """ + :return: map containing details about the connections security + """ + return self.details diff --git a/tests/security/test_security_multistream.py b/tests/security/test_security_multistream.py index 8b23e16d..aae8ce3a 100644 --- a/tests/security/test_security_multistream.py +++ b/tests/security/test_security_multistream.py @@ -7,6 +7,7 @@ from libp2p.peer.peerinfo import info_from_p2p_addr from tests.utils import cleanup, set_up_nodes_by_transport_opt from libp2p.security.security_multistream import SecurityMultistream from libp2p.security.insecure_security import InsecureConn, InsecureTransport +from simple_security import SimpleSecurityTransport # TODO: Add tests for multiple streams being opened on different # protocols through the same connection @@ -42,21 +43,10 @@ async def perform_simple_test(assertion_func, transports_for_initiator, transpor await connect(node1, node2) - # Fill initiator - # sec_multi_initiator = SecurityMultistream() - # for i, transport in enumerate(transports_for_initiator): - # sec_multi_initiator.add_transport(str(i), transport) - - # # Fill non-initiator - # sec_multi_noninitiator = SecurityMultistream() - # for i, transport in enumerate(transports_for_noninitiator): - # sec_multi_noninitiator.add_transport(str(i), transport) - - # # Perform negotiation - # tasks = [] - # tasks.append(asyncio.ensure_future(sec_multi_initiator.secure_inbound(conn))) - # tasks.append(asyncio.ensure_future(sec_multi_noninitiator.secure_inbound(conn))) - # mplex_conns = await asyncio.gather(*tasks) + # Wait a very short period to allow conns to be stored (since the functions + # storing the conns are async, they may happen at slightly different times + # on each node) + await asyncio.sleep(0.1) # Get conns node1_conn = node1.get_network().connections[peer_id_for_node(node2)] @@ -71,7 +61,7 @@ async def perform_simple_test(assertion_func, transports_for_initiator, transpor @pytest.mark.asyncio -async def test_single_security_transport_succeeds(): +async def test_single_insecure_security_transport_succeeds(): transports_for_initiator = [InsecureTransport("foo")] transports_for_noninitiator = [InsecureTransport("foo")] @@ -81,3 +71,14 @@ async def test_single_security_transport_succeeds(): await perform_simple_test(assertion_func, transports_for_initiator, transports_for_noninitiator) +@pytest.mark.asyncio +async def test_single_simple_test_security_transport_succeeds(): + transports_for_initiator = [SimpleSecurityTransport("tacos")] + transports_for_noninitiator = [SimpleSecurityTransport("tacos")] + + def assertion_func(details): + assert details["key_phrase"] == "tacos" + + await perform_simple_test(assertion_func, + transports_for_initiator, transports_for_noninitiator) +