def inbox_service(request, inbox_name): """Handles TAXII Inbox Service requests.""" logger = logging.getLogger('yeti.taxii_services.views.inbox_service') logger.debug('Entering Inbox service') resp = handlers.validate_taxii_request(request) if resp: return resp # if validation failed, return the response try: taxii_message = tm.get_message_from_xml(request.body) except Exception as ex: logger.debug('Unable to parse inbound message: %s', ex.message) m = tm.StatusMessage(tm.generate_message_id(), '0', status_type=tm.ST_BAD_MESSAGE, message='Message received could not be parsed') return handlers.create_taxii_response(m, use_https=request.is_secure()) logger.debug('Inbox [%s] received TAXII message with id [%s] and type [%s]', make_safe(inbox_name), make_safe(taxii_message.message_id), make_safe(taxii_message.message_type)) if taxii_message.message_type != tm.MSG_INBOX_MESSAGE: logger.info('TAXII message with id [%s] was not Inbox type [%s]', make_safe(taxii_message.message_id), make_safe(taxii_message.message_type)) m = tm.StatusMessage(tm.generate_message_id(), taxii_message.message_id, status_type=tm.ST_FAILURE, message='Message sent to Inbox service did not have an inbox Message type') return handlers.create_taxii_response(m, use_https=request.is_secure()) resp = handlers.inbox_add_content(request, inbox_name, taxii_message) return resp
def poll_service(request): """Handles TAXII Poll Service requests.""" logger = logging.getLogger("yeti.taxii_services.views.poll_service") logger.debug('Entering poll service') resp = handlers.validate_taxii_request(request) if resp: return resp # if validation failed, return the response try: taxii_message = tm11.get_message_from_xml(request.body) except tm11.UnsupportedQueryException as e: logger.debug('Unsupported query found in TAXII Message') m = tm11.StatusMessage(tm11.generate_message_id(), '0', status_type=tm11.ST_UNSUPPORTED_QUERY, message='The message used an unsupported query format') return handlers.create_taxii_response(m, use_https=request.is_secure()) except Exception as ex: logger.debug('Unable to parse inbound message: %s', ex.message) m = tm11.StatusMessage(tm11.generate_message_id(), '0', status_type=tm11.ST_BAD_MESSAGE, message='Message received could not be parsed') return handlers.create_taxii_response(m, use_https=request.is_secure()) logger.debug('Poll service received TAXII message with id [%s] and type [%s]', make_safe(taxii_message.message_id), make_safe(taxii_message.message_type)) if taxii_message.message_type != tm11.MSG_POLL_REQUEST: logger.info('TAXII message with id [%s] was not Poll request [%s]', make_safe(taxii_message.message_id), make_safe(taxii_message.message_type)) m = tm11.StatusMessage(tm11.generate_message_id(), taxii_message.message_id, status_type=tm11.ST_FAILURE, message='Message sent to Poll service did not have a poll request message type') return handlers.create_taxii_response(m, use_https=request.is_secure()) resp = handlers.poll_get_content(request, taxii_message) return resp
def poll_get_content(request, taxii_message): """Returns a Poll response for a given Poll Request Message""" logger = logging.getLogger('taxii_services.utils.handlers.poll_get_content') logger.debug('Polling data from data collection [%s] - begin_ts: %s, end_ts: %s', make_safe(taxii_message.collection_name), taxii_message.exclusive_begin_timestamp_label, taxii_message.inclusive_end_timestamp_label) try: data_collection = DataCollection.objects.get(name=taxii_message.collection_name) except: logger.debug('Attempting to poll unknown data collection [%s]', make_safe(taxii_message.collection_name)) m = tm11.StatusMessage(tm11.generate_message_id(), taxii_message.message_id, status_type=tm11.ST_NOT_FOUND, message='Data collection does not exist [%s]' % (make_safe(taxii_message.collection_name))) return create_taxii_response(m, use_https=request.is_secure()) # build query for poll results query_params = {} if taxii_message.exclusive_begin_timestamp_label: query_params['timestamp_label__gt'] = taxii_message.exclusive_begin_timestamp_label current_datetime = datetime.datetime.now(tzutc()) if taxii_message.inclusive_end_timestamp_label and (taxii_message.inclusive_end_timestamp_label < current_datetime): query_params['timestamp_label__lte'] = taxii_message.inclusive_end_timestamp_label else: query_params['timestamp_label__lte'] = current_datetime if taxii_message.poll_parameters.content_bindings: query_params['content_binding__in'] = taxii_message.content_bindings content_blocks = data_collection.content_blocks.filter(**query_params).order_by('timestamp_label') logger.debug('Returned [%d] content blocks from data collection [%s]', len(content_blocks), make_safe(data_collection.name)) # TAXII Poll Requests have exclusive begin timestamp label fields, while Poll Responses # have *inclusive* begin timestamp label fields. To satisfy this, we add one millisecond # to the Poll Request's begin timestamp label. # # This will be addressed in future versions of TAXII inclusive_begin_ts = None if taxii_message.exclusive_begin_timestamp_label: inclusive_begin_ts = taxii_message.exclusive_begin_timestamp_label + datetime.timedelta(milliseconds=1) # build poll response poll_response_message = tm11.PollResponse(tm11.generate_message_id(), taxii_message.message_id, collection_name=data_collection.name, exclusive_begin_timestamp_label=inclusive_begin_ts, inclusive_end_timestamp_label=query_params['timestamp_label__lte'], record_count=tm11.RecordCount(len(content_blocks), False)) if taxii_message.poll_parameters.response_type == tm11.RT_FULL: for content_block in content_blocks: cb = tm11.ContentBlock(tm11.ContentBinding(content_block.content_binding.binding_id), content_block.content, content_block.timestamp_label) if content_block.padding: cb.padding = content_block.padding poll_response_message.content_blocks.append(cb) return create_taxii_response(poll_response_message, use_https=request.is_secure())
def inbox_add_content(request, inbox_name, taxii_message): """Adds content to inbox and associated data collections""" logger = logging.getLogger('taxii_services.utils.handlers.inbox_add_content') logger.debug('Adding content to inbox [%s]', make_safe(inbox_name)) if len(taxii_message.destination_collection_names) > 0: logger.debug('Client specified a Destination Collection Name, which is not supported by YETI.') m = tm11.StatusMessage(tm11.generate_message_id(), taxii_message.message_id, status_type=tm11.ST_DESTINATION_COLLECTION_ERROR, message='Destination Collection Names are not allowed') return create_taxii_response(m, use_https=request.is_secure()) try: inbox = Inbox.objects.get(name=inbox_name) except: logger.debug('Attempting to push content to unknown inbox [%s]', make_safe(inbox_name)) m = tm11.StatusMessage(tm11.generate_message_id(), taxii_message.message_id, status_type=tm11.ST_NOT_FOUND, message='Inbox does not exist [%s]' % (make_safe(inbox_name))) return create_taxii_response(m, use_https=request.is_secure()) logger.debug('TAXII message [%s] contains [%d] content blocks', make_safe(taxii_message.message_id), len(taxii_message.content_blocks)) for content_block in taxii_message.content_blocks: try: content_binding_id = ContentBindingId.objects.get(binding_id=content_block.content_binding) except: logger.debug('TAXII message [%s] contained unrecognized content binding [%s]', make_safe(taxii_message.message_id), make_safe(content_block.content_binding)) continue # cannot proceed - move on to the next content block if content_binding_id not in inbox.supported_content_bindings.all(): logger.debug('Inbox [%s] does not accept content with binding id [%s]', make_safe(inbox_name), make_safe(content_block.content_binding)) else: c = ContentBlock() c.message_id = taxii_message.message_id c.content_binding = content_binding_id c.content = content_block.content if content_block.padding: c.padding = content_block.padding if request.user.is_authenticated(): c.submitted_by = request.user c.save() inbox.content_blocks.add(c) # add content block to inbox for data_collection in inbox.data_collections.all(): if content_binding_id in data_collection.supported_content_bindings.all(): data_collection.content_blocks.add(c) data_collection.save() else: logger.debug('Inbox [%s] received data using content binding [%s] - ' 'associated data collection [%s] does not support this binding.', make_safe(inbox_name), make_safe(content_block.content_binding), make_safe(data_collection.name)) inbox.save() m = tm11.StatusMessage(tm11.generate_message_id(), taxii_message.message_id, status_type = tm11.ST_SUCCESS) return create_taxii_response(m, use_https=request.is_secure())
def validate_taxii_request(request): """Validates the broader request parameters and request type for a TAXII exchange""" logger = logging.getLogger("taxii_services.utils.handlers.validate_taxii_request") logger.debug('Attempting to validate request') if request.method != 'POST': logger.info('Request was not POST - returning error') m = tm11.StatusMessage(tm11.generate_message_id(), '0', status_type=tm11.ST_FAILURE, message='Request must be POST') return create_taxii_response(m, use_https=request.is_secure()) header_validation_resp = validate_taxii_headers(request, '0') # TODO: What to use for request message id? if header_validation_resp: # If response is not None an validation of the TAXII headers failed logger.info('TAXII header validation failed for reason [%s]', make_safe(header_validation_resp.message)) return header_validation_resp if len(request.body) == 0: m = tm11.StatusMessage(tm11.generate_message_id(), '0', status_type=tm11.ST_FAILURE, message='No POST data') logger.info('Request had a body length of 0. Returning error.') return create_taxii_response(m, use_https=request.is_secure()) logger.debug('Request was valid') return None
def discovery_service(request): """Handles TAXII Discovery Service requests""" logger = logging.getLogger('yeti.taxii_services.views.discovery_service') logger.debug('Entering discovery service') resp = handlers.validate_taxii_request(request) if resp: return resp # if validation fails, return the response try: taxii_message = tm.get_message_from_xml(request.body) except Exception as ex: logger.debug('Unable to parse inbound message: %s', ex.message) m = tm.StatusMessage(tm.generate_message_id(), '0', status_type=tm.ST_BAD_MESSAGE, message='Message received could not be parsed') return handlers.create_taxii_response(m, use_https=request.is_secure()) logger.debug('Discovery service received TAXII message with id [%s] and type [%s]', make_safe(taxii_message.message_id), make_safe(taxii_message.message_type)) if taxii_message.message_type != tm.MSG_DISCOVERY_REQUEST: logger.info('TAXII message with id [%s] was not Discovery request [%s]', make_safe(taxii_message.message_id), make_safe(taxii_message.message_type)) m = tm.StatusMessage(tm.generate_message_id(), taxii_message.message_id, status_type=tm.ST_FAILURE, message='Message sent to discovery service did not have a discovery request message type') return handlers.create_taxii_response(m, use_https=request.is_secure()) resp = handlers.discovery_get_services(request, taxii_message) return resp