I am working on a server for a smart house. This part of code is responsible for communication with client (separate application), sending requested data and ensuring everything is safe.
I've decided to use multithreaded version of Python socketserver in order to avoid bottlenecks (I want it to be flexible enough to manage a something bigger than a flat). The
server_forever() method is called from separate part of the program, not important for this workflow. The
handle() method triggers actions specific to the type of order chosen by the user I've decided to use abstract factory for this task.
Everything afterwards is implemented separately for each order type. If the authentication fails the address is banned for a short time to prevent attacks (orders are sent by another application so any mistake can be expected to be caused by an attempt to gain unauthorized access).
Here are my questions:
- I needed
banned_addressesto be remembered but
ConnectionHandleris created each time new connection is set up. Is it ok to store them in the
- I assume that i will need to lock sensitive data, which in this case is the list of banned addresses not to get a mess while removing ban. Is this mechanism implemented correctly? I haven't faced any problems while testing but I might have not noticed something.
- I want to extend it in future so that there would be multiple users with different privileges logging in. It would be done in
__authorize_connection__()part after asking the user to send login and password and checking if they can perform a specific order. Do you have any ideas about any potential jeopardy?
- Any other ideas on how to improve security? What do you think about this generally?
- I am rather inexperienced when it comes to python programming so any suggestions on how to make this code more "pythonic" are welcome.
import socketserver from datetime import datetime from Networking import Errors, OrderFactory import threading def setup_connection_handler(host, port): return ThreadedTCP((host, port), ConnectionHandler) class BannedAddresses: def __init__(self, address): self.address = address self.ban_timestamp = datetime.now() class ThreadedTCP(socketserver.ThreadingMixIn, socketserver.TCPServer): banned_addresses = [BannedAddresses(None)] lock = threading.Lock() class ConnectionHandler(socketserver.BaseRequestHandler): def handle(self): try: self.__authorize_connection__() self.__receive_data_from_network__() order_factory = OrderFactory.OrderFactory.create_factory(self.data) order = order_factory.create_order(self.request) order.perform_order() except Errors.UnknownOrderError: # If we receive wring order we can assume that unauthorized connection is attempted. # Therefore connection is being shut down. print('Wrong order! Shutting connection down.') self.request.close() self.__ban_client__() except Errors.AuthorizationError: self.request.close() def __receive_data_from_network__(self): self.data = self.request.recv(1024) self.data = self.data.decode('utf-8') # TODO: extend this, introduce password checking def __authorize_connection__(self): self.__unban_after_withdrawal_period__() if self.__is_banned__(): raise Errors.AuthorizationError def __unban_after_withdrawal_period__(self): current_timestamp = datetime.now() ThreadedTCP.lock.acquire() to_delete =  for banned in ThreadedTCP.banned_addresses: elapsed = current_timestamp - banned.ban_timestamp if elapsed.days >= 1 or elapsed.seconds > 60: to_delete.append(banned) for td in to_delete: ThreadedTCP.banned_addresses.remove(td) ThreadedTCP.lock.release() def __is_banned__(self): banned_addresses = (l.address for l in ThreadedTCP.banned_addresses) if self.client_address in banned_addresses: return True def __ban_client__(self): ThreadedTCP.banned_addresses.append(BannedAddresses(self.client_address))