def _inbound_connection_request_callback(self, request, result, connection=None): connection_response = ConnectionResponse() connection_response.ParseFromString(result.content) if connection_response.status == connection_response.ERROR: LOGGER.debug( "Received an error response to the NETWORK_CONNECT " "we sent. Removing connection: %s", connection.connection_id) self.remove_connection(connection.connection_id) # Send correct Authorization Request for network role auth_type = {"trust": [], "challenge": []} for role_entry in connection_response.roles: if role_entry.auth_type == connection_response.TRUST: auth_type["trust"].append(role_entry.role) elif role_entry.auth_type == connection_response.CHALLENGE: auth_type["challenge"].append(role_entry.role) if auth_type["trust"]: auth_trust_request = AuthorizationTrustRequest( roles=[RoleType.Value("NETWORK")], public_key=self._public_key) self.send(validator_pb2.Message.AUTHORIZATION_TRUST_REQUEST, auth_trust_request.SerializeToString(), connection) if auth_type["challenge"]: auth_challenge_request = AuthorizationChallengeRequest() self.send(validator_pb2.Message.AUTHORIZATION_CHALLENGE_REQUEST, auth_challenge_request.SerializeToString(), connection, callback=partial( self._inbound_challenge_authorization_callback, connection=connection))
def _connect_callback(self, request, result, connection=None, success_callback=None, failure_callback=None): connection_response = ConnectionResponse() connection_response.ParseFromString(result.content) if connection_response.status == connection_response.ERROR: LOGGER.debug( "Received an error response to the NETWORK_CONNECT " "we sent. Removing connection: %s", connection.connection_id) self.remove_connection(connection.connection_id) if failure_callback: failure_callback(connection_id=connection.connection_id) elif connection_response.status == connection_response.OK: LOGGER.debug("Connection to %s was acknowledged", connection.connection_id) if self._authorize: auth_trust_request = AuthorizationTrustRequest( roles=[RoleType.Value("NETWORK")], public_key=self._pub_key) connection.send( validator_pb2.Message.AUTHORIZATION_TRUST_REQUEST, auth_trust_request.SerializeToString(), callback=partial(self._authorization_callback, connection=connection, success_callback=success_callback, failure_callback=failure_callback)) else: if success_callback: success_callback(connection_id=connection.connection_id)
def handle(self, connection_id, message_content): """ A connection must use one of the supported authorization types to prove their identity. If a requester deviates from the procedure in any way, the requester will be rejected and the connection will be closed. The same is true if the requester sends multiple ConnectionRequests or multiple of any authorization-type message. The validator receiving a new connection will receive a ConnectionRequest. The validator will respond with a ConnectionResponse message. The ConnectionResponse message will contain a list of RoleEntry messages and an AuthorizationType. Role entries are the accepted type of connections that are supported on the endpoint that the ConnectionRequest was sent to. AuthorizationType describes the procedure required to gain access to that role. If the validator is not accepting connections or does not support the listed authorization type, return an ConnectionResponse.ERROR and close the connection. """ message = ConnectionRequest() message.ParseFromString(message_content) LOGGER.debug("got connect message from %s. sending ack", connection_id) # Need to use join here to get the string "0.0.0.0". Otherwise, # bandit thinks we are binding to all interfaces and returns a # Medium security risk. interfaces = ["*", ".".join(["0", "0", "0", "0"])] interfaces += netifaces.interfaces() for interface in interfaces: if interface in message.endpoint: LOGGER.debug("Endpoint cannot include '%s': %s", interface, message.endpoint) connection_response = ConnectionResponse( status=ConnectionResponse.ERROR) return HandlerResult(HandlerStatus.RETURN_AND_CLOSE, message_out=connection_response, message_type=validator_pb2.Message. AUTHORIZATION_CONNECTION_RESPONSE) LOGGER.debug("Endpoint of connecting node is %s", message.endpoint) self._network.update_connection_endpoint(connection_id, message.endpoint) # Get what AuthorizationType the network role requires roles = self._network.roles auth_type = roles.get("network") if auth_type == AuthorizationType.TRUST: role_type = ConnectionResponse.RoleEntry( role=RoleType.Value("NETWORK"), auth_type=ConnectionResponse.TRUST) connection_response = ConnectionResponse(roles=[role_type]) elif auth_type == AuthorizationType.CHALLENGE: role_type = ConnectionResponse.RoleEntry( role=RoleType.Value("NETWORK"), auth_type=ConnectionResponse.CHALLENGE) connection_response = ConnectionResponse(roles=[role_type]) else: LOGGER.warning( "Network role is set to an unsupported" "Authorization Type: %s", auth_type) connection_response = ConnectionResponse( status=ConnectionResponse.ERROR) return HandlerResult(HandlerStatus.RETURN_AND_CLOSE, message_out=connection_response, message_type=validator_pb2.Message. AUTHORIZATION_CONNECTION_RESPONSE) try: is_outbound_connection = self._network.is_outbound_connection( connection_id) except KeyError: # Connection has gone away, drop message return HandlerResult(HandlerStatus.DROP) if not is_outbound_connection: if self._network.allow_inbound_connection(): LOGGER.debug("Allowing incoming connection: %s", connection_id) connection_response.status = connection_response.OK else: connection_response.status = connection_response.ERROR return HandlerResult(HandlerStatus.RETURN_AND_CLOSE, message_out=connection_response, message_type=validator_pb2.Message. AUTHORIZATION_CONNECTION_RESPONSE) if self._network.get_connection_status(connection_id) is not None: LOGGER.debug( "Connection has already sent ConnectionRequest:" " %s, Remove connection.", connection_id) connection_response.status = connection_response.ERROR return HandlerResult(HandlerStatus.RETURN_AND_CLOSE, message_out=connection_response, message_type=validator_pb2.Message. AUTHORIZATION_CONNECTION_RESPONSE) self._network.update_connection_status( connection_id, ConnectionStatus.CONNECTION_REQUEST) return HandlerResult(HandlerStatus.RETURN, message_out=connection_response, message_type=validator_pb2.Message. AUTHORIZATION_CONNECTION_RESPONSE)
def handle(self, connection_id, message_content): """ A connection must use one of the supported authorization types to prove their identity. If a requester deviates from the procedure in any way, the requester will be rejected and the connection will be closed. The same is true if the requester sends multiple ConnectionRequests or multiple of any authorization-type message. The validator receiving a new connection will receive a ConnectionRequest. The validator will respond with a ConnectionResponse message. The ConnectionResponse message will contain a list of RoleEntry messages and an AuthorizationType. Role entries are the accepted type of connections that are supported on the endpoint that the ConnectionRequest was sent to. AuthorizationType describes the procedure required to gain access to that role. If the validator is not accepting connections or does not support the listed authorization type, return an ConnectionResponse.ERROR and close the connection. """ message = ConnectionRequest() message.ParseFromString(message_content) LOGGER.debug("got connect message from %s. sending ack", connection_id) # Need to use join here to get the string "0.0.0.0". Otherwise, # bandit thinks we are binding to all interfaces and returns a # Medium security risk. interfaces = ["*", ".".join(["0", "0", "0", "0"])] interfaces += netifaces.interfaces() if self.is_valid_endpoint_host(interfaces, message.endpoint) is False: LOGGER.warning("Connecting peer provided an invalid endpoint: %s; " "Ignoring connection request.", message.endpoint) connection_response = ConnectionResponse( status=ConnectionResponse.ERROR) return HandlerResult( HandlerStatus.RETURN_AND_CLOSE, message_out=connection_response, message_type=validator_pb2.Message. AUTHORIZATION_CONNECTION_RESPONSE) LOGGER.debug("Endpoint of connecting node is %s", message.endpoint) self._network.update_connection_endpoint(connection_id, message.endpoint) # Get what AuthorizationType the network role requires roles = self._network.roles auth_type = roles.get("network") if auth_type == AuthorizationType.TRUST: role_type = ConnectionResponse.RoleEntry( role=RoleType.Value("NETWORK"), auth_type=ConnectionResponse.TRUST) connection_response = ConnectionResponse(roles=[role_type]) elif auth_type == AuthorizationType.CHALLENGE: role_type = ConnectionResponse.RoleEntry( role=RoleType.Value("NETWORK"), auth_type=ConnectionResponse.CHALLENGE) connection_response = ConnectionResponse(roles=[role_type]) else: LOGGER.warning("Network role is set to an unsupported" "Authorization Type: %s", auth_type) connection_response = ConnectionResponse( status=ConnectionResponse.ERROR) return HandlerResult( HandlerStatus.RETURN_AND_CLOSE, message_out=connection_response, message_type=validator_pb2.Message. AUTHORIZATION_CONNECTION_RESPONSE) try: is_outbound_connection = self._network.is_outbound_connection( connection_id) except KeyError: # Connection has gone away, drop message return HandlerResult(HandlerStatus.DROP) if not is_outbound_connection: if self._network.allow_inbound_connection(): LOGGER.debug("Allowing incoming connection: %s", connection_id) connection_response.status = connection_response.OK else: connection_response.status = connection_response.ERROR return HandlerResult( HandlerStatus.RETURN_AND_CLOSE, message_out=connection_response, message_type=validator_pb2.Message. AUTHORIZATION_CONNECTION_RESPONSE) if self._network.get_connection_status(connection_id) is not None: LOGGER.debug("Connection has already sent ConnectionRequest:" " %s, Remove connection.", connection_id) connection_response.status = connection_response.ERROR return HandlerResult( HandlerStatus.RETURN_AND_CLOSE, message_out=connection_response, message_type=validator_pb2.Message. AUTHORIZATION_CONNECTION_RESPONSE) self._network.update_connection_status( connection_id, ConnectionStatus.CONNECTION_REQUEST) return HandlerResult( HandlerStatus.RETURN, message_out=connection_response, message_type=validator_pb2.Message. AUTHORIZATION_CONNECTION_RESPONSE)