def _execute_traffic_simulation_query(self, source, destination, service, target=None): with report_soap_failure(AlgoSecAPIError): params = dict(QueryInput={ 'Source': source, 'Destination': destination, 'Service': service }) if target is not None: params['QueryTarget'] = target simulation_query_response = self.client.service.query( SessionID=self._session_id, **params).QueryResult query_url = getattr(simulation_query_response[0], "QueryHTMLPath", None) if simulation_query_response is None or not simulation_query_response[ 0].QueryItem: devices = [] else: devices = simulation_query_response[0].QueryItem.Device if type(devices) is not list: # In case there is only one object in the result, we listify the object devices = [devices] # Making a dict from the result type to a list of devices. Keep it always ordered by the result type query_results = self._prepare_simulation_query_results(devices) return query_results, query_url, simulation_query_response
def test_report_soap_failure__detailed_transport_error(self): wsdl_path = "http://some-wsdl-path" api_error = "some error description" responses.add(responses.GET, wsdl_path, json={"error": api_error}, status=500) with pytest.raises(AlgoSecAPIError) as e: with report_soap_failure(AlgoSecAPIError): # Force an api soap call, that is destined to fail client.Client(wsdl_path, transport=suds_requests.RequestsTransport()) assert "status_code: 500" in str(e) assert api_error in str(e)
def create_change_request( self, subject, requestor_name, email, traffic_lines, description="", template=None, ): """Create a new change request. Args: subject (str): The ticket subject, will be shown on FireFlow. requestor_name (str): The ticket creator name, will be shown on FireFlow. email (str): The email address of the requestor. traffic_lines (list[algosec.models.ChangeRequestTrafficLine]): List of traffic lines each describing its sources, destinations and services. description (str): description for the ticket, will be shown on FireFlow. template (str): When different than None, this template will be passed on to FireFlow to be used as the template for the new change requets. Raises: :class:`~algosec.errors.AlgoSecAPIError`: If change request creation failed. Returns: str: The URL for the newley create change request on FireFlow """ # Create ticket and traffic lines objects ticket = self.client.factory.create('ticket') ticket.description = description ticket.requestor = '{} {}'.format(requestor_name, email) ticket.subject = subject if template is not None: ticket.template = template for traffic_line in traffic_lines: ticket.trafficLines.append( self._create_soap_traffic_line(traffic_line)) # Actually create the ticket with report_soap_failure(AlgoSecAPIError): ticket_added = self.client.service.createTicket( sessionId=self._session_id, ticket=ticket) ticket_url = ticket_added.ticketDisplayURL # normalize ticket url hostname that is sometimes incorrect from the FireFlow server (which uses it's own # internal IP to build this url. url = list(urllib.parse.urlsplit(ticket_url)) url[1] = self.server_ip return urllib.parse.urlunsplit(url)
def _initiate_client(self): """Return a connected suds client and save the new session id to ``self._session_id`` Raises: AlgoSecLoginError: If login using the username/password failed. Returns: suds.client.Client """ client = self._get_soap_client(self._wsdl_url_path, location=self._soap_service_location) with report_soap_failure(AlgoSecLoginError): self._session_id = client.service.connect(UserName=self.user, Password=self.password, Domain='') return client
def get_change_request_by_id(self, change_request_id): """Get a change request by its ID. Useful for checking the status of a change request you opened through the API. Args: change_request_id: The ID of the change request to fetch. Raises: :class:`~algosec.errors.AlgoSecAPIError`: If the change request was not found on the server or another error occurred while fetching the change request. Returns: The change request ticket object. """ with report_soap_failure(AlgoSecAPIError): response = self.client.service.getTicket( sessionId=self._session_id, ticketId=change_request_id) return response.ticket
def _get_soap_client(self, wsdl_path, **kwargs): """. Args: wsdl_path (str): The url for the wsdl to connect to. **kwargs: Keyword-arguments that are forwarded to the suds client constructor. Returns: suds.client.Client: A suds SOAP client. """ session = requests.Session() session.verify = self.verify_ssl # use ``requests`` based suds implementation to handle AlgoSec's self-signed certificate properly. with report_soap_failure(AlgoSecAPIError): return client.Client( wsdl_path, transport=suds_requests.RequestsTransport(session), plugins=[LogSOAPMessages()], cache=NoCache(), **kwargs)
def test_report_soap_failure__no_failure(self): # See that no exception is raised with report_soap_failure(AlgoSecAPIError): pass
def test_report_soap_failure__webfault_is_fetched(self): """See that webfault is translated into AlgoSecAPIError""" with pytest.raises(AlgoSecAPIError): with report_soap_failure(AlgoSecAPIError): raise WebFault("Some Error", document={})