2018-11-28 22:51:00 +01:00
|
|
|
"""Python STIX2 TAXIICollection Source/Sink"""
|
|
|
|
|
2017-11-16 23:47:27 +01:00
|
|
|
from requests.exceptions import HTTPError
|
2017-05-24 17:25:40 +02:00
|
|
|
|
2018-11-01 12:57:09 +01:00
|
|
|
from stix2 import v20, v21
|
2017-09-22 17:29:17 +02:00
|
|
|
from stix2.base import _STIXBase
|
2018-07-13 17:10:05 +02:00
|
|
|
from stix2.datastore import (
|
|
|
|
DataSink, DataSource, DataSourceError, DataStoreMixin,
|
|
|
|
)
|
2018-04-11 19:36:52 +02:00
|
|
|
from stix2.datastore.filters import Filter, FilterSet, apply_common_filters
|
2020-03-27 10:53:39 +01:00
|
|
|
from stix2.parsing import parse
|
2017-09-29 17:24:19 +02:00
|
|
|
from stix2.utils import deduplicate
|
2017-05-30 22:56:27 +02:00
|
|
|
|
2018-05-15 21:41:46 +02:00
|
|
|
try:
|
2020-12-21 23:53:53 +01:00
|
|
|
from taxii2client import v20 as tcv20
|
|
|
|
from taxii2client import v21 as tcv21
|
2020-04-03 23:19:36 +02:00
|
|
|
from taxii2client.exceptions import ValidationError
|
2018-05-15 21:41:46 +02:00
|
|
|
_taxii2_client = True
|
|
|
|
except ImportError:
|
|
|
|
_taxii2_client = False
|
|
|
|
|
|
|
|
|
2017-07-12 16:58:31 +02:00
|
|
|
TAXII_FILTERS = ['added_after', 'id', 'type', 'version']
|
2017-05-24 17:25:40 +02:00
|
|
|
|
|
|
|
|
2018-03-01 17:27:37 +01:00
|
|
|
class TAXIICollectionStore(DataStoreMixin):
|
2017-09-29 17:24:19 +02:00
|
|
|
"""Provides an interface to a local/remote TAXII Collection
|
2017-09-22 17:29:17 +02:00
|
|
|
of STIX data. TAXIICollectionStore is a wrapper
|
|
|
|
around a paired TAXIICollectionSink and TAXIICollectionSource.
|
2017-07-12 16:58:31 +02:00
|
|
|
|
2017-09-22 17:29:17 +02:00
|
|
|
Args:
|
2017-10-24 15:15:09 +02:00
|
|
|
collection (taxii2.Collection): TAXII Collection instance
|
2017-11-29 18:03:10 +01:00
|
|
|
allow_custom (bool): whether to allow custom STIX content to be
|
|
|
|
pushed/retrieved. Defaults to True for TAXIICollectionSource
|
|
|
|
side(retrieving data) and False for TAXIICollectionSink
|
|
|
|
side(pushing data). However, when parameter is supplied, it will
|
|
|
|
be applied to both TAXIICollectionSource/Sink.
|
2021-02-02 06:04:04 +01:00
|
|
|
items_per_page (int): How many STIX objects to request per call
|
|
|
|
to TAXII Server. The value can be tuned, but servers may override
|
|
|
|
if their internal limit is surpassed. Used by TAXIICollectionSource
|
2017-11-29 18:03:10 +01:00
|
|
|
|
2017-09-22 17:29:17 +02:00
|
|
|
"""
|
2021-02-02 06:04:04 +01:00
|
|
|
def __init__(self, collection, allow_custom=None, items_per_page=5000):
|
2018-02-26 22:56:24 +01:00
|
|
|
if allow_custom is None:
|
2017-11-29 18:03:10 +01:00
|
|
|
allow_custom_source = True
|
|
|
|
allow_custom_sink = False
|
|
|
|
else:
|
|
|
|
allow_custom_sink = allow_custom_source = allow_custom
|
|
|
|
|
2017-11-08 19:53:21 +01:00
|
|
|
super(TAXIICollectionStore, self).__init__(
|
2021-02-02 06:04:04 +01:00
|
|
|
source=TAXIICollectionSource(collection, allow_custom=allow_custom_source, items_per_page=items_per_page),
|
2018-07-13 17:10:05 +02:00
|
|
|
sink=TAXIICollectionSink(collection, allow_custom=allow_custom_sink),
|
2017-11-08 19:53:21 +01:00
|
|
|
)
|
2017-11-03 02:29:25 +01:00
|
|
|
|
2017-07-12 16:58:31 +02:00
|
|
|
|
|
|
|
class TAXIICollectionSink(DataSink):
|
2017-09-29 17:24:19 +02:00
|
|
|
"""Provides an interface for pushing STIX objects to a local/remote
|
2017-09-22 17:29:17 +02:00
|
|
|
TAXII Collection endpoint.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
collection (taxii2.Collection): TAXII2 Collection instance
|
2017-11-29 18:03:10 +01:00
|
|
|
allow_custom (bool): Whether to allow custom STIX content to be
|
|
|
|
added to the TAXIICollectionSink. Default: False
|
2017-09-22 17:29:17 +02:00
|
|
|
|
2017-07-12 16:58:31 +02:00
|
|
|
"""
|
2017-11-29 18:03:10 +01:00
|
|
|
def __init__(self, collection, allow_custom=False):
|
2017-09-01 14:15:50 +02:00
|
|
|
super(TAXIICollectionSink, self).__init__()
|
2018-05-15 21:41:46 +02:00
|
|
|
if not _taxii2_client:
|
|
|
|
raise ImportError("taxii2client library is required for usage of TAXIICollectionSink")
|
|
|
|
|
2018-05-15 17:28:34 +02:00
|
|
|
try:
|
2018-05-15 21:41:46 +02:00
|
|
|
if collection.can_write:
|
|
|
|
self.collection = collection
|
|
|
|
else:
|
2018-07-13 17:10:05 +02:00
|
|
|
raise DataSourceError(
|
|
|
|
"The TAXII Collection object provided does not have write access"
|
|
|
|
" to the underlying linked Collection resource",
|
|
|
|
)
|
2018-05-15 21:41:46 +02:00
|
|
|
|
|
|
|
except (HTTPError, ValidationError) as e:
|
2018-07-13 17:10:05 +02:00
|
|
|
raise DataSourceError(
|
|
|
|
"The underlying TAXII Collection resource defined in the supplied TAXII"
|
|
|
|
" Collection object provided could not be reached. Receved error:", e,
|
|
|
|
)
|
2018-05-15 17:28:34 +02:00
|
|
|
|
2017-11-29 18:03:10 +01:00
|
|
|
self.allow_custom = allow_custom
|
2017-07-12 16:58:31 +02:00
|
|
|
|
2018-12-06 21:11:30 +01:00
|
|
|
def add(self, stix_data, version=None):
|
2017-10-24 15:15:09 +02:00
|
|
|
"""Add/push STIX content to TAXII Collection endpoint
|
2017-09-22 17:29:17 +02:00
|
|
|
|
|
|
|
Args:
|
2018-07-10 21:49:36 +02:00
|
|
|
stix_data (STIX object OR dict OR str OR list): valid STIX2
|
|
|
|
content in a STIX object (or Bundle), STIX object dict (or
|
|
|
|
Bundle dict), or a STIX2 json encoded string, or list of
|
|
|
|
any of the following.
|
2018-12-06 21:11:30 +01:00
|
|
|
version (str): If present, it forces the parser to use the version
|
|
|
|
provided. Otherwise, the library will make the best effort based
|
|
|
|
on checking the "spec_version" property.
|
2017-09-22 17:29:17 +02:00
|
|
|
|
2017-07-12 16:58:31 +02:00
|
|
|
"""
|
2017-09-22 17:29:17 +02:00
|
|
|
if isinstance(stix_data, _STIXBase):
|
|
|
|
# adding python STIX object
|
2018-06-30 00:38:04 +02:00
|
|
|
if stix_data['type'] == 'bundle':
|
2018-07-10 21:49:36 +02:00
|
|
|
bundle = stix_data.serialize(encoding='utf-8', ensure_ascii=False)
|
|
|
|
elif 'spec_version' in stix_data:
|
|
|
|
# If the spec_version is present, use new Bundle object...
|
2018-11-01 12:57:09 +01:00
|
|
|
bundle = v21.Bundle(stix_data, allow_custom=self.allow_custom).serialize(encoding='utf-8', ensure_ascii=False)
|
2018-03-15 18:51:47 +01:00
|
|
|
else:
|
2018-07-10 21:49:36 +02:00
|
|
|
bundle = v20.Bundle(stix_data, allow_custom=self.allow_custom).serialize(encoding='utf-8', ensure_ascii=False)
|
2017-09-22 17:29:17 +02:00
|
|
|
|
|
|
|
elif isinstance(stix_data, dict):
|
|
|
|
# adding python dict (of either Bundle or STIX obj)
|
2018-06-30 00:38:04 +02:00
|
|
|
if stix_data['type'] == 'bundle':
|
2018-12-06 21:11:30 +01:00
|
|
|
bundle = parse(stix_data, allow_custom=self.allow_custom, version=version).serialize(encoding='utf-8', ensure_ascii=False)
|
2018-07-10 21:49:36 +02:00
|
|
|
elif 'spec_version' in stix_data:
|
|
|
|
# If the spec_version is present, use new Bundle object...
|
2018-11-01 12:57:09 +01:00
|
|
|
bundle = v21.Bundle(stix_data, allow_custom=self.allow_custom).serialize(encoding='utf-8', ensure_ascii=False)
|
2017-09-22 17:29:17 +02:00
|
|
|
else:
|
2018-07-10 21:49:36 +02:00
|
|
|
bundle = v20.Bundle(stix_data, allow_custom=self.allow_custom).serialize(encoding='utf-8', ensure_ascii=False)
|
2017-09-22 17:29:17 +02:00
|
|
|
|
|
|
|
elif isinstance(stix_data, list):
|
|
|
|
# adding list of something - recurse on each
|
|
|
|
for obj in stix_data:
|
2018-12-06 21:11:30 +01:00
|
|
|
self.add(obj, version=version)
|
2018-03-19 17:03:25 +01:00
|
|
|
return
|
2017-09-29 17:24:19 +02:00
|
|
|
|
2017-09-22 17:29:17 +02:00
|
|
|
elif isinstance(stix_data, str):
|
|
|
|
# adding json encoded string of STIX content
|
2018-12-06 21:11:30 +01:00
|
|
|
stix_data = parse(stix_data, allow_custom=self.allow_custom, version=version)
|
2018-06-30 00:38:04 +02:00
|
|
|
if stix_data['type'] == 'bundle':
|
2018-07-10 21:49:36 +02:00
|
|
|
bundle = stix_data.serialize(encoding='utf-8', ensure_ascii=False)
|
|
|
|
elif 'spec_version' in stix_data:
|
|
|
|
# If the spec_version is present, use new Bundle object...
|
2018-11-01 12:57:09 +01:00
|
|
|
bundle = v21.Bundle(stix_data, allow_custom=self.allow_custom).serialize(encoding='utf-8', ensure_ascii=False)
|
2017-09-22 17:29:17 +02:00
|
|
|
else:
|
2018-07-10 21:49:36 +02:00
|
|
|
bundle = v20.Bundle(stix_data, allow_custom=self.allow_custom).serialize(encoding='utf-8', ensure_ascii=False)
|
2017-09-22 17:29:17 +02:00
|
|
|
|
2017-09-29 17:24:19 +02:00
|
|
|
else:
|
|
|
|
raise TypeError("stix_data must be as STIX object(or list of),json formatted STIX (or list of), or a json formatted STIX bundle")
|
2017-05-24 17:25:40 +02:00
|
|
|
|
2017-09-29 17:24:19 +02:00
|
|
|
self.collection.add_objects(bundle)
|
2017-05-24 17:25:40 +02:00
|
|
|
|
2017-07-12 16:58:31 +02:00
|
|
|
|
|
|
|
class TAXIICollectionSource(DataSource):
|
2017-09-29 17:24:19 +02:00
|
|
|
"""Provides an interface for searching/retrieving STIX objects
|
2017-09-22 17:29:17 +02:00
|
|
|
from a local/remote TAXII Collection endpoint.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
collection (taxii2.Collection): TAXII Collection instance
|
2017-11-29 18:03:10 +01:00
|
|
|
allow_custom (bool): Whether to allow custom STIX content to be
|
|
|
|
added to the FileSystemSink. Default: True
|
2020-12-21 23:53:53 +01:00
|
|
|
items_per_page (int): How many STIX objects to request per call
|
2021-02-02 06:04:04 +01:00
|
|
|
to TAXII Server. The value can be tuned, but servers may override
|
2020-12-21 23:53:53 +01:00
|
|
|
if their internal limit is surpassed.
|
2017-09-22 17:29:17 +02:00
|
|
|
|
2017-07-12 16:58:31 +02:00
|
|
|
"""
|
2020-12-21 23:53:53 +01:00
|
|
|
def __init__(self, collection, allow_custom=True, items_per_page=5000):
|
2017-09-01 14:15:50 +02:00
|
|
|
super(TAXIICollectionSource, self).__init__()
|
2018-05-15 21:41:46 +02:00
|
|
|
if not _taxii2_client:
|
|
|
|
raise ImportError("taxii2client library is required for usage of TAXIICollectionSource")
|
|
|
|
|
2018-05-15 17:28:34 +02:00
|
|
|
try:
|
2018-05-15 21:41:46 +02:00
|
|
|
if collection.can_read:
|
|
|
|
self.collection = collection
|
|
|
|
else:
|
2018-07-13 17:10:05 +02:00
|
|
|
raise DataSourceError(
|
|
|
|
"The TAXII Collection object provided does not have read access"
|
|
|
|
" to the underlying linked Collection resource",
|
|
|
|
)
|
2018-05-15 21:41:46 +02:00
|
|
|
|
|
|
|
except (HTTPError, ValidationError) as e:
|
2018-07-13 17:10:05 +02:00
|
|
|
raise DataSourceError(
|
|
|
|
"The underlying TAXII Collection resource defined in the supplied TAXII"
|
|
|
|
" Collection object provided could not be reached. Recieved error:", e,
|
|
|
|
)
|
2018-05-15 17:28:34 +02:00
|
|
|
|
2017-11-29 18:03:10 +01:00
|
|
|
self.allow_custom = allow_custom
|
2020-12-21 23:53:53 +01:00
|
|
|
self.items_per_page = items_per_page
|
2017-07-12 16:58:31 +02:00
|
|
|
|
2018-12-06 21:11:30 +01:00
|
|
|
def get(self, stix_id, version=None, _composite_filters=None):
|
2017-10-24 15:15:09 +02:00
|
|
|
"""Retrieve STIX object from local/remote STIX Collection
|
2017-09-22 17:29:17 +02:00
|
|
|
endpoint.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
stix_id (str): The STIX ID of the STIX object to be retrieved.
|
2018-12-06 21:11:30 +01:00
|
|
|
version (str): If present, it forces the parser to use the version
|
|
|
|
provided. Otherwise, the library will make the best effort based
|
|
|
|
on checking the "spec_version" property.
|
2018-07-10 21:49:36 +02:00
|
|
|
_composite_filters (FilterSet): collection of filters passed from
|
|
|
|
the parent CompositeDataSource, not user supplied
|
2017-09-22 17:29:17 +02:00
|
|
|
|
|
|
|
Returns:
|
|
|
|
(STIX object): STIX object that has the supplied STIX ID.
|
|
|
|
The STIX object is received from TAXII has dict, parsed into
|
|
|
|
a python STIX object and then returned
|
|
|
|
|
2017-07-12 16:58:31 +02:00
|
|
|
"""
|
|
|
|
# combine all query filters
|
2018-04-11 19:36:52 +02:00
|
|
|
query = FilterSet()
|
|
|
|
|
2017-09-29 17:24:19 +02:00
|
|
|
if self.filters:
|
2018-04-11 19:36:52 +02:00
|
|
|
query.add(self.filters)
|
2017-07-12 16:58:31 +02:00
|
|
|
if _composite_filters:
|
2018-04-11 19:36:52 +02:00
|
|
|
query.add(_composite_filters)
|
2017-05-24 17:25:40 +02:00
|
|
|
|
2018-07-10 21:49:36 +02:00
|
|
|
# don't extract TAXII filters from query (to send to TAXII endpoint)
|
|
|
|
# as directly retrieving a STIX object by ID
|
2017-11-16 23:47:27 +01:00
|
|
|
try:
|
2018-06-30 00:38:04 +02:00
|
|
|
stix_objs = self.collection.get_object(stix_id)['objects']
|
2017-11-16 23:47:27 +01:00
|
|
|
stix_obj = list(apply_common_filters(stix_objs, query))
|
2017-05-24 17:25:40 +02:00
|
|
|
|
2018-05-16 19:23:50 +02:00
|
|
|
except HTTPError as e:
|
|
|
|
if e.response.status_code == 404:
|
2018-07-10 21:49:36 +02:00
|
|
|
# if resource not found or access is denied from TAXII server,
|
|
|
|
# return None
|
2018-05-15 17:28:34 +02:00
|
|
|
stix_obj = []
|
|
|
|
else:
|
2018-05-16 19:23:50 +02:00
|
|
|
raise DataSourceError("TAXII Collection resource returned error", e)
|
2017-05-24 17:25:40 +02:00
|
|
|
|
2017-09-29 17:24:19 +02:00
|
|
|
if len(stix_obj):
|
2018-12-06 21:11:30 +01:00
|
|
|
stix_obj = parse(stix_obj[0], allow_custom=self.allow_custom, version=version)
|
2020-09-29 17:21:02 +02:00
|
|
|
if stix_obj['id'] != stix_id:
|
2017-10-25 20:36:20 +02:00
|
|
|
# check - was added to handle erroneous TAXII servers
|
|
|
|
stix_obj = None
|
2017-07-12 16:58:31 +02:00
|
|
|
else:
|
|
|
|
stix_obj = None
|
2017-05-24 17:25:40 +02:00
|
|
|
|
2017-10-06 16:56:24 +02:00
|
|
|
return stix_obj
|
2017-05-24 17:25:40 +02:00
|
|
|
|
2018-12-06 21:11:30 +01:00
|
|
|
def all_versions(self, stix_id, version=None, _composite_filters=None):
|
2017-10-24 15:15:09 +02:00
|
|
|
"""Retrieve STIX object from local/remote TAXII Collection
|
2017-09-22 17:29:17 +02:00
|
|
|
endpoint, all versions of it
|
|
|
|
|
|
|
|
Args:
|
|
|
|
stix_id (str): The STIX ID of the STIX objects to be retrieved.
|
2018-12-06 21:11:30 +01:00
|
|
|
version (str): If present, it forces the parser to use the version
|
|
|
|
provided. Otherwise, the library will make the best effort based
|
|
|
|
on checking the "spec_version" property.
|
2018-04-11 19:36:52 +02:00
|
|
|
_composite_filters (FilterSet): collection of filters passed from the parent
|
2017-09-22 17:29:17 +02:00
|
|
|
CompositeDataSource, not user supplied
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
(see query() as all_versions() is just a wrapper)
|
|
|
|
|
2017-05-26 21:24:33 +02:00
|
|
|
"""
|
2017-05-24 17:25:40 +02:00
|
|
|
# make query in TAXII query format since 'id' is TAXII field
|
|
|
|
query = [
|
2018-06-30 00:38:04 +02:00
|
|
|
Filter('id', '=', stix_id),
|
2018-07-13 17:10:05 +02:00
|
|
|
Filter('version', '=', 'all'),
|
2017-05-24 17:25:40 +02:00
|
|
|
]
|
|
|
|
|
2017-11-29 18:03:10 +01:00
|
|
|
all_data = self.query(query=query, _composite_filters=_composite_filters)
|
2017-05-24 17:25:40 +02:00
|
|
|
|
2017-10-25 20:36:20 +02:00
|
|
|
# parse STIX objects from TAXII returned json
|
2018-12-06 21:11:30 +01:00
|
|
|
all_data = [parse(stix_obj, allow_custom=self.allow_custom, version=version) for stix_obj in all_data]
|
2017-10-25 20:36:20 +02:00
|
|
|
|
|
|
|
# check - was added to handle erroneous TAXII servers
|
2020-09-29 17:21:02 +02:00
|
|
|
all_data_clean = [stix_obj for stix_obj in all_data if stix_obj['id'] == stix_id]
|
2017-10-25 20:36:20 +02:00
|
|
|
|
|
|
|
return all_data_clean
|
2017-05-24 17:25:40 +02:00
|
|
|
|
2018-12-06 21:11:30 +01:00
|
|
|
def query(self, query=None, version=None, _composite_filters=None):
|
2017-10-24 15:15:09 +02:00
|
|
|
"""Search and retreive STIX objects based on the complete query
|
2017-09-22 17:29:17 +02:00
|
|
|
|
|
|
|
A "complete query" includes the filters from the query, the filters
|
|
|
|
attached to MemorySource, and any filters passed from a
|
|
|
|
CompositeDataSource (i.e. _composite_filters)
|
|
|
|
|
|
|
|
Args:
|
|
|
|
query (list): list of filters to search on
|
2018-12-06 21:11:30 +01:00
|
|
|
version (str): If present, it forces the parser to use the version
|
|
|
|
provided. Otherwise, the library will make the best effort based
|
|
|
|
on checking the "spec_version" property.
|
2018-07-10 21:49:36 +02:00
|
|
|
_composite_filters (FilterSet): collection of filters passed from
|
|
|
|
the CompositeDataSource, not user supplied
|
2017-09-22 17:29:17 +02:00
|
|
|
|
|
|
|
Returns:
|
|
|
|
(list): list of STIX objects that matches the supplied
|
|
|
|
query. The STIX objects are received from TAXII as dicts,
|
|
|
|
parsed into python STIX objects and then returned.
|
|
|
|
|
2017-05-26 21:24:33 +02:00
|
|
|
"""
|
2018-04-11 19:36:52 +02:00
|
|
|
query = FilterSet(query)
|
2017-05-24 17:25:40 +02:00
|
|
|
|
|
|
|
# combine all query filters
|
2017-09-29 17:24:19 +02:00
|
|
|
if self.filters:
|
2018-04-11 19:36:52 +02:00
|
|
|
query.add(self.filters)
|
2017-05-24 17:25:40 +02:00
|
|
|
if _composite_filters:
|
2018-04-11 19:36:52 +02:00
|
|
|
query.add(_composite_filters)
|
2017-05-24 17:25:40 +02:00
|
|
|
|
2018-03-21 22:19:05 +01:00
|
|
|
# parse taxii query params (that can be applied remotely)
|
2017-05-24 17:25:40 +02:00
|
|
|
taxii_filters = self._parse_taxii_filters(query)
|
|
|
|
|
2018-03-21 22:19:05 +01:00
|
|
|
# taxii2client requires query params as keywords
|
|
|
|
taxii_filters_dict = dict((f.property, f.value) for f in taxii_filters)
|
|
|
|
|
2017-07-12 16:58:31 +02:00
|
|
|
# query TAXII collection
|
2020-12-21 23:53:53 +01:00
|
|
|
all_data = []
|
2021-08-24 06:15:50 +02:00
|
|
|
paged_request = tcv21.as_pages if isinstance(self.collection, tcv21.Collection) else tcv20.as_pages
|
2017-11-16 23:47:27 +01:00
|
|
|
try:
|
2021-02-02 06:08:11 +01:00
|
|
|
for resource in paged_request(self.collection.get_objects, per_request=self.items_per_page, **taxii_filters_dict):
|
|
|
|
all_data.extend(resource.get("objects", []))
|
2018-05-15 23:42:19 +02:00
|
|
|
except HTTPError as e:
|
2017-11-16 23:47:27 +01:00
|
|
|
# if resources not found or access is denied from TAXII server, return empty list
|
2018-05-15 23:42:19 +02:00
|
|
|
if e.response.status_code == 404:
|
2018-07-13 17:10:05 +02:00
|
|
|
raise DataSourceError(
|
|
|
|
"The requested STIX objects for the TAXII Collection resource defined in"
|
|
|
|
" the supplied TAXII Collection object are either not found or access is"
|
|
|
|
" denied. Received error: ", e,
|
|
|
|
)
|
2021-08-24 21:04:05 +02:00
|
|
|
|
|
|
|
# TAXII 2.0 paging can result in a 416 (Range Not Satisfiable) if
|
|
|
|
# the server isn't sending Content-Range headers, so the pager just
|
|
|
|
# goes until it runs out of pages. So 416 can't be treated as a
|
|
|
|
# real error, just an end-of-pages condition. For other codes,
|
|
|
|
# propagate the exception.
|
2021-08-24 06:15:50 +02:00
|
|
|
elif e.response.status_code != 416:
|
|
|
|
raise
|
|
|
|
|
|
|
|
# deduplicate data (before filtering as reduces wasted filtering)
|
|
|
|
all_data = deduplicate(all_data)
|
|
|
|
|
|
|
|
# apply local (CompositeDataSource, TAXIICollectionSource and query) filters
|
|
|
|
query.remove(taxii_filters)
|
|
|
|
all_data = list(apply_common_filters(all_data, query))
|
2017-05-24 17:25:40 +02:00
|
|
|
|
2017-09-22 17:29:17 +02:00
|
|
|
# parse python STIX objects from the STIX object dicts
|
2018-12-06 21:11:30 +01:00
|
|
|
stix_objs = [parse(stix_obj_dict, allow_custom=self.allow_custom, version=version) for stix_obj_dict in all_data]
|
2017-09-22 17:29:17 +02:00
|
|
|
|
|
|
|
return stix_objs
|
2017-05-24 17:25:40 +02:00
|
|
|
|
|
|
|
def _parse_taxii_filters(self, query):
|
2018-03-21 22:19:05 +01:00
|
|
|
"""Parse out TAXII filters that the TAXII server can filter on
|
|
|
|
|
|
|
|
Does not put in TAXII spec format as the TAXII2Client (that we use)
|
|
|
|
does this for us.
|
|
|
|
|
2018-11-30 15:39:05 +01:00
|
|
|
Note:
|
2018-03-21 22:19:05 +01:00
|
|
|
Currently, the TAXII2Client can handle TAXII filters where the
|
2018-07-10 21:49:36 +02:00
|
|
|
filter value is list, as both a comma-seperated string or python
|
|
|
|
list.
|
2017-05-24 17:25:40 +02:00
|
|
|
|
2018-03-21 22:19:05 +01:00
|
|
|
For instance - "?match[type]=indicator,sighting" can be in a
|
|
|
|
filter in any of these formats:
|
|
|
|
|
|
|
|
Filter("type", "<any op>", "indicator,sighting")
|
|
|
|
Filter("type", "<any op>", ["indicator", "sighting"])
|
2017-08-11 14:10:20 +02:00
|
|
|
|
2017-05-24 17:25:40 +02:00
|
|
|
Args:
|
2018-04-11 19:36:52 +02:00
|
|
|
query (list): list of filters to extract which ones are TAXII
|
2017-05-26 21:24:33 +02:00
|
|
|
specific.
|
2017-05-24 17:25:40 +02:00
|
|
|
|
2018-04-23 20:11:08 +02:00
|
|
|
Returns:
|
|
|
|
A list of TAXII filters that meet the TAXII filtering parameters.
|
2017-05-24 17:25:40 +02:00
|
|
|
|
2017-08-11 14:10:20 +02:00
|
|
|
"""
|
2018-04-11 19:36:52 +02:00
|
|
|
taxii_filters = []
|
2017-05-24 17:25:40 +02:00
|
|
|
|
2017-07-12 16:58:31 +02:00
|
|
|
for filter_ in query:
|
2017-11-01 15:40:10 +01:00
|
|
|
if filter_.property in TAXII_FILTERS:
|
2018-04-11 19:36:52 +02:00
|
|
|
taxii_filters.append(filter_)
|
2018-03-21 22:19:05 +01:00
|
|
|
|
|
|
|
return taxii_filters
|