Example #1
0
 def setUp( self ):
     self.services = Services()
     self.iface_registry = self.services.iface_registry
     test_iface.register_types()
     self.iface_registry.register(test_iface)
     self.remoting = self.services.remoting
     self.test_module = TestModule()  # self-registering
     self.server = Server(server_identity)
     self.session_list = TransportSessionList()
Example #2
0
def main():
    logging.basicConfig(level=logging.DEBUG, format='%(asctime)-15s  %(message)s')

    parser = argparse.ArgumentParser(description='Hyperapp server')
    parser.add_argument('identity_fpath', help='path to identity file')
    parser.add_argument('addr', nargs='?', help='address to listen at', default=DEFAULT_ADDR)
    parser.add_argument('--test-delay', type=float, help='artificial delay for handling requests, seconds')
    args = parser.parse_args()

    identity = Identity.load_from_file(args.identity_fpath)
    host, port = parse_addr(args.addr)
    services = Services()
    server = Server(identity, args.test_delay)
    tcp_server = TcpServer(services.remoting, server, host, port)
    management_url = services.modules.server_management.get_management_url(server.get_public_key())
    url_with_routes = management_url.clone_with_routes(tcp_server.get_routes())
    log.info('Management url: %s', url_with_routes.to_str())
    tcp_server.run()
Example #3
0
class ServerTest(unittest.TestCase):

    def setUp( self ):
        self.services = Services()
        self.iface_registry = self.services.iface_registry
        test_iface.register_types()
        self.iface_registry.register(test_iface)
        self.remoting = self.services.remoting
        self.test_module = TestModule()  # self-registering
        self.server = Server(server_identity)
        self.session_list = TransportSessionList()

    def test_simple_request( self ):
        request_data = tRequest(
            iface='test_iface',
            path=[TestModule.name, TestObject.class_name, '1'],
            command_id='echo',
            params=test_iface.get_request_params_type('echo')(test_param='hello'),
            request_id='001',
            )
        pprint(tClientPacket, request_data)
        request = RequestBase.from_data(None, Peer(PhonyChannel()), self.iface_registry, request_data)

        response = self.server.process_request(request)

        pprint(tServerPacket, response.to_data())
        self.assertEqual('hello to you too', response.result.test_result)

    def transport_id2encoding( self, transport_id ):
        if transport_id in ['tcp.cdr', 'tcp.json']:
            return transport_id.split('.')[1]
        else:
            return 'cdr'

    def encode_packet( self, transport_id, rec, type ):
        return packet_coders.encode(self.transport_id2encoding(transport_id), rec, type)

    def decode_packet( self, transport_id, data, type ):
        return packet_coders.decode(self.transport_id2encoding(transport_id), data, type)

    def encrypt_packet( self, session_list, transport_id, data ):
        if transport_id != 'encrypted_tcp':
            return data
        session = session_list.get_transport_session('test.encrypted_tcp')
        if session is None:
            session = TestSession()
            session.session_key = make_session_key()
            session_list.set_transport_session('test.encrypted_tcp', session)
        packet = encrypt_initial_packet(session.session_key, server_identity.get_public_key(), data)
        return self.encode_packet(transport_id, packet, tEncryptedPacket)

    def decrypt_transport_response_packets( self, session_list, transport_id, packets ):
        if transport_id != 'encrypted_tcp':
            if len(packets) == 0:
                return None  # no response
            self.assertEqual(1, len(packets), repr(packets))
            self.assertEqual(transport_id, packets[0].transport_id)
            return packets[0].data
        session = session_list.get_transport_session('test.encrypted_tcp')
        assert session is not None  # must be created by encrypt_packet
        for packet in packets:
            self.assertEqual(transport_id, packet.transport_id)
            encrypted_packet = self.decode_packet(transport_id, packet.data, tEncryptedPacket)
            if isinstance(encrypted_packet, tSubsequentEncryptedPacket):
                session_key, packet_data = decrypt_packet(server_identity, session.session_key, encrypted_packet)
                return packet_data
        return None  # no response

    def make_tcp_transport_request( self, session_list, transport_id, obj_id, command_id, **kw ):
        request = tRequest(
            iface='test_iface',
            path=[TestModule.name, TestObject.class_name, obj_id],
            command_id=command_id,
            params=test_iface.get_request_params_type(command_id)(**kw),
            request_id='001',
            )
        log.info('Sending request:')
        pprint(tClientPacket, request)
        request_packet = tPacket(
            aux_info=tAuxInfo(requirements=[], type_modules=[], modules=[], routes=[], resources=[]),
            payload=self.encode_packet(transport_id, request, tClientPacket))
        request_packet_data = self.encode_packet(transport_id, request_packet, tPacket)
        transport_request = tTransportPacket(
            transport_id=transport_id,
            data=self.encrypt_packet(session_list, transport_id, request_packet_data))
        return transport_request

    def make_tcp_transport_notification( self, session_list, transport_id, obj_id, command_id, **kw ):
        request = tClientNotification(
            iface='test_iface',
            path=[TestModule.name, TestObject.class_name, obj_id],
            command_id=command_id,
            params=test_iface.get_request_params_type(command_id)(**kw),
            )
        log.info('Sending client notification:')
        pprint(tClientPacket, request)
        request_packet = tPacket(
            aux_info=tAuxInfo(requirements=[], type_modules=[], modules=[], routes=[], resources=[]),
            payload=self.encode_packet(transport_id, request, tClientPacket))
        request_packet_data = self.encode_packet(transport_id, request_packet, tPacket)
        transport_request = tTransportPacket(
            transport_id=transport_id,
            data=self.encrypt_packet(session_list, transport_id, request_packet_data))
        return transport_request

    def decode_tcp_transport_response( self, session_list, transport_id, response_transport_packets ):
        packet_data = self.decrypt_transport_response_packets(session_list, transport_id, response_transport_packets)
        if packet_data is None:
            return None  # no response
        response_packet = self.decode_packet(transport_id, packet_data, tPacket)
        log.info('Received response:')
        pprint(tPacket, response_packet)
        response = self.decode_packet(transport_id, response_packet.payload, tServerPacket)
        pprint(tServerPacket, response)
        return response

    def execute_tcp_request( self, transport_id, obj_id, command_id, session_list=None, **kw ):
        if session_list is None:
            session_list = self.session_list
        transport_request = self.make_tcp_transport_request(session_list, transport_id, obj_id, command_id, **kw)
        response_transport_packets = self.remoting.process_packet(self.iface_registry, self.server, session_list, transport_request)
        response = self.decode_tcp_transport_response(session_list, transport_id, response_transport_packets)
        return response

    def execute_tcp_notification( self, transport_id, obj_id, command_id, session_list=None, **kw ):
        if session_list is None:
            session_list = self.session_list
        transport_request = self.make_tcp_transport_notification(session_list, transport_id, obj_id, command_id, **kw)
        response_transport_packets = self.remoting.process_packet(self.iface_registry, self.server, self.session_list, transport_request)
        response = self.decode_tcp_transport_response(session_list, transport_id, response_transport_packets)
        self.assertIsNone(response)

    def test_tcp_cdr_echo_request( self ):
        self._test_tcp_echo_request('tcp.cdr')

    def test_tcp_json_echo_request( self ):
        self._test_tcp_echo_request('tcp.json')

    def test_encrypted_tcp_echo_request( self ):
        self._test_tcp_echo_request('encrypted_tcp')

    def _test_tcp_echo_request( self, transport_id ):
        response = self.execute_tcp_request(transport_id, obj_id='1', command_id='echo', test_param='hello')
        self.assertEqual('hello to you too', response.result.test_result)

    def test_tcp_cdr_broadcast_request( self ):
        self._test_broadcast_tcp_request('tcp.cdr')

    def test_tcp_json_broadcast_request( self ):
        self._test_broadcast_tcp_request('tcp.json')

    def test_encrypted_tcp_broadcast_request( self ):
        self._test_broadcast_tcp_request('encrypted_tcp')

    def _test_broadcast_tcp_request( self, transport_id ):
        message = 'hi, all!'
        obj_id = '1'

        response = self.execute_tcp_request(transport_id, obj_id=obj_id, command_id='subscribe')
        response = self.execute_tcp_request(transport_id, obj_id=obj_id, command_id='broadcast', message=message)

        self.assertEqual(1, len(response.updates))
        update = response.updates[0]
        self.assertEqual('test_iface', update.iface)
        self.assertEqual([TestModule.name, TestObject.class_name, obj_id], update.path)
        self.assertEqual(message, update.diff)

    def test_tcp_cdr_unsubscribe_notification_request( self ):
        self._test_unsubscribe_notification_tcp_request('tcp.cdr')

    def test_tcp_json_unsubscribe_notification_request( self ):
        self._test_unsubscribe_notification_tcp_request('tcp.json')

    def test_encrypted_tcp_unsubscribe_notification_request( self ):
        self._test_unsubscribe_notification_tcp_request('encrypted_tcp')

    def _test_unsubscribe_notification_tcp_request( self, transport_id ):
        obj_id = '1'
        response = self.execute_tcp_request(transport_id, obj_id=obj_id, command_id='subscribe')
        response = self.execute_tcp_notification(transport_id, obj_id=obj_id, command_id='unsubscribe')

    def test_tcp_cdr_server_notification( self ):
        self._test_tcp_server_notification('tcp.cdr')

    def test_tcp_json_server_notification( self ):
        self._test_tcp_server_notification('tcp.json')

    def test_encrypted_tcp_server_notification( self ):
        self._test_tcp_server_notification('encrypted_tcp')

    def _test_tcp_server_notification( self, transport_id ):
        message = 'hi, all!'
        obj_id = '1'
        session1 = TransportSessionList()
        session2 = TransportSessionList()

        response = self.execute_tcp_request(transport_id, obj_id=obj_id, command_id='subscribe', session_list=session1)
        response = self.execute_tcp_request(transport_id, obj_id=obj_id, command_id='subscribe', session_list=session2)

        response = self.execute_tcp_request(transport_id, obj_id=obj_id, command_id='broadcast', session_list=session2, message=message)

        notifications = session1.pull_notification_transport_packets()

        self.assertEqual(1, len(notifications))
        notification_packet = notifications[0]
        assert isinstance(notification_packet, tTransportPacket), repr(notification_packet)
        notification = self.decode_tcp_transport_response(session1, transport_id, [notification_packet])
        self.assertEqual(1, len(notification.updates))
        update = notification.updates[0]
        self.assertEqual('test_iface', update.iface)
        self.assertEqual([TestModule.name, TestObject.class_name, obj_id], update.path)
        self.assertEqual(message, update.diff)

    def pick_pop_channelge_from_responses( self, transport_id, response_transport_packets ):
        for packet in response_transport_packets:
            encrypted_packet = self.decode_packet(transport_id, packet.data, tEncryptedPacket)
            if isinstance(encrypted_packet, tPopChallengePacket):
                return encrypted_packet.challenge
        self.fail('No challenge packet in response')

    def encode_pop_transport_request( self, transport_id, challenge, pop_records ):
        pop_packet = tProofOfPossessionPacket(challenge, pop_records)
        pop_packet_data = self.encode_packet(transport_id, pop_packet, tEncryptedPacket)
        return tTransportPacket(transport_id=transport_id, data=pop_packet_data)

    def test_proof_of_possession( self ):
        transport_id = 'encrypted_tcp'
        transport_request = self.make_tcp_transport_request(self.session_list, transport_id, obj_id='1', command_id='echo', test_param='hi')
        response_transport_packets = self.remoting.process_packet(self.iface_registry, self.server, self.session_list, transport_request)
        challenge = self.pick_pop_channelge_from_responses(transport_id, response_transport_packets)

        identity_1 = Identity.generate(fast=True)
        identity_2 = Identity.generate(fast=True)

        pop_record_1 = tPopRecord(
            identity_1.get_public_key().to_der(),
            identity_1.sign(challenge))
        pop_record_2 = tPopRecord(
            identity_2.get_public_key().to_der(),
            identity_2.sign(challenge + b'x'))  # make invlid signature; verification must fail
        transport_request = self.encode_pop_transport_request(transport_id, challenge, [pop_record_1, pop_record_2])

        response_transport_packets = self.remoting.process_packet(self.iface_registry, self.server, self.session_list, transport_request)

        session = self.session_list.get_transport_session(transport_id)
        self.assertIn(identity_1.get_public_key(), session.peer_public_keys)
        self.assertNotIn(identity_2.get_public_key(), session.peer_public_keys)

    # when NotAuthorizedError raised in first request before pop is returned, that request must be reprocessed when pop is processed
    def test_unauthorized_request_reprocess( self ):
        transport_id = 'encrypted_tcp'
        transport_request = self.make_tcp_transport_request(self.session_list, transport_id, obj_id='1', command_id='required_auth')
        response_transport_packets = self.remoting.process_packet(
            self.iface_registry, self.server, self.session_list, transport_request)
        challenge = self.pick_pop_channelge_from_responses(transport_id, response_transport_packets)

        authorized_peer_identity
        
        pop_record = tPopRecord(
            authorized_peer_identity.get_public_key().to_der(),
            authorized_peer_identity.sign(challenge))
        transport_request = self.encode_pop_transport_request(transport_id, challenge, [pop_record])

        response_transport_packets = self.remoting.process_packet(
            self.iface_registry, self.server, self.session_list, transport_request)

        response = self.decode_tcp_transport_response(self.session_list, transport_id, response_transport_packets)
        self.assertIsNotNone(response)  # now, after pop is received, first request must be processed
        self.assertEqual('ok', response.result.test_result)